最近在分析安卓的FirstStageMount阶段,这部分代码量还是挺大的,而且不容易理解,所以记录一下自己学习的心得和成果。本文都是基于Android S来分析的。
源码地址如下:Android S源码
根据安卓的启动流程,从Kernel进入到Init进程后,首先会执行FirstStageMain
,里面又分为第一阶段挂在DoFirstStageMount
和第二部分selinux_setup配置
,这个系列的文章会分析DoFirstStageMount所有的流程;
// 路径:/system/core/init/first_stage_init.cpp
int FirstStageMain(int argc, char** argv) {
// ...
if (!DoFirstStageMount(!created_devices)) {
LOG(FATAL) << "Failed to mount required partitions early ...";
}
// ...
}
// 路径: /system/core/init/first_stage_mount.cpp
// 在设备树中挂载由fstab文件指定的分区
bool DoFirstStageMount(bool create_devices) {
// -----------------------------第一部分-----------------------------
auto fsm = FirstStageMount::Create();
if (!fsm.ok()) {
LOG(ERROR) << "Failed to create FirstStageMount " << fsm.error();
return false;
}
// ...这边是判断之前是否创建过devices,可以打印Log看一下,显然之前没有创建过,所以这里是False
if (create_devices) {
if (!(*fsm)->DoCreateDevices()) return false;
}
// -----------------------------第二部分-----------------------------
return (*fsm)->DoFirstStageMount();
}
可以看到DoFirstStageMount的做了两件事,分别为:
本文先讲解第一部分
Create
方法
// 路径:/system/core/init/first_stage_mount.cpp
Result<std::unique_ptr<FirstStageMount>> FirstStageMount::Create() {
// 读取第一阶段的Fstab文件
auto fstab = ReadFirstStageFstab();
if (!fstab.ok()) {
return fstab.error();
}
// AVB2应该返回一个由fstab转译的独占指针【这里也说名了第二部分的fsm指针是啥】
if (IsDtVbmetaCompatible(*fstab)) {
return std::make_unique<FirstStageMountVBootV2>(std::move(*fstab));
} else {
return std::make_unique<FirstStageMountVBootV1>(std::move(*fstab));
}
}
// 路径: /system/core/init/first_stage_mount.cpp
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;
}
从函数的字面意思,我们大致推断:
fs_mgr_flags
中没有first_stage_mount
不为1的,也就是这个参数没有设置// 路径: /system/core/fs_mgr/fs_mgr_fstab.cpp
bool ReadDefaultFstab(Fstab* fstab) {
fstab->clear();
// 调用ReadFstabFromDt(fstab, false)重载函数
ReadFstabFromDt(fstab, false /* verbose */);
std::string default_fstab_path;
// Use different fstab paths for normal boot and recovery boot, respectively
if (access("/system/bin/recovery", F_OK) == 0) {
default_fstab_path = "/etc/recovery.fstab";
} else { // normal boot
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();
}
-------------------------------------------------------------------------------------
// Returns fstab entries parsed from the device tree if they exist
bool ReadFstabFromDt(Fstab* fstab, bool verbose) {
// 调用ReadFstabFromDt()重载函数
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() {
// ...
// 拼接设备树地址 + "/fstab"
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;
// 每一个元素fstab_dt_entries is .
std::vector<std::pair<std::string, std::string>> fstab_dt_entries;
while ((dp = readdir(fstabdir.get())) != NULL) {
// skip over name, compatible and .
if (dp->d_type != DT_DIR || dp->d_name[0] == '.') continue;
// 创建fstab_entry,格式为: \n
// 将fstab文件中key-value键值对放到fstab_entry中
std::vector<std::string> fstab_entry;
std::string file_name;
std::string value;
// skip a partition entry if the status property is present and not set to ok
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_entry添加到fstab_dt_entries中
fstab_dt_entries.emplace_back(mount_point, android::base::Join(fstab_entry, " "));
}
// 根据挂载点mount_point对fstab_dt_entries进行排序,确保/vendor在/vendor/xxx前
std::sort(fstab_dt_entries.begin(), fstab_dt_entries.end(),
[](const auto& a, const auto& b) { return a.first < b.first; });
// 返回fstab中读取的值,放到fstab_result中返回
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()
,所以我们选择从后往前看
这个函数会去读取fstab文件中的值,然后返回一个字符串,这个字符串以\n
分割
每一个\n分割的是不同的一个fstab_entry,其格式为
bool ReadFstabFromDt(Fstab* fstab, bool verbose) {
// 获取从ReadFstabFromDt读取到的FstEntry字符串
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);
// 调用ReadFstabFile
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;
}
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 the last character is a newline, shorten the string by 1 byte */
if (line[len - 1] == '\n') {
line[len - 1] = '\0';
}
/* Skip any leading whitespace */
p = line;
while (isspace(*p)) {
p++;
}
/* ignore comments or empty lines */
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);
// For /proc/mounts, ignore everything after mnt_freq and mnt_passno
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 an A/B partition, modify block device to be the real block device */
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;
}
这个函数主要的作用我们可以分析一下:
FstabEntry
对象,然后将其放在Fstab
中// 路径:/system/core/fs_mgr/fs_mgr_slotselect.cpp
bool fs_mgr_update_for_slotselect(Fstab* fstab) {
std::string ab_suffix;
for (auto& entry : *fstab) {
// slot_select 为非0 且 slot_select_other 为非0【这种是错的,不存在这种两个都是非0的,检查dts文件吧】
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();
// Return false if failed to get ab_suffix when MF_SLOTSELECT is specified.
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逻辑分区的名字 += update_suffix
// 如果是AB分区的话应该是 system_a或者vendor_a之类的
entry.logical_partition_name = entry.logical_partition_name + update_suffix;
}
return true;
}
bool ReadDefaultFstab(Fstab* fstab) {
fstab->clear();
// 调用ReadFstabFromDt(fstab, false)重载函数
ReadFstabFromDt(fstab, false /* verbose */);
std::string default_fstab_path;
// Use different fstab paths for normal boot and recovery boot, respectively
if (access("/system/bin/recovery", F_OK) == 0) {
default_fstab_path = "/etc/recovery.fstab";
} else { // normal boot
default_fstab_path = GetFstabPath();
}
// 添加正常启动normal boot的路径中的Fst文件
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();
}
这里画一张流程图
2022.8.1 22:59身体不适,等身体好了再画