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) {
- 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"
- 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"
- 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) {
- }
- }
- }
- }
6. ShutdownThread类在下列文件中实现:
- 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 ---
- 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 ;
- }
调用本地JNI接口rebootNative().
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
- }
上面的各种宏定义于文件:bionic/libc/kernel/common/linux/reboot.h
- #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);
- }
可以看出,recovery和reset都是往RTC_PDN1的bit5:bit4上分别写01和10来标识。
12. 正常的log如下:
- #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的动作。