Android init阶段loop回环设备的使用

环回设备是一种特殊的块设备,它允许你将一个普通的文件当作块设备来使用。这种功能在需要将文件系统挂载到一个文件上时特别有用,比如在处理磁盘镜像文件时。

内核驱动:drivers/block/loop.c。 在内核驱动初始化时会自动创建一定数量的loop设备,上层在通过/dev/loop-control节点ioctrl LOOP_CTL_GET_FREE时,如果没有设备会自动创建。

在ramdisk init阶段需要创建/dev/loop-control和/dev/block/loop0-3节点,并绑定内核环回设备:

c 复制代码
system/core$
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index d050ed783..b34003635 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -233,7 +233,7 @@ int FirstStageMain(int argc, char** argv) {
     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(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755,size=1024M"));
     CHECKCALL(mkdir("/dev/pts", 0755));
     CHECKCALL(mkdir("/dev/socket", 0755));
     CHECKCALL(mkdir("/dev/dm-user", 0755));
@@ -266,6 +266,12 @@ int FirstStageMain(int argc, char** argv) {
     // 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)));
+    CHECKCALL(mknod("/dev/loop-control", S_IFCHR | 0666, makedev(10, 237)));
+    CHECKCALL(mkdir("/dev/block", 0755));
+    CHECKCALL(mknod("/dev/block/loop0", S_IFBLK | 0755, makedev(7, 0)));
+    CHECKCALL(mknod("/dev/block/loop1", S_IFBLK | 0755, makedev(7, 8)));
+    CHECKCALL(mknod("/dev/block/loop2", S_IFBLK | 0755, makedev(7, 16)));
+    CHECKCALL(mknod("/dev/block/loop3", S_IFBLK | 0755, makedev(7, 24)));
  • mknod(const char *pathname, mode_t mode, dev_t dev) 是一个系统调用,用于创建一个文件系统节点(文件、设备特殊文件或命名管道)。

  • 参数解释:

    • "/dev/block/loop0":这是要创建的设备文件的路径。
    • S_IFBLK | 0755:这是文件的模式。S_IFBLK 表示创建的是一个块设备,0755 是文件的权限(所有者可读、写、执行,其他用户可读和执行)。
    • makedev(7, 0):这是设备号,makedev 函数用于生成设备号,7 是主设备号,0 是次设备号。对于环回设备,主设备号通常是 7。 主从设备号需要从机器里面通过ls -la /dev/block/loop*查看,不同的内核版本可能不一样
shell 复制代码
rk3588_t:/ $ ls -l /dev/block/loop*
brwxr-xr-x 1 root root 7,   0 2025-01-13 00:17 /dev/block/loop0
brwxr-xr-x 1 root root 7,   8 2025-01-13 00:17 /dev/block/loop1
brw------- 1 root root 7,  80 2025-01-13 00:18 /dev/block/loop10
brw------- 1 root root 7,  88 2025-01-13 00:18 /dev/block/loop11
brw------- 1 root root 7,  96 2025-01-13 00:18 /dev/block/loop12
brw------- 1 root root 7, 104 2025-01-13 00:18 /dev/block/loop13
brw------- 1 root root 7, 112 2025-01-13 00:18 /dev/block/loop14
brw------- 1 root root 7, 120 2025-01-13 00:18 /dev/block/loop15
brwxr-xr-x 1 root root 7,  16 2025-01-13 00:17 /dev/block/loop2
brwxr-xr-x 1 root root 7,  24 2025-01-13 00:18 /dev/block/loop3
brw------- 1 root root 7,  32 2025-01-13 00:18 /dev/block/loop4
brw------- 1 root root 7,  40 2025-01-13 00:18 /dev/block/loop5
brw------- 1 root root 7,  48 2025-01-13 00:18 /dev/block/loop6
brw------- 1 root root 7,  56 2025-01-13 00:18 /dev/block/loop7
brw------- 1 root root 7,  64 2025-01-13 00:18 /dev/block/loop8
brw------- 1 root root 7,  72 2025-01-13 00:18 /dev/block/loop9

在init中编写代码将镜像文件绑定到loop设备上面

c++ 复制代码
std::string setup_loop_device(const std::string& file_path) {
       std::string system_device;
    if (Loop::create(file_path, system_device) != 0) {
        LOG(ERROR) << "Failed to create loop device file_path";
        return nullptr;
    }
    LOG(INFO) << "created loop device: " << system_device;
    return system_device;
}

int Loop::create(const std::string& target, std::string& out_device) {
    unique_fd ctl_fd(open("/dev/loop-control", O_RDWR | O_CLOEXEC));
    if (ctl_fd.get() == -1) {
        PLOG(ERROR) << "Failed to open loop-control";
        return -errno;
    }

    int num = ioctl(ctl_fd.get(), LOOP_CTL_GET_FREE);
    if (num == -1) {
        PLOG(ERROR) << "Failed LOOP_CTL_GET_FREE";
        
		for (size_t id = 0; id < 3; ++id) {
			int ret = ioctl(ctl_fd.get(), LOOP_CTL_ADD, id);
			LOG(INFO) << "LOOP_CTL_ADD ADD ID=" << id;
			if (ret < 0 && errno != EEXIST) {
				LOG(ERROR) << "Failed LOOP_CTL_ADD";
				return -errno;
			}
		}
		num = ioctl(ctl_fd.get(), LOOP_CTL_GET_FREE);
		if (num == -1) {
			PLOG(ERROR) << "Failed LOOP_CTL_GET_FREE";       
			return -errno;
		}
	}

    out_device = StringPrintf("/dev/block/loop%d", num);

    unique_fd target_fd;
    for (size_t i = 0; i != kLoopDeviceRetryAttempts; ++i) {
        target_fd.reset(open(target.c_str(), O_RDWR | O_CLOEXEC));
        if (target_fd.get() != -1) {
            break;
        }
        usleep(50000);
    }
    if (target_fd.get() == -1) {
        PLOG(ERROR) << "Failed to open " << target;
        return -errno;
    }
    if (!android::fs_mgr::WaitForFile(out_device, 2s)) {
        LOG(ERROR) << "Failed to find " << out_device;
        return -ENOENT;
    }
    unique_fd device_fd(open(out_device.c_str(), O_RDWR | O_CLOEXEC));
    if (device_fd.get() == -1) {
        PLOG(ERROR) << "Failed to open " << out_device;
        return -errno;
    }

    if (ioctl(device_fd.get(), LOOP_SET_FD, target_fd.get()) == -1) {
        PLOG(ERROR) << "Failed to LOOP_SET_FD";
        return -errno;
    }

    struct loop_info64 li;
    memset(&li, 0, sizeof(li));
    strlcpy((char*)li.lo_crypt_name, kVoldPrefix, LO_NAME_SIZE);
    if (ioctl(device_fd.get(), LOOP_SET_STATUS64, &li) == -1) {
        PLOG(ERROR) << "Failed to LOOP_SET_STATUS64";
        return -errno;
    }

    return 0;
}
相关推荐
DogDaoDao4 小时前
Android 硬件编码器参数完全指南:MediaCodec 深度解析
android·音视频·视频编解码·h264·硬编码·视频直播·mediacodec
JohnnyDeng945 小时前
Android 自定义 View:Canvas 绘图与事件分发深度解析
android
Android小码家8 小时前
Framework之Launcher小窗开发
android·framework·虚拟屏·小窗
赏金术士8 小时前
第七章:状态管理实战与架构总结
android·ui·kotlin·compose
颂love9 小时前
MySQL的执行流程
android·数据库·mysql
云起SAAS14 小时前
抖音小游戏源码 - 消消乐 | 含激励广告+成就系统 | 开箱即用商业级消除游戏模板
android·游戏·广告联盟·看激励广告联盟流量主·抖音小游戏源码 - 消消乐
大貔貅喝啤酒15 小时前
基于Windows下载安装Android Studio 3.3.2版本教程(2026详细图文版)
android·java·windows·android studio
程序员码歌15 小时前
OpenSpec 到 Superpowers:AI 编码从说清到做对
android·前端·人工智能
2501_9151063216 小时前
深入解析无源码iOS加固原理与方案,保护应用安全
android·安全·ios·小程序·uni-app·cocoa·iphone
黄林晴19 小时前
重磅官宣:Android UI 开发正式进入 Compose-first 时代
android·google io