First stage init
目录
- 概述
- 源码解析
- 1. first stage init-还在内核上下文中
- 2. FirstStageMount类
- 2.1 Create-读fstab文件,创建FirstStageMountVBootV2类
- 2.2 IsDtVbmetaCompatible-看dts是否配置vbmeta和fstab配置了avb
- 2.3 FirstStageMount-构造函数,获取super分区名字,super分区不一定叫super
- 2.4 DoFirstStageMount-创建分区设备节点,挂载分区
- 2.5 IsDmLinearEnabled-logical标志
- 2.6 InitDevices-创建device-mapper和分区设备和super分区设备
- 2.7 InitRequiredDevices-创建device-mapper设备节点,以及vbmeta,vbmeta_system,vbmeta_vendor,boot,super块设备节点和链接
- 2.8 MountPartitions-挂载metadata,system,product,vendor分区,以及remount相关
- 2.9 MountPartition-创建逻辑分区,dm设备,挂载分区
- 2.10 CopyDsuAvbKeys-拷贝avb keys到metadata目录中
- 2.11 CreateLogicalPartitions-创建逻辑分区
- 2.12 InitDmLinearBackingDevices-初始化blockdevice,super分区在之前早就初始化好了,所以这里什么都没做
- 2.13 TrySwitchSystemAsRoot-挂载system分区并设为根目录
- 2.14 PreloadAvbKeys-读/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey文件,放到preload_avb_key_blobs_中
- 3. FirstStageMountVBootV2类
- 4. util类
- 5. BlockDevInitializer类
- 6. DeviceHandler类
- 7. UeventListener类
- 8. switch root模块
- 9. FirstStageConsole模块
- 补充
- 问题
- 参考
概述
1. 进行第一阶段挂载工作
主要工作:
1. 读dts中的fstab,以及fstab文件
2. 创建分区的设备节点,设备节点的文件链接。dm设备
3. 配置avb,创建dm-verity设备
4. 挂载分区
5. 将根目录切换到/system目录下
源码解析
android/system/core/init/first_stage_main.cpp
android/system/core/init/first_stage_init.cpp
android/system/core/init/first_stage_mount.cpp
1. first stage init-还在内核上下文中
1.1 main
int main(int argc, char** argv) {
return android::init::FirstStageMain(argc, argv);
}
1.2 FirstStageMain
int FirstStageMain(int argc, char** argv) {
// 配置panic的时候重启到bootloader
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
}
boot_clock::time_point start_time = boot_clock::now();
std::vector<std::pair<std::string, int>> errors;
#define CHECKCALL(x) \
if ((x) != 0) errors.emplace_back(#x " failed", errno);
// Clear the umask.
umask(0);
CHECKCALL(clearenv());
CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));
// Get the basic filesystem setup we need put together in the initramdisk
// on / and then we'll let the rc file figure out the rest.
CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
CHECKCALL(mkdir("/dev/pts", 0755));
CHECKCALL(mkdir("/dev/socket", 0755));
CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
#define MAKE_STR(x) __STRING(x)
CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
#undef MAKE_STR
// Don't expose the raw commandline to unprivileged processes.
CHECKCALL(chmod("/proc/cmdline", 0440));
std::string cmdline;
android::base::ReadFileToString("/proc/cmdline", &cmdline);
gid_t groups[] = {AID_READPROC};
CHECKCALL(setgroups(arraysize(groups), groups));
CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));
CHECKCALL(mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11)));
if constexpr (WORLD_WRITABLE_KMSG) {
CHECKCALL(mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11)));
}
CHECKCALL(mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8)));
CHECKCALL(mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9)));
// This is needed for log wrapper, which gets called before ueventd runs.
CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2)));
CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3)));
// These below mounts are done in first stage init so that first stage mount can mount
// subdirectories of /mnt/{vendor,product}/. Other mounts, not required by first stage mount,
// should be done in rc files.
// Mount staging areas for devices managed by vold
// See storage config details at http://source.android.com/devices/storage/
CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
"mode=0755,uid=0,gid=1000"));
// /mnt/vendor is used to mount vendor-specific partitions that can not be
// part of the vendor partition, e.g. because they are mounted read-write.
CHECKCALL(mkdir("/mnt/vendor", 0755));
// /mnt/product is used to mount product-specific partitions that can not be
// part of the product partition, e.g. because they are mounted read-write.
CHECKCALL(mkdir("/mnt/product", 0755));
// 挂载debug_ramdisk到tmpfs中
// /debug_ramdisk is used to preserve additional files from the debug ramdisk
CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
"mode=0755,uid=0,gid=0"));
#undef CHECKCALL
// std的输出,输出到null
SetStdioToDevNull(argv);
// Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
// talk to the outside world...
// 设置log输出到/dev/kmsg
InitKernelLogging(argv);
if (!errors.empty()) {
for (const auto& [error_string, error_errno] : errors) {
LOG(ERROR) << error_string << " " << strerror(error_errno);
}
LOG(FATAL) << "Init encountered errors starting first stage, aborting";
}
// 打印第一句LOG
LOG(INFO) << "init first stage started!";
auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir};
if (!old_root_dir) {
PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk";
}
struct stat old_root_info;
if (stat("/", &old_root_info) != 0) {
PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
old_root_dir.reset();
}
// 设置串口输出,userdebug版本默认开启
auto want_console = ALLOW_FIRST_STAGE_CONSOLE ? FirstStageConsole(cmdline) : 0;
// 加载内核模块
if (!LoadKernelModules(IsRecoveryMode() && !ForceNormalBoot(cmdline), want_console)) {
if (want_console != FirstStageConsoleParam::DISABLED) {
LOG(ERROR) << "Failed to load kernel modules, starting console";
} else {
LOG(FATAL) << "Failed to load kernel modules";
}
}
if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) {
StartConsole();
}
// 注意env.cfg中要配置androidboot.force_normal_boot=1,不然的话,刷gki会进recovery
// 限制ramdisk在/first_stage_ramdisk文件夹内
if (ForceNormalBoot(cmdline)) {
mkdir("/first_stage_ramdisk", 0755);
// SwitchRoot() must be called with a mount point as the target, so we bind mount the
// target directory to itself here.
if (mount("/first_stage_ramdisk", "/first_stage_ramdisk", nullptr, MS_BIND, nullptr) != 0) {
LOG(FATAL) << "Could not bind mount /first_stage_ramdisk to itself";
}
SwitchRoot("/first_stage_ramdisk");
}
// If this file is present, the second-stage init will use a userdebug sepolicy
// and load adb_debug.prop to allow adb root, if the device is unlocked.
if (access("/force_debuggable", F_OK) == 0) {
std::error_code ec; // to invoke the overloaded copy_file() that won't throw.
// 将adb_debug.prop和userdebug_plat_sepolicy.cil文件拷贝到/debug_ramdisk/adb_debug.prop和/debug_ramdisk/userdebug_plat_sepolicy.cil
if (!fs::copy_file("/adb_debug.prop", kDebugRamdiskProp, ec) ||
!fs::copy_file("/userdebug_plat_sepolicy.cil", kDebugRamdiskSEPolicy, ec)) {
LOG(ERROR) << "Failed to setup debug ramdisk";
} else {
// setenv for second-stage init to read above kDebugRamdisk* files.
// 然后在这里设1
setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
}
}
// 1. 进行第一阶段挂载
if (!DoFirstStageMount()) {
LOG(FATAL) << "Failed to mount required partitions early ...";
}
struct stat new_root_info;
if (stat("/", &new_root_info) != 0) {
PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
old_root_dir.reset();
}
if (old_root_dir && old_root_info.st_dev != new_root_info.st_dev) {
// 卸载了ramdisk了
FreeRamdisk(old_root_dir.get(), old_root_info.st_dev);
}
SetInitAvbVersionInRecovery();
setenv(kEnvFirstStageStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(),
1);
const char* path = "/system/bin/init";
const char* args[] = {path, "selinux_setup", nullptr};
auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
// 2. 第二阶段init,selinux_setup配置
execv(path, const_cast<char**>(args));
// execv() only returns if an error happened, in which case we
// panic and never fall through this conditional.
PLOG(FATAL) << "execv(\"" << path << "\") failed";
return 1;
}
bool ForceNormalBoot(const std::string& cmdline) {
return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos;
}
1.3 DoFirstStageMount-进行第一阶段挂载
bool DoFirstStageMount() {
// Skips first stage mount if we're in recovery mode.
if (IsRecoveryMode()) {
LOG(INFO) << "First stage mount skipped (recovery mode)";
return true;
}
std::unique_ptr<FirstStageMount> handle = FirstStageMount::Create();
if (!handle) {
LOG(ERROR) << "Failed to create FirstStageMount";
return false;
}
return handle->DoFirstStageMount();
}
1.4 ReadFirstStageFstab-读fstab
static Fstab ReadFirstStageFstab() {
Fstab fstab;
// 从dts中读取fstab的值
if (!ReadFstabFromDt(&fstab)) {
// 读取/vendor/etc/fstab.sun50iw10p1文件
if (ReadDefaultFstab(&fstab)) {
fstab.erase(std::remove_if(fstab.begin(), fstab.end(),
[](const auto& entry) {
// 去掉没有first_stage_mount标志的
return !entry.fs_mgr_flags.first_stage_mount;
}),
fstab.end());
} else {
LOG(INFO) << "Failed to fstab for first stage mount";
}
}
return fstab;
}
1.5 LoadKernelModules-加载内核模块
#define MODULE_BASE_DIR "/lib/modules"
bool LoadKernelModules(bool recovery, bool want_console) {
struct utsname uts;
if (uname(&uts)) {
LOG(FATAL) << "Failed to get kernel version.";
}
int major, minor;
if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
LOG(FATAL) << "Failed to parse kernel version " << uts.release;
}
std::unique_ptr<DIR, decltype(&closedir)> base_dir(opendir(MODULE_BASE_DIR), closedir);
if (!base_dir) {
LOG(INFO) << "Unable to open /lib/modules, skipping module loading.";
return true;
}
dirent* entry;
std::vector<std::string> module_dirs;
while ((entry = readdir(base_dir.get()))) {
if (entry->d_type != DT_DIR) {
continue;
}
int dir_major, dir_minor;
if (sscanf(entry->d_name, "%d.%d", &dir_major, &dir_minor) != 2 || dir_major != major ||
dir_minor != minor) {
continue;
}
module_dirs.emplace_back(entry->d_name);
}
// Sort the directories so they are iterated over during module loading
// in a consistent order. Alphabetical sorting is fine here because the
// kernel version at the beginning of the directory name must match the
// current kernel version, so the sort only applies to a label that
// follows the kernel version, for example /lib/modules/5.4 vs.
// /lib/modules/5.4-gki.
std::sort(module_dirs.begin(), module_dirs.end());
//module_dirs是为空的,/lib/modules/下没有文件夹
for (const auto& module_dir : module_dirs) {
std::string dir_path = MODULE_BASE_DIR "/";
dir_path.append(module_dir);
Modprobe m({dir_path}, GetModuleLoadList(recovery, dir_path));
bool retval = m.LoadListedModules(!want_console);
int modules_loaded = m.GetModuleCount();
if (modules_loaded > 0) {
return retval;
}
}
// "/lib/modules","modules.load"
Modprobe m({MODULE_BASE_DIR}, GetModuleLoadList(recovery, MODULE_BASE_DIR));
bool retval = m.LoadListedModules(!want_console);
int modules_loaded = m.GetModuleCount();
if (modules_loaded > 0) {
return retval;
}
return true;
}
1.6 GetModuleLoadList
std::string GetModuleLoadList(bool recovery, const std::string& dir_path) {
auto module_load_file = "modules.load";
if (recovery) {
struct stat fileStat;
std::string recovery_load_path = dir_path + "/modules.load.recovery";
if (!stat(recovery_load_path.c_str(), &fileStat)) {
module_load_file = "modules.load.recovery";
}
}
return module_load_file;
}
2. FirstStageMount类
2.1 Create-读fstab文件,创建FirstStageMountVBootV2类
std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
// 读fstab文件
auto fstab = ReadFirstStageFstab();
if (IsDtVbmetaCompatible(fstab)) {
// avb2.0走这里,走FirstStageMount类和构造函数构造函数
return std::make_unique<FirstStageMountVBootV2>(std::move(fstab));
} else {
return std::make_unique<FirstStageMountVBootV1>(std::move(fstab));
}
}
2.2 IsDtVbmetaCompatible-看dts是否配置vbmeta和fstab配置了avb
static inline bool IsDtVbmetaCompatible(const Fstab& fstab) {
if (std::any_of(fstab.begin(), fstab.end(),
// fstab中avb标志的
[](const auto& entry) { return entry.fs_mgr_flags.avb; })) {
return true;
}
// 读/proc/device-tree/firmware/android/vbmeta/compatible文件,为android,vbmeta
return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
}
2.3 FirstStageMount-构造函数,获取super分区名字,super分区不一定叫super
// fstab_的值为system,product,vendor;配了avb就是need_dm_verity_为true
FirstStageMount::FirstStageMount(Fstab fstab) : need_dm_verity_(false), fstab_(std::move(fstab)) {
// super值
super_partition_name_ = fs_mgr_get_super_partition_name();
}
2.4 DoFirstStageMount-创建分区设备节点,挂载分区
bool FirstStageMount::DoFirstStageMount() {
// 配置了logical标志
if (!IsDmLinearEnabled() && fstab_.empty()) {
// Nothing to mount.
LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)";
return true;
}
// 创建分区设备节点
if (!InitDevices()) return false;
// 挂载分区
if (!MountPartitions()) return false;
return true;
}
2.5 IsDmLinearEnabled-logical标志
bool FirstStageMount::IsDmLinearEnabled() {
for (const auto& entry : fstab_) {
if (entry.fs_mgr_flags.logical) return true;
}
return false;
}
2.6 InitDevices-创建device-mapper和分区设备和super分区设备
bool FirstStageMount::InitDevices() {
std::set<std::string> devices;
// 加入super分区
GetSuperDeviceName(&devices);
// vbmeta,vbmeta_system,vbmeta_vendor,boot,super分区
if (!GetDmVerityDevices(&devices)) {
return false;
}
// vbmeta,vbmeta_system,vbmeta_vendor,boot,super分区
if (!InitRequiredDevices(std::move(devices))) {
return false;
}
if (IsDmLinearEnabled()) {
auto super_symlink = "/dev/block/by-name/"s + super_partition_name_;
// 获取/dev/block/mmcblkp04
if (!android::base::Realpath(super_symlink, &super_path_)) {
PLOG(ERROR) << "realpath failed: " << super_symlink;
return false;
}
}
return true;
}
void FirstStageMount::GetSuperDeviceName(std::set<std::string>* devices) {
// Add any additional devices required for dm-linear mappings.
if (!IsDmLinearEnabled()) {
return;
}
// 加入super分区
devices->emplace(super_partition_name_);
}
2.7 InitRequiredDevices-创建device-mapper设备节点,以及vbmeta,vbmeta_system,vbmeta_vendor,boot,super块设备节点和链接
bool FirstStageMount::InitRequiredDevices(std::set<std::string> devices) {
// 创建devicemapper设备节点
if (!block_dev_init_.InitDeviceMapper()) {
return false;
}
if (devices.empty()) {
return true;
}// vbmeta,vbmeta_system,vbmeta_vendor,boot,super分区块设备节点
return block_dev_init_.InitDevices(std::move(devices));
}
2.8 MountPartitions-挂载metadata,system,product,vendor分区,以及remount相关
bool FirstStageMount::MountPartitions() {
// Mount /metadata before creating logical partitions, since we need to
// know whether a snapshot merge is in progress.
auto metadata_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
return entry.mount_point == "/metadata";
});
if (metadata_partition != fstab_.end()) {
// 1. 先挂载metadata分区
if (MountPartition(metadata_partition, true /* erase_same_mounts */)) {
// Copies DSU AVB keys from the ramdisk to /metadata.
// Must be done before the following TrySwitchSystemAsRoot().
// Otherwise, ramdisk will be inaccessible after switching root.
// 拷贝dsuavb密钥
CopyDsuAvbKeys();
}
}
// 2. 创建logical分区
if (!CreateLogicalPartitions()) return false;
// 3. 将system分区设为root
if (!TrySwitchSystemAsRoot()) return false;
// gsi的时候,不挂载/oem /product /system_ext分区
if (!SkipMountingPartitions(&fstab_)) return false;
for (auto current = fstab_.begin(); current != fstab_.end();) {
// We've already mounted /system above.
// 省略掉system分区
if (current->mount_point == "/system") {
++current;
continue;
}
// Skip raw partition entries such as boot, dtbo, etc.
// Having emmc fstab entries allows us to probe current->vbmeta_partition
// in InitDevices() when they are AVB chained partitions.
if (current->fs_type == "emmc") {
++current;
continue;
}
Fstab::iterator end;
// 挂载product和vendor分区
if (!MountPartition(current, false /* erase_same_mounts */, &end)) {
if (current->fs_mgr_flags.no_fail) {
LOG(INFO) << "Failed to mount " << current->mount_point
<< ", ignoring mount for no_fail partition";
} else if (current->fs_mgr_flags.formattable) {
LOG(INFO) << "Failed to mount " << current->mount_point
<< ", ignoring mount for formattable partition";
} else {
PLOG(ERROR) << "Failed to mount " << current->mount_point;
return false;
}
}
current = end;
}
// remount相关,overlayfs相关的
// If we don't see /system or / in the fstab, then we need to create an root entry for
// overlayfs.
if (!GetEntryForMountPoint(&fstab_, "/system") && !GetEntryForMountPoint(&fstab_, "/")) {
FstabEntry root_entry;
if (GetRootEntry(&root_entry)) {
fstab_.emplace_back(std::move(root_entry));
}
}
// heads up for instantiating required device(s) for overlayfs logic
auto init_devices = [this](std::set<std::string> devices) -> bool {
for (auto iter = devices.begin(); iter != devices.end();) {
if (android::base::StartsWith(*iter, "/dev/block/dm-")) {
if (!block_dev_init_.InitDmDevice(*iter)) {
return false;
}
iter = devices.erase(iter);
} else {
iter++;
}
}
return InitRequiredDevices(std::move(devices));
};
MapScratchPartitionIfNeeded(&fstab_, init_devices);
fs_mgr_overlayfs_mount_all(&fstab_);
return true;
}
2.9 MountPartition-创建逻辑分区,dm设备,挂载分区
bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
Fstab::iterator* end) {
// Sets end to begin + 1, so we can just return on failure below.
if (end) {
*end = begin + 1;
}
if (begin->fs_mgr_flags.logical) {
// 更新block_device的值,system_a 变为/dev/block/dm-0设备
if (!fs_mgr_update_logical_partition(&(*begin))) {
return false;
}
// 创建dm-0设备节点,/dev/block/dm-0
if (!block_dev_init_.InitDmDevice(begin->blk_device)) {
return false;
}
}
// 创建dm-verity设备,设置avb相关的配置
if (!SetUpDmVerity(&(*begin))) {
PLOG(ERROR) << "Failed to setup verity for '" << begin->mount_point << "'";
return false;
}
// 进行挂载
bool mounted = (fs_mgr_do_mount_one(*begin) == 0);
// Try other mounts with the same mount point.
Fstab::iterator current = begin + 1;
for (; current != fstab_.end() && current->mount_point == begin->mount_point; current++) {
if (!mounted) {
// blk_device is already updated to /dev/dm-<N> by SetUpDmVerity() above.
// Copy it from the begin iterator.
current->blk_device = begin->blk_device;
mounted = (fs_mgr_do_mount_one(*current) == 0);
}
}
if (erase_same_mounts) {
current = fstab_.erase(begin, current);
}
if (end) {
*end = current;
}
return mounted;
}
2.10 CopyDsuAvbKeys-拷贝avb keys到metadata目录中
void FirstStageMount::CopyDsuAvbKeys() {
std::error_code ec;
// Removing existing keys in gsi::kDsuAvbKeyDir as they might be stale.
// 删除/metadata/gsi/dsu/avb/目录
std::filesystem::remove_all(gsi::kDsuAvbKeyDir, ec);
if (ec) {
LOG(ERROR) << "Failed to remove directory " << gsi::kDsuAvbKeyDir << ": " << ec.message();
}
// Copy keys from the ramdisk /avb/* to gsi::kDsuAvbKeyDir.
static constexpr char kRamdiskAvbKeyDir[] = "/avb";
// 将ramdisk下的key拷贝到/metadata/gsi/dsu/avb/目录
std::filesystem::copy(kRamdiskAvbKeyDir, gsi::kDsuAvbKeyDir, ec);
if (ec) {
LOG(ERROR) << "Failed to copy " << kRamdiskAvbKeyDir << " into " << gsi::kDsuAvbKeyDir
<< ": " << ec.message();
}
}
2.11 CreateLogicalPartitions-创建逻辑分区
bool FirstStageMount::CreateLogicalPartitions() {
if (!IsDmLinearEnabled()) {
return true;
}
if (super_path_.empty()) {
LOG(ERROR) << "Could not locate logical partition tables in partition "
<< super_partition_name_;
return false;
}
// 这个是virtual AB升级相关的,/metadata/ota/snapshot-boot目录是否存在
if (SnapshotManager::IsSnapshotManagerNeeded()) {
auto sm = SnapshotManager::NewForFirstStageMount();
if (!sm) {
return false;
}
if (sm->NeedSnapshotsInFirstStageMount()) {
// When COW images are present for snapshots, they are stored on
// the data partition.
if (!InitRequiredDevices({"userdata"}) && !InitRequiredDevices({"UDISK"})) {
return false;
}
return sm->CreateLogicalAndSnapshotPartitions(super_path_);
}
}
// 读super分区的metadata信息
auto metadata = android::fs_mgr::ReadCurrentMetadata(super_path_);
if (!metadata) {
LOG(ERROR) << "Could not read logical partition metadata from " << super_path_;
return false;
}
// 初始化blockdevice,super分区在之前早就初始化好了,所以这里什么都没做
if (!InitDmLinearBackingDevices(*metadata.get())) {
return false;
}
// 创建dm-0等逻辑设备,super_path_为/dev/block/mmcblk0p9
return android::fs_mgr::CreateLogicalPartitions(*metadata.get(), super_path_);
}
2.12 InitDmLinearBackingDevices-初始化blockdevice,super分区在之前早就初始化好了,所以这里什么都没做
bool FirstStageMount::InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata) {
std::set<std::string> devices;
// super分区
auto partition_names = android::fs_mgr::GetBlockDevicePartitionNames(metadata);
for (const auto& partition_name : partition_names) {
// The super partition was found in the earlier pass.
if (partition_name == super_partition_name_) {
continue;
}
devices.emplace(partition_name);
}
if (devices.empty()) {
return true;
}
return InitRequiredDevices(std::move(devices));
}
2.13 TrySwitchSystemAsRoot-挂载system分区并设为根目录
bool FirstStageMount::TrySwitchSystemAsRoot() {
// dsu相关的
UseDsuIfPresent();
// Preloading all AVB keys from the ramdisk before switching root to /system.
// 读/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey文件,放到preload_avb_key_blobs_中
PreloadAvbKeys();
auto system_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
return entry.mount_point == "/system";
});
if (system_partition == fstab_.end()) return true;
// 挂载system分区
if (MountPartition(system_partition, false /* erase_same_mounts */)) {
if (dsu_not_on_userdata_ && fs_mgr_verity_is_check_at_most_once(*system_partition)) {
LOG(ERROR) << "check_most_at_once forbidden on external media";
return false;
}
SwitchRoot("/system");
} else {
PLOG(ERROR) << "Failed to mount /system";
return false;
}
return true;
}
2.14 PreloadAvbKeys-读/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey文件,放到preload_avb_key_blobs_中
void FirstStageMount::PreloadAvbKeys() {
for (const auto& entry : fstab_) {
// No need to cache the key content if it's empty, or is already cached.
if (entry.avb_keys.empty() || preload_avb_key_blobs_.count(entry.avb_keys)) {
continue;
}
// Determines all key paths first.
std::vector<std::string> key_paths;
if (is_dir(entry.avb_keys.c_str())) { // fstab_keys might be a dir, e.g., /avb.
const char* avb_key_dir = entry.avb_keys.c_str();
std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(avb_key_dir), closedir);
if (!dir) {
LOG(ERROR) << "Failed to opendir: " << dir;
continue;
}
// Gets all key pathes under the dir.
struct dirent* de;
while ((de = readdir(dir.get()))) {
if (de->d_type != DT_REG) continue;
std::string full_path = StringPrintf("%s/%s", avb_key_dir, de->d_name);
key_paths.emplace_back(std::move(full_path));
}
std::sort(key_paths.begin(), key_paths.end());
} else {
// avb_keys are key paths separated by ":", if it's not a dir.
key_paths = Split(entry.avb_keys, ":");
}
// Reads the key content then cache it.
std::vector<std::string> key_blobs;
for (const auto& path : key_paths) {
std::string key_value;
// 读/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey文件,放到preload_avb_key_blobs_中
if (!ReadFileToString(path, &key_value)) {
continue;
}
key_blobs.emplace_back(std::move(key_value));
}
// Maps entry.avb_keys to actual key blobs.
preload_avb_key_blobs_[entry.avb_keys] = std::move(key_blobs);
}
}
3. FirstStageMountVBootV2类
3.1 FirstStageMountVBootV2构造函数-读配置的vbmeta分区
FirstStageMountVBootV2::FirstStageMountVBootV2(Fstab fstab)
: FirstStageMount(std::move(fstab)), avb_handle_(nullptr) {
std::string device_tree_vbmeta_parts;
// 读/proc/device-tree/firmware/android/ + vbmeta/parts文件
// vbmeta验证的分区:vbmeta,vbmeta_system,vbmeta_vendor,boot
read_android_dt_file("vbmeta/parts", &device_tree_vbmeta_parts);
for (auto&& partition : Split(device_tree_vbmeta_parts, ",")) {
if (!partition.empty()) {
vbmeta_partitions_.emplace_back(std::move(partition));
}
}
for (const auto& entry : fstab_) {
// avb=vbmeta指定的分区
if (!entry.vbmeta_partition.empty()) {
vbmeta_partitions_.emplace_back(entry.vbmeta_partition);
}
}
if (vbmeta_partitions_.empty()) {
LOG(ERROR) << "Failed to read vbmeta partitions.";
}
}
3.2 GetDmVerityDevices-找avb相关的分区设备
bool FirstStageMountVBootV2::GetDmVerityDevices(std::set<std::string>* devices) {
need_dm_verity_ = false;
std::set<std::string> logical_partitions;
// fstab_rec->blk_device has A/B suffix.
for (const auto& fstab_entry : fstab_) {
if (fstab_entry.fs_mgr_flags.avb) {
// avb配置
need_dm_verity_ = true;
}
if (fstab_entry.fs_mgr_flags.logical) {
// Don't try to find logical partitions via uevent regeneration.
// logical_partitions的值为system,vendor,product
logical_partitions.emplace(basename(fstab_entry.blk_device.c_str()));
} else {
devices->emplace(basename(fstab_entry.blk_device.c_str()));
}
}
// Any partitions needed for verifying the partitions used in first stage mount, e.g. vbmeta
// must be provided as vbmeta_partitions.
if (need_dm_verity_) {
if (vbmeta_partitions_.empty()) {
LOG(ERROR) << "Missing vbmeta partitions";
return false;
}
// 获取androidboot.slot_suffix的值
std::string ab_suffix = fs_mgr_get_slot_suffix();
for (const auto& partition : vbmeta_partitions_) {
std::string partition_name = partition + ab_suffix;
// 跳过logical_partitions分区,system,vendor,product分区
if (logical_partitions.count(partition_name)) {
continue;
}
// devices is of type std::set so it's not an issue to emplace a
// partition twice. e.g., /vendor might be in both places:
// - device_tree_vbmeta_parts_ = "vbmeta,boot,system,vendor"
// - mount_fstab_recs_: /vendor_a
// vbmeta,vbmeta_system,vbmeta_vendor,boot分区
devices->emplace(partition_name);
}
}
return true;
}
3.3 SetUpDmVerity-avb相关-创建dm设备
bool FirstStageMountVBootV2::SetUpDmVerity(FstabEntry* fstab_entry) {
AvbHashtreeResult hashtree_result;
// It's possible for a fstab_entry to have both avb_keys and avb flag.
// In this case, try avb_keys first, then fallback to avb flag.
if (!fstab_entry->avb_keys.empty()) {
if (!InitAvbHandle()) return false;
// Checks if hashtree should be disabled from the top-level /vbmeta.
if (avb_handle_->status() == AvbHandleStatus::kHashtreeDisabled ||
avb_handle_->status() == AvbHandleStatus::kVerificationDisabled) {
LOG(ERROR) << "Top-level vbmeta is disabled, skip Hashtree setup for "
<< fstab_entry->mount_point;
return true; // Returns true to mount the partition directly.
} else {
auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(
*fstab_entry, preload_avb_key_blobs_[fstab_entry->avb_keys]);
if (!avb_standalone_handle) {
LOG(ERROR) << "Failed to load offline vbmeta for " << fstab_entry->mount_point;
// Fallbacks to built-in hashtree if fs_mgr_flags.avb is set.
if (!fstab_entry->fs_mgr_flags.avb) return false;
LOG(INFO) << "Fallback to built-in hashtree for " << fstab_entry->mount_point;
hashtree_result =
avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
} else {
// Sets up hashtree via the standalone handle.
if (IsStandaloneImageRollback(*avb_handle_, *avb_standalone_handle, *fstab_entry)) {
return false;
}
hashtree_result = avb_standalone_handle->SetUpAvbHashtree(
fstab_entry, false /* wait_for_verity_dev */);
}
}
} else if (fstab_entry->fs_mgr_flags.avb) {
if (!InitAvbHandle()) return false;
hashtree_result =
avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
} else {
return true; // No need AVB, returns true to mount the partition directly.
}
switch (hashtree_result) {
case AvbHashtreeResult::kDisabled:
return true; // Returns true to mount the partition.
case AvbHashtreeResult::kSuccess:
// The exact block device name (fstab_rec->blk_device) is changed to
// "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
// first stage.
return block_dev_init_.InitDmDevice(fstab_entry->blk_device);
default:
return false;
}
}
4. util类
4.1 is_android_dt_value_expected-dts是否配置了
bool is_android_dt_value_expected(const std::string& sub_path, const std::string& expected_content) {
std::string dt_content;
if (read_android_dt_file(sub_path, &dt_content)) {
if (dt_content == expected_content) {
return true;
}
}
return false;
}
static std::string init_android_dt_dir() {
// Use the standard procfs-based path by default
std::string android_dt_dir = kDefaultAndroidDtDir;
// The platform may specify a custom Android DT path in kernel cmdline
ImportKernelCmdline([&](const std::string& key, const std::string& value) {
if (key == "androidboot.android_dt_dir") {
android_dt_dir = value;
}
});
LOG(INFO) << "Using Android DT directory " << android_dt_dir;
return android_dt_dir;
}
// FIXME: The same logic is duplicated in system/core/fs_mgr/
const std::string& get_android_dt_dir() {
// Set once and saves time for subsequent calls to this function
static const std::string kAndroidDtDir = init_android_dt_dir();
return kAndroidDtDir;
}
4.2 read_android_dt_file-读/proc/device-tree/firmware/android/里面的东西
bool read_android_dt_file(const std::string& sub_path, std::string* dt_content) {
// 读/proc/device-tree/firmware/android/ + vbmeta/compatible文件,为android,vbmeta
const std::string file_name = get_android_dt_dir() + sub_path;
if (android::base::ReadFileToString(file_name, dt_content)) {
if (!dt_content->empty()) {
// 在字符串末尾删除一个字符,删除'\0'字符
dt_content->pop_back(); // Trims the trailing '\0' out.
return true;
}
}
return false;
}
4.3 mkdir_recursive-递归创建文件夹
bool mkdir_recursive(const std::string& path, mode_t mode) {
std::string::size_type slash = 0;
while ((slash = path.find('/', slash + 1)) != std::string::npos) {
auto directory = path.substr(0, slash);
struct stat info;
// 如果文件夹不存在
if (stat(directory.c_str(), &info) != 0) {
// 则创建它
auto ret = make_dir(directory, mode);
if (!ret && errno != EEXIST) return false;
}
}
auto ret = make_dir(path, mode);
if (!ret && errno != EEXIST) return false;
return true;
}
bool make_dir(const std::string& path, mode_t mode) {
std::string secontext;
// 找文件的selabel
if (SelabelLookupFileContext(path, mode, &secontext) && !secontext.empty()) {
setfscreatecon(secontext.c_str());
}
// 创建文件夹
int rc = mkdir(path.c_str(), mode);
if (!secontext.empty()) {
int save_errno = errno;
setfscreatecon(nullptr);
errno = save_errno;
}
return rc == 0;
}
4.4 is_dir-判断是否是文件夹
bool is_dir(const char* pathname) {
struct stat info;
if (stat(pathname, &info) == -1) {
return false;
}
return S_ISDIR(info.st_mode);
}
4.5 SetStdioToDevNull-标准输出重定向到/dev/null
void SetStdioToDevNull(char** argv) {
// Make stdin/stdout/stderr all point to /dev/null.
int fd = open("/dev/null", O_RDWR); // NOLINT(android-cloexec-open)
if (fd == -1) {
int saved_errno = errno;
android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
errno = saved_errno;
PLOG(FATAL) << "Couldn't open /dev/null";
}
// 两个描述符都指向/dev/null文件,将log重定向到/dev/null中
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO) close(fd);
}
4.6 InitKernelLogging-初始化串口输出
void InitKernelLogging(char** argv) {
SetFatalRebootTarget();
android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
}
4.7 InitAborter-fatal log的时候调用这个函数
static void InitAborter(const char* abort_message) {
// When init forks, it continues to use this aborter for LOG(FATAL), but we want children to
// simply abort instead of trying to reboot the system.
if (getpid() != 1) {
android::base::DefaultAborter(abort_message);
return;
}
InitFatalReboot(SIGABRT);
}
5. BlockDevInitializer类
5.1 BlockDevInitializer构造函数-读boot_devices
BlockDevInitializer::BlockDevInitializer() : uevent_listener_(16 * 1024 * 1024) {
auto boot_devices = android::fs_mgr::GetBootDevices();
device_handler_ = std::make_unique<DeviceHandler>(
std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{},
std::move(boot_devices), false);
}
5.2 InitDeviceMapper-往/sys目录下的所有设备发送uevent事件,创建device-mapper设备节点
bool BlockDevInitializer::InitDeviceMapper() {
const std::string dm_path = "/devices/virtual/misc/device-mapper";
bool found = false;
auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
if (uevent.path == dm_path) {
// 如果是device-mapper设备的话,则调用HandleUevent函数处理信息
// { 'add'(action), '/devices/virtual/misc/device-mapper'(path), 'misc'(subsystem), ''(firmware), 10(major), 236(minor) }
device_handler_->HandleUevent(uevent);
found = true;
return ListenerAction::kStop;
}
return ListenerAction::kContinue;
};
// 触发/sys目录下所有设备的uevent事件
uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
if (!found) {
LOG(INFO) << "device-mapper device not found in /sys, waiting for its uevent";
Timer t;
uevent_listener_.Poll(dm_callback, 10s);
LOG(INFO) << "Wait for device-mapper returned after " << t;
}
if (!found) {
LOG(ERROR) << "device-mapper device not found after polling timeout";
return false;
}
return true;
}
5.3 InitDevices-创建dts中的vbmeta,vbmeta_system,vbmeta_vendor,boot,super分区设备
bool BlockDevInitializer::InitDevices(std::set<std::string> devices) {
auto uevent_callback = [&, this](const Uevent& uevent) -> ListenerAction {
return HandleUevent(uevent, &devices);
};
uevent_listener_.RegenerateUevents(uevent_callback);
// UeventCallback() will remove found partitions from |devices|. So if it
// isn't empty here, it means some partitions are not found.
if (!devices.empty()) {
LOG(INFO) << __PRETTY_FUNCTION__
<< ": partition(s) not found in /sys, waiting for their uevent(s): "
<< android::base::Join(devices, ", ");
Timer t;
uevent_listener_.Poll(uevent_callback, 10s);
LOG(INFO) << "Wait for partitions returned after " << t;
}
if (!devices.empty()) {
LOG(ERROR) << __PRETTY_FUNCTION__ << ": partition(s) not found after polling timeout: "
<< android::base::Join(devices, ", ");
return false;
}
return true;
}
6.5 HandleUevent-看uevent中的partition_name是否和devices中的匹配
ListenerAction BlockDevInitializer::HandleUevent(const Uevent& uevent,
std::set<std::string>* devices) {
// Ignore everything that is not a block device.
// 忽略不是block的uevent事件
if (uevent.subsystem != "block") {
return ListenerAction::kContinue;
}
auto name = uevent.partition_name;
if (name.empty()) {
size_t base_idx = uevent.path.rfind('/');
if (base_idx == std::string::npos) {
return ListenerAction::kContinue;
}
name = uevent.path.substr(base_idx + 1);
}
// vbmeta,vbmeta_system,vbmeta_vendor,boot,super分区设备中找
auto iter = devices->find(name);
if (iter == devices->end()) {
// 没有找到就返回
return ListenerAction::kContinue;
}
LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << name;
// 找到了就擦掉
devices->erase(iter);
// 然后处理它的uevent事件
device_handler_->HandleUevent(uevent);
return devices->empty() ? ListenerAction::kStop : ListenerAction::kContinue;
}
6.6 InitDmDevice-往/sys/block/dm-0发uevent信息
// Creates "/dev/block/dm-XX" for dm nodes by running coldboot on /sys/block/dm-XX.
bool BlockDevInitializer::InitDmDevice(const std::string& device) {
// dm-0
const std::string device_name(basename(device.c_str()));
const std::string syspath = "/sys/block/" + device_name;
bool found = false;
auto uevent_callback = [&device_name, &device, this, &found](const Uevent& uevent) {
if (uevent.device_name == device_name) {
LOG(VERBOSE) << "Creating device-mapper device : " << device;
// 创建links和/dev/block/dm-0设备
device_handler_->HandleUevent(uevent);
found = true;
return ListenerAction::kStop;
}
return ListenerAction::kContinue;
};
uevent_listener_.RegenerateUeventsForPath(syspath, uevent_callback);
if (!found) {
LOG(INFO) << "dm device '" << device << "' not found in /sys, waiting for its uevent";
Timer t;
uevent_listener_.Poll(uevent_callback, 10s);
LOG(INFO) << "wait for dm device '" << device << "' returned after " << t;
}
if (!found) {
LOG(ERROR) << "dm device '" << device << "' not found after polling timeout";
return false;
}
return true;
}
6. DeviceHandler类
6.1 DeviceHandler构造函数
DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions,
std::vector<SysfsPermissions> sysfs_permissions,
std::vector<Subsystem> subsystems, std::set<std::string> boot_devices,
bool skip_restorecon)
: dev_permissions_(std::move(dev_permissions)),
sysfs_permissions_(std::move(sysfs_permissions)),
subsystems_(std::move(subsystems)),
// soc@2900000/4020000.sdmmc,soc@2900000/4022000.sdmmc,soc@2900000
boot_devices_(std::move(boot_devices)),
skip_restorecon_(skip_restorecon),
sysfs_mount_point_("/sys") {}
6.2 HandleUevent-处理uevent事件-创建设备节点和links
{ 'add'(action), '/devices/virtual/misc/device-mapper'(path), 'misc'(subsystem), ''(firmware), 10(major), 236(minor) }事件
{'add'(action), '/devices/platform/soc@2900000/4022000.sdmmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p16', 'block', '', 259, 8}事件
{ 'add', '/devices/virtual/block/dm-0', 'block', '', 254, 0 }
void DeviceHandler::HandleUevent(const Uevent& uevent) {
if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
// selinux相关的,
FixupSysPermissions(uevent.path, uevent.subsystem);
}
// if it's not a /dev device, nothing to do
if (uevent.major < 0 || uevent.minor < 0) return;
std::string devpath;
std::vector<std::string> links;
bool block = false;
if (uevent.subsystem == "block") {
block = true;
// /dev/block/mmcblk0p16
devpath = "/dev/block/" + Basename(uevent.path);
if (StartsWith(uevent.path, "/devices")) {
// 创建links,dm也要创建
links = GetBlockDeviceSymlinks(uevent);
}
} else if (const auto subsystem =
std::find(subsystems_.cbegin(), subsystems_.cend(), uevent.subsystem);
subsystem != subsystems_.cend()) {
devpath = subsystem->ParseDevPath(uevent);
} else if (uevent.subsystem == "usb") {
if (!uevent.device_name.empty()) {
devpath = "/dev/" + uevent.device_name;
} else {
// This imitates the file system that would be created
// if we were using devfs instead.
// Minors are broken up into groups of 128, starting at "001"
int bus_id = uevent.minor / 128 + 1;
int device_id = uevent.minor % 128 + 1;
devpath = StringPrintf("/dev/bus/usb/%03d/%03d", bus_id, device_id);
}
} else if (StartsWith(uevent.subsystem, "usb")) {
// ignore other USB events
return;
} else {
// misc走这里,devpath=/dev/device-mapper
devpath = "/dev/" + Basename(uevent.path);
}
// 创建/dev/device-mapper
mkdir_recursive(Dirname(devpath), 0755);
HandleDevice(uevent.action, devpath, block, uevent.major, uevent.minor, links);
// Duplicate /dev/ashmem device and name it /dev/ashmem<boot_id>.
// TODO(b/111903542): remove once all users of /dev/ashmem are migrated to libcutils API.
// device_name == "ashmem"才走这里
HandleAshmemUevent(uevent);
}
void DeviceHandler::FixupSysPermissions(const std::string& upath,
const std::string& subsystem) const {
// upaths omit the "/sys" that paths in this list
// contain, so we prepend it...
std::string path = "/sys" + upath;
// sysfs_permissions_是空的,不会走这里
for (const auto& s : sysfs_permissions_) {
if (s.MatchWithSubsystem(path, subsystem)) s.SetPermissions(path);
}
// skip_restorecon_为false
if (!skip_restorecon_ && access(path.c_str(), F_OK) == 0) {
LOG(VERBOSE) << "restorecon_recursive: " << path;
// 会对path路径进行restorecon,修正selinux的selabel
if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
PLOG(ERROR) << "selinux_android_restorecon(" << path << ") failed";
}
}
}
6.3 HandleDevice-创建设备节点和links
void DeviceHandler::HandleDevice(const std::string& action, const std::string& devpath, bool block,
int major, int minor, const std::vector<std::string>& links) const {
if (action == "add") {
// 创建节点
MakeDevice(devpath, block, major, minor, links);
}
// We don't have full device-mapper information until a change event is fired.
if (action == "add" || (action == "change" && StartsWith(devpath, "/dev/block/dm-"))) {
// device-mapper的时候links为空的
// links都链接到/dev/block/mmcblkp16
for (const auto& link : links) {
if (!mkdir_recursive(Dirname(link), 0755)) {
PLOG(ERROR) << "Failed to create directory " << Dirname(link);
}
if (symlink(devpath.c_str(), link.c_str())) {
if (errno != EEXIST) {
PLOG(ERROR) << "Failed to symlink " << devpath << " to " << link;
} else if (std::string link_path;
Readlink(link, &link_path) && link_path != devpath) {
PLOG(ERROR) << "Failed to symlink " << devpath << " to " << link
<< ", which already links to: " << link_path;
}
}
}
}
if (action == "remove") {
if (StartsWith(devpath, "/dev/block/dm-")) {
RemoveDeviceMapperLinks(devpath);
}
for (const auto& link : links) {
std::string link_path;
if (Readlink(link, &link_path) && link_path == devpath) {
unlink(link.c_str());
}
}
unlink(devpath.c_str());
}
}
6.4 MakeDevice-创建设备节点
void DeviceHandler::MakeDevice(const std::string& path, bool block, int major, int minor,
const std::vector<std::string>& links) const {
auto[mode, uid, gid] = GetDevicePermissions(path, links);
// 字符设备或者块设备
mode |= (block ? S_IFBLK : S_IFCHR);
std::string secontext;
// selinux相关
if (!SelabelLookupFileContextBestMatch(path, links, mode, &secontext)) {
PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
return;
}
if (!secontext.empty()) {
setfscreatecon(secontext.c_str());
}
// 创建设备ID,用来创建设备节点
dev_t dev = makedev(major, minor);
/* Temporarily change egid to avoid race condition setting the gid of the
* device node. Unforunately changing the euid would prevent creation of
* some device nodes, so the uid has to be set with chown() and is still
* racy. Fixing the gid race at least fixed the issue with system_server
* opening dynamic input devices under the AID_INPUT gid. */
// 将用户转为gid
if (setegid(gid)) {
PLOG(ERROR) << "setegid(" << gid << ") for " << path << " device failed";
goto out;
}
/* If the node already exists update its SELinux label to handle cases when
* it was created with the wrong context during coldboot procedure. */
// 创建设备节点
if (mknod(path.c_str(), mode, dev) && (errno == EEXIST) && !secontext.empty()) {
char* fcon = nullptr;
int rc = lgetfilecon(path.c_str(), &fcon);
if (rc < 0) {
PLOG(ERROR) << "Cannot get SELinux label on '" << path << "' device";
goto out;
}
bool different = fcon != secontext;
freecon(fcon);
if (different && lsetfilecon(path.c_str(), secontext.c_str())) {
PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path
<< "' device";
}
}
out:
chown(path.c_str(), uid, -1);
// 又换回root用户
if (setegid(AID_ROOT)) {
PLOG(FATAL) << "setegid(AID_ROOT) failed";
}
if (!secontext.empty()) {
setfscreatecon(nullptr);
}
}
6.5 GetBlockDeviceSymlinks-创建links
std::vector<std::string> DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uevent) const {
std::string device;
std::string type;
std::string partition;
std::string uuid;
// /devices/platform/soc@2900000/4022000.sdmmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p16
if (FindPlatformDevice(uevent.path, &device)) {
// Skip /devices/platform or /devices/ if present
static const std::string devices_platform_prefix = "/devices/platform/";
static const std::string devices_prefix = "/devices/";
// /devices/platform/soc@2900000/4022000.sdmmc
if (StartsWith(device, devices_platform_prefix)) {
// soc@2900000/4022000.sdmmc
device = device.substr(devices_platform_prefix.length());
} else if (StartsWith(device, devices_prefix)) {
device = device.substr(devices_prefix.length());
}
type = "platform";
} else if (FindPciDevicePrefix(uevent.path, &device)) {
type = "pci";
} else if (FindVbdDevicePrefix(uevent.path, &device)) {
type = "vbd";
// dm设备走这里,/devices/virtual/block/dm-0
// /sys/devices/virtual/block/dm-0/dm/name获得partition,system_a和uuid
} else if (FindDmDevice(uevent.path, &partition, &uuid)) {
// 创建两个链接:/dev/block/mapper/system_a -> /dev/block/dm-0
std::vector<std::string> symlinks = {"/dev/block/mapper/" + partition};
if (!uuid.empty()) {
symlinks.emplace_back("/dev/block/mapper/by-uuid/" + uuid);
}
return symlinks;
} else {
return {};
}
std::vector<std::string> links;
LOG(VERBOSE) << "found " << type << " device " << device;
// /dev/block/platform/soc@2900000/4022000.sdmmc
auto link_path = "/dev/block/" + type + "/" + device;
// is_boot_device为true
bool is_boot_device = boot_devices_.find(device) != boot_devices_.end();
// partition_name 为dtbo
// dm设备为空的
if (!uevent.partition_name.empty()) {
std::string partition_name_sanitized(uevent.partition_name);
// 将不可接受的,替换为_
SanitizePartitionName(&partition_name_sanitized);
if (partition_name_sanitized != uevent.partition_name) {
LOG(VERBOSE) << "Linking partition '" << uevent.partition_name << "' as '"
<< partition_name_sanitized << "'";
}
// /dev/block/platform/soc@2900000/4022000.sdmmc/by-name/dtbo
links.emplace_back(link_path + "/by-name/" + partition_name_sanitized);
// Adds symlink: /dev/block/by-name/<partition_name>.
if (is_boot_device) {
// /dev/block/by-name/dtbo
links.emplace_back("/dev/block/by-name/" + partition_name_sanitized);
}
if ((partition_name_sanitized == "userdata") || (partition_name_sanitized == "UDISK")) {
links.emplace_back(link_path + "/by-name/userdata");
// Adds symlink: /dev/block/by-name/<partition_name>.
if (is_boot_device) {
links.emplace_back("/dev/block/by-name/userdata");
}
}
} else if (is_boot_device) {
// If we don't have a partition name but we are a partition on a boot device, create a
// symlink of /dev/block/by-name/<device_name> for symmetry.
links.emplace_back("/dev/block/by-name/" + uevent.device_name);
}
// /dev/block/platform/soc@2900000/4022000.sdmmc/mmcblk0p16 -> /dev/block/mmcblk0p16
auto last_slash = uevent.path.rfind('/');
links.emplace_back(link_path + "/" + uevent.path.substr(last_slash + 1));
return links;
}
6.6 FindPlatformDevice-获取platform_device_path
bool DeviceHandler::FindPlatformDevice(std::string path, std::string* platform_device_path) const {
platform_device_path->clear();
// /devices/platform/soc@2900000/4022000.sdmmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p16
// Uevents don't contain the mount point, so we need to add it here.
// 加上/sys
path.insert(0, sysfs_mount_point_);
std::string directory = Dirname(path);
while (directory != "/" && directory != ".") {
std::string subsystem_link_path;
if (Realpath(directory + "/subsystem", &subsystem_link_path) &&
subsystem_link_path == sysfs_mount_point_ + "/bus/platform") {
// We need to remove the mount point that we added above before returning.
directory.erase(0, sysfs_mount_point_.size());
// /devices/platform/soc@2900000/4022000.sdmmc
*platform_device_path = directory;
return true;
}
auto last_slash = path.rfind('/');
if (last_slash == std::string::npos) return false;
// 一层层的去掉,直到找到subsystem为/bus/platform的
path.erase(last_slash);
directory = Dirname(path);
}
return false;
}
6.7 FindDmDevice-获得分区名和uuid
static bool FindDmDevice(const std::string& path, std::string* name, std::string* uuid) {
// /devices/virtual/block/dm-0
if (!StartsWith(path, "/devices/virtual/block/dm-")) return false;
// system_a
if (!ReadFileToString("/sys" + path + "/dm/name", name)) {
return false;
}
// uuid
ReadFileToString("/sys" + path + "/dm/uuid", uuid);
*name = android::base::Trim(*name);
*uuid = android::base::Trim(*uuid);
return true;
}
7. UeventListener类
7.1 RegenerateUeventsForPath-往path目录下的所有子目录的uevent节点发送add事件
ListenerAction UeventListener::RegenerateUeventsForPath(const std::string& path,
const ListenerCallback& callback) const {
std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path.c_str()), closedir);
if (!d) return ListenerAction::kContinue;
return RegenerateUeventsForDir(d.get(), callback);
}
ListenerAction UeventListener::RegenerateUeventsForDir(DIR* d,
const ListenerCallback& callback) const {
int dfd = dirfd(d);
// 打开uevent
int fd = openat(dfd, "uevent", O_WRONLY | O_CLOEXEC);
if (fd >= 0) {
// 写add
write(fd, "add\n", 4);
close(fd);
Uevent uevent;
// 分析uevent事件
while (ReadUevent(&uevent)) {
// 并调用callback函数
if (callback(uevent) == ListenerAction::kStop) return ListenerAction::kStop;
}
}
dirent* de;
// 循环读/sys目录下的文件
while ((de = readdir(d)) != nullptr) {
if (de->d_type != DT_DIR || de->d_name[0] == '.') continue;
fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
if (fd < 0) continue;
std::unique_ptr<DIR, decltype(&closedir)> d2(fdopendir(fd), closedir);
if (d2 == 0) {
close(fd);
} else {
if (RegenerateUeventsForDir(d2.get(), callback) == ListenerAction::kStop) {
return ListenerAction::kStop;
}
}
}
// default is always to continue looking for uevents
return ListenerAction::kContinue;
}
7.2 ReadUevent-从uevent socket中读uevent事件
bool UeventListener::ReadUevent(Uevent* uevent) const {
char msg[UEVENT_MSG_LEN + 2];
// 读uevent的信息
int n = uevent_kernel_multicast_recv(device_fd_, msg, UEVENT_MSG_LEN);
if (n <= 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
PLOG(ERROR) << "Error reading from Uevent Fd";
}
return false;
}
if (n >= UEVENT_MSG_LEN) {
LOG(ERROR) << "Uevent overflowed buffer, discarding";
// Return true here even if we discard as we may have more uevents pending and we
// want to keep processing them.
return true;
}
msg[n] = '\0';
msg[n + 1] = '\0';
// 解析uevent的信息
ParseEvent(msg, uevent);
return true;
}
static void ParseEvent(const char* msg, Uevent* uevent) {
uevent->partition_num = -1;
uevent->major = -1;
uevent->minor = -1;
uevent->action.clear();
uevent->path.clear();
uevent->subsystem.clear();
uevent->firmware.clear();
uevent->partition_name.clear();
uevent->device_name.clear();
uevent->modalias.clear();
// currently ignoring SEQNUM
while (*msg) {
if (!strncmp(msg, "ACTION=", 7)) {
msg += 7;
uevent->action = msg;
} else if (!strncmp(msg, "DEVPATH=", 8)) {
msg += 8;
// 比对这个path
uevent->path = msg;
} else if (!strncmp(msg, "SUBSYSTEM=", 10)) {
msg += 10;
uevent->subsystem = msg;
} else if (!strncmp(msg, "FIRMWARE=", 9)) {
msg += 9;
uevent->firmware = msg;
} else if (!strncmp(msg, "MAJOR=", 6)) {
msg += 6;
uevent->major = atoi(msg);
} else if (!strncmp(msg, "MINOR=", 6)) {
msg += 6;
uevent->minor = atoi(msg);
} else if (!strncmp(msg, "PARTN=", 6)) {
msg += 6;
uevent->partition_num = atoi(msg);
} else if (!strncmp(msg, "PARTNAME=", 9)) {
msg += 9;
uevent->partition_name = msg;
} else if (!strncmp(msg, "DEVNAME=", 8)) {
msg += 8;
uevent->device_name = msg;
} else if (!strncmp(msg, "MODALIAS=", 9)) {
msg += 9;
uevent->modalias = msg;
}
// advance to after the next \0
while (*msg++)
;
}
if (LOG_UEVENTS) {
// 可以打开这个打印,通过串口看发了哪个uevent了
LOG(INFO) << "event { '" << uevent->action << "', '" << uevent->path << "', '"
<< uevent->subsystem << "', '" << uevent->firmware << "', " << uevent->major
<< ", " << uevent->minor << " }";
}
}
7.3 UeventListener构造函数
UeventListener::UeventListener(size_t uevent_socket_rcvbuf_size) {
// 打开uevent的socket
device_fd_.reset(uevent_open_socket(uevent_socket_rcvbuf_size, true));
if (device_fd_ == -1) {
LOG(FATAL) << "Could not open uevent socket";
}
// 设置为非阻塞的形式
fcntl(device_fd_, F_SETFL, O_NONBLOCK);
}
7.4 RegenerateUevents-往/sys/devices发uevent事件-add事件
static const char* kRegenerationPaths[] = {"/sys/devices"};
void UeventListener::RegenerateUevents(const ListenerCallback& callback) const {
for (const auto path : kRegenerationPaths) {
if (RegenerateUeventsForPath(path, callback) == ListenerAction::kStop) return;
}
}
8. switch root模块
8.1 SwitchRoot-切换根目录
std::vector<std::string> GetMounts(const std::string& new_root) {
auto fp = std::unique_ptr<std::FILE, decltype(&endmntent)>{setmntent("/proc/mounts", "re"),
endmntent};
if (fp == nullptr) {
PLOG(FATAL) << "Failed to open /proc/mounts";
}
std::vector<std::string> result;
mntent* mentry;
while ((mentry = getmntent(fp.get())) != nullptr) {
// We won't try to move rootfs.
// 去掉root
if (mentry->mnt_dir == "/"s) {
continue;
}
// The new root mount is handled separately.
// /system的去掉
if (mentry->mnt_dir == new_root) {
continue;
}
// Move operates on subtrees, so do not try to move children of other mounts.
// /sys/fs/cgroup/devices和/sys/fs/cgroup/memory都算/sys
if (std::find_if(result.begin(), result.end(), [&mentry](const auto& older_mount) {
return StartsWith(mentry->mnt_dir, older_mount);
}) != result.end()) {
continue;
}
result.emplace_back(mentry->mnt_dir);
}
return result;
}
void SwitchRoot(const std::string& new_root) {
auto mounts = GetMounts(new_root);
LOG(INFO) << "Switching root to '" << new_root << "'";
for (const auto& mount_path : mounts) {
auto new_mount_path = new_root + mount_path;
mkdir(new_mount_path.c_str(), 0755);
// 使用MS_MOVE标志,将/sys移到/system/sys目录下
if (mount(mount_path.c_str(), new_mount_path.c_str(), nullptr, MS_MOVE, nullptr) != 0) {
PLOG(FATAL) << "Unable to move mount at '" << mount_path << "'";
}
}
// 将工作目录改变到/system目录下
if (chdir(new_root.c_str()) != 0) {
PLOG(FATAL) << "Could not chdir to new_root, '" << new_root << "'";
}
// 然后将/system目录移到/目录下
if (mount(new_root.c_str(), "/", nullptr, MS_MOVE, nullptr) != 0) {
PLOG(FATAL) << "Unable to move root mount to new_root, '" << new_root << "'";
}
// 然后改变root文件夹
if (chroot(".") != 0) {
PLOG(FATAL) << "Unable to chroot to new root";
}
}
9. FirstStageConsole模块
9.1 FirstStageConsole构造函数
int FirstStageConsole(const std::string& cmdline) {
auto pos = cmdline.find("androidboot.first_stage_console=");
if (pos != std::string::npos) {
int val = 0;
// 加载内核模块,fail的时候才打开串口
if (sscanf(cmdline.c_str() + pos, "androidboot.first_stage_console=%d", &val) != 1) {
return FirstStageConsoleParam::DISABLED;
}
if (val <= FirstStageConsoleParam::MAX_PARAM_VALUE && val >= 0) {
return val;
}
}
return FirstStageConsoleParam::DISABLED;
}
enum FirstStageConsoleParam {
DISABLED = 0,
CONSOLE_ON_FAILURE = 1,
IGNORE_FAILURE = 2,
MAX_PARAM_VALUE = IGNORE_FAILURE,
};
9.2 StartConsole-创建/dev/console设备,然后打开/dev/console设备,执行/first_stage.sh文件,或者sh
void StartConsole() {
// 创建设备
if (mknod("/dev/console", S_IFCHR | 0600, makedev(5, 1))) {
PLOG(ERROR) << "unable to create /dev/console";
return;
}
pid_t pid = fork();
if (pid != 0) {
int status;
waitpid(pid, &status, 0);
LOG(ERROR) << "console shell exited with status " << status;
return;
}
int fd = -1;
int tries = 50; // should timeout after 5s
// The device driver for console may not be ready yet so retry for a while in case of failure.
while (tries--) {
// 打开设备
fd = open("/dev/console", O_RDWR);
if (fd != -1) {
break;
}
std::this_thread::sleep_for(100ms);
}
if (fd == -1) {
LOG(ERROR) << "Could not open /dev/console, errno = " << errno;
_exit(127);
}
ioctl(fd, TIOCSCTTY, 0);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
// 执行/first_stage.sh文件
RunScript();
// 执行sh
const char* path = "/system/bin/sh";
const char* args[] = {path, nullptr};
int rv = execv(path, const_cast<char**>(args));
LOG(ERROR) << "unable to execv, returned " << rv << " errno " << errno;
_exit(127);
}
static void RunScript() {
LOG(INFO) << "Attempting to run /first_stage.sh...";
pid_t pid = fork();
if (pid != 0) {
int status;
waitpid(pid, &status, 0);
LOG(INFO) << "/first_stage.sh exited with status " << status;
return;
}
const char* path = "/system/bin/sh";
const char* args[] = {path, "/first_stage.sh", nullptr};
int rv = execv(path, const_cast<char**>(args));
LOG(ERROR) << "unable to execv /first_stage.sh, returned " << rv << " errno " << errno;
}
补充
1. c++
1.1 成员变量的构造函数调用
先调用成员变量的构造函数,然后调用本类的构造函数
问题
1. Android P system-as-root-内核挂载分区失败
system-as-root方式需要在内核init阶段挂载system分区,由于mmc还没有初始化完成,导致没有分区。需要在env.cfg文件的mmc那里加上rootwait
而Android Q之后,使用的是ramdisk的方式,所以不需要rootwait标志。
[ 2.241183] VFS: Cannot open root device "mmcblk0p4" or unknown-block(0,0): error -6
[ 2.249997] Please append a correct "root=" boot option; here are the available partitions:
2. 卡启动需要配置dts-不然会显示找不到super分区-boot_devices要配置上sdcard的
firmware {
android {
compatible = "android,firmware";
name = "android";
boot_devices = "soc@2900000/4020000.sdmmc,soc@2900000/4022000.sdmmc,soc@2900000";
};
optee {
compatible = "linaro,optee-tz";
method = "smc";
};
};
3. uevent事件不对
"device-mapper device not found in /sys, waiting for its uevent"
一般是产生的uevent事件和dts里面配置的分区,或者device-mapper的uevent没有上来导致的
或者是根本就没有产生uevent事件,这时候只需要把uevent相关的debug log打开即可
if (LOG_UEVENTS) {
// 可以打开这个打印,通过串口看发了哪个uevent了
LOG(INFO) << "event { '" << uevent->action << "', '" << uevent->path << "', '"
<< uevent->subsystem << "', '" << uevent->firmware << "', " << uevent->major
<< ", " << uevent->minor << " }";
}
forcenormalboot