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

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: androidQ(10.0) 预装集成apk到data分区

前情提要


关于预装APK相关知识可参考

Android 源码编译如何确定模块安装的位置

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


遇到问题


当我按照 Android O、P、Q 版本如何预装 APK 一文将 PMS 中 patch 回退,并在 Android.mk 中指定


LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) 输出到 data/app 目录下,编译后apk也确实位于


data/app/中,而且 userdata.img 大小也明显变大了,但是当烧写完成后,开机并不能正常启动,而是


自动进入了 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会没了,因为我们


预装app就在 data 分区下,恢复出厂将 data 分区格式化了,所以 app 没了,而且系统能正常开机了。那么看来问题


就在 data 分区上了,难道 AndroidQ 不允许将apk预装到 data 分区了吗?


解决办法


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

system/extras/libfscrypt/fscrypt_init_extensions.cpp

@@ -88,7 +88,7 @@ int fscrypt_set_directory_policy(const char* dir)
         "media",
         "data", "user", "user_de",
         "apex", "preloads", "app-staging",
-        "gsi",
+        "gsi","app",
     };
  std::string prefix = "/data/";
    for (const auto& d: directories_to_exclude) {
        if ((prefix + d) == dir) {
            LOG(INFO) << "Not setting policy on " << dir;
            return 0;
        }
    }
    return set_system_de_policy_on(dir);


分析过程


由上面的问题现象开始定位到 data 分区,问了朋友后说可能和分区格式有关系,userdata 改成f2sf才能内置东西,


于是照着 Android 如何将 data 分区格式由 ext4 转为 f2fs 一文修改后重新编译,烧写后发现问题依旧,还是提示


一样的问题,回厂进入系统后 adb shell 查看 data 分区格式确实已经变成 f2fs 了,这么说和 ext4、f2fs 没关系,但


如果需要过 GMS 的话,确实需要修改 data 格式为 f2fs。

Nd5cDK.png


好吧,看来这条路走不通了。那就只能启用终极奥义,看串口Log了,乘着硬件小哥飞串口线的时间,我们

先来把系统的串口 Log 打开。

kernel-4.9/kernel/printk/printk.c

@@ -75,7 +75,7 @@ module_param_named(disable_uart, printk_disable_uart, int, 0644);
 bool mt_get_uartlog_status(void)
 {
        if (printk_disable_uart == 1)
-               return false;
+               return true;//false;
        else if ((printk_disable_uart == 0) || (printk_disable_uart == 2))
                return true;
        return true;
@@ -94,7 +94,7 @@ void mt_disable_uart(void)
 {
        /* uart print not always enable */
        if ((mt_need_uart_console != 1) && (printk_disable_uart != 2))
-               printk_disable_uart = 1;
+               printk_disable_uart = 0;
 }
 void mt_enable_uart(void)
 {

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


@@ -1233,7 +1233,7 @@ int boot_linux_fdt(void *kernel, unsigned *tags,
 #endif
                                cmdline_append("printk.disable_uart=0");
                        else
-                               cmdline_append("printk.disable_uart=1");
+                               cmdline_append("printk.disable_uart=0");
                        break;
                case BUILD_TYPE_USERDEBUG:
@@ -1243,13 +1243,13 @@ int boot_linux_fdt(void *kernel, unsigned *tags,
 #else
                            (is_meta_log_disable() == 1))
 #endif
-                               cmdline_append("printk.disable_uart=1 slub_debug=O");
+                               cmdline_append("printk.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("printk.disable_uart=1 slub_debug=-");
+                               cmdline_append("printk.disable_uart=0 slub_debug=-");
                        else
                                cmdline_append("printk.disable_uart=0");
                        break;
@@ -1257,7 +1257,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("printk.disable_uart=1 slub_debug=O");
+                               cmdline_append("printk.disable_uart=0 slub_debug=O");
                        else
                                cmdline_append("printk.disable_uart=0 ddebug_query=\"file *mediatek* +p ; file *gpu* =_\"");
                        break;


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

[   21.147710] <2>.(2)[1:init]init 15: Setting policy on /data/vendor
[   21.148630] <2>.(2)[1:init]init 15: Policy for /data/vendor set to 579af1fc730f2e34 modes 1/4
[   21.151349] <2>.(2)[1:init]init 19: ReapLogF PropSet [apexd.status]=[ready]21.147147 Done
[   21.152406] <2>.(2)[1:init]init 15: Not setting policy on /data/vendor_ce
[   21.154164] <2>.(2)[1:init]init 15: Not setting policy on /data/vendor_de
[   21.159953] <2>.(2)[1:init]init 3: Not setting policy on /data/data
[   21.162020] <2>.(2)[1:init]init 3: Setting policy on /data/app-private
[   21.163054] <2>.(2)[1:init]init 3: Policy for /data/app-private set to 579af1fc730f2e34 modes 1/4
[   21.165331] <2>.(2)[1:init]init 3: Setting policy on /data/app-ephemeral
[   21.166299] <2>.(2)[1:init]init 3: Policy for /data/app-ephemeral set to 579af1fc730f2e34 modes 1/4
[   21.169022] <2>.(2)[1:init]init 3: Setting policy on /data/app-asec
[   21.169960] <2>.(2)[1:init]init 3: Policy for /data/app-asec set to 579af1fc730f2e34 modes 1/4
[   21.172106] <2>.(2)[1:init]init 3: Setting policy on /data/app-lib
[   21.173001] <2>.(2)[1:init]init 3: Policy for /data/app-lib set to 579af1fc730f2e34 modes 1/4
[   21.176232] <2>.(2)[1:init]init 15: Setting policy on /data/app
[   21.177618] <2>.(2)[1:init]init 15: Failed to get encryption policy for /data/app: No data available
[   21.202980] <3>.(3)[384:logd.auditd]type=1400 audit(1262304028.716:5): avc: denied { associate } for comm="init" name="boot_boost" scontext=u:object_r:proc_perfmgr:s0 tcontext=u:object_r:proc:s0 tclass=filesystem permissive=1
[   21.205523] <3>.(3)[384:logd.auditd]type=1400 audit(1262304029.180:6): avc: denied { dac_override } for comm="ls" capability=1 scontext=u:r:toolbox:s0 tcontext=u:r:toolbox:s0 tclass=capability permissive=1
[   21.205797] <3>.(2)[1:init]init 15: Setting 579af1fc policy on /data/app failed!
[   21.205825] <3>.(2)[1:init]init 15: Rebooting into recovery
[   21.209288] <3>.(2)[1:init]init 15: Received sys.powerctl='reboot,recovery' from pid: 1 (/system/bin/init)
[   21.209678] <3>.(2)[1:init]init 3: ReapLogF PropSet [sys.powerctl]=[reboot,recovery]21.206530 Done
[   21.209689] <3>.(2)[1:init]init 15: Clear action queue and start shutdown trigger
[   21.209819] <3>.(2)[1:init]init 15: processing action (shutdown_done) from (<Builtin Action>:0)
[   21.209851] <3>.(2)[1:init]init 15: Reboot start, reason: reboot,recovery, rebootTarget: recovery
[   21.215330] <3>.(3)[384:logd.auditd]type=1400 audit(1262304029.180:6): avc: denied { dac_override } for comm="ls" capability=1 scontext=u:r:toolbox:s0 tcontext=u:r:toolbox:s0 tclass=capability permissive=1
[   21.217674] <3>.(3)[384:logd.auditd]type=1400 audit(1262304029.180:7): avc: denied { read } for comm="ls" name="app" dev="mmcblk0p36" ino=6 scontext=u:r:toolbox:s0 tcontext=u:object_r:apk_data_file:s0 tclass=dir permissive=1
[   21.220472] <3>.(3)[384:logd.auditd]type=1400 audit(1262304029.180:7): avc: denied { read } for comm="ls" name="app" dev="mmcblk0p36" ino=6 scontext=u:r:toolbox:s0 tcontext=u:object_r:apk_data_file:s0 tclass=dir permissive=1
[   21.223103] <3>.(3)[384:logd.auditd]type=1400 audit(1262304029.180:8): avc: denied { open } for comm="ls" path="/data/app" dev="mmcblk0p36" ino=6 scontext=u:r:toolbox:s0 tcontext=u:object_r:apk_data_file:s0 tclass=dir permissive=1
[   21.244124] <2>.(2)[1:init]init 3: ReapLogF PropSet [persist.sys.boot.reason]=[recovery]21.207330 Done
[   21.245320] <2>.(2)[1:init]init 15: Shutdown timeout: 6000 ms
[   21.246820] <2>.(2)[1:init]init 19: starting service 'blank_screen'...
[   21.251021] <2>.(2)[1:init]init 19: starting service 'light-hal-2-0'...
[   21.254702] <2>.(2)[1:init]init 19: terminating init services

找到其中关键日志 Rebooting into recovery,往上看到 Setting 579af1fc policy on /data/app failed!


嗯,和 data 相关的东西出现了。Failed to get encryption policy for /data/app: No data available


通过搜索 Failed to get encryption policy 找到文件 system/extras/libfscrypt/fscrypt.cpp

static bool fscrypt_policy_get(const char *directory, char *policy,
                               size_t policy_length,
                               int contents_encryption_mode,
                               int filenames_encryption_mode) {
  ....
    fscrypt_policy fp;
    memset(&fp, 0, sizeof(fscrypt_policy));
    if (ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, &fp) != 0) {
        PLOG(ERROR) << "Failed to get encryption policy for " << directory;
        close(fd);
        log_ls(directory);
        return false;
    }
    close(fd);
    if ((fp.version != 0)
            || (fp.contents_encryption_mode != contents_encryption_mode)
            || (fp.filenames_encryption_mode != filenames_encryption_mode)
            || (fp.flags !=
                fscrypt_get_policy_flags(filenames_encryption_mode))) {
        LOG(ERROR) << "Failed to find matching encryption policy for " << directory;
        return false;
    }
    memcpy(policy, fp.master_key_descriptor, FS_KEY_DESCRIPTOR_SIZE);
    return true;
}

应该就是在这里打印的,简单看了下源码,和设置文件加密解密策略有关,开始看到了日志中


Rebooting into recovery 附近一堆 avc: denied,以为和 SELinux 权限有关系,就先挨个把权限都给


补上了,再次编译后开机,呵呵,还是一样的问题,不过日志中已经没有 avc: denied 相关字眼。再仔细品一品


串口日志,既然问题出在读取 /data/app encryption policy 上,那么是不是跳过 /data/app 就行了呢。


回到源码中看下调用流程

fscrypt_policy_get(
  fscrypt_policy_check()
    fscrypt_policy_get()


然鹅 fscrypt_policy_get() 的调用在 system/extras/libfscrypt/fscrypt_init_extensions.cpp 中


看到 fscrypt_set_directory_policy() 调用了 fscrypt_policy_get() ,在之前进行了 for 循环判断,如果


传递的文件目录在 vector 中则跳过读取检查,这正是我们所需要的,直接在 vector 中添加 app 目录。

int fscrypt_set_directory_policy(const char* dir)
{
    if (!dir || strncmp(dir, "/data/", 6)) {
        return 0;
    }
    // Special-case /data/media/obb per b/64566063
    if (strcmp(dir, "/data/media/obb") == 0) {
        // Try to set policy on this directory, but if it is non-empty this may fail.
        set_system_de_policy_on(dir);
        return 0;
    }
    // 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 (strchr(dir + 6, '/')) {
        return 0;
    }
    // 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","app",
    };
    std::string prefix = "/data/";
    for (const auto& d: directories_to_exclude) {
        if ((prefix + d) == dir) {
            LOG(INFO) << "Not setting policy on " << dir;
            return 0;
        }
    }
    return set_system_de_policy_on(dir);
}
static int set_system_de_policy_on(char const* dir) {
    std::string ref_filename = std::string("/data") + fscrypt_key_ref;
    std::string policy;
    if (!android::base::ReadFileToString(ref_filename, &policy)) {
        LOG(ERROR) << "Unable to read system policy to set on " << dir;
        return -1;
    }
    auto type_filename = std::string("/data") + fscrypt_key_mode;
    std::string modestring;
    if (!android::base::ReadFileToString(type_filename, &modestring)) {
        LOG(ERROR) << "Cannot read mode";
    }
    std::vector<std::string> modes = android::base::Split(modestring, ":");
    if (modes.size() < 1 || modes.size() > 2) {
        LOG(ERROR) << "Invalid encryption mode string: " << modestring;
        return -1;
    }
    LOG(INFO) << "Setting policy on " << dir;
    int result = fscrypt_policy_ensure(dir, policy.c_str(), policy.length(),
                                       modes[0].c_str(),
                                       modes.size() >= 2 ?
                                            modes[1].c_str() : "aes-256-cts");
    if (result) {
        LOG(ERROR) << android::base::StringPrintf(
            "Setting %02x%02x%02x%02x policy on %s failed!",
            policy[0], policy[1], policy[2], policy[3], dir);
        return -1;
    }
    return 0;
}

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

[    7.101127] <0>.(0)[1:init]init 19: Not setting policy on /data/vendor_de
[    7.106596] <0>.(0)[1:init]init 19: Not setting policy on /data/data
[    7.109088] <0>.(0)[1:init]init 19: Setting policy on /data/app-private
[    7.110129] <0>.(0)[1:init]init 19: Policy for /data/app-private set to e2d0272afa66497a modes 1/4
[    7.112834] <0>.(0)[1:init]init 19: Setting policy on /data/app-ephemeral
[    7.124062] <0>.(0)[1:init]init 3: Not setting policy on /data/app
[    7.126336] <0>.(0)[1:init]init 3: Setting policy on /data/property
[    7.127449] <0>.(0)[1:init]init 3: Found policy e2d0272afa66497a at /data/property which matches expected valu

可能还存在的问题


我在 userdebug 版本下测试,烧写完成后第一次开机启动正常,app 都存在,再次重启后发现 data 下的 app 被卸载了,抓到对应的日志

2020-06-24 16:23:22.767 1144-1144/system_process V/PackageManager: reconcileAppsData for null u0 0x1 migrateAppData=true
2020-06-24 16:23:22.771 1144-1144/system_process W/PackageManager: Destroying /data/user_de/0/cn.cpe.contacts due to: com.android.server.pm.PackageManagerException: Package cn.cpe.contact is unknown
2020-06-24 16:23:22.780 1144-1144/system_process W/PackageManager: Destroying /data/user_de/0/cn.cpe.broswer due to: com.android.server.pm.PackageManagerException: Package cn.cpe.brosweris unknown
2020-06-24 16:23:22.944 1144-1144/system_process V/PackageManager: reconcileAppsData finished 31 packages
2020-06-24 16:23:23.068 1144-1144/system_process E/PackageManager: There should probably be a verifier, but, none were found
2020-06-24 16:23:25.260 1144-1144/system_process W/PackageManager: Destroying orphaned/data/app/CeContact
2020-06-24 16:23:25.270 1144-1144/system_process W/PackageManager: Destroying orphaned/data/app/CeBroswer
PackageManager: System package cn.cpe.contact no longer exists; it's data will be wiped
2020-06-30 15:23:16.505 1126-1126/system_process W/PackageManager: System package cn.cpe.broswer no longer exists; it's data will be wiped

PackageManager 中重启后进行了再次检查

我在 user 版本下验证并未出现这个现象,所以就不再深究了,感兴趣的可以去找 PackageManagerService 对应位置分析

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
6月前
|
分布式计算 DataWorks Java
DataWorks产品使用合集之数据集成如何按照分表导入多分区
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
60 0
|
6月前
|
NoSQL Java MongoDB
Java一分钟之-Spring Data MongoDB:MongoDB集成
【6月更文挑战第11天】Spring Data MongoDB简化Java应用与MongoDB集成,提供模板和Repository模型。本文介绍其基本用法、常见问题及解决策略。包括时间字段的UTC转换、异常处理和索引创建。通过添加相关依赖、配置MongoDB连接、定义Repository接口及使用示例,帮助开发者高效集成MongoDB到Spring Boot应用。注意避免时间差、异常处理不充分和忽视索引的问题。
177 0
|
7月前
|
Android开发
Android 高通平台集成无源码apk示例
Android 高通平台集成无源码apk示例
107 0
|
JSON Java 关系型数据库
Spring Boot 学习研究笔记(十三) Spring Data JPA与PostgreSQL的jsonb类型集成
Spring Boot 学习研究笔记(十三) Spring Data JPA与PostgreSQL的jsonb类型集成
351 0
|
机器学习/深度学习 人工智能 算法
【数据编制架构】Data Fabric 架构是实现数据管理和集成现代化的关键
【数据编制架构】Data Fabric 架构是实现数据管理和集成现代化的关键
|
Android开发 开发工具
Android开发教程 - 使用Data Binding(二)集成与配置
本系列目录 使用Data Binding(一)介绍 使用Data Binding(二)集成与配置 使用Data Binding(三)在Activity中的使用 使用Data Binding(四)在Fragment中的使用 使用Data Binding(五)数据绑定 使用Data Binding(六.
1147 0
|
存储 Java Redis
Spring集成redis(Spring Data Redis)
转载地址:http://blog.csdn.net/zhu_tianwei/article/details/44923001 Spring-data-redis是spring大家族的一部分,提供了在srping应用中通过简单的配置访问redis服务,对reids底层开发包(Jedis, JRedis, and RJC)进行了高度封装,RedisTemplate提供了redis各种操作、异常处理及序列化,支持发布订阅,并对spring 3.1 cache进行了实现。
6256 0
|
IDE Java 开发工具
《Spring Data实战》——2.4 IDE集成
在3.0版本中,Spring工具套件(Spring Tool Suite,STS)提供了与Spring Data Repository抽象进行集成的功能。STS为Spring Data所提供的核心支持是查找方法的查询衍生机制。
1700 0
|
2月前
|
Java Maven Docker
gitlab-ci 集成 k3s 部署spring boot 应用
gitlab-ci 集成 k3s 部署spring boot 应用

热门文章

最新文章