2. 这个广播的接收者在收到广播之后会开启一个java服务线程:MasterClearReceiver:RebootThread
frameworks/base/services/java/com/android/server/MasterClearReceiver.java -- TAG = "MasterClear"
public void onReceive(Context context, Intent intent) {
RebootThread mThread = new RebootThread(context, intent); mThread.start(); }
3. RecoverySystem类定义于文件:frameworks/base/core/java/android/os/RecoverySystem.java -- TAG = "RecoverySystem"
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?)"); } }
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类,这个类定义于文件:
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) { } } } }
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) { } } } }
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) { ... } ... } }
7. Power类定义于文件: 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 ; }
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 ; }
8. Power类对应的JNI接口函数定义于文件:
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 }
#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
#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
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); }
#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()
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的动作。