首页 > 其他分享 >Android 启动时判断overlay fs是否挂载

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

时间:2024-08-28 13:57:50浏览次数:17  
标签:__ fs return overlay dev init argv path Android

一、背景

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.cpp

int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif

    if (!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.cpp

int 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.cpp

bool 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 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));
    };

...

}

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

system/core/init/init.cpp


int 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 init

file = 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博客

标签:__,fs,return,overlay,dev,init,argv,path,Android
From: https://blog.csdn.net/u013463707/article/details/141348912

相关文章

  • c++算法3-广度优先搜索算法dfs
    搜索算法众所周知,搜索算法分为常见的两种深度优先搜索算法(dfs)广度优先搜索算法(bfs)深度优先搜索算法深度优先搜索算法就是一条道走到黑,如迷宫问题,重复不断地向前探索如果碰到死胡同就说明前面已经没有路了,这时候就可以想其他方向搜索,最终走到终点。回溯回溯是一种搜索算法......
  • DSC远程归档存放在NFS盘
    目录1.节点1操作1.1下载并且配置NFS1.2节点2操作2.节点2操作2.1配置共享文件2.2节点1操作3.节点1的归档配置4.节点2的归档配置5.启动实例话不多说,直接开整!现在我们是节点1挂节点2,节点2挂节点1,俗称互挂!1.节点1操作这里我们先把节点1当服务端1.1下载并且配置NFS......
  • Android面试高阶问题:Android屏幕刷新机制与优化指南
    目录1屏幕刷新基础概念1.1CPU与GPU的作用2.2SurfaceFlinger与图形合成2.3帧、帧率与屏幕刷新率2屏幕撕裂与双缓冲机制2.1屏幕撕裂的原因与影响2.2双缓冲机制的工作原理3优化策略与实践3.1性能分析工具与方法3.2优化案例分析与实施3.2.1案例四:异步加载与......
  • 面试必考问题:Android APP耗电最全解析和优化指南
    目录1AndroidAPP耗电原因分析1.1后台应用持续运行1.2高CPU使用率1.3网络使用不当1.4错误代码实现2Android不同版本的耗电优化功能2.1JobSchedulingAPI与BatteryHistorian2.2JobSchedulingAPI的深入解析2.3BatteryHistorian的实际应用2.4结合JobSch......
  • Android网络请求 |(一) 网络基础概念
    一、前端和后端 前端和后端通过接口交互。前端web端:使用的网页,打开的网站都是前端(使用html、css等语言)显示页面以及做一些简单的校验,比如说非空校验app端:android或者object-C(开发ios上的app)开发的app,后端在页面上操作的业务逻辑、功能如:后端控制购物的时候扣除的余额,......
  • 如何有效学习Android Framework:从系统编译到Framework深入
    Android开发者中,不少人希望从应用开发过渡到系统层次的开发,特别是深入理解和掌握Framework的开发技能,这不仅能为你打开新的职业大门,还能让你更深入地理解Android系统的运行机制。本文将介绍如何从系统编译开始,逐步深入到系统应用和Framework的学习路径。1.掌握系统编译:打好基础......
  • 自建 NFS 服务器实现 Kubernetes 持久化存储
    1.简介在Kubernetes集群中,持久化存储是一个非常重要的组件。它允许我们保存需要长期保留的数据,即使Pod被删除或重新调度,这些数据也不会丢失。网络文件系统(NFS)是一种简单、可靠且广泛使用的存储解决方案。本文将详细介绍如何在CentOS7系统上搭建NFS服务器,并......
  • FPGA与STM32_FSMC总线通信实验
    在嵌入式系统设计中,FPGA(现场可编程门阵列)与微控制器如STM32的通信是常见的应用场景。STM32通过FSMC(灵活静态存储控制器)接口与FPGA进行数据交换,可以实现高速数据传输和复杂逻辑控制。本文将介绍如何通过FSMC总线实现STM32与FPGA之间的通信。实验目的理解FSMC总线的基本工作......
  • Android开发 - IInterface 接口 Binder 机制跨进程通信 (IPC)解析
    什么是IInterfaceIInterface一个接口,用于跨进程通信(IPC)。有时需要让一个应用程序与另一个应用程序或服务进行通信。这些应用程序可能运行在不同的进程中,使用Binder机制来实现这种通信,而IInterface就是Binder机制的一部分简单来说,IInterface是一个基础接口,它为跨......
  • NTFS安全权限和SMB文件共享服务器
    NTFS安全权限右键文件或文件夹属性-->安全可以修改权限基本权限读取允许查看文件、目录的内容、属性写入允许修改文件、添加新的文件扩展允许执行文件或遍历目录修改读取、写入、删除完全控制允许执行所有权限,包括更改权限和拥有权原则最小权限原则......