美文网首页
Android之Recovery业务(二)-恢复出厂设置

Android之Recovery业务(二)-恢复出厂设置

作者: 锄禾豆 | 来源:发表于2022-01-24 09:14 被阅读0次

    简介

    简单介绍ota升级业务和恢复出厂设置业务在流程上的差异性
    

    框架

    Settings
    --> Android(MasterClearReceiver) 
    --RecoverySystem--> RecoverySystemService 
    --> uncrypt
    

    代码列表

    packages/apps/Settings
    
    frameworks/base/core/res/AndroidManifest.xml
    frameworks/base/core/java/android/os/RecoverySystem.java
    frameworks/base/services/core/java/com/android/server/
    RecoverySystemService.java
    MasterClearReceiver.java
    
    bootable/recovery
    注:
    7.1
    

    分析
    1.app调用系统接口:RecoverySystem.rebootWipeUserData

    权限:
    android.permission.REBOOT
    
    Settings发送广播
        private void doMasterClear() {
            Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
            intent.putExtra(Intent.EXTRA_REASON, "MasterClearConfirm");
            intent.putExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, mEraseSdCard);
            getActivity().sendBroadcast(intent);
            // Intent handling is asynchronous -- assume it will happen soon.
        }
        
    Android AndroidManifest.xml定义接受
       Thread thr = new Thread("Reboot") {
                @Override
                public void run() {
                    try {
                        RecoverySystem.rebootWipeUserData(context, shutdown, reason, forceWipe);
                        Log.wtf(TAG, "Still running after master clear?!");
                    } catch (IOException e) {
                        Slog.e(TAG, "Can't perform master clear/factory reset", e);
                    } catch (SecurityException e) {
                        Slog.e(TAG, "Can't perform master clear/factory reset", e);
                    }
                }
            };
    
        thr.start();
    
    RecoverySystem分析业务
    rebootWipeUserData --> bootCommand
        public static void rebootWipeUserData(Context context, boolean shutdown, String reason,
                boolean force) throws IOException {
            ···
            String shutdownArg = null;
            if (shutdown) {
                shutdownArg = "--shutdown_after";
            }
    
            String reasonArg = null;
            if (!TextUtils.isEmpty(reason)) {
                reasonArg = "--reason=" + sanitizeArg(reason);
            }
    
            final String localeArg = "--locale=" + Locale.getDefault().toString();
            
            bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg);
        }
    
        private static void bootCommand(Context context, String... args) throws IOException {
            LOG_FILE.delete();
    
            StringBuilder command = new StringBuilder();
            for (String arg : args) {
                if (!TextUtils.isEmpty(arg)) {
                    command.append(arg);
                    command.append("\n");
                }
            }
    
            // Write the command into BCB (bootloader control block) and boot from
            // there. Will not return unless failed.
            RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
            rs.rebootRecoveryWithCommand(command.toString());//写入RecoverySystemService
    
            throw new IOException("Reboot failed (no permissions?)");
        }
    

    2.RecoverySystemService接收数据进行处理

    RecoverySystemService.BinderService
            public void rebootRecoveryWithCommand(String command) {
                synchronized (sRequestLock) {
                    if (!setupOrClearBcb(true, command)) {
                        return;
                    }
    
                    // Having set up the BCB, go ahead and reboot.
                    PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
                    pm.reboot(PowerManager.REBOOT_RECOVERY);
                }
            }
    注意:
    1.ota升级也是调入setupOrClearBcb,差异仅仅在于command
    2.ota升级实在RecoverySystem中操作reboot,参数为REBOOT_RECOVERY_UPDATE
      这是是在RecoverySystemService中操作reboot,参数为REBOOT_RECOVERY
    这样的目的就是谁控制权限问题
    

    3.uncrypt通过socket与RecoverySystemService建立联系,将数据写入misc分区

    省略--此过程可参考:Android之Recovery业务(一)-升级过程
    

    4.PowerManager.reboot差异

    Powermanager.reboot(PowerManager.REBOOT_RECOVERY)
    -->> PowerManagerService.reboot 
    -->> ShutdownThread.reboot --> shutdownInner --> beginShutdownSequence --> run
    
        public void run() {
            ···
            if (mRebootHasProgressBar) {//此时mRebootHasProgressBar=false
                sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);
    
                // If it's to reboot to install an update and uncrypt hasn't been
                // done yet, trigger it now.
                uncrypt();
            }
            ···
            rebootOrShutdown(mContext, mReboot, mReason);
        }
    

    5.recovery部分日志及文件分析

    1)快速进入recovery的方式
    adb reboot recovery
    
    2)日志分析
    日记重定向   //可控制日志是否保存文件还是串口输出
    bootable/recovery/Android.mk
    REDIRECT_LOG_TO := SDCARD
    
    日志所在位置
    /cache/recovery
    
    涉及文件:
    last_install   //升级成功与否的标记
    ---------------------------------------------
    例如
    @/cache/recovery/block.map //update.zip的存储位置
    1    //这个代表成功
    time_total: 51
    retry: 0
    bytes_written_system: 790208512
    bytes_stashed_system: 0
    uncrypt_time: 0
    ---------------------------------------------------
    
    last_log**   //日志
    -----------------------
    last_log   //最新的
    last_log*  //代表过去的
    特别注意:
    recovery系统中有对应的build.prop等信息 如果更新过 则last_log可查
    升级过程可以看到需要升级的目标版本信息,例如:
    [    5.866441] Target: Android/rk3288/rk3288:7.1.2/NHG47K/iotuse08190934:userdebug/test-keys
    -------------------------
    
    last_kmsg** //kernel日志
    last_locale  //语言区域
    
    uncrypt_file  //system中,update.zip所在的路径
    -------------------------------------
    /data/Firmware/update.zip  //system中,update.zip所在的路径
    ------------------------------------
    

    其他

    PowerManagerService
        SystemProperties.set("sys.powerctl", "reboot,recovery");
    
    system/core/rootdir/init.rc
        on property:sys.powerctl=*
        powerctl ${sys.powerctl}
    
    system/core/init/builtins.cpp
        {"powerctl",                {1,     1,    do_powerctl}},
        
        android_reboot_with_callback
    
    system/core/libcutils/android_reboot.c
    int android_reboot_with_callback(
        int cmd, int flags __unused, const char *arg,
        void (*cb_on_remount)(const struct mntent*))
    {
        int ret;
        remount_ro(cb_on_remount);
        switch (cmd) {
            case ANDROID_RB_RESTART:
                ret = reboot(RB_AUTOBOOT);
                break;
    
            case ANDROID_RB_POWEROFF:
                ret = reboot(RB_POWER_OFF);
                break;
    
            case ANDROID_RB_RESTART2:
                ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
                               LINUX_REBOOT_CMD_RESTART2, arg);
                break;
    
            default:
                ret = -1;
        }
    
        return ret;
    }
    
    //syscall 这是native和kernel打交道的接口
    
    kernel/kernel/reboot.c
        case LINUX_REBOOT_CMD_RESTART2:
            ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1);
            if (ret < 0) {
                ret = -EFAULT;
                break;
            }
            buffer[sizeof(buffer) - 1] = '\0';
    
            kernel_restart(buffer);
            break;
            
    
    void kernel_restart(char *cmd)
    {
        kernel_restart_prepare(cmd);
        migrate_to_reboot_cpu();
        syscore_shutdown();
        if (!cmd)
            pr_emerg("Restarting system\n");
        else
            pr_emerg("Restarting system with command '%s'\n", cmd);
        kmsg_dump(KMSG_DUMP_RESTART);
        machine_restart(cmd);
    }
    

    相关文章

      网友评论

          本文标题:Android之Recovery业务(二)-恢复出厂设置

          本文链接:https://www.haomeiwen.com/subject/ixpthrtx.html