linux如何进去recovery模式,Android------recovery 模式启动进入流程

长孙景焕
2023-12-01

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) {

html

RebootThread mThread =newRebootThread(context, intent);

mThread.start();

}

在线程的run函数中会调用函数:RecoverySystem.rebootWipeUserData(mContext);这个方法是RecoverySystem类的静态方法。

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

java

publicclassRecoverySystem {

/** Used to communicate with recovery.  See bootable/recovery/recovery.c. */

privatestaticFile RECOVERY_DIR =newFile("/cache/recovery");

privatestaticFile COMMAND_FILE =newFile(RECOVERY_DIR,"command");

privatestaticFile LOG_FILE =newFile(RECOVERY_DIR,"log");

publicstaticvoidrebootWipeUserData(Context context)

throws IOException {

bootCommand(context, "--wipe_data");

}

privatestaticvoidbootCommand(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 = newFileWriter(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方法

thrownewIOException("Reboot failed (no permissions?)");

}

}

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

publicclassPowerManager

{

...

publicvoidreboot(String reason)

{

try{

mService.reboot(reason);

} catch(RemoteException e) {

}

}

publicPowerManager(IPowerManager service, Handler handler)

{

mService = service;

mHandler = handler;

}

IPowerManager mService;

Handler mHandler;

}

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

linux

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.

*/

publicvoidreboot(String reason)

{

mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);

if(mHandler == null || !ActivityManagerNative.isSystemReady()) {

thrownewIllegalStateException("Too early to call reboot()");

}

final String finalReason = reason;

Runnable runnable = newRunnable() {

publicvoidrun() {

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.

*/

publicvoidreboot(String reason)

{

mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);

if(mHandler == null || !ActivityManagerNative.isSystemReady()) {

thrownewIllegalStateException("Too early to call reboot()");

}

final String finalReason = reason;

Runnable runnable = newRunnable() {

publicvoidrun() {

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"

publicfinalclassShutdownThread extends Thread {

...

publicstaticvoidreboot(final Context context, String reason, boolean confirm) {

mReboot = true;

mRebootReason = reason;

shutdown(context, confirm);

}

...

publicvoidrun() {

...

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);

}

} elseif(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    ---

android

publicclassPower

{

...

publicstaticvoidreboot(String reason) throws IOException

{

rebootNative(reason);

}

privatestaticnativevoidrebootNative(String reason) throws IOException ;

}

frameworks/base/core/java/android/os/Power.java    ---

publicclassPower

{

...

publicstaticvoidreboot(String reason) throws IOException

{

rebootNative(reason);

}

privatestaticnativevoidrebootNative(String reason) throws IOException ;

}

调用本地JNI接口rebootNative().

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

app

frameworks/base/core/jni/android_os_Power.cpp

staticvoidandroid_os_Power_reboot(JNIEnv *env, jobject clazz, jstring reason)

{

sync();

#ifdef HAVE_ANDROID_OS

if(reason == NULL) {

reboot(RB_AUTOBOOT);

} else{

constchar*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.Sionic

#include 

.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

ide

SYSCALL_DEFINE4(reboot,int, magic1,int, magic2, unsignedint, cmd,void__user *, arg)

{

charbuffer[256];

intret = 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) {

...

caseLINUX_REBOOT_CMD_POWER_OFF:

kernel_power_off();

unlock_kernel();

do_exit(0);

break;

caseLINUX_REBOOT_CMD_RESTART2:

if(strncpy_from_user(&buffer[0], arg,sizeof(buffer) - 1) 

unlock_kernel();

return-EFAULT;

}

buffer[sizeof(buffer) - 1] ='\0';

kernel_restart(buffer);

break;

...

default:

ret = -EINVAL;

break;

}

unlock_kernel();

returnret;

}

voidkernel_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);

}

voidkernel_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)(charstr,constchar*cmd) = arm_machine_restart;

voidmachine_restart(char*cmd)

{

arm_pm_restart(reboot_mode, cmd);

}

voidarm_machine_restart(charmode,constchar*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

voidarch_reset(charmode,constchar*cmd)

{

printk("arch_reset: cmd = %s\n", cmd ? :"NULL");

if(cmd && !strcmp(cmd,"charger")) {

/* do nothing */

} elseif(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() */

voidrtc_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() */

voidrtc_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()函数

BOOLrecovery_check_command_trigger(void)

{

structmisc_message misc_msg;

structmisc_message *pmisc_msg = &misc_msg;

constunsignedintsize = NAND_WRITE_SIZE * MISC_PAGES;

unsigned char*pdata;

intret;

pdata = (uchar*)malloc(sizeof(uchar)*size);

ret = mboot_recovery_load_misc(pdata, size);

if(ret 

{

returnFALSE;

}

#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;

}

returnTRUE;

}

// recovery模式检测

BOOLrecovery_detection(void)

{

if((DRV_Reg16(RTC_PDN1) & 0x0030) == 0x0010) {/* factory data reset */

g_boot_mode = RECOVERY_BOOT;

returnTRUE;

} // 读取寄存器的值

if(recovery_check_key_trigger())

{

returnTRUE;

}

// 检测是否有快捷键按下

#ifdef CFG_NAND_BOOT

recovery_check_command_trigger();

#endif

// 检测是否经过将忘MISC分区写命令的方式

// 以上若是都不是,那么最后一次检查模式全局量是够是RECOVERY_BOOT

if(g_boot_mode == RECOVERY_BOOT)

{ returnTRUE;

}

else

{ returnFALSE;

}

}

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的动做。oop

 类似资料: