赞
踩
开启AB升级方案的项目,因为很多需要升级的镜像都有两份,所以存储空间比较浪费。为缓解此问题,有个针对odex的优化方案。
编译版本会生成两个system镜像:system.img和system_other.img,其中,system_other.img中存储的就是odex文件,这样system.img就能小很多,意味着可以为system分区划分较小的空间。
在首次开机时,假设system.img镜像存储在A slot,那么此时的B slot是闲置的。所以可以把system.img刷入A slot的system分区,把system_other.img刷入B slot的system分区。在首次开机时,再把system_other.img中的odex文件拷贝到data分区。
https://source.android.com/devices/tech/dalvik/configure.html#other_odex
开机后copy odex文件的相关代码
- /frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
-
- public PackageManagerService(Context context, Installer installer,
- boolean factoryTest, boolean onlyCore) {
- ...
- // 首次开机时才执行
- if (!mOnlyCore && mFirstBoot) {
- requestCopyPreoptedFiles();
- }
- ...
- }
-
- /**
- * Requests that files preopted on a secondary system partition be copied to the data partition
- * if possible. Note that the actual copying of the files is accomplished by init for security
- * reasons. This simply requests that the copy takes place and awaits confirmation of its
- * completion. See platform/system/extras/cppreopt/ for the implementation of the actual copy.
- */
- private static void requestCopyPreoptedFiles() {
- final int WAIT_TIME_MS = 100;
- final String CP_PREOPT_PROPERTY = "sys.cppreopt";
- if (SystemProperties.getInt("ro.cp_system_other_odex", 0) == 1) {
- SystemProperties.set(CP_PREOPT_PROPERTY, "requested");
- // We will wait for up to 100 seconds.
- final long timeStart = SystemClock.uptimeMillis();
- final long timeEnd = timeStart + 100 * 1000;
- long timeNow = timeStart;
- while (!SystemProperties.get(CP_PREOPT_PROPERTY).equals("finished")) {
- try {
- Thread.sleep(WAIT_TIME_MS);
- } catch (InterruptedException e) {
- // Do nothing
- }
- timeNow = SystemClock.uptimeMillis();
- if (timeNow > timeEnd) {
- SystemProperties.set(CP_PREOPT_PROPERTY, "timed-out");
- Slog.wtf(TAG, "cppreopt did not finish!");
- break;
- }
- }
-
- Slog.i(TAG, "cppreopts took " + (timeNow - timeStart) + " ms");
- }
- }
这里是在PSM初始化时,PMS_scan_START之前进行copy动作,且只在首次开机执行。
有开关控制此功能:ro.cp_system_other_odex=1则打开,默认为0
如注释中提到的,PMS并不负责真正的copy,因为它没有相关权限,而是由init进程来执行。
PMS和init的交互是通过系统属性:sys.cppreopt
PMS将其设置为requested,来请求init去copy;每隔一段时间检测下是否已经变更为finished。
当sys.cppreopt=requested时,触发copy;结束后,设置为finished
如下是对应rc文件,相关操作会在init进程中执行。
这个代码给我们提供了一个普通进程和init进程交互的方法:透过property通信
- /system/extras/cppreopts/cppreopts.rc
- on property:sys.cppreopt=requested && property:ro.boot.slot_suffix=_a
- mount ext4 /dev/block/by-name/system_b /postinstall ro nosuid nodev noexec
- exec - root -- /system/bin/cppreopts.sh /postinstall
- # Optional script to copy additional preloaded content to data directory
- exec - system system -- /system/bin/preloads_copy.sh /postinstall
- umount /postinstall
- setprop sys.cppreopt finished
-
- on property:sys.cppreopt=requested && property:ro.boot.slot_suffix=_b
- mount ext4 /dev/block/by-name/system_a /postinstall ro nosuid nodev noexec
- exec - root -- /system/bin/cppreopts.sh /postinstall
- # Optional script to copy additional preloaded content to data directory
- exec - system system -- /system/bin/preloads_copy.sh /postinstall
- umount /postinstall
- setprop sys.cppreopt finished
具体copy流程:
把system_other.img镜像mount到/postinstall,然后运行/system/bin/cppreopts.sh,之后umount。这个sh脚步在/system/extras/cppreopts/cppreopts.sh
在copy时,需要用到preopt2cachename来生成目标文件路径和名称:system/extras/preopt2cachename/,这个bin档会输出一个string
std::cout << output_file_location;
一般地,system/app和system/priv-app/目录下的odex文件会生成到system_other.img
- /build/make/core/dex_preopt.mk
-
- # The default filter for which files go into the system_other image (if it is
- # being used). To bundle everything one should set this to '%'
- SYSTEM_OTHER_ODEX_FILTER ?= app/% priv-app/%
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。