我这边主要是讲下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 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
}
重点关注__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);
/*
* 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);
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这个动作了,大致流程是这样,希望对大家有帮助,偶人比较懒不喜欢多写注释,有兴趣的可以
根据这个路径自己看代码理解。