首页 / 操作系统 / Linux / Android recovery 和reboot
recovery工作的是要bootloader支持的,因为bootloader要选择启动哪个kernel和ramdisk。 推荐阅读:Android Service 之Bound Service http://www.linuxidc.com/Linux/2011-09/42255.htm设置模块中进行恢复出厂设置操作,recovery Power.reboot("recovery"); reboot system case1: factory reset Settings/src/com/android/settings/MasterClear.java sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR")); -> frameworks/base/services/java/com/android/server/MasterClearReceiver.java RecoverySystem.rebootWipeUserData(context); -> frameworks/base/core/java/android/os/RecoverySystem.java bootCommand(context, "--wipe_data"); -> PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); pm.reboot("recovery"); -> frameworks/base/services/java/com/android/server/PowerManagerService.java public void reboot(String reason){ ShutdownThread.reboot(mContext, finalReason, false); } -> frameworks/base/core/java/com/android/internal/app/ShutdownThread.java rebootOrShutdown(){ Power.reboot(reason); } -> frameworks/base/core/java/android/os/Power.java rebootNative(reason); -> frameworks/base/core/jni/anroid_os_Power.cpp __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (char*) chars); -> kernel/kernel/sys.c case LINUX_REBOOT_CMD_RESTART2: kernel_restart(buffer); -> machine_restart(cmd); -> kernel/arch/arm/kernel/process.c void arm_machine_restart(char mode, const char *cmd){ //set flag and reboot } 参数表示reboot的原因 然后会到JNI 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 } 这里会调用到c库里面的函数 __reboot: .save {r4, r7} stmfd sp!, {r4, r7} ldr r7, =__NR_reboot swi #0 ldmfd sp!, {r4, r7} movs r0, r0 bxpl lr b __set_syscall_errno .fnend c库实际上到最底下就是系统调用的封装了, 一般都是sys_reboot的实现了, 不过Qualcomm这里用了宏来定义的。 调用了系统调用,kernel里面实现,我们就到了kernel里面 SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg) switch (cmd) { case LINUX_REBOOT_CMD_RESTART: kernel_restart(NULL); break; case LINUX_REBOOT_CMD_CAD_ON: C_A_D = 1; break; case LINUX_REBOOT_CMD_CAD_OFF: C_A_D = 0; break; case LINUX_REBOOT_CMD_HALT: kernel_halt(); unlock_kernel(); do_exit(0); break; 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); 走到kernel_restart 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 machine_restart(char * __unused) { arm_pm_restart(reboot_mode); } arm_pm_restart(reboot_mode); 这个函数是要每个target自己定义的, 以Qualcomm来说 static void msm_pm_restart(char str) { msm_rpcrouter_close(); msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0); for (;;) ; } 这里的restart reason是recovery static int msm_reboot_call (struct notifier_block *this, unsigned long code, void *_cmd) { if ((code == SYS_RESTART) && _cmd) { char *cmd = _cmd; if (!strcmp(cmd, "bootloader")) { restart_reason = 0x77665500; } else if (!strcmp(cmd, "recovery")) { restart_reason = 0x77665502; } else if (!strcmp(cmd, "eraseflash")) { restart_reason = 0x776655EF; } else if (!strncmp(cmd, "oem-", 4)) { unsigned code = simple_strtoul(cmd + 4, 0, 16) & 0xff; restart_reason = 0x6f656d00 | code; } else { restart_reason = 0x77665501; } } return NOTIFY_DONE; } 会把这个原因写到smem里面去 下次启动的时候怎么管用呢? bootloader下次起来的时候会去读这个值 Qualcomm的bootloader是appsboot.mbn void aboot_init(const struct app_descriptor *app) { unsigned reboot_mode = 0; unsigned disp_init = 0; #if DISPLAY_SPLASH_SCREEN display_init(); dprintf(INFO, "Diplay initialized/n"); disp_init = 1; #endif page_size = flash_page_size(); page_mask = page_size - 1; if (keys_get_state(KEY_HOME) != 0) boot_into_recovery = 1; if (keys_get_state(KEY_BACK) != 0) goto fastboot; if (keys_get_state(KEY_CLEAR) != 0) goto fastboot; if (keys_get_state(KEY_VOLUMEUP) != 0) goto fastboot; if (keys_get_state(KEY_CAMERA) != 0) goto fastboot; if (keys_get_state(KEY_VOLUMEDOWN) != 0) boot_into_recovery = 1; //goto fastboot; reboot_mode = check_reboot_mode(); if (reboot_mode == RECOVERY_MODE){ boot_into_recovery = 1; }else if(reboot_mode == FASTBOOT_MODE){ goto fastboot; } recovery_init(); boot_linux_from_flash(); dprintf(CRITICAL, "ERROR: Could not do normal boot. Reverting " "to fastboot mode./n"); fastboot: if(!disp_init) { display_init(); } else { fbcon_clear(); } dprintf(INFO, "Diplay initialized/n"); udc_init(&surf_udc_device); fastboot_register("boot", cmd_boot); fastboot_register("erase:", cmd_erase); fastboot_register("flash:", cmd_flash); fastboot_register("continue", cmd_continue); fastboot_register("reboot", cmd_reboot); fastboot_register("reboot-bootloader", cmd_reboot_bootloader); fastboot_publish("product", "swordfish"); fastboot_publish("kernel", "lk"); fastboot_init(target_get_scratch_address(), 150 * 1024 * 1024); udc_start(); target_battery_charging_enable(1, 0); } APP_START(aboot) .init = aboot_init, APP_END aboot函数进入recovery有三种情况 1:如果按键就会进入recovery 2:如果check_boot_mode是recovery的时候就会做 3 : 如果recovery_init返回的是真的话就会进入recovery mode 第一种很好理解,按组合按键进入 第二种会去读smem unsigned check_reboot_mode(void) { unsigned mode[2] = {0, 0}; unsigned int mode_len = sizeof(mode); unsigned smem_status; smem_status = smem_read_alloc_entry(SMEM_APPS_BOOT_MODE, &mode, mode_len ); if(smem_status) { dprintf(CRITICAL, "ERROR: unable to read shared memory for reboot mode/n"); return 0; } return mode[0]; } unsigned smem_read_alloc_entry(smem_mem_type_t type, void *buf, int len) { struct smem_alloc_info *ainfo; unsigned *dest = buf; unsigned src; unsigned size; if (((len & 0x3) != 0) || (((unsigned)buf & 0x3) != 0)) return 1; if (type < SMEM_FIRST_VALID_TYPE || type > SMEM_LAST_VALID_TYPE) return 1; /* TODO: Use smem spinlocks */ ainfo = &smem->alloc_info[type]; if (readl(&ainfo->allocated) == 0) return 1; if ((size = readl(&ainfo->size)) != (unsigned)len) return 1; src = MSM_SHARED_BASE + readl(&ainfo->offset); for (; size > 0; src += 4, size -= 4) *(dest++) = readl(src); return 0; } 这个文章只解释如何进入recovery。
收藏该网址