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

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 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

@@ -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

+++ 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


@@ -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

@@ -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;


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

[   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

// 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

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

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 中

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

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/ 相关

[   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)解析

目录
相关文章
|
13天前
|
安全 Android开发 数据安全/隐私保护
深入探讨iOS与Android系统安全性对比分析
在移动操作系统领域,iOS和Android无疑是两大巨头。本文从技术角度出发,对这两个系统的架构、安全机制以及用户隐私保护等方面进行了详细的比较分析。通过深入探讨,我们旨在揭示两个系统在安全性方面的差异,并为用户提供一些实用的安全建议。
|
2月前
|
开发工具 Android开发 Swift
安卓与iOS开发环境对比分析
在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统无疑是主角。它们各自拥有独特的特点和优势,为开发者提供了不同的开发环境和工具。本文将深入浅出地探讨安卓和iOS开发环境的主要差异,包括开发工具、编程语言、用户界面设计、性能优化以及市场覆盖等方面,旨在帮助初学者更好地理解两大平台的开发特点,并为他们选择合适的开发路径提供参考。通过比较分析,我们将揭示不同环境下的开发实践,以及如何根据项目需求和目标受众来选择最合适的开发平台。
51 2
|
21天前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
46 15
Android 系统缓存扫描与清理方法分析
|
1月前
|
存储 Linux Android开发
Android底层:通熟易懂分析binder:1.binder准备工作
本文详细介绍了Android Binder机制的准备工作,包括打开Binder驱动、内存映射(mmap)、启动Binder主线程等内容。通过分析系统调用和进程与驱动层的通信,解释了Binder如何实现进程间通信。文章还探讨了Binder主线程的启动流程及其在进程通信中的作用,最后总结了Binder准备工作的调用时机和重要性。
Android底层:通熟易懂分析binder:1.binder准备工作
|
2月前
|
安全 Android开发 数据安全/隐私保护
探索安卓与iOS的安全性差异:技术深度分析与实践建议
本文旨在深入探讨并比较Android和iOS两大移动操作系统在安全性方面的不同之处。通过详细的技术分析,揭示两者在架构设计、权限管理、应用生态及更新机制等方面的安全特性。同时,针对这些差异提出针对性的实践建议,旨在为开发者和用户提供增强移动设备安全性的参考。
136 3
|
1月前
|
开发工具 Android开发 Swift
安卓与iOS开发环境的差异性分析
【10月更文挑战第8天】 本文旨在探讨Android和iOS两大移动操作系统在开发环境上的不同,包括开发语言、工具、平台特性等方面。通过对这些差异性的分析,帮助开发者更好地理解两大平台,以便在项目开发中做出更合适的技术选择。
|
3月前
|
安全 Java Android开发
【Android P】OTA升级包定制,移除不需要更新的分区,重新打包签名
如何解压OTA升级包、编辑升级包内容(例如移除不需要更新的分区)、重新打包、签名以及验证OTA文件的过程。
273 2
【Android P】OTA升级包定制,移除不需要更新的分区,重新打包签名
|
2月前
|
安全 Linux Android开发
探索安卓与iOS的安全性差异:技术深度分析
本文深入探讨了安卓(Android)和iOS两个主流操作系统平台在安全性方面的不同之处。通过比较它们在架构设计、系统更新机制、应用程序生态和隐私保护策略等方面的差异,揭示了每个平台独特的安全优势及潜在风险。此外,文章还讨论了用户在使用这些设备时可以采取的一些最佳实践,以增强个人数据的安全。
|
2月前
|
IDE 开发工具 Android开发
安卓与iOS开发环境对比分析
本文将探讨安卓和iOS这两大移动操作系统在开发环境上的差异,从工具、语言、框架到生态系统等多个角度进行比较。我们将深入了解各自的优势和劣势,并尝试为开发者提供一些实用的建议,以帮助他们根据自己的需求选择最适合的开发平台。
47 1
|
3月前
|
算法 安全 数据安全/隐私保护
Android经典实战之常见的移动端加密算法和用kotlin进行AES-256加密和解密
本文介绍了移动端开发中常用的数据加密算法,包括对称加密(如 AES 和 DES)、非对称加密(如 RSA)、散列算法(如 SHA-256 和 MD5)及消息认证码(如 HMAC)。重点讲解了如何使用 Kotlin 实现 AES-256 的加密和解密,并提供了详细的代码示例。通过生成密钥、加密和解密数据等步骤,展示了如何在 Kotlin 项目中实现数据的安全加密。
126 1