android11.0(R) data分区节点加密控制分析

前情提要

androidQ(10.0) 预装集成apk到data分区

Android O、P、Q 版本如何预装 APK

遇到问题

当然是和之前一样啦,开机并不能正常启动,而是

自动进入了 recovery 界面,且界面显示

Can't load Android system. You'r data may be corrupt.If you continue to get this message, you may

need to perform a factory data reset and erase all user data stored on this devices.

按照提示我进行了恢复出厂操作,恢复出厂后能正常开机。但是预装的app没了,很明显预装app会没了。

按照之前 Q 版本的经验去修改代码后,问题依旧,还是不能正常开机,这就离谱,难道谷歌把这个地方给

堵死了???这还能难倒我么,上才艺。

解决办法

跳过 data 分区下 app 目录加密策略读取和设置即可

system/core/init/util.cpp

java 复制代码
@@ -88,7 +88,7 @@ static FscryptAction FscryptInferAction(const std::string& dir)
// Special case various directories that must not be encrypted,
    // often because their subdirectories must be encrypted.
    // This isn't a nice way to do this, see b/26641735
    std::vector<std::string> directories_to_exclude = {
            "lost+found", "system_ce", "system_de", "misc_ce",     "misc_de",
            "vendor_ce",  "vendor_de", "media",     "data",        "user",
-			"user_de",    "apex",      "preloads",  "app-staging", "gsi",
+            "user_de",    "apex",      "preloads",  "app-staging", "gsi", "app",
    };
    for (const auto& d : directories_to_exclude) {
        if ((prefix + d) == dir) {
            return FscryptAction::kNone;
        }
    }

跳过 init.rc 中 /data/app 节点加密

system/core/rootdir/init.rc

java 复制代码
+++ b/alps/system/core/rootdir/init.rc
@@ -658,7 +658,7 @@ on post-fs-data
     mkdir /data/app-ephemeral 0771 system system encryption=Require
     mkdir /data/app-asec 0700 root root encryption=Require
     mkdir /data/app-lib 0771 system system encryption=Require
-    mkdir /data/app 0771 system system encryption=Require
+    mkdir /data/app 0771 system system encryption=None
     mkdir /data/property 0700 root root encryption=Require
     mkdir /data/tombstones 0771 system system encryption=Require
     mkdir /data/vendor/tombstones 0771 root root

分析过程

当然要打开串口 Log 记录呀,它又不是那么简单的。R 版本的串口打开修改地方如下

kernel-4.19\drivers\misc\mediatek\mtprintk\mtk_printk_ctrl.c

java 复制代码
@@ -43,7 +43,7 @@ module_param_named(disable_uart, printk_ctrl, int, 0644);
 bool mt_get_uartlog_status(void)
 {
        if (printk_ctrl == 1)
-               return false;
+               return true;
        else if ((printk_ctrl == 0) || (printk_ctrl == 2))
                return true;
        return true;
		
@@ -53,7 +53,7 @@ void mt_disable_uart(void)
 {
        /* uart print not always enable */
        if (printk_ctrl != 2)
-               printk_ctrl = 1;
+               printk_ctrl = 0;
 }
 EXPORT_SYMBOL_GPL(mt_disable_uart);
 

vendor/mediatek/proprietary/bootable/bootloader/lk/app/mt_boot/mt_boot.c

java 复制代码
@@ -1345,7 +1345,7 @@ int boot_linux_fdt(void *kernel, unsigned *tags,
 #endif
                                cmdline_append("mtk_printk_ctrl.disable_uart=0");
                        else
-                               cmdline_append("mtk_printk_ctrl.disable_uart=1");
+                               cmdline_append("mtk_printk_ctrl.disable_uart=0");
                        break;
 
                case BUILD_TYPE_USERDEBUG:
@@ -1355,13 +1355,13 @@ int boot_linux_fdt(void *kernel, unsigned *tags,
 #else
                            (is_meta_log_disable() == 1))
 #endif
-                               cmdline_append("mtk_printk_ctrl.disable_uart=1 slub_debug=O");
+                               cmdline_append("mtk_printk_ctrl.disable_uart=0 slub_debug=O");
 #ifdef LOG_STORE_SUPPORT
                        else if (boot_ftrace && g_boot_arg->log_dynamic_switch == 0)
 #else
                        else if (boot_ftrace)
 #endif
-                               cmdline_append("mtk_printk_ctrl.disable_uart=1 slub_debug=-");
+                               cmdline_append("mtk_printk_ctrl.disable_uart=0 slub_debug=-");
                        else
                                cmdline_append("mtk_printk_ctrl.disable_uart=0");
                        break;
@@ -1369,7 +1369,7 @@ int boot_linux_fdt(void *kernel, unsigned *tags,
                case BUILD_TYPE_ENG:
                        if ((g_boot_mode == META_BOOT) && is_meta_log_disable &&
                            (is_meta_log_disable() == 1))
-                               cmdline_append("mtk_printk_ctrl.disable_uart=1 slub_debug=O");
+                               cmdline_append("mtk_printk_ctrl.disable_uart=0 slub_debug=O");
                        else
                                cmdline_append("mtk_printk_ctrl.disable_uart=0 ddebug_query=\"file *mediatek* +p ; file *gpu* =_\"");
                        break;

重新编译烧写开机得到如下串口日志

java 复制代码
[   13.654157] <4>.(4)[1:init]init 21: [13623][0]Switched to default mount namespace
[   13.655223] <4>.(4)[1:init]init 21: [13624][0]Not setting encryption policy on: /data/apex
[   13.663218] <4>.(4)[1:init]init 21: [13632][0]Not setting encryption policy on: /data/app-staging
[   13.666087] <4>.(4)[1:init]init 21: [13635][0]starting service 'apexd'...
) failed: No such file or directory
[   13.677980] <4>.(4)[1:init]init 25: [13644][0]Encryption policy of /data/misc set to d27f72eaf61213e463b2a9ec48dae65d v2 modes 1/4 flags 0x2
d input file '/data/misc/recovery/ro.build.fingerprint': open() failed: No such file or directory
ata/misc/recovery/proc/version': open() failed: No such file or directory
[   13.692959] <7>.(7)[456:apexd]apexd: Scanning /system/apex for preinstalled data
[   13.698614] <1>.(1)[456:apexd]apexd: Scanning /system_ext/apex for preinstalled data
[   13.699725] <1>.(1)[456:apexd]apexd: ... does not exist. Skipping
path.utils.link]=[stopped]13507 [init.svc_debug_pid.mtk.plpath.utils.link]=[]13507 [dev.mnt.blk.data]=[dm-7]13509 [init.svc.apexd]=[running]13639 [ro.boottime.apexd]=[13638876462]13640 [init.svc_debug_pid.apexd]=[456]13641 Done
[   13.700519] <1>.(1)[456:apexd]apexd: Scanning /product/apex for preinstalled data
[   13.706583] <1>.(1)[456:apexd]apexd: ... does not exist. Skipping
[   13.707396] <1>.(1)[456:apexd]apexd: Scanning /vendor/apex for preinstalled data
[   13.708382] <1>.(1)[456:apexd]apexd: ... does not exist. Skipping
[   13.709166] <1>.(1)[456:apexd]apexd: Populating APEX database from mounts...
[   13.710720] <1>.(1)[456:apexd]apexd: 0 packages restored.
[   13.711617] <1>.(1)[456:apexd]apexd: Marking APEXd as starting
[   13.730259] <3>.(3)[1:init]init 25: [13698][0]Encryption policy of /data/local set to d27f72eaf61213e463b2a9ec48dae65d v2 modes 1/4 flags 0x2
[   13.745616] <1>.(1)[456:apexd]EXT4-fs (loop6): mounted filesystem without journal. Opts: (null)
[   13.758344] <3>.(3)[1:init]init 25: [13727][0]Not setting encryption policy on: /data/preloads
[   13.762309] <3>.(3)[1:init]init 25: [13730][0]Encryption policy of /data/vendor set to d27f72eaf61213e463b2a9ec48dae65d v2 modes 1/4 flags 0x2
[   13.764161] <3>.(3)[1:init]init 25: [13733][0]Not setting encryption policy on: /data/vendor_ce
[   13.766555] <3>.(3)[1:init]init 25: [13735][0]Not setting encryption policy on: /data/vendor_de
[   13.773079] <3>.(3)[1:init]init 25: [13742][0]Not setting encryption policy on: /data/data
[   13.776787] <1>.(1)[456:apexd]EXT4-fs (loop7): mounted filesystem without journal. Opts: (null)
[   13.777475] <3>.(3)[1:init]init 21: [13745][0]Encryption policy of /data/app-private set to d27f72eaf61213e463b2a9ec48dae65d v2 modes 1/4 flags 0x2
[   13.781923] <0>.(0)[1:init]init 21: [13749][0]Encryption policy of /data/app-ephemeral set to d27f72eaf61213e463b2a9ec48dae65d v2 modes 1/4 flags 0x2
[   13.785340] <0>.(0)[1:init]init 21: [13753][0]Encryption policy of /data/app-asec set to d27f72eaf61213e463b2a9ec48dae65d v2 modes 1/4 flags 0x2
[   13.788729] <0>.(0)[1:init]init 21: [13756][0]Encryption policy of /data/app-lib set to d27f72eaf61213e463b2a9ec48dae65d v2 modes 1/4 flags 0x2
[   13.790485] <0>.(0)[1:init]init 21: [13759][0]Inferred action different from explicit one, expected 0 but got 2
[   13.792434] <0>.(0)[1:init]init 21: [13759][0]Failed to set encryption policy of /data/app to d27f72eaf61213e463b2a9ec48dae65d v2 modes 1/4 flags 0x2: Directory not empty
:s0 tclass=file permissive=1
[   13.800279] <2>.(2)[1:init]ls 21: [13759][0]executing ls failed: No such file or directory
[   13.800313] <2>.(1)[462:init]logwrapper 21: executing ls failed: No such file or directory
[   13.800321] <2>.(1)[462:init]logwrapper 21: 
[   13.805673] <2>.(2)[1:init]ls 21: [13759][0]ls terminated by exit(255)
[   13.806716] <2>.(2)[1:init]init: 1 output lines suppressed due to ratelimiting
[   13.807641] <2>.(2)[1:init]init 25: [13759][0]ls -laZ /data/app returned failure: 255
[   13.808723] <2>.(2)[1:init]init 25: [13759][0]Setting d27f72eaf61213e463b2a9ec48dae65d policy on /data/app failed!
[   13.809210] <0>.(0)[456:apexd]EXT4-fs (loop8): mounted filesystem without journal. Opts: (null)
[   13.810098] <2>.(2)[1:init]init 25: [13759][0]Rebooting into recovery

和原来还是一样的配方,错误提示

Failed to set encryption policy of /data/app to d27f72eaf61213e463b2a9ec48dae65d v2 modes 1/4 flags 0x2: Directory not empty

R 版本上谷歌对 libfscrypt 这块进行了重构,代码移到了 system/core/init/util.cpp

现在来看下整体的流程,切入点从 init.rc 开始

mkdir /data/app 0771 system system encryption=Require

相比较 Q 版本的 init.rc R 多出了 encryption=Require 属性,就是这个属性决定了 boot

阶段需要检查文件加密情况。mkdir 指令应该调用 builtins 中 do_mkdir(args) 方法

system\core\init\builtins.cpp

java 复制代码
// mkdir <path> [mode] [owner] [group] [<option> ...]
static Result<void> do_mkdir(const BuiltinArguments& args) {
    auto options = ParseMkdir(args.args);
    if (!options.ok()) return options.error();
    return make_dir_with_options(*options);
}

static Result<void> make_dir_with_options(const MkdirOptions& options) {
    std::string ref_basename;
    if (options.ref_option == "ref") {
        ref_basename = fscrypt_key_ref;
    } else if (options.ref_option == "per_boot_ref") {
        ref_basename = fscrypt_key_per_boot_ref;
    } else {
        return Error() << "Unknown key option: '" << options.ref_option << "'";
    }

    struct stat mstat;
    if (lstat(options.target.c_str(), &mstat) != 0) {
        if (errno != ENOENT) {
            return ErrnoError() << "lstat() failed on " << options.target;
        }
        if (!make_dir(options.target, options.mode)) {
            return ErrnoErrorIgnoreEnoent() << "mkdir() failed on " << options.target;
        }
        if (lstat(options.target.c_str(), &mstat) != 0) {
            return ErrnoError() << "lstat() failed on new " << options.target;
        }
    }
    if (!S_ISDIR(mstat.st_mode)) {
        return Error() << "Not a directory on " << options.target;
    }
    bool needs_chmod = (mstat.st_mode & ~S_IFMT) != options.mode;
    if ((options.uid != static_cast<uid_t>(-1) && options.uid != mstat.st_uid) ||
        (options.gid != static_cast<gid_t>(-1) && options.gid != mstat.st_gid)) {
        if (lchown(options.target.c_str(), options.uid, options.gid) == -1) {
            return ErrnoError() << "lchown failed on " << options.target;
        }
        // chown may have cleared S_ISUID and S_ISGID, chmod again
        needs_chmod = true;
    }
    if (needs_chmod) {
        if (fchmodat(AT_FDCWD, options.target.c_str(), options.mode, AT_SYMLINK_NOFOLLOW) == -1) {
            return ErrnoError() << "fchmodat() failed on " << options.target;
        }
    }
    if (fscrypt_is_native()) {
        if (!FscryptSetDirectoryPolicy(ref_basename, options.fscrypt_action, options.target)) {
            return reboot_into_recovery(
                    {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + options.target});
        }
    }
    return {};
}

可以看到其中调用 ParseMkdir(args.args) 获取 options,然后根据 options 创建文件夹,

如果过程中没遇到问题,则 return {} 可以看到出问题的时候进入 recovery 界面,应该是走的

reboot_into_recovery( {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + options.target})

那么来看下 FscryptSetDirectoryPolicy() 方法是如何判断的

system\core\init\fscrypt_init_extensions.cpp

java 复制代码
bool FscryptSetDirectoryPolicy(const std::string& ref_basename, FscryptAction action,
                               const std::string& dir) {
    if (action == FscryptAction::kNone) {
        return true;
    }
    if (SetPolicyOn(ref_basename, dir) || action == FscryptAction::kAttempt) {
        return true;
    }
    if (action == FscryptAction::kDeleteIfNecessary) {
        LOG(ERROR) << "Setting policy failed, deleting: " << dir;
        delete_dir_contents(dir);
        return SetPolicyOn(ref_basename, dir);
    }
    return false;
}

可以看到要想不进入 recovery 界面,action 为 FscryptAction::kNone 即可,也就是跳过

action 的取值 options.fscrypt_action,回到 builtins.cpp 中关注 auto options = ParseMkdir(args.args);

system\core\init\util.cpp

java 复制代码
Result<MkdirOptions> ParseMkdir(const std::vector<std::string>& args) {
    mode_t mode = 0755;
    Result<uid_t> uid = -1;
    Result<gid_t> gid = -1;
	//第一次赋值 fscrypt_action,FscryptInferAction() 和之前一样有白名单可跳过
    FscryptAction fscrypt_inferred_action = FscryptInferAction(args[1]);
    FscryptAction fscrypt_action = fscrypt_inferred_action;
    std::string ref_option = "ref";
    bool set_option_encryption = false;
    bool set_option_key = false;

    for (size_t i = 2; i < args.size(); i++) {
        switch (i) {
            case 2:
                mode = std::strtoul(args[2].c_str(), 0, 8);
                break;
            case 3:
                uid = DecodeUid(args[3]);
                if (!uid.ok()) {
                    return Error()
                           << "Unable to decode UID for '" << args[3] << "': " << uid.error();
                }
                break;
            case 4:
                gid = DecodeUid(args[4]);
                if (!gid.ok()) {
                    return Error()
                           << "Unable to decode GID for '" << args[4] << "': " << gid.error();
                }
                break;
            default:
                auto parts = android::base::Split(args[i], "=");
                if (parts.size() != 2) {
                    return Error() << "Can't parse option: '" << args[i] << "'";
                }
                auto optname = parts[0];
                auto optval = parts[1];
				//第二次赋值 fscrypt_action,根据 optval 值再次判断
				//这里增加 log 打印后发现 optname = encryption  optval = Require/None 在init.rc中配置
                if (optname == "encryption") {
                    if (set_option_encryption) {
                        return Error() << "Duplicated option: '" << optname << "'";
                    }
                    if (optval == "Require") {
                        fscrypt_action = FscryptAction::kRequire;
                    } else if (optval == "None") {
                        fscrypt_action = FscryptAction::kNone;
                    } else if (optval == "Attempt") {
                        fscrypt_action = FscryptAction::kAttempt;
                    } else if (optval == "DeleteIfNecessary") {
                        fscrypt_action = FscryptAction::kDeleteIfNecessary;
                    } else {
                        return Error() << "Unknown encryption option: '" << optval << "'";
                    }
                    set_option_encryption = true;
                } else if (optname == "key") {
                    if (set_option_key) {
                        return Error() << "Duplicated option: '" << optname << "'";
                    }
                    if (optval == "ref" || optval == "per_boot_ref") {
                        ref_option = optval;
                    } else {
                        return Error() << "Unknown key option: '" << optval << "'";
                    }
                    set_option_key = true;
                } else {
                    return Error() << "Unknown option: '" << args[i] << "'";
                }
        }
    }
    if (set_option_key && fscrypt_action == FscryptAction::kNone) {
        return Error() << "Key option set but encryption action is none";
    }
    const std::string prefix = "/data/";
    if (StartsWith(args[1], prefix) &&
        args[1].find_first_of('/', prefix.size()) == std::string::npos) {
        if (!set_option_encryption) {
            LOG(WARNING) << "Top-level directory needs encryption action, eg mkdir " << args[1]
                         << " <mode> <uid> <gid> encryption=Require";
        }
        if (fscrypt_action == FscryptAction::kNone) {
            LOG(INFO) << "Not setting encryption policy on: " << args[1];
        }
    }
    if (fscrypt_action != fscrypt_inferred_action) {
        LOG(WARNING) << "Inferred action different from explicit one, expected "
                     << static_cast<int>(fscrypt_inferred_action) << " but got "
                     << static_cast<int>(fscrypt_action);
    }
	//构建 options 返回
    return MkdirOptions{args[1], mode, *uid, *gid, fscrypt_action, ref_option};
}

static FscryptAction FscryptInferAction(const std::string& dir) {
    const std::string prefix = "/data/";

    if (!android::base::StartsWith(dir, prefix)) {
        return FscryptAction::kNone;
    }

    // Special-case /data/media/obb per b/64566063
    if (dir == "/data/media/obb") {
        // Try to set policy on this directory, but if it is non-empty this may fail.
        return FscryptAction::kAttempt;
    }

    // Only set policy on first level /data directories
    // To make this less restrictive, consider using a policy file.
    // However this is overkill for as long as the policy is simply
    // to apply a global policy to all /data folders created via makedir
    if (dir.find_first_of('/', prefix.size()) != std::string::npos) {
        return FscryptAction::kNone;
    }

    // Special case various directories that must not be encrypted,
    // often because their subdirectories must be encrypted.
    // This isn't a nice way to do this, see b/26641735
    std::vector<std::string> directories_to_exclude = {
            "lost+found", "system_ce", "system_de", "misc_ce",     "misc_de",
            "vendor_ce",  "vendor_de", "media",     "data",        "user",
            "user_de",    "apex",      "preloads",  "app-staging", "gsi", 
    };
	//在 directories_to_exclude 集合中则跳过
    for (const auto& d : directories_to_exclude) {
        if ((prefix + d) == dir) {
            return FscryptAction::kNone;
        }
    }
    // Empty these directories if policy setting fails.
    std::vector<std::string> wipe_on_failure = {
            "rollback", "rollback-observer",  // b/139193659
            "connsyslog", "debuglogger", "ramdump",
            "mdlog", "log_temp", "aee_exp", "mdl",
    };
    for (const auto& d : wipe_on_failure) {
        if ((prefix + d) == dir) {
            return FscryptAction::kDeleteIfNecessary;
        }
    }
    return FscryptAction::kRequire;
}

可以看到这样正常的流程就走完了,接下来看下错误的流程

回到 fscrypt_init_extensions.cpp 中

java 复制代码
bool FscryptSetDirectoryPolicy(const std::string& ref_basename, FscryptAction action,
                               const std::string& dir) {
    if (action == FscryptAction::kNone) {
        return true;
    }
    if (SetPolicyOn(ref_basename, dir) || action == FscryptAction::kAttempt) {
        return true;
    }
    if (action == FscryptAction::kDeleteIfNecessary) {
        LOG(ERROR) << "Setting policy failed, deleting: " << dir;
        delete_dir_contents(dir);
        return SetPolicyOn(ref_basename, dir);
    }
    return false;
}

static bool SetPolicyOn(const std::string& ref_basename, const std::string& dir) {
    EncryptionPolicy policy;
    if (!LookupPolicy(ref_basename, &policy)) return false;
    if (!EnsurePolicyOrLog(policy, dir)) return false;
    return true;
}

static bool EnsurePolicyOrLog(const EncryptionPolicy& policy, const std::string& dir) {
    if (!EnsurePolicy(policy, dir)) {
        std::string ref_hex;
        BytesToHex(policy.key_raw_ref, &ref_hex);
        LOG(ERROR) << "Setting " << ref_hex << " policy on " << dir << " failed!";
        return false;
    }
    return true;
}

最终调用到 system\extras\libfscrypt\fscrypt.cpp

java 复制代码
bool EnsurePolicy(const EncryptionPolicy& policy, const std::string& directory) {
    union {
        fscrypt_policy_v1 v1;
        fscrypt_policy_v2 v2;
    } kern_policy;
    memset(&kern_policy, 0, sizeof(kern_policy));

    switch (policy.options.version) {
        case 1:
            if (policy.key_raw_ref.size() != FSCRYPT_KEY_DESCRIPTOR_SIZE) {
                LOG(ERROR) << "Invalid key descriptor length for v1 policy: "
                           << policy.key_raw_ref.size();
                return false;
            }
            // Careful: FSCRYPT_POLICY_V1 is actually 0 in the API, so make sure
            // to use it here instead of a literal 1.
            kern_policy.v1.version = FSCRYPT_POLICY_V1;
            kern_policy.v1.contents_encryption_mode = policy.options.contents_mode;
            kern_policy.v1.filenames_encryption_mode = policy.options.filenames_mode;
            kern_policy.v1.flags = policy.options.flags;
            policy.key_raw_ref.copy(reinterpret_cast<char*>(kern_policy.v1.master_key_descriptor),
                                    FSCRYPT_KEY_DESCRIPTOR_SIZE);
            break;
        case 2:
            if (policy.key_raw_ref.size() != FSCRYPT_KEY_IDENTIFIER_SIZE) {
                LOG(ERROR) << "Invalid key identifier length for v2 policy: "
                           << policy.key_raw_ref.size();
                return false;
            }
            kern_policy.v2.version = FSCRYPT_POLICY_V2;
            kern_policy.v2.contents_encryption_mode = policy.options.contents_mode;
            kern_policy.v2.filenames_encryption_mode = policy.options.filenames_mode;
            kern_policy.v2.flags = policy.options.flags;
            policy.key_raw_ref.copy(reinterpret_cast<char*>(kern_policy.v2.master_key_identifier),
                                    FSCRYPT_KEY_IDENTIFIER_SIZE);
            break;
        default:
            LOG(ERROR) << "Invalid encryption policy version: " << policy.options.version;
            return false;
    }

    android::base::unique_fd fd(open(directory.c_str(), O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC));
    if (fd == -1) {
        PLOG(ERROR) << "Failed to open directory " << directory;
        return false;
    }

    bool already_encrypted = fscrypt_is_encrypted(fd);

    // FS_IOC_SET_ENCRYPTION_POLICY will set the policy if the directory is
    // unencrypted; otherwise it will verify that the existing policy matches.
    // Setting the policy will fail if the directory is already nonempty.
    if (ioctl(fd, FS_IOC_SET_ENCRYPTION_POLICY, &kern_policy) != 0) {
        std::string reason;
        switch (errno) {
            case EEXIST:
                reason = "The directory already has a different encryption policy.";
                break;
            default:
                reason = strerror(errno);
                break;
        }
        LOG(ERROR) << "Failed to set encryption policy of " << directory << " to "
                   << PolicyDebugString(policy) << ": " << reason;
        if (errno == ENOTEMPTY) {
            log_ls(directory.c_str());
        }
        return false;
    }

    if (already_encrypted) {
        LOG(INFO) << "Verified that " << directory << " has the encryption policy "
                  << PolicyDebugString(policy);
    } else {
        LOG(INFO) << "Encryption policy of " << directory << " set to "
                  << PolicyDebugString(policy);
    }
    return true;
}

重新编译烧写后成功开机的log,可以看到打印了跳过 /data/app/ 相关

java 复制代码
[   14.186668] <0>.(0)[1:init]init 16: [14155][0]ccz ParseMkdir encryption policy on: /data/app-lib
[   14.187866] <0>.(0)[1:init]init 16: [14155][0]ccz ParseMkdir encryption optname: encryption
[   14.189007] <0>.(0)[1:init]init 19: [14155][0]ccz ParseMkdir encryption optval: Require
[   14.191729] <0>.(0)[1:init]init 19: [14155][0]Encryption policy of /data/app-lib set to ef2067add1858706a84cc01d25260ea5 v2 modes 1/4 flags 0x2
[   14.193467] <0>.(0)[1:init]init 19: [14162][0]ccz ParseMkdir encryption policy on: /data/app
[   14.194557] <0>.(0)[1:init]init 19: [14162][0]ccz ParseMkdir encryption optname: encryption
[   14.195651] <0>.(0)[1:init]init 19: [14162][0]ccz ParseMkdir encryption optval: None
[   14.196637] <0>.(0)[1:init]init 19: [14162][0]ccz ParseMkdir encryption hook: 
[   14.197555] <0>.(0)[1:init]init 19: [14162][0]Not setting encryption policy on: /data/app
[   14.198574] <5>.(5)[317:init]init 16: [14167][200]ReapLogT PropSet [apexd.status]=[starting]13967 Done
[   14.198737] <0>.(0)[1:init]init 19: [14167][0]ccz ParseMkdir encryption policy on: /data/property
[   14.200913] <0>.(0)[1:init]init 19: [14167][0]ccz ParseMkdir encryption optname: encryption
[   14.201996] <0>.(0)[1:init]init 25: [14167][0]ccz ParseMkdir encryption optval: Require
[   14.204488] <0>.(0)[1:init]init 25: [14167][0]Encryption policy of /data/property set to ef2067add1858706a84cc01d25260ea5 v2 modes 1/4 flags 0x2
[   14.206220] <0>.(0)[1:init]init 25: [14175][0]ccz ParseMkdir encryption policy on: /data/tombstones
[   14.207437] <0>.(0)[1:init]init 25: [14175][0]ccz ParseMkdir encryption optname: encryption
[   14.208516] <0>.(0)[1:init]init 25: [14175][0]ccz ParseMkdir encryption optval: Require
[   14.211116] <0>.(0)[1:init]init 25: [14175][0]Encryption policy of /data/tombstones set to ef2067add1858706a84cc01d25260ea5 v2 modes 1/4 flags 0x2
[   14.212936] <0>.(0)[1:init]init 25: [14181][0]ccz ParseMkdir encryption policy on: /data/vendor/tombstones
[   14.215671] <0>.(0)[1:init]init 25: [14184][0]ccz ParseMkdir encryption policy on: /data/vendor/tombstones/wifi

关于 init.rc 启动可以参考下面

Android Q 开机启动流程 Android的init过程(二):初始化语言(init.rc)解析

相关推荐
Good_tea_h1 小时前
Android中的单例模式
android·单例模式
计算机源码社6 小时前
分享一个基于微信小程序的居家养老服务小程序 养老服务预约安卓app uniapp(源码、调试、LW、开题、PPT)
android·微信小程序·uni-app·毕业设计项目·毕业设计源码·计算机课程设计·计算机毕业设计开题
丶白泽6 小时前
重修设计模式-结构型-门面模式
android
晨春计8 小时前
【git】
android·linux·git
标标大人9 小时前
c语言中的局部跳转以及全局跳转
android·c语言·开发语言
竹林海中敲代码9 小时前
Qt安卓开发连接手机调试(红米K60为例)
android·qt·智能手机
木鬼与槐10 小时前
MySQL高阶1783-大满贯数量
android·数据库·mysql
iofomo10 小时前
【Abyss】Android 平台应用级系统调用拦截框架
android·开发工具·移动端
AirDroid_cn12 小时前
在家找不到手机?除了语音助手,还可以用远程控制!
android·智能手机·远程控制·手机使用技巧·远程控制手机
Good_tea_h20 小时前
Android中如何处理运行时权限?
android