android重启流程

 

我这边主要是讲下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这个动作了,大致流程是这样,希望对大家有帮助,偶人比较懒不喜欢多写注释,有兴趣的可以

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

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页