做外贸必须用的社交网站,免费装修设计图app,wordpress缩略图不清晰怎么办,门户网站特点Android 12 S 系统开机流程分析-FirstStageMain#xff08;一#xff09;
本文接着上文开始讲解#xff0c;上文中最后一步执行后会执行init启动过程中的第二步SetupSelinux(Selinux配置阶段)#xff0c;这样又会走到main.cpp中的main方法。
目录
1. SetupSelinux
1.1 …Android 12 S 系统开机流程分析-FirstStageMain一
本文接着上文开始讲解上文中最后一步执行后会执行init启动过程中的第二步SetupSelinux(Selinux配置阶段)这样又会走到main.cpp中的main方法。
目录
1. SetupSelinux
1.1 初始化kernel log系统
1.2 ReadPolicy
1.3 加载策略
1.4 使能/关闭Selinux并写入节点
1.5 selinux_android_restorecon
1.6 重新执行init进程并携带参数second_stage 1. SetupSelinux
由于上一篇中最后一步在重新执行init的时候携带了参数selinux_setup所以此处会走入SetupSelinux方法加载selinux的策略。
SetupSelinux主要功能 1open sepolicy 2load sepolicy 3使能/关闭selinux int main(int argc, char** argv) {
...if (!strcmp(argv[1], selinux_setup)) {
//执行此处return SetupSelinux(argv);}if (!strcmp(argv[1], second_stage)) {return SecondStageMain(argc, argv);}}return FirstStageMain(argc, argv);
}
1.1 初始化kernel log系统
1初始化kernel log
2若系统发生了panic则走InstallRebootSignalHandlers
InstallRebootSignalHandlers中主要做了以下几件事 1. 初始化了一个自定义信号集将其所有信号都填充满即将信号集中的所有的标志位都置为1使得这个集合包含所有可接受的信号也就是阻塞所有信号。这个函数可以用于快速创建一个包含所有信号的信号集然后可以根据需要删除其中的某些信号。 2. init创建出来的子进程不做处理直接exit如果不是子进程则代表是init进程则执行InitFatalReboot 3. 通过syscall向内核发送重启命令 4. 捕获一些信号
int SetupSelinux(char** argv) {SetStdioToDevNull(argv);InitKernelLogging(argv);if (REBOOT_BOOTLOADER_ON_PANIC) {InstallRebootSignalHandlers();}boot_clock::time_point start_time boot_clock::now();
//这是R上为了R system.img/system_ext.img作为system_ext.img工作在old vendor.img上。
//我们在init第二阶段挂载system_ext因为在system-only OTA场景中boot.img的init第一阶段是不会被更新的。MountMissingSystemPartitions();SelinuxSetupKernelLogging();LOG(INFO) Opening SELinux policy;SelinuxGetVendorAndroidVersion主要作用是读/vendor/etc/selinux/plat_sepolicy_vers.txt中的第一行获取Selinux vendor version。
int SelinuxGetVendorAndroidVersion() {static int vendor_android_version [] {if (!IsSplitPolicyDevice()) {
//如果这个设备不拆分sepolicy文件它就不是一个Treble设备return __ANDROID_API_FUTURE__;}std::string version;
//获取vendor Selinux version
//读/vendor/etc/selinux/plat_sepolicy_vers.txt中的第一行
//可以adb看下vendor版本
//adb shell cat /vendor/etc/selinux/plat_sepolicy_vers.txt
//32.0if (!GetVendorMappingVersion(version)) {LOG(FATAL) Could not read vendor SELinux version;}
//解析version值version一般是带小数点的比如32.0。int major_version;std::string major_version_str(version, 0, version.find(.));if (!ParseInt(major_version_str, major_version)) {PLOG(FATAL) Failed to parse the vendor sepolicy major version major_version_str;}
//返回version中整数return major_version;}();return vendor_android_version;
}
1.2 ReadPolicy ReadPolicy主要做了两件事 1open split policy 2读sepolicy 这个是SetupSelinux的主要功能之一。 // Read the policy before potentially killing snapuserd.std::string policy;ReadPolicy(policy);auto snapuserd_helper SnapuserdSelinuxHelper::CreateIfNeeded();if (snapuserd_helper) {// Kill the old snapused to avoid audit messages. After this we cannot// read from /system (or other dynamic partitions) until we call// FinishTransition().snapuserd_helper-StartTransition();} ReadPolicy的主要功能是 如果设备中存在/system/etc/selinux/plat_sepolicy.cil文件并可以访问则IsSplitPolicyDevice为true,会走OpenSplitPolicy流程这个设备中默认都有这个文件的。 void ReadPolicy(std::string* policy) {PolicyFile policy_file;
//constexpr const char plat_policy_cil_file[] /system/etc/selinux/plat_sepolicy.cil;//bool IsSplitPolicyDevice() {
// return access(plat_policy_cil_file, R_OK) ! -1;
//}
//IsSplitPolicyDevice如上如果能访问设备中的/system/etc/selinux/plat_sepolicy.cil文件
//则IsSplitPolicyDevice为true,会走OpenSplitPolicybool ok IsSplitPolicyDevice() ? OpenSplitPolicy(policy_file): OpenMonolithicPolicy(policy_file);if (!ok) {LOG(FATAL) Unable to open SELinux policy;}if (!android::base::ReadFdToString(policy_file.fd, policy)) {PLOG(FATAL) Failed to read policy file: policy_file.path;}
} OpenSplitPolicy的主要功能是 1如果设备是userdebug版本设备unlock存在/debug_ramdisk/adb_debug.prop并且可以访问则加载userdebug system sepolicy 2从代码看是access systemvendorsystem_ext和vendor下etc/selinux/mapping/下的.cil文件 3再查看对应目录下的.cil文件内容是否为空,不为空则将对应目录下的.cil文件内容push进compile_args 4执行compile_args并等待决定include哪个mapping下的.cil文件 5将临时文件/dev/sepolicy.XXXXXX的fd和path保存进policy_file-fd和 policy_file-path。 bool OpenSplitPolicy(PolicyFile* policy_file) {
//若存在/force_debuggable则在init启动第一阶段force_debuggable_env 环境变量已经设置好了
//setenv(INIT_FORCE_DEBUGGABLE, true, 1);const char* force_debuggable_env getenv(INIT_FORCE_DEBUGGABLE);
//是userdebug版本设备unlock存在/debug_ramdisk/adb_debug.prop并且可以访问
//则加载userdebug system sepolicybool use_userdebug_policy ((force_debuggable_env trues force_debuggable_env) AvbHandle::IsDeviceUnlocked() access(kDebugRamdiskSEPolicy, F_OK) 0);if (use_userdebug_policy) {LOG(WARNING) Using userdebug system sepolicy;}if (!use_userdebug_policy) {if (auto res FindPrecompiledSplitPolicy(); res.ok()) {unique_fd fd(open(res-c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));if (fd ! -1) {policy_file-fd std::move(fd);policy_file-path std::move(*res);return true;}} else {LOG(INFO) res.error();}}// No suitable precompiled policy could be loaded
//没有合适的策略可以加载LOG(INFO) Compiling SELinux policy;// We store the output of the compilation on /dev because this is the most convenient tmpfs// storage mount available this early in the boot sequence.char compiled_sepolicy[] /dev/sepolicy.XXXXXX;
//mkostemp创建临时文件
//创建临时文件/dev/sepolicy.XXXXXX其fd为compiled_sepolicy_fdunique_fd compiled_sepolicy_fd(mkostemp(compiled_sepolicy, O_CLOEXEC));if (compiled_sepolicy_fd 0) {PLOG(ERROR) Failed to create temporary file compiled_sepolicy;return false;}
...
//从代码看是access systemvendorsystem_ext和vendor下etc/selinux/mapping/下的.cil文件
//再查看对应目录下的.cil文件内容是否为空,不为空则将对应目录下的.cil文件内容push进compile_args
//执行compile_args并等待
//将临时文件/dev/sepolicy.XXXXXX的fd和path保存进policy_file-fd和 policy_file-path。
//决定include哪个mapping下的.cil文件std::string vend_plat_vers;if (!GetVendorMappingVersion(vend_plat_vers)) {return false;}std::string plat_mapping_file(/system/etc/selinux/mapping/ vend_plat_vers .cil);std::string plat_compat_cil_file(/system/etc/selinux/mapping/ vend_plat_vers .compat.cil);if (access(plat_compat_cil_file.c_str(), F_OK) -1) {plat_compat_cil_file.clear();}std::string system_ext_policy_cil_file(/system_ext/etc/selinux/system_ext_sepolicy.cil);if (access(system_ext_policy_cil_file.c_str(), F_OK) -1) {system_ext_policy_cil_file.clear();}std::string system_ext_mapping_file(/system_ext/etc/selinux/mapping/ vend_plat_vers .cil);if (access(system_ext_mapping_file.c_str(), F_OK) -1) {system_ext_mapping_file.clear();}std::string system_ext_compat_cil_file(/system_ext/etc/selinux/mapping/ vend_plat_vers .compat.cil);if (access(system_ext_compat_cil_file.c_str(), F_OK) -1) {system_ext_compat_cil_file.clear();}std::string product_policy_cil_file(/product/etc/selinux/product_sepolicy.cil);if (access(product_policy_cil_file.c_str(), F_OK) -1) {product_policy_cil_file.clear();}std::string product_mapping_file(/product/etc/selinux/mapping/ vend_plat_vers .cil);if (access(product_mapping_file.c_str(), F_OK) -1) {product_mapping_file.clear();}// vendor_sepolicy.cil and plat_pub_versioned.cil are the new design to replace// nonplat_sepolicy.cil.std::string plat_pub_versioned_cil_file(/vendor/etc/selinux/plat_pub_versioned.cil);std::string vendor_policy_cil_file(/vendor/etc/selinux/vendor_sepolicy.cil);if (access(vendor_policy_cil_file.c_str(), F_OK) -1) {// For backward compatibility.// TODO: remove this after no device is using nonplat_sepolicy.cil.vendor_policy_cil_file /vendor/etc/selinux/nonplat_sepolicy.cil;plat_pub_versioned_cil_file.clear();} else if (access(plat_pub_versioned_cil_file.c_str(), F_OK) -1) {LOG(ERROR) Missing plat_pub_versioned_cil_file;return false;}// odm_sepolicy.cil is default but optional.std::string odm_policy_cil_file(/odm/etc/selinux/odm_sepolicy.cil);if (access(odm_policy_cil_file.c_str(), F_OK) -1) {odm_policy_cil_file.clear();}const std::string version_as_string std::to_string(SEPOLICY_VERSION);//有一些代码我们并不想让clang-format调整格式这时可以使用注释临时禁用clang-format// clang-format offstd::vectorconst char* compile_args {/system/bin/secilc,use_userdebug_policy ? kDebugRamdiskSEPolicy: plat_policy_cil_file,-m, -M, true, -G, -N,-c, version_as_string.c_str(),plat_mapping_file.c_str(),-o, compiled_sepolicy,// We dont care about file_contexts output by the compiler-f, /sys/fs/selinux/null, // /dev/null is not yet available};// clang-format on//将对应目录下的.cil文件内容push进compile_argsif (!plat_compat_cil_file.empty()) {compile_args.push_back(plat_compat_cil_file.c_str());}if (!system_ext_policy_cil_file.empty()) {compile_args.push_back(system_ext_policy_cil_file.c_str());}if (!system_ext_mapping_file.empty()) {compile_args.push_back(system_ext_mapping_file.c_str());}if (!system_ext_compat_cil_file.empty()) {compile_args.push_back(system_ext_compat_cil_file.c_str());}if (!product_policy_cil_file.empty()) {compile_args.push_back(product_policy_cil_file.c_str());}if (!product_mapping_file.empty()) {compile_args.push_back(product_mapping_file.c_str());}if (!plat_pub_versioned_cil_file.empty()) {compile_args.push_back(plat_pub_versioned_cil_file.c_str());}if (!vendor_policy_cil_file.empty()) {compile_args.push_back(vendor_policy_cil_file.c_str());}if (!odm_policy_cil_file.empty()) {compile_args.push_back(odm_policy_cil_file.c_str());}compile_args.push_back(nullptr);
//执行compile_args并等待if (!ForkExecveAndWaitForCompletion(compile_args[0], (char**)compile_args.data())) {unlink(compiled_sepolicy);return false;}unlink(compiled_sepolicy);
//将临时文件/dev/sepolicy.XXXXXX的fd和path保存进policy_file-fd和 policy_file-path。policy_file-fd std::move(compiled_sepolicy_fd);policy_file-path compiled_sepolicy;return true;
}
1.3 加载策略
这也是SetupSelinux中最重要的功能之一。 LoadSelinuxPolicy(policy); 上一节中对policy进行了赋值。
static void LoadSelinuxPolicy(std::string policy) {LOG(INFO) Loading SELinux policy;set_selinuxmnt(/sys/fs/selinux);if (security_load_policy(policy.data(), policy.size()) 0) {PLOG(FATAL) SELinux: Could not load policy;}
} security_load_policy主要功能是 1open $selinux_mnt/load获取其对应fd 2根据fd将/dev/sepolicy.XXXXXX中的内容写入$selinux_mnt/load中。selinux_mnt如下#define SELINUXMNT /sys/fs/selinux external/selinux/libselinux/src/load_policy.c
int security_load_policy(void *data, size_t len)
{char path[PATH_MAX];int fd, ret;if (!selinux_mnt) {errno ENOENT;return -1;}snprintf(path, sizeof path, %s/load, selinux_mnt);fd open(path, O_RDWR | O_CLOEXEC);if (fd 0)return -1;ret write(fd, data, len);close(fd);if (ret 0)return -1;return 0;
}
1.4 使能/关闭Selinux并写入节点 获取selinux状态是否是enforce然后将selinux状态is_enforcing写入 $selinux_mnt/enforce中。selinux_mnt如下 #define SELINUXMNT /sys/fs/selinux if (snapuserd_helper) {// Before enforcing, finish the pending snapuserd transition.snapuserd_helper-FinishTransition();snapuserd_helper nullptr;}SelinuxSetEnforcement();
void SelinuxSetEnforcement() {bool kernel_enforcing (security_getenforce() 1);
//check selinux是否是enforce状态开启selinuxbool is_enforcing IsEnforcing();if (kernel_enforcing ! is_enforcing) {if (security_setenforce(is_enforcing)) {PLOG(FATAL) security_setenforce( (is_enforcing ? true : false) ) failed;}}if (auto result WriteFile(/sys/fs/selinux/checkreqprot, 0); !result.ok()) {LOG(FATAL) Unable to write to /sys/fs/selinux/checkreqprot: result.error();}
}
bool IsEnforcing() {
//如果关闭系统的selinux,即将selinux置为permissive此处直接返回false即可
//return false;if (ALLOW_PERMISSIVE_SELINUX) {return StatusFromProperty() SELINUX_ENFORCING;}return true;
}
/external/selinux/libselinux/src/setenforce.c
int security_setenforce(int value)
{int fd, ret;char path[PATH_MAX];char buf[20];if (!selinux_mnt) {errno ENOENT;return -1;}snprintf(path, sizeof path, %s/enforce, selinux_mnt);fd open(path, O_RDWR | O_CLOEXEC);if (fd 0)return -1;snprintf(buf, sizeof buf, %d, value);ret write(fd, buf, strlen(buf));close(fd);if (ret 0)return -1;return 0;
}1.5 selinux_android_restorecon
从kernel domain域过渡到init domain域 文件系统在xattrs中存储了SELabels比如ext4不需要restorecon但其他文件系统需要
//从kernel domain域过渡到init domain域
//文件系统在xattrs中存储了SELabels比如ext4不需要restorecon但其他文件系统需要if (selinux_android_restorecon(/system/bin/init, 0) -1) {PLOG(FATAL) restorecon failed of /system/bin/init failed;}
1.6 重新执行init进程并携带参数second_stage setenv(kEnvSelinuxStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(), 1);const char* path /system/bin/init;const char* args[] {path, second_stage, nullptr};execv(path, const_castchar**(args));// execv() only returns if an error happened, in which case we// panic and never return from this function.PLOG(FATAL) execv(\ path \) failed;return 1;
}
到了SetupSelinux的最后一步这一步还是重新执行/system/bin/init这样就会再次走init bin程序的main函数由代码可以看到此次携带了参数second_stage。
后面接着讲启动流程