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;
}
相关推荐
太空漫步111 小时前
android社畜模拟器
android
海绵宝宝_4 小时前
【HarmonyOS NEXT】获取正式应用签名证书的签名信息
android·前端·华为·harmonyos·鸿蒙·鸿蒙应用开发
凯文的内存6 小时前
android 定制mtp连接外设的设备名称
android·media·mtp·mtpserver
天若子6 小时前
Android今日头条的屏幕适配方案
android
林的快手7 小时前
伪类选择器
android·前端·css·chrome·ajax·html·json
望佑8 小时前
Tmp detached view should be removed from RecyclerView before it can be recycled
android
xvch10 小时前
Kotlin 2.1.0 入门教程(二十四)泛型、泛型约束、绝对非空类型、下划线运算符
android·kotlin
人民的石头14 小时前
Android系统开发 给system/app传包报错
android
yujunlong391914 小时前
android,flutter 混合开发,通信,传参
android·flutter·混合开发·enginegroup
rkmhr_sef14 小时前
万字详解 MySQL MGR 高可用集群搭建
android·mysql·adb