美文网首页
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业务(二)-恢复出厂设置

    简介 框架 代码列表 分析1.app调用系统接口:RecoverySystem.rebootWipeUserDat...

  • Android4.4.2恢复出厂设置(二)

    Android4.4.2恢复出厂设置(二)根据前文所述,UI层最终发送Intent消息MASTER_CLEAR进行...

  • Android恢复出厂设置

    一般只有在开发Launcher和Setting一般才会用到恢复出厂设置,恢复出厂设置在应用层开发相对来说比较简单,...

  • 小米手机账号锁解除

    捡到一台小米2sc在recovery模式清除数据恢复出厂设置以后开机联网会提示账号锁,如图解决办法: 不想刷机,进...

  • 恢复出厂设置--frameworks层流程分析

    开篇先啰嗦几句:Android系统原生 "设置" 应用都会有恢复出厂设置这一功能。此功能的主要意图是为了擦除用户在...

  • Android4.4.2恢复出厂设置(一)

    Android系统的恢复出厂设置可以分为如下几个部分来描述,分别是: UI操作部分 Framework层操作部分 ...

  • 手机和微信使用技巧

    1、*#*#7780#*#*——恢复出厂设置,不会删除内置程序和SD内容 2、*2767*3855#——恢复出厂设...

  • 恢复出厂设置

    手机卡的厉害,由于资金不到位暂时没换,于是乎就恢复出厂设置了,一开始觉得会很麻烦,后来当弄完所有一切之后感觉自己也...

  • 恢复出厂设置

    手机很卡,孩子说:恢复出厂设置,几分钟后手机里的装置简洁如初 在人间行走了很多年的这颗心承载了太多的伤痛有没有一个...

  • 恢复出厂设置

    没有什么是删不除,忘不掉的。 你想留下的终究还是会用你无法挽回的方式失去了。 那些你留恋的一切,都不是永恒不变的。...

网友评论

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

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