Android 启动时判断overlay fs是否挂载

2024-08-29 12:12

本文主要是介绍Android 启动时判断overlay fs是否挂载,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、背景

Android新版本使用super分区替代原来的system、vendor后,就采用了overlayfs文件系统。这种文件系统在执行adb remount 后,修改system 、vendor分区内容并不是真正存储在原来的位置,而是单独利用super剩余空间或data分区存了一份新的,原来的文件并没有改变。系统使用时判断有overlay的就用新的,没有就是有原文件。具体概念可查看https://www.cnblogs.com/loongson-artc-lyc/p/15981855.html 了解。

这就带来一个问题,调试时使用adb push 更新了需要开机下载的固件,但是开机过程中不是一开始就挂载overlay fs的,这就可能导致加载的还是老的固件。我们需要在kernel中判断何时挂载了overlay fs再去加载固件,就可以解决这个问题。

二、Init阶段overlay fs挂载前后阶段分析

adb remount log

adb remount[libfs_mgr]fs_mgr_do_format: Format /dev/block/dm-5 as 'f2fs'
Using overlayfs for /vendor
Now reboot your device for settings to take effect
remount succeeded

init 启动代码

system/core/init/main.cppint main(int argc, char** argv) {
#if __has_feature(address_sanitizer)__asan_set_error_report_callback(AsanReportCallback);
#endifif (!strcmp(basename(argv[0]), "ueventd")) {return ueventd_main(argc, argv);}if (argc > 1) {if (!strcmp(argv[1], "subcontext")) {android::base::InitLogging(argv, &android::base::KernelLogger);const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();return SubcontextMain(argc, argv, &function_map);}if (!strcmp(argv[1], "selinux_setup")) {return SetupSelinux(argv);}if (!strcmp(argv[1], "second_stage")) {return SecondStageMain(argc, argv);}}return FirstStageMain(argc, argv);
}

 上面函数会执行多次,执行FirstStageMain时会调用DoFirstStageMount跟据fstab挂载物理分区

和overlay fs

system/core/init/first_stage_init.cppint FirstStageMain(int argc, char** argv) {if (REBOOT_BOOTLOADER_ON_PANIC) {InstallRebootSignalHandlers();}boot_clock::time_point start_time = boot_clock::now();....if (access("/force_debuggable", F_OK) == 0) {std::error_code ec;  // to invoke the overloaded copy_file() that won't throw.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.setenv("INIT_FORCE_DEBUGGABLE", "true", 1);}}if (!DoFirstStageMount()) {LOG(FATAL) << "Failed to mount required partitions early ...";}...}system/core/init/first_stage_mount.cppbool FirstStageMount::DoFirstStageMount() {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;
}bool FirstStageMount::MountPartitions() {...// 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 logicauto 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));};...}

执行SecondStageMain会创建/dev/.booting和/dev/__properties__文件

system/core/init/init.cppint SecondStageMain(int argc, char** argv) {...close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));...PropertyInit();//此函数会创建/dev/__properties__...}

 所以只需要我们在init的第二个阶段去加载固件就可以保证overlay fs已挂载,加载的是新的固件。

判断是否处于第二阶段可以判断/dev/.booting或/dev/__properties__是否存在即可。

三、内核增加判断示例

//#define SECOND_INIT_STAGE_FILE "/dev/.booting" //this file will be deleted when firmware load
#define SECOND_INIT_STAGE_FILE "/dev/__properties__" //this is a dir created at second initfile = filp_open(SECOND_INIT_STAGE_FILE, O_RDONLY, 0);
if (IS_ERR(file)){dev_info(sdev->dev, "%s: open '%s' failed, ret %d\n",__func__, SECOND_INIT_STAGE_FILE, ret);} else {filp_close(file,NULL);
}或bool folder_exists(struct path *path, const char *name) {struct path lookup_path = *path; // 初始路径struct qstr qname = QSTR_INIT(name, strlen(name));int err = path_lookupat(lookup_path.dentry, lookup_path.mnt, qname, &lookup_path);if (err == 0) {// 文件夹存在path_put(&lookup_path); // 释放路径return true;}return false; // 文件夹不存在
}或error = vfs_stat(path,&stat)if(error) {return -ENOENT;//路径不存在
}
if(S_ISDIR(stat.mode)){//是目录
}
else if(S_ISREG(stat.mode)) {//是文件
}else {//其他类型
}

参考:Android 动态分区详解(七) overlayfs 与 adb remount 操作_android overlayfs-CSDN博客

android 系统相关_android super分区-CSDN博客

这篇关于Android 启动时判断overlay fs是否挂载的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1117823

相关文章

JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法

《JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法》:本文主要介绍JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法,每种方法结合实例代码给大家介绍的非常... 目录引言:为什么"相等"判断如此重要?方法1:使用some()+includes()(适合小数组)方法2

如何通过try-catch判断数据库唯一键字段是否重复

《如何通过try-catch判断数据库唯一键字段是否重复》在MyBatis+MySQL中,通过try-catch捕获唯一约束异常可避免重复数据查询,优点是减少数据库交互、提升并发安全,缺点是异常处理开... 目录1、原理2、怎么理解“异常走的是数据库错误路径,开销比普通逻辑分支稍高”?1. 普通逻辑分支 v

Android协程高级用法大全

《Android协程高级用法大全》这篇文章给大家介绍Android协程高级用法大全,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友跟随小编一起学习吧... 目录1️⃣ 协程作用域(CoroutineScope)与生命周期绑定Activity/Fragment 中手

SpringBoot通过main方法启动web项目实践

《SpringBoot通过main方法启动web项目实践》SpringBoot通过SpringApplication.run()启动Web项目,自动推断应用类型,加载初始化器与监听器,配置Spring... 目录1. 启动入口:SpringApplication.run()2. SpringApplicat

从基础到进阶详解Python条件判断的实用指南

《从基础到进阶详解Python条件判断的实用指南》本文将通过15个实战案例,带你大家掌握条件判断的核心技巧,并从基础语法到高级应用一网打尽,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录​引言:条件判断为何如此重要一、基础语法:三行代码构建决策系统二、多条件分支:elif的魔法三、

解决Nginx启动报错Job for nginx.service failed because the control process exited with error code问题

《解决Nginx启动报错Jobfornginx.servicefailedbecausethecontrolprocessexitedwitherrorcode问题》Nginx启... 目录一、报错如下二、解决原因三、解决方式总结一、报错如下Job for nginx.service failed bec

Linux实现查看某一端口是否开放

《Linux实现查看某一端口是否开放》文章介绍了三种检查端口6379是否开放的方法:通过lsof查看进程占用,用netstat区分TCP/UDP监听状态,以及用telnet测试远程连接可达性... 目录1、使用lsof 命令来查看端口是否开放2、使用netstat 命令来查看端口是否开放3、使用telnet

Spring Boot项目如何使用外部application.yml配置文件启动JAR包

《SpringBoot项目如何使用外部application.yml配置文件启动JAR包》文章介绍了SpringBoot项目通过指定外部application.yml配置文件启动JAR包的方法,包括... 目录Spring Boot项目中使用外部application.yml配置文件启动JAR包一、基本原理

Android 缓存日志Logcat导出与分析最佳实践

《Android缓存日志Logcat导出与分析最佳实践》本文全面介绍AndroidLogcat缓存日志的导出与分析方法,涵盖按进程、缓冲区类型及日志级别过滤,自动化工具使用,常见问题解决方案和最佳实... 目录android 缓存日志(Logcat)导出与分析全攻略为什么要导出缓存日志?按需过滤导出1. 按

解决若依微服务框架启动报错的问题

《解决若依微服务框架启动报错的问题》Invalidboundstatement错误通常由MyBatis映射文件未正确加载或Nacos配置未读取导致,需检查XML的namespace与方法ID是否匹配,... 目录ruoyi-system模块报错报错详情nacos文件目录总结ruoyi-systnGLNYpe