您的位置:首页 > 移动开发 > Android开发

android手机reboot流程分析

2014-05-08 23:17 246 查看
android reboot走的流程以及所设计的代码,直接从framework层开始。
framework会提供系统重启的接口:

代码路径:frameworks/base/core/java/android/os/Power.java

public static void
reboot(String reason) throws IOException

{

rebootNative(reason);

}


而嵌套的rebootNative(reason);其实是个native接口,其实现是在frameworks/base/core/jni/android_os_Power.cpp

{ "rebootNative", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot },



static void android_os_Power_reboot(JNIEnv *env, jobject clazz, jstring reason)

{

sync();

#ifdef H***E_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

}


重点关注__reboot这个函数,其带4个参数,具体函数定义是在内核里kernel/sys.c,可以跟踪一下代码,很重要

SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int,
cmd,

void __user *, arg)


{

.......

.......

/* For safety, we require "magic" arguments. */

if (magic1 != LINUX_REBOOT_MAGIC1 || //从这里可以看出其实magic1和magic2这两个参数其实没啥用,只是linux为了自身安全而带的两个参数

(magic2 != LINUX_REBOOT_MAGIC2 && //重点在cmd这个参数

magic2 != LINUX_REBOOT_MAGIC2A &&

magic2 != LINUX_REBOOT_MAGIC2B &&

magic2 != LINUX_REBOOT_MAGIC2C))

return -EINVAL;


.......

.......

.......

根据不同的cmd内核会选择做不同的事,停止、下电或者重启,这里主要讲重启的流程,那就接着从LINUX_REBOOT_CMD_RESTART2往下看吧

case LINUX_REBOOT_CMD_HALT:

kernel_halt();

do_exit(0);

panic("cannot halt");


case LINUX_REBOOT_CMD_POWER_OFF:

kernel_power_off();

do_exit(0);

break;


case LINUX_REBOOT_CMD_RESTART2:

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

ret = -EFAULT;

break;

}

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


kernel_restart(buffer);

break;




}

我们接着从kernel_restart(buffer);往下走,看调用

kernel/sys.c:

void kernel_restart(char *cmd)

{


......

......

machine_restart(cmd);

}


----->arch/arm/kernel/process.c:

void machine_restart(char *cmd)

{

arm_pm_restart(reboot_mode,
cmd);

}


----->arch/arm/kernel/process.c:

void arm_machine_restart(char mode, const char *cmd)

{

......


......

arch_reset(mode, cmd);//这个接口分布到各个平台对应的reset,如高通的,可以具体跟踪一下高通代码



/*

* Whoops - the architecture was unable to reboot.

* Tell the user!

*/

mdelay(1000);

printk("Reboot failed -- System halted\n");

while (1);

}


----->arch/arm/mach-mmp/reset.c:

void arch_reset(char mode, const char *cmd)

{

if (cpu_is_pxa910() || cpu_is_pxa168())

pxa_arch_reset(mode, cmd);

else

return;

}


----->arch/arm/mach-mmp/reset.c:

static void pxa_arch_reset(char
mode, const char *cmd)

{

switch (mode) {

case 's':

/* Jump into ROM at address 0 */

cpu_reset(0);

break;

case 'w':

default:

do_wdt_reset(cmd);//这里采用的是看门狗bite方式重启

break;

}

}


----->arch/arm/mach-mmp/reset.c:

static void do_wdt_reset(const char *cmd)

{


......

......

if (cpu_is_pxa910())

watchdog_virt_base = CP_TIMERS2_VIRT_BASE;

else if (cpu_is_pxa168())

watchdog_virt_base = TIMERS1_VIRT_BASE;

else

return;


/* reset/enable WDT clock */

writel(0x7, MPMU_WDTPCR);

readl(MPMU_WDTPCR);

writel(0x3, MPMU_WDTPCR);

readl(MPMU_WDTPCR);


if (cpu_is_pxa910()) {

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

for (i = 0, backup = 0; i < 4; i++) {

backup <<= 8;

backup |= *(cmd + i);

}

do {

writel(backup, REG_RTC_BR0);

} while (readl(REG_RTC_BR0) != backup);



.......

.......

.......

}

最终就会走到对应平台的reset函数里,根据不同平台会设置自己的一些寄存器参数,并且可以根据用户层传下的arg值来

做不同的事情,比如这里

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

for (i = 0, backup = 0; i < 4; i++) {

backup <<= 8;

backup |= *(cmd + i);

}

如果传下来的字符串是recovery那么,就在RTC寄存器里设置某个特定值,当uboot里读取RTC寄存器的时候如果获取了这个


特定值,那就可以起recovery这个动作了,大致流程是这样,希望对大家有帮助,偶人比较懒不喜欢多写注释,有兴趣的可以

根据这个路径自己看代码理解。

http://blog.csdn.net/tronteng/article/details/7580741
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: