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

相关文章

MySQL数据库宕机,启动不起来,教你一招搞定!

作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等)公众号:老苏畅谈运维欢迎关注本人公众号,更多精彩与您分享。 MySQL数据库宕机,数据页损坏问题,启动不起来,该如何排查和解决,本文将为你说明具体的排查过程。 查看MySQL error日志 查看 MySQL error日志,排查哪个表(表空间

springboot3打包成war包,用tomcat8启动

1、在pom中,将打包类型改为war <packaging>war</packaging> 2、pom中排除SpringBoot内置的Tomcat容器并添加Tomcat依赖,用于编译和测试,         *依赖时一定设置 scope 为 provided (相当于 tomcat 依赖只在本地运行和测试的时候有效,         打包的时候会排除这个依赖)<scope>provided

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int

用命令行的方式启动.netcore webapi

用命令行的方式启动.netcore web项目 进入指定的项目文件夹,比如我发布后的代码放在下面文件夹中 在此地址栏中输入“cmd”,打开命令提示符,进入到发布代码目录 命令行启动.netcore项目的命令为:  dotnet 项目启动文件.dll --urls="http://*:对外端口" --ip="本机ip" --port=项目内部端口 例: dotnet Imagine.M

Linux服务器Java启动脚本

Linux服务器Java启动脚本 1、初版2、优化版本3、常用脚本仓库 本文章介绍了如何在Linux服务器上执行Java并启动jar包, 通常我们会使用nohup直接启动,但是还是需要手动停止然后再次启动, 那如何更优雅的在服务器上启动jar包呢,让我们一起探讨一下吧。 1、初版 第一个版本是常用的做法,直接使用nohup后台启动jar包, 并将日志输出到当前文件夹n

zoj 1721 判断2条线段(完全)相交

给出起点,终点,与一些障碍线段。 求起点到终点的最短路。 枚举2点的距离,然后最短路。 2点可达条件:没有线段与这2点所构成的线段(完全)相交。 const double eps = 1e-8 ;double add(double x , double y){if(fabs(x+y) < eps*(fabs(x) + fabs(y))) return 0 ;return x + y ;

POJ1269 判断2条直线的位置关系

题目大意:给两个点能够确定一条直线,题目给出两条直线(由4个点确定),要求判断出这两条直线的关系:平行,同线,相交。如果相交还要求出交点坐标。 解题思路: 先判断两条直线p1p2, q1q2是否共线, 如果不是,再判断 直线 是否平行, 如果还不是, 则两直线相交。  判断共线:  p1p2q1 共线 且 p1p2q2 共线 ,共线用叉乘为 0  来判断,  判断 平行:  p1p