• recovery 根据@/cache/recovery/block.map描述从data分区升级


      随着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
        oneshot
    
    service setup-bcb /system/bin/uncrypt --setup-bcb
        class main
        socket uncrypt stream 600 system system
        disabled
        oneshot
    
    service 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 + "
    ");
                        } 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 + "
    ";
                final String localeArg = "--locale=" + Locale.getDefault().toLanguageTag() + "
    ";
                final String securityArg = "--security
    ";
    
                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

  • 相关阅读:
    [HDU1561]The more, The Better
    [洛谷P1352][codevs1380]没有上司的舞会
    【51Nod1773】A国的贸易 解题报告
    快速沃尔什变换
    【SDOI2015】序列统计 解题报告
    【CF438E】小朋友和二叉树 解题报告
    多项式Ⅰ
    洛谷 P5105 不强制在线的动态快速排序
    【BZOJ4916】神犇和蒟蒻 解题报告
    【BZOJ3309】DZY Loves Math 解题报告
  • 原文地址:https://www.cnblogs.com/codeking100/p/10338075.html
Copyright © 2020-2023  润新知