Android 关机流程分析-----(2)JNI和kernel层

      最近遇到fastboot关机电流偏高的问题,虽然最后确认是硬件的问题,但还是顺便分析了一下android开关机的流程。总结一下,加深印象,也方便日后查阅。

Android智能手机和平板一般都有Power key,长按Power key弹出关机对话框,选择power off就会让系统关闭。关机动作从按键触发中断,linux kernel层给android framework层返回按键事件进入framework层,再从 framework层到kernel层执行关机任务。本文分析过程将分成两篇,(1)Framework层 (2)JNI和Kernel层,代码基于自己的android4.3源码。

前面的文章Android 关机流程分析-----(1)Framework层中,分析了framework层的关机流程,本文会继续分析JNI和Kernel层的关机流程。

五、JNI层的接口:android_reboot()

framework层最后执行lowLevelShutdown(),进入nativeShutdown()。在JNI层,有如下对nativeShutdown()以及nativeReboot()的定义。

frameworks/base/services/jni/com_android_server_power_PowerManagerService.cpp

static void nativeShutdown(JNIEnv *env, jclass clazz) {
    android_reboot(ANDROID_RB_POWEROFF, 0, 0);
}

static void nativeReboot(JNIEnv *env, jclass clazz, jstring reason) {
    if (reason == NULL) {
        android_reboot(ANDROID_RB_RESTART, 0, 0);
    } else {
        const char *chars = env->GetStringUTFChars(reason, NULL);
        android_reboot(ANDROID_RB_RESTART2, 0, (char *) chars);
        env->ReleaseStringUTFChars(reason, chars);  // In case it fails.
    }
    jniThrowIOException(env, errno);
}

// ----------------------------------------------------------------------------

static JNINativeMethod gPowerManagerServiceMethods[] = {
    /* name, signature, funcPtr */
    { "nativeInit", "()V",
            (void*) nativeInit },
    { "nativeSetPowerState", "(ZZ)V",
            (void*) nativeSetPowerState },
    { "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V",
            (void*) nativeAcquireSuspendBlocker },
    { "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",
            (void*) nativeReleaseSuspendBlocker },
    { "nativeSetInteractive", "(Z)V",
            (void*) nativeSetInteractive },
    { "nativeSetAutoSuspend", "(Z)V",
            (void*) nativeSetAutoSuspend },
    { "nativeShutdown", "()V",
            (void*) nativeShutdown },
    { "nativeReboot", "(Ljava/lang/String;)V",
            (void*) nativeReboot },
};
在JNI中,framework层中的nativeShutdown()还是被JNI成nativeShutdown(),然后进入android_reboot(ANDROID_RB_POWEROFF, 0, 0)。
android_reboot()在system/core/libcutils/Android_reboot.c中定义如下:

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

    if (!(flags & ANDROID_RB_FLAG_NO_SYNC))
        sync();

    if (!(flags & ANDROID_RB_FLAG_NO_REMOUNT_RO))
        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;
}
1. 参数cmd是命令行参数,在system/core/include/cutils/Android_reboot.h中定义如下:

/* Commands */
#define ANDROID_RB_RESTART  0xDEAD0001
#define ANDROID_RB_POWEROFF 0xDEAD0002
#define ANDROID_RB_RESTART2 0xDEAD0003

/* Flags */
#define ANDROID_RB_FLAG_NO_SYNC       0x1
#define ANDROID_RB_FLAG_NO_REMOUNT_RO 0x2

int android_reboot(int cmd, int flags, char *arg);
分别代表三种不同的shutdown动作。

2. switch(cmd)如果进入ANDROID_RB_POWEROFF,则会执行reboot(RB_POWER_OFF),即shutdown的linux系统调用。reboot()定义在bionic/libc/bionic/reboot.c中。

int reboot (int  mode) 
{
    return __reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL );
}
__reboot是通往linux kernel层的入口,执行__reboot就进入了linux kernel的关机过程。

六、linux kernel的shutdown过程

如前所述,__reboot()进入kernel的关机过程。进入kernel,首先执行SYSCALL_DEFINE4(),根据switch(cmd)语句选择的情况,执行不同的关机动作。

SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
		void __user *, arg)
{
	char buffer[256];
	int ret = 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;

	/* Instead of trying to make the power_off code look like
	 * halt when pm_power_off is not set do it the easy way.
	 */
	if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
		cmd = LINUX_REBOOT_CMD_HALT;

	lock_kernel();
	switch (cmd) {
	case LINUX_REBOOT_CMD_RESTART:
		kernel_restart(NULL);
		break;

	case LINUX_REBOOT_CMD_CAD_ON:
		C_A_D = 1;
		break;

	case LINUX_REBOOT_CMD_CAD_OFF:
		C_A_D = 0;
		break;

	case LINUX_REBOOT_CMD_HALT:
		kernel_halt();
		unlock_kernel();
		do_exit(0);
		panic("cannot halt");

	case LINUX_REBOOT_CMD_POWER_OFF:
		kernel_power_off();
		unlock_kernel();
		do_exit(0);
		break;

	case LINUX_REBOOT_CMD_RESTART2:
		if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {
			unlock_kernel();
			return -EFAULT;
		}
		buffer[sizeof(buffer) - 1] = '\0';

		kernel_restart(buffer);
		break;

#ifdef CONFIG_KEXEC
	case LINUX_REBOOT_CMD_KEXEC:
		ret = kernel_kexec();
		break;
#endif

#ifdef CONFIG_HIBERNATION
	case LINUX_REBOOT_CMD_SW_SUSPEND:
		ret = hibernate();
		break;
#endif

	default:
		ret = -EINVAL;
		break;
	}
	unlock_kernel();
	return ret;
}
如果cmd为LINUX_REBOOT_CMD_POWER_OFF,则进入kernel_power_off()。因为本文主要分析kernel_power_off(),其他情况类似,就不分析了。
/**
 *	kernel_power_off - power_off the system
 *
 *	Shutdown everything and perform a clean system power_off.
 */
void kernel_power_off(void)
{
	kernel_shutdown_prepare(SYSTEM_POWER_OFF);
	if (pm_power_off_prepare)
		pm_power_off_prepare();
	disable_nonboot_cpus();
	sysdev_shutdown();
	printk(KERN_EMERG "Power down.\n");
	machine_power_off();
}
1. kernel_shutdown_prepare(),这个函数中首先会用一个链表的操作block notifier,关于链表的操作可以自己去研究。

然后更新system_state,最后执行device_shutdown()去关闭所有的devices。

static void kernel_shutdown_prepare(enum system_states state)
{
	blocking_notifier_call_chain(&reboot_notifier_list,
		(state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL);
	system_state = state;
	device_shutdown();
}
2. disable_nonboot_cpus(),这一步骤和系统suspend时调用的disable_nonboot_cpus()是一样的,即关掉nonboot的cpu。

3. sysdev_shutdown(),系统设备的shutdown。

4. machine_power_off(),这是一个平台相关的关机指针,执行最后的关机动作。在include/kernel/reboot.h中声明此函数为外部的,针对不同的平台,就会编译不同的machine_power_off()函数。

对应找到arch/arm/kernel/process.c的machine_power_off()。

void machine_power_off(void)
{
	if (pm_power_off)
		pm_power_off();
}
如果pm_power_off非空,继续执行pm_power_off()进入PMIC执行硬件的power off。

拿at91sam9260举例,在这里定义了pm_power_off的具体事例。 pm_power_off = at91sam9260_poweroff;

static void at91sam9260_poweroff(void)
{
	at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
}
这就是power off最后执行的平台相关的操作,接下来的操作就交给硬件了。

分析到这里,两篇Android关机流程分析到此结束。



你可能感兴趣的:(android,linux,kernel,power)