Platform: RK3368

OS: Android 6.0

Kernel: 3.10.0



文章目录

  • 禁止Android系统进入休眠
  • 1. 系统配置
  • 2. PowerManagerService
  • 3. 禁止Android系统进入休眠
  • 4. 代码跟踪分析:
  • 4.1 自动挂起状态
  • 4.2 交互状态


禁止Android系统进入休眠

1. 系统配置

想要禁止Android系统进入休眠,首先来了解一下Android系统提供的几个电源管理相关的配置,因为PowerManagerService会用到这些配置:
frameworks/base/core/res/res/values/config.xml

<bool name="config_powerDecoupleAutoSuspendModeFromDisplay">false</bool>
    <bool name="config_powerDecoupleInteractiveModeFromDisplay">false</bool>

将配置的注释翻译一下大概意思:
config_powerDecoupleAutoSuspendModeFromDisplay
电源管理:指定是否将设备的自动挂起状态与显示器开/关状态分离。
如果为false,将在显示器打开之前调用autosuspend_disable ( )
并且在显示器关闭后将调用autosuspend_enable ( )。此模式为使用传统电源管理的设备提供最佳兼容性像
early suspend / late resume等功能。

如果为true,无论显示器是打开还是关闭,都会调用autosuspend _ display ( )和autosuspend _ enable ( )。此模式使电源管理器能够在显示器打开时暂停应用处理器。

该资源应设置为“true”,当指定了doz组件以最大限度地节省电能,但并非所有设备都支持时。

config_powerDecoupleInteractiveModeFromDisplay
电源管理:指定是否将设备的交互状态与显示器的开/关状态分离。
如果为false,将在显示器打开前调用setInteractive(…, true),并在显示器关闭后调用setInteractive(…, false)。
该模式为期望交互状态与显示状态相关联的设备提供最佳兼容性。

如果为true,不管显示器是打开还是关闭,将会独立调用setInteractive(…)。此模式使电源管理能够在显示器打开时减少时钟并禁用触控。

当指定了doz组件以最大限度地节省电能,但并非所有设备都支持时,该资源应设置为“真”。


2. PowerManagerService

代码位于frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java.
代码里面可以看到PowerManagerService对系统的电源管理配置读取:

mDecoupleHalAutoSuspendModeFromDisplayConfig = resources.getBoolean(
                com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay);
        mDecoupleHalInteractiveModeFromDisplayConfig = resources.getBoolean(
                com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay);

在PowerManagerService一开始就初始化了两个wakelock,分别是mWakeLockSuspendBlocker和mDisplaySuspendBlocker,用于控制显示器开关的锁和控制系统挂起;

public PowerManagerService(Context context) {
......
        synchronized (mLock) {
            mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
            mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");

通过查看/sys/power/wake_lock文件,可以看到这两个锁:

# cat /sys/power/wake_lock
PowerManagerService.Display PowerManagerService.WakeLocks

当Activity用户无操作活动超时,按下电源键,显示屏状态变化,电池状态变化,应用获得wakelock或者释放wakelock等等都会去更新PowerStateLocked从而影响挂起状态和交互状态。关于wakelock这里就不做过多的介绍了,将重点关注系统挂起相关的代码.

3. 禁止Android系统进入休眠

如果想实现关闭屏幕后系统不进入休眠,可以强制关闭自动挂起,加两个SystemProperties方便控制。

因为当前系统配置config_powerDecoupleAutoSuspendModeFromDisplay为false,所以当显示器状态变化时代码会通过onDisplayStateChange来设置自动挂起状态及交互状态,不会通过updateSuspendBlockerLocked来设置:

@Override
        public void onDisplayStateChange(int state) {
            // This method is only needed to support legacy display blanking behavior
            // where the display's power state is coupled to suspend or to the power HAL.
            // The order of operations matters here.
            synchronized (mLock) {
                if (mDisplayState != state) {
                    mDisplayState = state;
                    if (state == Display.STATE_OFF) {
                        if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+                            if (SystemProperties.getBoolean("ro.pms.interactive_mode", false)){
+                                Slog.d(TAG, "enable interactive mode");
+                                setHalInteractiveModeLocked(true);
+                            } else {
                            setHalInteractiveModeLocked(false);
+                            }
                        }
                        if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+                            if (!SystemProperties.getBoolean("ro.pms.auto_suspend", true)){
+                                Slog.d(TAG, "disable auto suspend");
+                                setHalAutoSuspendModeLocked(false);
+                            } else {
                            setHalAutoSuspendModeLocked(true);
+                            }
                        }

4. 代码跟踪分析:

在onDisplayStateChange里面有两个很重要的函数,分别是setHalAutoSuspendModeLocked和setHalInteractiveModeLocked。对应的就是挂起状态和交互状态的设置,关系到系统是否挂起和cpu是否关闭(kill CPU),特别是多核心的soc。

private void setHalAutoSuspendModeLocked(boolean enable) {
        if (enable != mHalAutoSuspendModeEnabled) {
            if (DEBUG) {
                Slog.d(TAG, "Setting HAL auto-suspend mode to " + enable);
            }
            mHalAutoSuspendModeEnabled = enable;
            Trace.traceBegin(Trace.TRACE_TAG_POWER, "setHalAutoSuspend(" + enable + ")");
            try {
                nativeSetAutoSuspend(enable);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_POWER);
            }
        }
    }

    private void setHalInteractiveModeLocked(boolean enable) {
        if (enable != mHalInteractiveModeEnabled) {
            if (DEBUG) {
                Slog.d(TAG, "Setting HAL interactive mode to " + enable);
            }
            mHalInteractiveModeEnabled = enable;
            Trace.traceBegin(Trace.TRACE_TAG_POWER, "setHalInteractive(" + enable + ")");
            try {
                nativeSetInteractive(enable);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_POWER);
            }
        }
    }

可以看到代码最后调用了JNI中的nativeSetAutoSuspend和nativeSetInteractive函数,来看看JNI代码实现:
frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp

static void nativeSetInteractive(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
    if (gPowerModule) {
        if (enable) {
            ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(true) while turning screen on");
            gPowerModule->setInteractive(gPowerModule, true);
        } else {
            ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(false) while turning screen off");
            gPowerModule->setInteractive(gPowerModule, false);
        }
    }
}

static void nativeSetAutoSuspend(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
    if (enable) {
        ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_enable() while turning screen off");
        autosuspend_enable();
    } else {
        ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_disable() while turning screen on");
        autosuspend_disable();
    }
}

nativeSetInteractive是通过调用power HAL来实现交互状态设置的。而nativeSetAutoSuspend是放在system core中实现的。所以需要将交互状态和自动挂起分开来分析了。

4.1 自动挂起状态

autosuspend_enable,autosuspend_disabled定义在system/core/libsuspend/autosuspend.c

int autosuspend_enable(void)
{
    int ret;

    ret = autosuspend_init();
    if (ret) {
        return ret;
    }

    ALOGV("autosuspend_enable\n");

    if (autosuspend_enabled) {
        return 0;
    }

    ret = autosuspend_ops->enable();
    if (ret) {
        return ret;
    }

    autosuspend_enabled = true;
    return 0;
}

autosuspend_ops的实现实际上是通过写入"mem"或"on"到sysfs文件/sys/power/state文件中,让内核开始处理自动挂起的流程,网上有很多关于linux系统休眠相关的文章这里就不继续跟代码了。
system/core/libsuspend/autosuspend_earlysuspend.c

#define EARLYSUSPEND_SYS_POWER_STATE "/sys/power/state"
static const char *pwr_state_mem = "mem";
static const char *pwr_state_on = "on";

struct autosuspend_ops autosuspend_earlysuspend_ops = {
        .enable = autosuspend_earlysuspend_enable,
        .disable = autosuspend_earlysuspend_disable,
};

static int autosuspend_earlysuspend_enable(void)
{
    char buf[80];
    int ret;

    ALOGV("autosuspend_earlysuspend_enable\n");

    ret = write(sPowerStatefd, pwr_state_mem, strlen(pwr_state_mem));
    if (ret < 0) {
        strerror_r(errno, buf, sizeof(buf));
        ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
        goto err;
    }

    if (wait_for_earlysuspend) {
        pthread_mutex_lock(&earlysuspend_mutex);
        while (earlysuspend_state != EARLYSUSPEND_MEM) {
            pthread_cond_wait(&earlysuspend_cond, &earlysuspend_mutex);
        }
        pthread_mutex_unlock(&earlysuspend_mutex);
    }

    ALOGV("autosuspend_earlysuspend_enable done\n");

    return 0;

err:
    return ret;
}

4.2 交互状态

在power HAL的实现中,一般是操作sysfs中的/sys/devices/system/cpu/cpuX/online文件来交互的。来看一下rk3368的power HAL。

hardware/rockchip/power/power.c
	static void rk_power_set_interactive(struct power_module *module, int on)
	{
......
		sysfs_write("/sys/devices/system/cpu/cpu2/online", on ? "1" : "0");
		sysfs_write("/sys/devices/system/cpu/cpu3/online", on ? "1" : "0");
		sysfs_write("/sys/devices/system/cpu/cpu4/online", on ? "1" : "0");
		sysfs_write("/sys/devices/system/cpu/cpu5/online", on ? "1" : "0");
		sysfs_write("/sys/devices/system/cpu/cpu6/online", on ? "1" : "0");
		sysfs_write("/sys/devices/system/cpu/cpu7/online", on ? "1" : "0");
	}

struct power_module HAL_MODULE_INFO_SYM = {
    common: {
        tag: HARDWARE_MODULE_TAG,
        module_api_version: POWER_MODULE_API_VERSION_0_2,
        hal_api_version: HARDWARE_HAL_API_VERSION,
        id: POWER_HARDWARE_MODULE_ID,
        name: TARGET_BOARD_PLATFORM " Power HAL",
        author: "Rockchip",
        methods: &power_module_methods,
    },

    init: rk_power_init,
    setInteractive: rk_power_set_interactive,
    powerHint: rk_power_hint,
};

用户空间写“0”,“1”到/sys/devices/system/cpu/cpuX/online文件,内核就会做解析处理,看一下linux内核中的实现:

./drivers/base/cpu.c
	static ssize_t __ref store_online(struct device *dev,
					  struct device_attribute *attr,
					  const char *buf, size_t count)
	{
		struct cpu *cpu = container_of(dev, struct cpu, dev);
		int cpuid = cpu->dev.id;
		int from_nid, to_nid;
		ssize_t ret;
		pr_info("%s %s\n", __func__, buf);

		cpu_hotplug_driver_lock();
		switch (buf[0]) {
		case '0':
			ret = cpu_down(cpuid);
			if (!ret)
				kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
			break;
		case '1':
			from_nid = cpu_to_node(cpuid);
			ret = cpu_up(cpuid);
......
		return ret;
	}
	static DEVICE_ATTR(online, 0644, show_online, store_online);

可以看到用户空间写入’0’的时,会调用cpu_down去关闭CPU。cpu_down实现在kernel/cpu.c

int __ref cpu_down(unsigned int cpu)
	{
		int err;

		cpu_maps_update_begin();

		if (cpu_hotplug_disabled) {
			err = -EBUSY;
			goto out;
		}

		err = _cpu_down(cpu, 0);

	out:
		cpu_maps_update_done();
		return err;
	}

	static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
	{
	......
		__cpu_die(cpu);

		/* CPU is completely dead: tell everyone.  Too late to complain. */
		cpu_notify_nofail(CPU_DEAD | mod, hcpu);

		check_for_tasks(cpu);

	out_release:
		cpu_hotplug_done();
		if (!err)
			cpu_notify_nofail(CPU_POST_DEAD | mod, hcpu);
		return err;
	}

因为soc是ARM 64位处理器,所以会调用./arch/arm64/kernel/smp.c中的void __cpu_die(unsigned int cpu)

./arch/arm64/kernel/smp.c
	void __cpu_die(unsigned int cpu)
	{
		pr_info("%s %d\n", __func__, cpu);

		if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) {
			pr_crit("CPU%u: cpu didn't die\n", cpu);
			return;
		}
	#ifdef CONFIG_CPUQUIET_FRAMEWORK
		if (system_state != SYSTEM_RUNNING)
	#endif
		pr_notice("CPU%u: shutdown\n", cpu);

		/*
		 * Now that the dying CPU is beyond the point of no return w.r.t.
		 * in-kernel synchronisation, try to get the firwmare to help us to
		 * verify that it has really left the kernel before we consider
		 * clobbering anything it might still be using.
		 */
		if (!op_cpu_kill(cpu))
			pr_warn("CPU%d may not have shut down cleanly\n", cpu);
	}

	static int op_cpu_kill(unsigned int cpu)
	{
		pr_info("%s %d\n", __func__, cpu);

		/*
		 * If we have no means of synchronising with the dying CPU, then assume
		 * that it is really dead. We can only wait for an arbitrary length of
		 * time and hope that it's dead, so let's skip the wait and just hope.
		 */
		if (!cpu_ops[cpu]->cpu_kill)
			return 1;

		return cpu_ops[cpu]->cpu_kill(cpu);
	}

cpu_ops是在内核启动时就初始化好的,代码在./arch/arm64/kernel/cpu_ops.c,rk3368的dts文件中定义了cpus里面cpu的enable-method = "psci"所以会用./arch/arm64/kernel/psci.c中的具体cpu_ops实现.

const struct cpu_operations cpu_psci_ops = {
		.name		= "psci",
	#ifdef CONFIG_CPU_IDLE
		.cpu_init_idle	= cpu_psci_cpu_init_idle,
	#endif
	#ifdef CONFIG_SMP
		.cpu_init	= cpu_psci_cpu_init,
		.cpu_prepare	= cpu_psci_cpu_prepare,
		.cpu_boot	= cpu_psci_cpu_boot,
	#ifdef CONFIG_HOTPLUG_CPU
		.cpu_disable	= cpu_psci_cpu_disable,
		.cpu_die	= cpu_psci_cpu_die,
		.cpu_kill	= cpu_psci_cpu_kill,
	#endif
	#endif
	#ifdef CONFIG_ARM64_CPU_SUSPEND
		.cpu_suspend	= cpu_psci_cpu_suspend,
	#endif
	};

好啦!接下来就是cpu_kill了,会将cpu关闭。