android reboot 流程

写这个的原因是在一个新的方案中,发现reboot recovery无法进入recovery模式。按照以往的理解,我一直以为android到recovery流程是因为在misc分区中写入了boot-recovery字段,但是翻来翻去,也没找到是在哪里写入,所以跟了一下reboot流程,发现boot-recovery的写入好像不是我原来想的那么一回事 ,这个流程不是在上层做的。

以重启进入recovery来说。

1、framework

1)RecoverySystem提供的接口中,顺序如此:
installPackage->bootCommand->pm.reboot(“recovery”);
2)这里调用powerManager的reboot接口
该接口唯一参数reason代表需要的特定重启模式,比如recovery,当然也可以为null。

    public void reboot(String reason) {
        try {
            mService.reboot(false, reason, true);
        } catch (RemoteException e) {
        }
    }

通过binder,调用到powerManagerService的reboot函数

    @Override // Binder call
    public void reboot(boolean confirm, String reason, boolean wait) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);

        final long ident = Binder.clearCallingIdentity();
        try {
            shutdownOrRebootInternal(false, confirm, reason, wait);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

 private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm,
            final String reason, boolean wait) {
        if (mHandler == null || !mSystemReady) {
            throw new IllegalStateException("Too early to call shutdown() or reboot()");
        }

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    if (shutdown) {
                        ShutdownThread.shutdown(mContext, confirm);
                    } else {
                        ShutdownThread.reboot(mContext, reason, confirm);
                    }
                }
            }
        };

.....省略
    }

3)调用到ShutdownThread.reboot(mContext, reason, confirm);

public static void reboot(final Context context, String reason, boolean confirm) {
        mReboot = true;
        mRebootSafeMode = false;
        mRebootReason = reason;
        shutdownInner(context, confirm);
    }

这里说明是需要重启,且不是安全模式,重启参数为传递下来的reason,shutdownInner的confirm参数是用来设置是否有确认提示框的,通过reboot接口调用重启是没有的,为false。
重启的实现在run()中,因为ShutdownThread是Thread的扩展,所以run会自动运行。
run中会调用rebootOrShutdown(mReboot, mRebootReason);
然后又重新回到PowerManagerService.lowLevelShutdown();

    public static void rebootOrShutdown(boolean reboot, String reason) {
        if (reboot) {
            Log.i(TAG, "Rebooting, reason: " + reason);
            PowerManagerService.lowLevelReboot(reason);
            Log.e(TAG, "Reboot failed, will attempt shutdown instead");
        }    
...省略
        PowerManagerService.lowLevelShutdown();
    }

我们跟回PowerManagerService看下,其实无论是lowLevelShutdown还是lowLevelReboot,就是设置属性”sys.powerctl”。
reboot是SystemProperties.set(“sys.powerctl”, “reboot,” + reason);

    public static void lowLevelReboot(String reason) {
        if (reason == null) {
            reason = "";
        }
        SystemProperties.set("sys.powerctl", "reboot," + reason);
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

2、init

SystemProperties.set(“sys.powerctl”, “reboot,” + reason);我们看下init.rc是怎么写的。

on property:sys.powerctl=*
    powerctl ${sys.powerctl}  

所以我们要再看下init的代码,可以看到对应的函数是do_powerctl
KEYWORD(powerctl, COMMAND, 1, do_powerctl)


int do_powerctl(int nargs, char **args)
{
    char command[PROP_VALUE_MAX];
    int res;
    int len = 0;
    int cmd = 0;
    char *reboot_target;

    res = expand_props(command, args[1], sizeof(command));
    if (res) {
        ERROR("powerctl: cannot expand '%s'\n", args[1]);
        return -EINVAL;
    }

    if (strncmp(command, "shutdown", 8) == 0) {
        cmd = ANDROID_RB_POWEROFF;
        len = 8;
    } else if (strncmp(command, "reboot", 6) == 0) {
        cmd = ANDROID_RB_RESTART2;
        len = 6;
    } else {
        ERROR("powerctl: unrecognized command '%s'\n", command);
        return -EINVAL;
    }

    if (command[len] == ',') {
        reboot_target = &command[len + 1];
    } else if (command[len] == '\0') {
        reboot_target = "";
    } else {
        ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);
        return -EINVAL;
    }

    return android_reboot(cmd, 0, reboot_target);
}

这里会继续去调用android_reboot函数,根据参入参数的不同
1)关机 ANDROID_RB_POWEROFF, 无需reason,直接调用reboot进行关机;
2)带参数的特殊重启 ANDROID_RB_RESTART2,可以有reason,也可以为“”
android_reboot在system/core/libcutils/android_reboot.c



int android_reboot(int cmd, int flags, char *arg)
{
    int ret,fd;

    sync();
    fd = open("/sys/class/remount/need_remount", O_WRONLY);
    if (fd < 0) {
        return -1;
    }
    write(fd, "1", 1);
    close(fd);
    remount_ro();

    switch (cmd) {
        case ANDROID_RB_RESTART:
            ret = reboot(RB_AUTOBOOT);
            break;

        case ANDROID_RB_POWEROFF:
            ret = reboot(RB_POWER_OFF);
            break;

        case ANDROID_RB_RESTART2:
            ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
                           LINUX_REBOOT_CMD_RESTART2, arg);
            break;

        default:
            ret = -1;
    }

    return ret;
}

首先做了一些关机重启前的预处理工作,sync()作用是将缓存中的信息写入磁盘,以免程序异常结束导致文件被损坏,linux系统关机前会做几次这样的动作;而remount_ro()作用是通过调用emergency_remount()强制将文件系统挂载为只读,不再允许任何写入操作,同时会通过检查/proc/mounts的设备状态来确认是否当前的所有写入工作已经完成,这个检查过程是阻塞操作。
以reboot recovery为例,arg即为recovery,会传入ANDROID_RB_RESTART2。
最终会调用:
__reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_RESTART2, arg);

3、kernel

__reboot通过syscall来到内核,这部分我也不懂,接下来参看别人的解读。
可参考:
http://blog.sina.com.cn/s/blog_6695f9eb0101hse4.html

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值