Android电源管理机制的实现

从电源模块的初始化函数(pm_init)开始分析:

/kernel/power/main.c

static int __init pm_init(void)
{
	int error = pm_start_workqueue();
	if (error)
		return error;
	hibernate_image_size_init();
	hibernate_reserved_size_init();
	power_kobj = kobject_create_and_add("power", NULL);//创建一个power的kobject
	if (!power_kobj)
		return -ENOMEM;
	return sysfs_create_group(power_kobj, &attr_group);//生成power的sys文件并返回
}

core_initcall(pm_init);
pm_init函数首先通过kobject_create_and_add函数动态创建一个power的kobject结构体,并将其初始化加入到kobject层次中,最终返回所创建的kobject指针。

调用sysfs_create_group在指定目录下生成sysfs文件。

static struct attribute_group attr_group = {
	.attrs = g,
};

static struct attribute * g[] = {
	&state_attr.attr,
#ifdef CONFIG_PM_TRACE
	&pm_trace_attr.attr,
	&pm_trace_dev_match_attr.attr,
#endif
#ifdef CONFIG_PM_SLEEP
	&pm_async_attr.attr,
	&wakeup_count_attr.attr,
#ifdef CONFIG_PM_DEBUG
	&pm_test_attr.attr,
#endif
#ifdef CONFIG_USER_WAKELOCK
	&wake_lock_attr.attr,
	&wake_unlock_attr.attr,
#endif
#endif
	&phone_actived_attr.attr,
	NULL,
};

至此,电源管理模块的初始化函数就已经完成,用户可以通过/sys/power/state来实现控制系统的电源状态。这里的sys文件操作使用了power_attr函数来声明。

#define power_attr(_name) \
static struct kobj_attribute _name##_attr = {	\
	.attr	= {				\
		.name = __stringify(_name),	\
		.mode = 0644,			\
	},					\
	.show	= _name##_show,			\
	.store	= _name##_store,		\
}
所以我们可以看出其文件操作包括显示(show)和写入(store)。下面来看看其具体的操作函数。

/* If set, devices may be suspended and resumed asynchronously. */
int pm_async_enabled = 1;

static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
			     char *buf)
{
	return sprintf(buf, "%d\n", pm_async_enabled);   //通过sprintf函数直接输出其内容
}

static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr,
			      const char *buf, size_t n)
{
	unsigned long val;

	if (strict_strtoul(buf, 10, &val))
		return -EINVAL;

	if (val > 1)
		return -EINVAL;

	pm_async_enabled = val;
	return n;
}

power_attr(pm_async);

我们暂且看一下strict_strtoul这个函数 ./linux-3.3/include/linux/kernel.h

#define strict_strtoul	kstrtoul

static inline int __must_check kstrtoul(const char *s, unsigned int base, unsigned long *res)
{
	/*
	 * We want to shortcut function call, but
	 * __builtin_types_compatible_p(unsigned long, unsigned long long) = 0.
	 */
	if (sizeof(unsigned long) == sizeof(unsigned long long) &&
	    __alignof__(unsigned long) == __alignof__(unsigned long long))
		return kstrtoull(s, base, (unsigned long long *)res);
	else
		return _kstrtoul(s, base, res);
}
/* Internal, do not use. */
int _kstrtoul(const char *s, unsigned int base, unsigned long *res)
{
    unsigned long long tmp;
    int rv;

    rv = kstrtoull(s, base, &tmp);
    if (rv < 0)
        return rv;
    if (tmp != (unsigned long long)(unsigned long)tmp)
        return -ERANGE;
    *res = tmp;
    return 0;
}
EXPORT_SYMBOL(_kstrtoul); 
strict_strtoul converts a string to an unsigned long only if the string is really an unsigned long string, any string containing any invalid char at the tail will be rejected and -EINVAL is returned, only a newline char at the tail is acceptible because people generally

change a module parameter in the following way:

echo 1024 > /sys/module/e1000/parameters/copybreak

echo will append a newline to the tail.

It returns 0 if conversion is successful and *res is set to the converted value, otherwise it returns -EINVAL and *res is set to 0.


现在来看电源管理状态操作的核心部分——power_attr(state)操作

struct kobject *power_kobj;

/**
 *	state - control system power state.
 *
 *	show() returns what states are supported, which is hard-coded to
 *	'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and
 *	'disk' (Suspend-to-Disk).
 *
 *	store() accepts one of those strings, translates it into the
 *	proper enumerated value, and initiates a suspend transition.
 */
static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
			  char *buf)
{
	char *s = buf;
#ifdef CONFIG_SUSPEND
	int i;

	for (i = 0; i < PM_SUSPEND_MAX; i++) {
		if (pm_states[i] && valid_state(i))
			s += sprintf(s,"%s ", pm_states[i]);
	}
#endif
#ifdef CONFIG_HIBERNATION
	s += sprintf(s, "%s\n", "disk");
#else
	if (s != buf)
		/* convert the last space to a newline */
		*(s-1) = '\n';
#endif
	return (s - buf);
}

static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
			   const char *buf, size_t n)
{
#ifdef CONFIG_SUSPEND
#ifdef CONFIG_EARLYSUSPEND
	suspend_state_t state = PM_SUSPEND_ON;
#else
	suspend_state_t state = PM_SUSPEND_STANDBY;
#endif
	const char * const *s;
#endif
	char *p;
	int len;
	int error = -EINVAL;

	p = memchr(buf, '\n', n);
	len = p ? p - buf : n;

	/* First, check if we are requested to hibernate */
	if (len == 4 && !strncmp(buf, "disk", len)) {
		error = hibernate();
		goto Exit;
	}

#ifdef CONFIG_SUSPEND
	for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
		if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
			break;
	}
	if (state < PM_SUSPEND_MAX && *s) {
#ifdef CONFIG_EARLYSUSPEND
		if (state == PM_SUSPEND_ON || valid_state(state)) {    //请求中断状态
			error = 0;
			request_suspend_state(state);                  //============Android系统从这个地方进入
		}
#else
		error = enter_state(state);
		if (error) {
			suspend_stats.fail++;
			dpm_save_failed_errno(error);
		} else
			suspend_stats.success++;
#endif
	}
#endif

 Exit:
	return error ? error : n;
}

power_attr(state);
显示函数很简单,就是根据各种宏定义来读取当前的状态字符串,并将其显示出来。对于写入函数,用户可以写入const char * const pm_state[]中定义的字符串:./linux-3.3/kernel/power/suspend.c
const char *const pm_states[PM_SUSPEND_MAX] = {
#ifdef CONFIG_EARLYSUSPEND
	[PM_SUSPEND_ON]		= "on",
#endif
	[PM_SUSPEND_STANDBY]	= "standby",
	[PM_SUSPEND_MEM]	= "mem",
	[PM_SUSPEND_BOOTFAST]	= "bootfast",
};
有"on", "standby", "mem", "bootfast"这几种状态.在Android中会调用request_suspend_state函数进入early suspend状态。刚才说到了请求中断状态,来看一下电源的中断和恢复驱动的具体实现,根据各平台的不同略有差异(driver/power/*)。

static struct platform_driver axp_battery_driver = {
  .driver = {
    .name = "axp22-supplyer",
    .owner  = THIS_MODULE,
  },
  .probe = axp_battery_probe,
  .remove = axp_battery_remove,
  .suspend = axp22_suspend,
  .resume = axp22_resume,
  .shutdown = axp22_shutdown,
};

static int axp_battery_init(void)
{
	int ret =0;
  ret = platform_driver_register(&axp_battery_driver);
  return ret;
}

static void axp_battery_exit(void)
{
  platform_driver_unregister(&axp_battery_driver);
}

subsys_initcall(axp_battery_init);
module_exit(axp_battery_exit);
接着看request_suspend_state的实现
void request_suspend_state(suspend_state_t new_state)
{
	unsigned long irqflags;
	int old_sleep;

	spin_lock_irqsave(&state_lock, irqflags);//保存本地中断状态并关闭,获取自旋锁
	old_sleep = state & SUSPEND_REQUESTED;
	if (debug_mask & DEBUG_USER_STATE) {
		struct timespec ts;
		struct rtc_time tm;
		getnstimeofday(&ts);
		rtc_time_to_tm(ts.tv_sec, &tm);
		pr_info("request_suspend_state: %s (%d->%d) at %lld "
			"(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
			new_state != PM_SUSPEND_ON ? "sleep" : "wakeup",
			requested_suspend_state, new_state,
			ktime_to_ns(ktime_get()),
			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
			tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
	}
	if (!old_sleep && new_state != PM_SUSPEND_ON) {
		state |= SUSPEND_REQUESTED;
 
        #ifdef CONFIG_EARLYSUSPEND_DELAY
        /* delay 5 seconds to enter suspend */
        wake_unlock(&ealysuspend_delay_work);
        wake_lock_timeout(&ealysuspend_delay_work, HZ * 5);
        #endif

		queue_work(suspend_work_queue, &early_suspend_work);//请求中断,则将early_suspend_work加入到队列排队,
                                                                    //调用early_suspend_work完成一级休眠工作
	} else if (old_sleep && new_state == PM_SUSPEND_ON) {       //中断之后的恢复
		state &= ~SUSPEND_REQUESTED;
		wake_lock(&main_wake_lock);
		queue_work(suspend_work_queue, &late_resume_work);  //late_resume_work加入到队列
	}
	requested_suspend_state = new_state;
	spin_unlock_irqrestore(&state_lock, irqflags);//完成释放锁、恢复本地中断到之前的状态
}

static DECLARE_WORK(early_suspend_work, early_suspend);
static DECLARE_WORK(late_resume_work, late_resume);
从上面可知early_suspend_work、late_resume_work的定义分别指向了early_suspend、late_resume。因此,最终处理中断和恢复的工作将在early_suspend和late_resume中进行。

void register_early_suspend(struct early_suspend *handler)
{
	struct list_head *pos;

	mutex_lock(&early_suspend_lock);
	list_for_each(pos, &early_suspend_handlers) {
		struct early_suspend *e;
		e = list_entry(pos, struct early_suspend, link);
		if (e->level > handler->level)
			break;
	}
	list_add_tail(&handler->link, pos);
	if ((state & SUSPENDED) && handler->suspend)
		handler->suspend(handler);
	mutex_unlock(&early_suspend_lock);
}
EXPORT_SYMBOL(register_early_suspend);

void unregister_early_suspend(struct early_suspend *handler)
{
    mutex_lock(&early_suspend_lock);
    list_del(&handler->link);
    mutex_unlock(&early_suspend_lock);
}
EXPORT_SYMBOL(unregister_early_suspend);

在注册函数中将支持中断设备的early_suspend的handler添加到early_suspend_handlers链表。然后在注销函数中将early_suspend_handlers链表清除即可。

=====early_suspend=====完成一级休眠工作

static void early_suspend(struct work_struct *work)
{
	struct early_suspend *pos;
	unsigned long irqflags;
	int abort = 0;
	ktime_t calltime;
	u64 usecs64;
	int usecs;
	ktime_t starttime;

	mutex_lock(&early_suspend_lock);
	spin_lock_irqsave(&state_lock, irqflags);
	if (state == SUSPEND_REQUESTED)//检查请求状态是否是suspend 
		state |= SUSPENDED;
	else
		abort = 1;
	spin_unlock_irqrestore(&state_lock, irqflags);

	if (abort) {
		if (debug_mask & DEBUG_SUSPEND)
			pr_info("early_suspend: abort, state %d\n", state);
		mutex_unlock(&early_suspend_lock);
		goto abort;
	}

	if (debug_mask & DEBUG_SUSPEND)
		pr_info("early_suspend: call handlers\n");
	list_for_each_entry(pos, &early_suspend_handlers, link) {//遍历链表依次调用每个驱动的handler
		if (pos->suspend != NULL) {
			if (debug_mask & DEBUG_VERBOSE){
				pr_info("early_suspend: calling %pf\n", pos->suspend);
				starttime = ktime_get();
				
			}
			
			pos->suspend(pos);//中断,调用二级休眠入口函数suspend

			if (debug_mask & DEBUG_VERBOSE){
				calltime = ktime_get();
				usecs64 = ktime_to_ns(ktime_sub(calltime, starttime));
				do_div(usecs64, NSEC_PER_USEC);
				usecs = usecs64;
				if (usecs == 0)
					usecs = 1;
				pr_info("early_suspend: %pf complete after %ld.%03ld msecs\n",
					pos->suspend, usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC);
			}
		}
	}
	standby_level = STANDBY_WITH_POWER;
	mutex_unlock(&early_suspend_lock);

	if (debug_mask & DEBUG_SUSPEND)
		pr_info("early_suspend: sync\n");

       queue_work(sync_work_queue, &sync_system_work);//同步文件系统sync_system
abort:
	spin_lock_irqsave(&state_lock, irqflags);
	if (state == SUSPEND_REQUESTED_AND_SUSPENDED)
		wake_unlock(&main_wake_lock);//释放main_wake_lock,这是个没有超时的锁,若不释放系统无法进入休眠
	spin_unlock_irqrestore(&state_lock, irqflags);
}

suspend调用pm_suspend,再调用enter_state(这里才是真正的二级待机入口)

唤醒恢复

唤醒通常有以下几种原因:

1):来电。如果是来电,那么Modem会通过RILD守护进程主动上报给Android系统,并通知WindowManager有来电响应,这样就会远程调用PowerManagerService将"on"写入到//sys/power/state中,从而启用late resume的设。

2):用户按键。用户按键事件会发送到WindowManager中,WindowManager会处理这些按键事件。按键分为几种情况,如果按键不是唤醒键,那么WindowManager会主动放弃WakeLock来使用系统进入再次休眠状态;如果是唤醒键,那么WindowManager就会调用PowerManagerService中的接口来执行Late Resume.

static void late_resume(struct work_struct *work)
{
	struct early_suspend *pos;
	unsigned long irqflags;
	int abort = 0;
	ktime_t calltime;
	u64 usecs64;
	int usecs;
	ktime_t starttime;
	
	mutex_lock(&early_suspend_lock);
	spin_lock_irqsave(&state_lock, irqflags);
	if (state == SUSPENDED)
		state &= ~SUSPENDED;
	else
		abort = 1;
	spin_unlock_irqrestore(&state_lock, irqflags);

	if (abort) {
		if (debug_mask & DEBUG_SUSPEND)
			pr_info("late_resume: abort, state %d\n", state);
		goto abort;
	}
	if (debug_mask & DEBUG_SUSPEND)
		pr_info("late_resume: call handlers\n");
	list_for_each_entry_reverse(pos, &early_suspend_handlers, link) {//遍历链表
		if (pos->resume != NULL) {
			if (debug_mask & DEBUG_VERBOSE){
				pr_info("late_resume: calling %pf\n", pos->resume);
				starttime = ktime_get();
			}

			pos->resume(pos);//恢复

			if (debug_mask & DEBUG_VERBOSE){
				calltime = ktime_get();
				usecs64 = ktime_to_ns(ktime_sub(calltime, starttime));
				do_div(usecs64, NSEC_PER_USEC);
				usecs = usecs64;
				if (usecs == 0)
					usecs = 1;
				pr_info("late_resume: %pf complete after %ld.%03ld msecs\n",
					pos->resume, usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC);
			}
	
		}
	}
	if (debug_mask & DEBUG_SUSPEND)
		pr_info("late_resume: done\n");

	standby_level = STANDBY_INITIAL;
abort:
	mutex_unlock(&early_suspend_lock);
}

下面来分析从非中断状态直接进入enter_state函数所执行的操作,该函数的定义如下:

/**
 *	enter_state - Do common work of entering low-power state.
 *	@state:		pm_state structure for state we're entering.
 *
 *	Make sure we're the only ones trying to enter a sleep state. Fail
 *	if someone has beat us to it, since we don't want anything weird to
 *	happen when we wake up.
 *	Then, do the setup for suspend, enter the state, and cleaup (after
 *	we've woken up).
 */
int enter_state(suspend_state_t state)
{
	int error;

	if (!valid_state(state))         //检测状态是否有效
		return -ENODEV;

	if (!mutex_trylock(&pm_mutex))   //加锁
		return -EBUSY;

	printk(KERN_INFO "PM: Syncing filesystems ... ");
	sys_sync();                      //同步更新文件系统
	printk("done.\n");

	pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
	error = suspend_prepare();       //中断准备
	if (error)
		goto Unlock;

	if (suspend_test(TEST_FREEZER))  //中断检测
		goto Finish;

	pr_debug("PM: Entering %s sleep\n", pm_states[state]);
	pm_restrict_gfp_mask();
	error = suspend_devices_and_enter(state); //中断外部设备
	pm_restore_gfp_mask();

 Finish:
	pr_debug("PM: Finishing wakeup.\n");
	suspend_finish();                         //中断完成
 Unlock:
	mutex_unlock(&pm_mutex);
	return error;
}
用户对/sys/power/state执行读和写操作时会调用main.c中的state_store()函数,用户可以写入const char * const pm_state[]中定义的字符串。state_store会调用enter_state(),它首先会检查一些状态参数,然后同步文件系统。首先使用valid_state()函数检测状态是否有效,然后通过suspend_prepare函数来准备中断,接着使用suspend_test函数来检测中断是否可行,最后会在suspend_devices_and_enter()函数中执行关于外部设备的中断操作。下面来分析准备中断的过程执行了哪些操作:

/**
 *	suspend_prepare - Do prep work before entering low-power state.
 *
 *	This is common code that is called for each state that we're entering.
 *	Run suspend notifiers, allocate a console and stop all processes.
 */
static int suspend_prepare(void)
{
	int error;

	if (!suspend_ops || !suspend_ops->enter)
		return -EPERM;

	pm_prepare_console();//分配一个虚拟终端来输出信息

	error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);//运行暂停、中断通知器
	if (error)
		goto Finish;

	error = usermodehelper_disable();//关闭用户态的helper进程
	if (error)
		goto Finish;

	error = suspend_freeze_processes();//进程冻结,并保存所有进程的当前状态
	if (!error)
		return 0;

	suspend_stats.failed_freeze++;     //冻结进程失败
	dpm_save_failed_step(SUSPEND_FREEZE);
	usermodehelper_enable();
 Finish:
	pm_notifier_call_chain(PM_POST_SUSPEND);//发送中断请求
	pm_restore_console();//重置控制台
	return error;
}
设备中断

/**
 *	suspend_devices_and_enter - suspend devices and enter the desired system
 *				    sleep state.
 *	@state:		  state to enter
 */
int suspend_devices_and_enter(suspend_state_t state)
{
	int error;
	bool wakeup = false;

	if (!suspend_ops)
		return -ENOSYS;

	trace_machine_suspend(state);
	if (suspend_ops->begin) {//开始
		error = suspend_ops->begin(state);
		if (error)
			goto Close;
	}
	suspend_console();         //控制台子系统进入休眠
	suspend_test_start();      //中断测试开始
	error = dpm_suspend_start(PMSG_SUSPEND);//Device suspend
	if (error) {
		printk(KERN_ERR "PM: Some devices failed to suspend\n");
		goto Recover_platform;
	}
	suspend_test_finish("suspend devices");//中断测试结束
	if (suspend_test(TEST_DEVICES))//测试要中断的设备
		goto Recover_platform;

	do {
		error = suspend_enter(state, &wakeup);//中断处理
	} while (!error && !wakeup
		&& suspend_ops->suspend_again && suspend_ops->suspend_again());

 Resume_devices:
	suspend_test_start();
	dpm_resume_end(PMSG_RESUME);
	suspend_test_finish("resume devices");
	resume_console();
 Close:
	if (suspend_ops->end)
		suspend_ops->end();
	trace_machine_suspend(PWR_EVENT_EXIT);
	return error;

 Recover_platform:
	if (suspend_ops->recover)
		suspend_ops->recover();
	goto Resume_devices;
}

/**
 * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices.
 * @state: PM transition of the system being carried out.
 */
int dpm_suspend(pm_message_t state)//遍历链表调用设备的prepare函数
{
    ktime_t starttime = ktime_get();
    int error = 0;

    might_sleep();

    mutex_lock(&dpm_list_mtx);
    pm_transition = state;
    async_error = 0;
    while (!list_empty(&dpm_prepared_list)) {
        struct device *dev = to_device(dpm_prepared_list.prev);

        get_device(dev);
        mutex_unlock(&dpm_list_mtx);

        error = device_suspend(dev);

        mutex_lock(&dpm_list_mtx);
        if (error) {
            pm_dev_err(dev, state, "", error);
            dpm_save_failed_dev(dev_name(dev));
            put_device(dev);
            break;
        }
        if (!list_empty(&dev->power.entry))
            list_move(&dev->power.entry, &dpm_suspended_list);
        put_device(dev);
        if (async_error)
            break;
    }
    mutex_unlock(&dpm_list_mtx);
    async_synchronize_full();
    if (!error)
        error = async_error;
    if (error) {
        suspend_stats.failed_suspend++;
        dpm_save_failed_step(SUSPEND_SUSPEND);
    } else
        dpm_show_time(starttime, state, NULL);
    return error;
}

/**
 * dpm_prepare - Prepare all non-sysdev devices for a system PM transition.
 * @state: PM transition of the system being carried out.
 *
 * Execute the ->prepare() callback(s) for all devices.
 */
int dpm_prepare(pm_message_t state)//遍历链表调用设备的prepare函数
{
	int error = 0;

	might_sleep();

	mutex_lock(&dpm_list_mtx);
	while (!list_empty(&dpm_list)) {
		struct device *dev = to_device(dpm_list.next);

		get_device(dev);
		mutex_unlock(&dpm_list_mtx);

		error = device_prepare(dev, state);

		mutex_lock(&dpm_list_mtx);
		if (error) {
			if (error == -EAGAIN) {
				put_device(dev);
				error = 0;
				continue;
			}
			printk(KERN_INFO "PM: Device %s not prepared "
				"for power transition: code %d\n",
				dev_name(dev), error);
			put_device(dev);
			break;
		}
		dev->power.is_prepared = true;
		if (!list_empty(&dev->power.entry))
			list_move_tail(&dev->power.entry, &dpm_prepared_list);
		put_device(dev);
	}
	mutex_unlock(&dpm_list_mtx);
	return error;
}

/**
 * dpm_suspend_start - Prepare devices for PM transition and suspend them.
 * @state: PM transition of the system being carried out.
 *
 * Prepare all non-sysdev devices for system PM transition and execute "suspend"
 * callbacks for them.
 */
int dpm_suspend_start(pm_message_t state)
{
	int error;

	error = dpm_prepare(state);
	if (error) {
		suspend_stats.failed_prepare++;
		dpm_save_failed_step(SUSPEND_PREPARE);
	} else
		error = dpm_suspend(state);
	return error;
}
EXPORT_SYMBOL_GPL(dpm_suspend_start);





你可能感兴趣的:(Android电源管理机制的实现)