android recovery 模式流程

    xiaoxiao2021-03-26  19

    1.  上层应用的设置->隐私权->恢复出厂设置对应的java代码在如下路径文件:  packages/apps/Settings/src/com/android/settings/MasterClear.java  MasterClear:mFinalClickListener()函数会发送一个广播出去:  sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));

    2.  这个广播的接收者在收到广播之后会开启一个Java服务线程:MasterClearReceiver:RebootThread  frameworks/base/services/java/com/Android/server/MasterClearReceiver.java  -- TAG = "MasterClear"  public void onReceive(Context context, Intent intent) {

    [cpp]  view plain  copy     RebootThread mThread = new RebootThread(context, intent);       mThread.start();   }       在线程的run函数中会调用函数:RecoverySystem.rebootWipeUserData(mContext);这个方法是RecoverySystem类的静态方法。

    3.  RecoverySystem类定义于文件:frameworks/base/core/java/android/os/RecoverySystem.java   --  TAG = "RecoverySystem"  

    [cpp]  view plain  copy public class RecoverySystem {     /** Used to communicate with recovery.  See bootable/recovery/recovery.c. */         private static File RECOVERY_DIR = new File("/cache/recovery");        private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");        private static File LOG_FILE = new File(RECOVERY_DIR, "log");          public static void rebootWipeUserData(Context context)            throws IOException {            bootCommand(context, "--wipe_data");        }                private static void bootCommand(Context context, String arg) throws IOException {            RECOVERY_DIR.mkdirs();  // In case we need it            COMMAND_FILE.delete();  // In case it's not writable            LOG_FILE.delete();                FileWriter command = new FileWriter(COMMAND_FILE);            try {                command.write(arg);  // 往文件/cache/recovery/command中写入recovery ELF的执行参数。                command.write("\n");            } finally {                command.close();            }                // Having written the command file, go ahead and reboot            PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);            pm.reboot("recovery");  // 调用PowerManager类中的reboot方法                throw new IOException("Reboot failed (no permissions?)");        }    }     4.  PowerManager类定义于文件:frameworks/base/core/java/android/os/PowerManager.java  --  TAG = "PowerManager" [cpp]  view plain  copy public class PowerManager   {    ...    public void reboot(String reason)       {           try {               mService.reboot(reason);           } catch (RemoteException e) {           }       }         public PowerManager(IPowerManager service, Handler handler)       {           mService = service;           mHandler = handler;       }        IPowerManager mService;       Handler mHandler;   }  

    5.  mService指向的是PowerManagerService类,这个类定义于文件:

    [cpp]  view plain  copy frameworks/base/services/java/com/android/server/PowerManagerService.java  --  TAG = "PowerManagerService"   /**      * Reboot the device immediately, passing 'reason' (may be null)      * to the underlying __reboot system call.  Should not return.      */      public void reboot(String reason)      {          mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);             if (mHandler == null || !ActivityManagerNative.isSystemReady()) {              throw new IllegalStateException("Too early to call reboot()");          }             final String finalReason = reason;          Runnable runnable = new Runnable() {              public void run() {                  synchronized (this) {                      ShutdownThread.reboot(mContext, finalReason, false);                  } // 调用ShutdownThread服务中的reboot方法                               }          };          // ShutdownThread must run on a looper capable of displaying the UI.          mHandler.post(runnable);             // PowerManager.reboot() is documented not to return so just wait for the inevitable.          synchronized (runnable) {              while (true) {                  try {                      runnable.wait();                  } catch (InterruptedException e) {                  }              }          }      }   [cpp]  view plain  copy frameworks/base/services/java/com/android/server/PowerManagerService.java  --  TAG = "PowerManagerService"   /**      * Reboot the device immediately, passing 'reason' (may be null)      * to the underlying __reboot system call.  Should not return.      */      public void reboot(String reason)      {          mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);             if (mHandler == null || !ActivityManagerNative.isSystemReady()) {              throw new IllegalStateException("Too early to call reboot()");          }             final String finalReason = reason;          Runnable runnable = new Runnable() {              public void run() {                  synchronized (this) {                      ShutdownThread.reboot(mContext, finalReason, false);                  } // 调用ShutdownThread服务中的reboot方法                               }          };          // ShutdownThread must run on a looper capable of displaying the UI.          mHandler.post(runnable);             // PowerManager.reboot() is documented not to return so just wait for the inevitable.          synchronized (runnable) {              while (true) {                  try {                      runnable.wait();                  } catch (InterruptedException e) {                  }              }          }      }   6.  ShutdownThread类在下列文件中实现: [cpp]  view plain  copy frameworks/base/core/java/com/android/internal/app/ShutdownThread.java   -- TAG = "ShutdownThread"   public final class ShutdownThread extends Thread {    ...    public static void reboot(final Context context, String reason, boolean confirm) {           mReboot = true;           mRebootReason = reason;           shutdown(context, confirm);       }             ...       public void run() {        ...        if (mReboot) {               Log.i(TAG, "Rebooting, reason: " + mRebootReason);               try {                   Power.reboot(mRebootReason);               } catch (Exception e) {                   Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);               }           } else if (SHUTDOWN_VIBRATE_MS > 0) {               ...           }           ...       }   }    流程:reboot() --> shutdown() --> beginShutdownSequence() --> sInstance.start() --> run() --> Power.reboot(mRebootReason).  最后调用Power类的reboot方法。

    7.  Power类定义于文件: frameworks/base/core/java/android/os/Power.java    --- 

    [cpp]  view plain  copy public class Power   {    ...    public static void reboot(String reason) throws IOException       {           rebootNative(reason);       }          private static native void rebootNative(String reason) throws IOException ;   }   [cpp]  view plain  copy frameworks/base/core/java/android/os/Power.java    ---   public class Power   {    ...    public static void reboot(String reason) throws IOException       {           rebootNative(reason);       }          private static native void rebootNative(String reason) throws IOException ;   }   调用本地JNI接口rebootNative().

    8. Power类对应的JNI接口函数定义于文件:

    [cpp]  view plain  copy frameworks/base/core/jni/android_os_Power.cpp   static void android_os_Power_reboot(JNIEnv *env, jobject clazz, jstring reason)   {       sync();   #ifdef HAVE_ANDROID_OS       if (reason == NULL) {           reboot(RB_AUTOBOOT);       } else {           const char *chars = env->GetStringUTFChars(reason, NULL);           __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,                    LINUX_REBOOT_CMD_RESTART2, (char*) chars);           env->ReleaseStringUTFChars(reason, chars);  // In case it fails.       }       jniThrowIOException(env, errno);   #endif   }    上面的各种宏定义于文件:bionic/libc/kernel/common/linux/reboot.h [cpp]  view plain  copy #define LINUX_REBOOT_MAGIC1 0xfee1dead   #define LINUX_REBOOT_MAGIC2 672274793   #define LINUX_REBOOT_MAGIC2A 85072278   #define LINUX_REBOOT_MAGIC2B 369367448   #define LINUX_REBOOT_MAGIC2C 537993216      /*   * Commands accepted by the _reboot() system call.   *   * RESTART     Restart system using default command and mode.   * HALT        Stop OS and give system control to ROM monitor, if any.   * CAD_ON      Ctrl-Alt-Del sequence causes RESTART command.   * CAD_OFF     Ctrl-Alt-Del sequence sends SIGINT to init task.   * POWER_OFF   Stop OS and remove all power from system, if possible.   * RESTART2    Restart system using given command string.   * SW_SUSPEND  Suspend system using software suspend if compiled in.   * KEXEC       Restart system using a previously loaded Linux kernel   */   #define LINUX_REBOOT_CMD_RESTART 0x01234567   #define LINUX_REBOOT_CMD_HALT 0xCDEF0123   #define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF   #define LINUX_REBOOT_CMD_CAD_OFF 0x00000000   #define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC   #define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4   #define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2   #define LINUX_REBOOT_CMD_KEXEC 0x45584543      bionic/libc/include/sys/reboot.h   #define RB_AUTOBOOT     LINUX_REBOOT_CMD_RESTART   #define RB_HALT_SYSTEM  LINUX_REBOOT_CMD_HALT   #define RB_ENABLE_CAD   LINUX_REBOOT_CMD_CAD_ON   #define RB_DISABLE_CAD  LINUX_REBOOT_CMD_CAD_OFF   #define RB_POWER_OFF    LINUX_REBOOT_CMD_POWER_OFF  

    9.  libc中__reboot的实现  bionic/libc/arch-arm/syscalls/__reboot.S

    [cpp]  view plain  copy  #include <sys/linux-syscalls.h>          .text       .type __reboot, #function       .globl __reboot       .align 4       .fnstart      __reboot:       .save   {r4, r7}       stmfd   sp!, {r4, r7}       ldr     r7, =__NR_reboot // 系统调用号 88, binoic/libc/include/sys/linux-syscalls.h       swi     #0            ldmfd   sp!, {r4, r7}       movs    r0, r0       bxpl    lr       b       __set_syscall_errno       .fnend  

    10. reboot系统调用实现  kernel/kernel/sys.c  

    [cpp]  view plain  copy SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg)    {     char buffer[256];     int ret = 0;         /* We only trust the superuser with rebooting the system. */     if (!capable(CAP_SYS_BOOT))      return -EPERM;         /* For safety, we require "magic" arguments. */     if (magic1 != LINUX_REBOOT_MAGIC1 ||         (magic2 != LINUX_REBOOT_MAGIC2 &&                     magic2 != LINUX_REBOOT_MAGIC2A &&       magic2 != LINUX_REBOOT_MAGIC2B &&                     magic2 != LINUX_REBOOT_MAGIC2C))      return -EINVAL;         if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)      cmd = LINUX_REBOOT_CMD_HALT;         lock_kernel();     switch (cmd) {      ...      case LINUX_REBOOT_CMD_POWER_OFF:       kernel_power_off();       unlock_kernel();       do_exit(0);       break;           case LINUX_REBOOT_CMD_RESTART2:       if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {        unlock_kernel();        return -EFAULT;       }       buffer[sizeof(buffer) - 1] = '\0';            kernel_restart(buffer);       break;            ...           default:       ret = -EINVAL;       break;     }     unlock_kernel();     return ret;    }       void kernel_restart(char *cmd)    {     kernel_restart_prepare(cmd);     if (!cmd)      printk(KERN_EMERG "Restarting system.\n");     else      printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);     machine_restart(cmd);    }    void kernel_restart_prepare(char *cmd)    {     blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); // 调用通知链reboot_notifier_list上的函数     system_state = SYSTEM_RESTART;     device_shutdown(); // shutdown设备     sysdev_shutdown(); // 系统设备shutdoen    }       @kernel/arch/arm/kernel/process.c    void (*arm_pm_restart)(char str, const char *cmd) = arm_machine_restart;    void machine_restart(char *cmd)    {     arm_pm_restart(reboot_mode, cmd);    }    void arm_machine_restart(char mode, const char *cmd)    {     /*     * Clean and disable cache, and turn off interrupts     */     cpu_proc_fin();         /*     * Tell the mm system that we are going to reboot -     * we may need it to insert some 1:1 mappings so that     * soft boot works.     */     setup_mm_for_reboot(mode);         /*     * Now call the architecture specific reboot code.     */     arch_reset(mode, cmd);   // reset硬件系统,写reboot标记,供bootloader中判断         /*     * Whoops - the architecture was unable to reboot.     * Tell the user!     */     mdelay(1000);     printk("Reboot failed -- System halted\n");     while (1);    }      11. arch_reset()    文件:kernel/arch/arm/mach-mt6516/system.c    void arch_reset(char mode, const char *cmd)    {     printk("arch_reset: cmd = %s\n", cmd ? : "NULL");         if (cmd && !strcmp(cmd, "charger")) {      /* do nothing */     } else if (cmd && !strcmp(cmd, "recovery")) {      rtc_mark_recovery();  // 写recovery的标记到寄存器中去。     } else {      rtc_mark_swreset();     }         DRV_WriteReg32(RGU_USRST1,0xbb1f);           printk("MT6516 SW Reset\n");     DRV_WriteReg32(WDT_MODE, 0x2221);     DRV_WriteReg32(WDT_RESTART, 0x1971);     DRV_WriteReg32(WDT_SWRST, 0x1209);         /* enter loop waiting for restart */     while (1);    }    @ kernel/driver/ret/ret-mt6516.c    /* used in arch_reset() */    void rtc_mark_recovery(void)    {     u16 pdn1;         spin_lock_irq(&rtc_lock);     pdn1 = rtc_read(RTC_PDN1) & ~0x0030;     pdn1 |= 0x0010;     rtc_writeif_unlock();     rtc_write(RTC_PDN1, pdn1);     rtc_writeif_lock();     spin_unlock_irq(&rtc_lock);    }    /* used in arch_reset() */    void rtc_mark_swreset(void)    {     u16 pdn1;         spin_lock_irq(&rtc_lock);     pdn1 = rtc_read(RTC_PDN1) & ~0x0030;     pdn1 |= 0x0020;     rtc_writeif_unlock();     rtc_write(RTC_PDN1, pdn1);     rtc_writeif_lock();     spin_unlock_irq(&rtc_lock);    }    可以看出,recovery和reset都是往RTC_PDN1的bit5:bit4上分别写01和10来标识。     12. 正常的log如下: [html]  view plain  copy #logcat ShutdownThread:D *:S &   # --------- beginning of /dev/log/system   --------- beginning of /dev/log/main   D/ShutdownThread(  127): !!! Request to shutdown !!!   D/ShutdownThread(  127): Notifying thread to start radio shutdown   D/ShutdownThread(  127): shutdown acquire partial WakeLock 2   I/ShutdownThread(  127): Sending shutdown broadcast...   I/ShutdownThread(  127): Shutting down activity manager...   W/ShutdownThread(  127): Turning off radio...   I/ShutdownThread(  127): Waiting for Bluetooth and Radio...   I/ShutdownThread(  127): Radio and Bluetooth shutdown complete.   I/ShutdownThread(  127): Shutting down MountService   W/ShutdownThread(  127): Result code 0 from MountService.shutdown   [  127.981918] save exit: isCheckpointed 1   [  127.985002] save exit: isCheckpointed 1   I/ShutdownThread(  127): Rebooting, reason: recovery   [  128.081532] [lizhiguo reboot1] LINUX_REBOOT_CMD_RESTART2.   [  128.082357] GPS: mt3326_gps_shutdown: Shutting down   [  128.083011] GPS: mt3326_gps_power: Switching GPS device off   [  128.083741] GPS: mt3326_gps_power: null pointer!!   [  128.084376] GPIO Shut down   [  128.089814] [MATV] shutdown   [  128.090193] [H264_DEC] h264_dec_shutdown   [  128.090710] JPEG Codec shutdown   [  128.091248] ----MT6516 M3D shutdown----   [  128.091839] m2d_shutdown() is called   [  128.092320] ******** MT6516 WDT driver shutdown!! ********   [  128.093040] [MM_QUEUE] mm_queue_shutdown   [  128.094333] [lizhiguo reboot2] kernel_restart.   [  128.094955] Restarting system with command 'recovery'.   [  128.097483] [lizhiguo reboot3] arm_machine_restart.   [  128.099275] arch_reset: cmd = recovery   [  128.100917] MT6516 SW Reset   u516 EVBgetflashID ADBC successful!!!   [MEM] complex R/W mem test pass  

    13. uboot中会先后检查三种方式进入recovery是否成立:第一种是kernel直接写一个寄存器来标记下次启动将进入recovery模式;第二种是快捷键:powerkey+downVOL;第三中就是上层应用发送下来的回复出厂设置的命令,这个命令在restart之前kernel会往MISC分区中写command(boot-recovery)。这项工作在文件:bootable/bootloader/uboot/board/mt6516/mt6516_recovery.c完成。 recovery_check_key_trigger() recovery_check_command_trigger()

    [cpp]  view plain  copy BOOL recovery_check_command_trigger(void)   {    struct misc_message misc_msg;    struct misc_message *pmisc_msg = &misc_msg;    const unsigned int size = NAND_WRITE_SIZE * MISC_PAGES;    unsigned char *pdata;        int ret;       pdata = (uchar*)malloc(sizeof(uchar)*size);       ret = mboot_recovery_load_misc(pdata, size);           if (ret < 0)       {        return FALSE;        }        #ifdef LOG_VERBOSE       MSG("\n--- get_bootloader_message ---\n");       dump_data(pdata, size);       MSG("\n");   #endif       memcpy(pmisc_msg, &pdata[NAND_WRITE_SIZE * MISC_COMMAND_PAGE], sizeof(misc_msg));     MSG("Boot command: %.*s\n"sizeof(misc_msg.command), misc_msg.command);    MSG("Boot status: %.*s\n"sizeof(misc_msg.status), misc_msg.status);    MSG("Boot message\n\"%.20s\"\n", misc_msg.recovery);       if(strcmp(misc_msg.command, "boot-recovery")==0)    { g_boot_mode = RECOVERY_BOOT;    }       return TRUE;   }   // recovery模式检测   BOOL recovery_detection(void)   {    if ((DRV_Reg16(RTC_PDN1) & 0x0030) == 0x0010) { /* factory data reset */     g_boot_mode = RECOVERY_BOOT;     return TRUE;    } // 读取寄存器的值          if(recovery_check_key_trigger())       {        return TRUE;       }       // 检测是否有快捷键按下             #ifdef CFG_NAND_BOOT    recovery_check_command_trigger();    #endif    // 检测是否通过将忘MISC分区写命令的方式    // 以上如果都不是,那么最后一次检查模式全局量是够是RECOVERY_BOOT    if (g_boot_mode == RECOVERY_BOOT)    { return TRUE;    }    else    { return FALSE;    }   }  

    14. g_boot_mode = RECOVERY_BOOT这个成立之后,uboot将会从RECOVERY分区加载recovery.img进SDRAM来运行。  其实这个recovery.img和boot.img结构类似,zImage一样,所不同的是ramdisk.img不同而已。  在运行recovery这个elf的时候会从/cache/recovery/comamnd中读取参数,这个参数是android的上层应用写进入的,--wipe-data,  之后会清除USERDATA和CACHE分区,在将recovery的log文件放在/cache/recovery/下,将原来的command文件删除,最后  调用函数reboot(RB_AUTOBOOT)来重新启动系统。  bootable/recovery/recovery.c    最后需要注意的一个问题是,recovery这个elf在编译user-release版本软件的时候没有copy到/system/bin下面去,需要修改  bootable/recovery/Android.mk文件中的如下地方:  /* BENGIN: lizhiguo 2011-07-27, copy recovery to /system/bin for user builds.*/  #LOCAL_MODULE_TAGS := eng  /* END: lizhiguo 2011-07-27 */  如果放开这行,将只会在eng版本软件中有copy到/system/bin的动作。

    转载请注明原文地址: https://ju.6miu.com/read-659780.html

    最新回复(0)