随着android版本的更新,系统固件的大小也越来越大,升级包也越来越大,cache分区已经不够存储update.zip了,所以应用把update.zip下载到data分区,默认情况下data分区是可以存储升级包的。

    我们有分区加密的功能,当打开加密分区后,data分区是加密的,当升级包存在data分区的时候,recovery下获取不到对应的秘钥,也没有对应的程序去解密,所以recovery无法正常挂载data分区,获取升级包升级。那么google是如何完成分区加密时,从data分区升级的呢?

    当应用从远程服务器下载update.zip升级包后,是如何一步步进入recovery升级的呢?

android P(9.0)aosp code:

frameworks/base/core/java/android/os/RecoverySystem.java

主要分为两步进行,第一步处理升级包(processPackage),第二步安装升级包(installPackage):

处理升级包:

public static void processPackage(Context context,                                      File packageFile,                                      final ProgressListener listener,                                      final Handler handler)            throws IOException {        String filename = packageFile.getCanonicalPath();        if (!filename.startsWith("/data/")) {            return;        }        RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);        IRecoverySystemProgressListener progressListener = null;        if (listener != null) {            final Handler progressHandler;            if (handler != null) {                progressHandler = handler;            } else {                progressHandler = new Handler(context.getMainLooper());            }            progressListener = new IRecoverySystemProgressListener.Stub() {                int lastProgress = 0;                long lastPublishTime = System.currentTimeMillis();                @Override                public void onProgress(final int progress) {                    final long now = System.currentTimeMillis();                    progressHandler.post(new Runnable() {                        @Override                        public void run() {                            if (progress > lastProgress &&                                    now - lastPublishTime > PUBLISH_PROGRESS_INTERVAL_MS) {                                lastProgress = progress;                                lastPublishTime = now;                                listener.onProgress(progress);                            }                        }                    });                }            };        }        if (!rs.uncrypt(filename, progressListener)) {            throw new IOException("process package failed");        }    }

主要做了如下工作:

(1) 只处理升级包在/data分区的场景

(2) 处理进度显示

(3)调用rs.uncrypt(filename, progressListener) 处理升级包

    /**     * Talks to RecoverySystemService via Binder to trigger uncrypt.     */    private boolean uncrypt(String packageFile, IRecoverySystemProgressListener listener) {        try {            return mService.uncrypt(packageFile, listener);        } catch (RemoteException unused) {        }        return false;    }

RecoverySystem 通过Binder 触发 uncrypt服务

/system/etc/init/uncrypt.rc

service uncrypt /system/bin/uncrypt    class main    socket uncrypt stream 600 system system    disabled    oneshotservice setup-bcb /system/bin/uncrypt --setup-bcb    class main    socket uncrypt stream 600 system system    disabled    oneshotservice clear-bcb /system/bin/uncrypt --clear-bcb    class main    socket uncrypt stream 600 system system    disabled    oneshot

调用了/system/bin/uncrypt程序来处理升级包, uncrypt对应的源码在 bootable/recovery/uncrypt/uncrypt.cpp

具体处理细节我们在章节详解:recovery uncrypt功能解析(bootable/recovery/uncrypt/uncrypt.cpp)

 

安装升级包:

 public static void installPackage(Context context, File packageFile, boolean processed)            throws IOException {        synchronized (sRequestLock) {            LOG_FILE.delete();            // Must delete the file in case it was created by system server.            UNCRYPT_PACKAGE_FILE.delete();            String filename = packageFile.getCanonicalPath();            Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");            // If the package name ends with "_s.zip", it's a security update.            boolean securityUpdate = filename.endsWith("_s.zip");            // If the package is on the /data partition, the package needs to            // be processed (i.e. uncrypt'd). The caller specifies if that has            // been done in 'processed' parameter.            if (filename.startsWith("/data/")) {                if (processed) {                    if (!BLOCK_MAP_FILE.exists()) {                        Log.e(TAG, "Package claimed to have been processed but failed to find "                                + "the block map file.");                        throw new IOException("Failed to find block map file");                    }                } else {                    FileWriter uncryptFile = new FileWriter(UNCRYPT_PACKAGE_FILE);                    try {                        uncryptFile.write(filename + "\n");                    } finally {                        uncryptFile.close();                    }                    // UNCRYPT_PACKAGE_FILE needs to be readable and writable                    // by system server.                    if (!UNCRYPT_PACKAGE_FILE.setReadable(true, false)                            || !UNCRYPT_PACKAGE_FILE.setWritable(true, false)) {                        Log.e(TAG, "Error setting permission for " + UNCRYPT_PACKAGE_FILE);                    }                    BLOCK_MAP_FILE.delete();                }                // If the package is on the /data partition, use the block map                // file as the package name instead.                filename = "@/cache/recovery/block.map";            }            final String filenameArg = "--update_package=" + filename + "\n";            final String localeArg = "--locale=" + Locale.getDefault().toLanguageTag() + "\n";            final String securityArg = "--security\n";            String command = filenameArg + localeArg;            if (securityUpdate) {                command += securityArg;            }            RecoverySystem rs = (RecoverySystem) context.getSystemService(                    Context.RECOVERY_SERVICE);            if (!rs.setupBcb(command)) {                throw new IOException("Setup BCB failed");            }            // Having set up the BCB (bootloader control block), go ahead and reboot            PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);            String reason = PowerManager.REBOOT_RECOVERY_UPDATE;            // On TV, reboot quiescently if the screen is off            if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {                WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);                if (wm.getDefaultDisplay().getState() != Display.STATE_ON) {                    reason += ",quiescent";                }            }            pm.reboot(reason);            throw new IOException("Reboot failed (no permissions?)");        }    }

主要做了如下工作:

(1) 如果升级包路径为/data开始的根目录,把升级包的名字写到文件/cache/recovery/uncrypt_file里

(2) 写升级命令--update_package=@/cache/recovery/block.map到文件/cache/recovery/command

(3) 调用pm.reboot(PowerManager.REBOOT_RECOVERY_UPDATE)重启。

 

 

参考资料:https://blog.csdn.net/miaotao/article/details/45129423

http://feed.askmaclean.com/archives/linux查看稀疏文件的哪些块没有分配空间.html

更多相关文章

  1. android指纹识别源码
  2. Android(安卓)获取wifi的加密方式
  3. android增加swap分区能提速反应很显著哦!
  4. android安全学习之2—android中.pem和.pk8是什么文件?
  5. Android(安卓)加解密类Cipher
  6. 谷歌要求马上升级!Android迎来安全更新:修复多个严重漏洞
  7. android设备静默升级
  8. [置顶] Android(安卓)实现书籍翻页效果----升级篇
  9. Android(安卓)Log升级版

随机推荐

  1. 第115天:Python 到底是值传递还是引用传递
  2. 【DG】物理DG中主库的LNSn、NSS、NSA进程
  3. 第116天:机器学习算法之朴素贝叶斯理论
  4. 第121天:机器学习之决策树
  5. 第124天: Web 开发 Django 模板
  6. 第125天:Flask 项目结构
  7. 主流技术栈的Restful API接口测试实战
  8. Oracle OCR的备份与恢复
  9. Oracle kill session相关问题
  10. 第126天:Seaborn-可视化统计关系