最近在分析安卓的FirstStageMount阶段,这部分代码量还是挺大的,而且不容易理解,所以记录一下自己学习的心得和成果。本文都是基于Android S来分析的。
源码地址如下:Android S源码
1.引言
根据安卓的启动流程,从Kernel进入到Init进程后,首先会执行FirstStageMain ,里面又分为第一阶段挂在DoFirstStageMount 和第二部分selinux_setup配置 ,这个系列的文章会分析DoFirstStageMount所有的流程;
int FirstStageMain(int argc, char** argv) {
if (!DoFirstStageMount(!created_devices)) {
LOG(FATAL) << "Failed to mount required partitions early ...";
}
}
2.开始DoFirstStageMount
bool DoFirstStageMount(bool create_devices) {
auto fsm = FirstStageMount::Create();
if (!fsm.ok()) {
LOG(ERROR) << "Failed to create FirstStageMount " << fsm.error();
return false;
}
if (create_devices) {
if (!(*fsm)->DoCreateDevices()) return false;
}
return (*fsm)->DoFirstStageMount();
}
可以看到DoFirstStageMount的做了两件事,分别为:
- 调用FirstStageMount类的Create方法,返回一个参数fsm【大概率跟FirstStageMount有关,因为第二部分调用了它的DoFirstStageMount方法】
- 第二部分,调用FirstStageMount类的DoFirstStageMount方法
本文先讲解第一部分Create 方法
3.FirstStageMount::Create()
Result<std::unique_ptr<FirstStageMount>> FirstStageMount::Create() {
auto fstab = ReadFirstStageFstab();
if (!fstab.ok()) {
return fstab.error();
}
if (IsDtVbmetaCompatible(*fstab)) {
return std::make_unique<FirstStageMountVBootV2>(std::move(*fstab));
} else {
return std::make_unique<FirstStageMountVBootV1>(std::move(*fstab));
}
}
3.1 ReadFirstStageFstab
static Result<Fstab> ReadFirstStageFstab() {
Fstab fstab;
if (!ReadFstabFromDt(&fstab)) {
if (ReadDefaultFstab(&fstab)) {
fstab.erase(std::remove_if(fstab.begin(), fstab.end(),
[](const auto& entry) {
return !entry.fs_mgr_flags.first_stage_mount;
}),
fstab.end());
} else {
return Error() << "failed to read default fstab for first stage mount";
}
}
return fstab;
}
从函数的字面意思,我们大致推断:
- 先从设备树文件中读取Fstab文件【ReadFstabFromDt】
- 如果失败了, 就去读取默认的Fstab文件;并且删除其中
fs_mgr_flags 中没有first_stage_mount 不为1的,也就是这个参数没有设置
3.2 ReadFstabFromDt
bool ReadDefaultFstab(Fstab* fstab) {
fstab->clear();
ReadFstabFromDt(fstab, false );
std::string default_fstab_path;
if (access("/system/bin/recovery", F_OK) == 0) {
default_fstab_path = "/etc/recovery.fstab";
} else {
default_fstab_path = GetFstabPath();
}
Fstab default_fstab;
if (!default_fstab_path.empty() && ReadFstabFromFile(default_fstab_path, &default_fstab)) {
for (auto&& entry : default_fstab) {
fstab->emplace_back(std::move(entry));
}
} else {
LINFO << __FUNCTION__ << "(): failed to find device default fstab";
}
return !fstab->empty();
}
-------------------------------------------------------------------------------------
bool ReadFstabFromDt(Fstab* fstab, bool verbose) {
std::string fstab_buf = ReadFstabFromDt();
if (fstab_buf.empty()) {
if (verbose) LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
return false;
}
std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
fstab_buf.length(), "r"), fclose);
if (!fstab_file) {
if (verbose) PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
return false;
}
if (!ReadFstabFile(fstab_file.get(), false, fstab)) {
if (verbose) {
LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl
<< fstab_buf;
}
return false;
}
SkipMountingPartitions(fstab, verbose);
return true;
}
-------------------------------------------------------------------------------------
std::string ReadFstabFromDt() {
std::string fstabdir_name = get_android_dt_dir() + "/fstab";
std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
if (!fstabdir) return {};
dirent* dp;
std::vector<std::pair<std::string, std::string>> fstab_dt_entries;
while ((dp = readdir(fstabdir.get())) != NULL) {
if (dp->d_type != DT_DIR || dp->d_name[0] == '.') continue;
std::vector<std::string> fstab_entry;
std::string file_name;
std::string value;
file_name = android::base::StringPrintf("%s/%s/status", fstabdir_name.c_str(), dp->d_name);
if (ReadDtFile(file_name, &value)) {
if (value != "okay" && value != "ok") {
LINFO << "dt_fstab: Skip disabled entry for partition " << dp->d_name;
continue;
}
}
file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
if (!ReadDtFile(file_name, &value)) {
LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
return {};
}
fstab_entry.push_back(value);
std::string mount_point;
file_name =
android::base::StringPrintf("%s/%s/mnt_point", fstabdir_name.c_str(), dp->d_name);
if (ReadDtFile(file_name, &value)) {
LINFO << "dt_fstab: Using a specified mount point " << value << " for " << dp->d_name;
mount_point = value;
} else {
mount_point = android::base::StringPrintf("/%s", dp->d_name);
}
fstab_entry.push_back(mount_point);
file_name = android::base::StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
if (!ReadDtFile(file_name, &value)) {
LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
return {};
}
fstab_entry.push_back(value);
file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
if (!ReadDtFile(file_name, &value)) {
LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
return {};
}
fstab_entry.push_back(value);
file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
if (!ReadDtFile(file_name, &value)) {
LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
return {};
}
fstab_entry.push_back(value);
fstab_dt_entries.emplace_back(mount_point, android::base::Join(fstab_entry, " "));
}
std::sort(fstab_dt_entries.begin(), fstab_dt_entries.end(),
[](const auto& a, const auto& b) { return a.first < b.first; });
std::string fstab_result;
for (const auto& [_, dt_entry] : fstab_dt_entries) {
fstab_result += dt_entry + "\n";
}
return fstab_result;
}
调用栈分别为:bool ReadDefaultFstab(Fstab* fstab) -> bool ReadFstabFromDt(Fstab* fstab, bool verbose) ->std::string ReadFstabFromDt() ,所以我们选择从后往前看
3.2.1 std::string ReadFstabFromDt()
这个函数会去读取fstab文件中的值,然后返回一个字符串,这个字符串以\n 分割 每一个\n分割的是不同的一个fstab_entry,其格式为<dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n
3.2.2 bool ReadFstabFromDt(Fstab* fstab, bool verbose)
bool ReadFstabFromDt(Fstab* fstab, bool verbose) {
std::string fstab_buf = ReadFstabFromDt();
std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
fstab_buf.length(), "r"), fclose);
if (!ReadFstabFile(fstab_file.get(), false, fstab)) {
if (verbose) {
LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl
<< fstab_buf;
}
return false;
}
SkipMountingPartitions(fstab, verbose);
return true;
}
3.2.3 ReadFstabFile
bool ReadFstabFile(FILE* fstab_file, bool proc_mounts, Fstab* fstab_out) {
ssize_t len;
size_t alloc_len = 0;
char *line = NULL;
const char *delim = " \t";
char *save_ptr, *p;
Fstab fstab;
while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
if (line[len - 1] == '\n') {
line[len - 1] = '\0';
}
p = line;
while (isspace(*p)) {
p++;
}
if (*p == '#' || *p == '\0')
continue;
FstabEntry entry;
if (!(p = strtok_r(line, delim, &save_ptr))) {
LERROR << "Error parsing mount source";
goto err;
}
entry.blk_device = p;
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing mount_point";
goto err;
}
entry.mount_point = p;
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing fs_type";
goto err;
}
entry.fs_type = p;
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing mount_flags";
goto err;
}
ParseMountFlags(p, &entry);
if (proc_mounts) {
p += strlen(p);
} else if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing fs_mgr_options";
goto err;
}
ParseFsMgrFlags(p, &entry);
if (entry.fs_mgr_flags.logical) {
entry.logical_partition_name = entry.blk_device;
}
fstab.emplace_back(std::move(entry));
}
if (fstab.empty()) {
LERROR << "No entries found in fstab";
goto err;
}
if (!fs_mgr_update_for_slotselect(&fstab)) {
LERROR << "Error updating for slotselect";
goto err;
}
free(line);
*fstab_out = std::move(fstab);
return true;
err:
free(line);
return false;
}
这个函数主要的作用我们可以分析一下:
- 将前面3.2.1的fstabEntry字符串正式映射成
FstabEntry 对象,然后将其放在Fstab 中 - 最后还要判断一下是不是包含A/B分区的,如果是AB分区的,调用fs_mgr_update_for_slotselect
- 如果是AB分区fs_mgr_update_for_slotselect添加逻辑分区的后缀
bool fs_mgr_update_for_slotselect(Fstab* fstab) {
std::string ab_suffix;
for (auto& entry : *fstab) {
if (!entry.fs_mgr_flags.slot_select && !entry.fs_mgr_flags.slot_select_other) {
continue;
}
if (ab_suffix.empty()) {
ab_suffix = fs_mgr_get_slot_suffix();
if (ab_suffix.empty()) return false;
}
const auto& update_suffix =
entry.fs_mgr_flags.slot_select ? ab_suffix : other_suffix(ab_suffix);
entry.blk_device = entry.blk_device + update_suffix;
entry.logical_partition_name = entry.logical_partition_name + update_suffix;
}
return true;
}
3.2.4 bool ReadDefaultFstab(Fstab* fstab)
bool ReadDefaultFstab(Fstab* fstab) {
fstab->clear();
ReadFstabFromDt(fstab, false );
std::string default_fstab_path;
if (access("/system/bin/recovery", F_OK) == 0) {
default_fstab_path = "/etc/recovery.fstab";
} else {
default_fstab_path = GetFstabPath();
}
Fstab default_fstab;
if (!default_fstab_path.empty() && ReadFstabFromFile(default_fstab_path, &default_fstab)) {
for (auto&& entry : default_fstab) {
fstab->emplace_back(std::move(entry));
}
} else {
LINFO << __FUNCTION__ << "(): failed to find device default fstab";
}
return !fstab->empty();
}
4.总结
这里画一张流程图 2022.8.1 22:59身体不适,等身体好了再画
|