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;
}
相关推荐
张拭心8 分钟前
春节后,有些公司明确要求 AI 经验了
android·前端·人工智能
张拭心19 分钟前
Android 17 来了!新特性介绍与适配建议
android·前端
Kapaseker3 小时前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
黄林晴3 小时前
Android17 为什么重写 MessageQueue
android
阿巴斯甜1 天前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker1 天前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95271 天前
Andorid Google 登录接入文档
android
黄林晴1 天前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab2 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿2 天前
Android MediaPlayer 笔记
android