Android休眠流程(kernel层)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mike8825/article/details/80420213

        在按下电源键后,会调用autosuspend_enable()函数,可参考https://blog.csdn.net/mike8825/article/details/80423842

system/core/libsuspend/autosuspend.c

int autosuspend_enable(void)
{
    autosuspend_init();
    autosuspend_ops->enable();   
}

int autosuspend_disable(void)
{
    autosuspend_init();
    autosuspend_ops->disable();
}

static int autosuspend_init(void)
{   
    autosuspend_ops = autosuspend_wakeup_count_init();
}

system/core/libsuspend/autosuspend_wakeup_count.c

#define SYS_POWER_WAKEUP_COUNT "/sys/power/wakeup_count"
struct autosuspend_ops *autosuspend_wakeup_count_init(void)
{
	wakeup_count_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_WAKEUP_COUNT, O_RDWR));
	pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL);
}

//没有锁,写mem>/sys/power/state
static void *suspend_thread_func(void *arg __attribute__((unused)))
{
    while (1) {
        usleep(100000);
        wakeup_count_len = read(wakeup_count_fd, wakeup_count,sizeof(wakeup_count));
        sem_wait(&suspend_lockout);

        ret=write(wakeup_count_fd, wakeup_count, wakeup_count_len));
        if (ret < 0) 
        {
        }
        else
        {
            write(state_fd, sleep_state, strlen(sleep_state)); 
        }
    }
}

static int autosuspend_wakeup_count_enable(void)
{
    sem_post(&suspend_lockout);
}

static int autosuspend_wakeup_count_disable(void)
{
    sem_wait(&suspend_lockout);
}

kernel/kernel/power/main.c

static ssize_t wakeup_count_show(struct kobject *kobj,struct kobj_attribute *attr,char *buf)
{
    unsigned int val;
    return pm_get_wakeup_count(&val, true) ?
		sprintf(buf, "%u\n", val) : -EINTR;
}

static ssize_t wakeup_count_store(struct kobject *kobj,struct kobj_attribute *attr,const char *buf, size_t n)
{
	unsigned int val;
	error = -EINVAL;
	if (sscanf(buf, "%u", &val) == 1) {
		if (pm_save_wakeup_count(val))
			error = n;
	}

 out:
	return error;
}
power_attr(wakeup_count);

bool pm_get_wakeup_count(unsigned int *count, bool block)
{
	unsigned int cnt, inpr;
	if (block) {
		DEFINE_WAIT(wait);

		for (;;) {
			prepare_to_wait(&wakeup_count_wait_queue, &wait,
					TASK_INTERRUPTIBLE);
			split_counters(&cnt, &inpr);
			if (inpr == 0 || signal_pending(current))
				break;

			schedule();
		}
		finish_wait(&wakeup_count_wait_queue, &wait);
	}

	split_counters(&cnt, &inpr);
	*count = cnt;
	return !inpr;
}

/**
 * pm_save_wakeup_count - Save the current number of registered wakeup events.
 * @count: Value to compare with the current number of registered wakeup events.
 *
 * If @count is equal to the current number of registered wakeup events and the
 * current number of wakeup events being processed is zero, store @count as the
 * old number of registered wakeup events for pm_check_wakeup_events(), enable
 * wakeup events detection and return 'true'.  Otherwise disable wakeup events
 * detection and return 'false'.
 */
bool pm_save_wakeup_count(unsigned int count)
{
	unsigned int cnt, inpr;
	unsigned long flags;

	events_check_enabled = false;
	spin_lock_irqsave(&events_lock, flags);
	split_counters(&cnt, &inpr);
	if (cnt == count && inpr == 0) {
		saved_count = count;
		events_check_enabled = true;
	}
	spin_unlock_irqrestore(&events_lock, flags);
	return events_check_enabled;
}

上面的作用是对/sys/power/wakeup_count进行读写(涉及到变量combined_event_count,

可参考https://blog.csdn.net/mike8825/article/details/80422993),如果所有的锁都已解锁,

则写"mem"到/sys/power/state进行休眠


kernel/kernel/power/main.c

static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n)
{
    state = decode_state(buf, n);//将"mem"转换成对应的数字
    error = pm_suspend(state);
}
int pm_suspend(suspend_state_t state)
{
	pm_suspend_marker("entry");
	error = enter_state(state);
	pm_suspend_marker("exit");
}


static int enter_state(suspend_state_t state)
{
	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(state);

	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();
}

static int suspend_prepare(suspend_state_t state)
{
	if (need_suspend_ops(state) && (!suspend_ops || !suspend_ops->enter))   //kernel/drivers/cpuidle/lpm-levels.c	suspend_set_ops(&lpm_suspend_ops);
		return -EPERM;  
	pm_prepare_console();
	error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
	error = suspend_freeze_processes();
	pm_notifier_call_chain(PM_POST_SUSPEND);
	pm_restore_console();
	return error;
}

static inline int suspend_freeze_processes(void)
{
	error = freeze_processes();
	error = freeze_kernel_threads();
}


int suspend_devices_and_enter(suspend_state_t state)
{
	int error;
	bool wakeup = false;

	if (need_suspend_ops(state) && !suspend_ops)
		return -ENOSYS;

	if (need_suspend_ops(state) && suspend_ops->begin) {
		error = suspend_ops->begin(state);
		if (error)
			goto Close;
	}
	suspend_console();
	error = dpm_suspend_start(PMSG_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 && need_suspend_ops(state)
		&& suspend_ops->suspend_again && suspend_ops->suspend_again());

 Resume_devices:
	dpm_resume_end(PMSG_RESUME);
	resume_console();
 Close:
	if (need_suspend_ops(state) && suspend_ops->end)
		suspend_ops->end();
	return error;

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

static int suspend_enter(suspend_state_t state, bool *wakeup)
{
	error = dpm_suspend_end(PMSG_SUSPEND);
	error = disable_nonboot_cpus();
	arch_suspend_disable_irqs();
	error = syscore_suspend();
	if (!error) {
		*wakeup = pm_wakeup_pending();
		if (!(suspend_test(TEST_CORE) || *wakeup)) {
			error = suspend_ops->enter(state);//停在这..........
			events_check_enabled = false;
		}
		syscore_resume();
	}
	arch_suspend_enable_irqs();
 Enable_cpus:
	enable_nonboot_cpus();

 Platform_wake:
	if (need_suspend_ops(state) && suspend_ops->wake)
		suspend_ops->wake();

	dpm_resume_start(PMSG_RESUME);

 Platform_finish:
	if (need_suspend_ops(state) && suspend_ops->finish)
		suspend_ops->finish();

	return error;
}

dpm(Device power management),有几个dpm开头的函数,其作用是运行设备的电源管理函数

int dpm_suspend_start(pm_message_t state)
{
	dpm_prepare(state);	//prepare  dpm_list
	dpm_suspend(state);	//suspend  dpm_prepared_list
}

int dpm_suspend_end(pm_message_t state)
{
	dpm_suspend_late(state);   //suspend_late      dpm_suspended_list
	dpm_suspend_noirq(state);  //suspend_noirq    dpm_late_early_list
}

void dpm_resume_start(pm_message_t state)  
{
	dpm_resume_noirq(state);  //resume_noirq
	dpm_resume_early(state);  //resume_early
}

void dpm_resume_end(pm_message_t state)
{
	dpm_resume(state);  //resume
	dpm_complete(state);//complete
}

休眠prepare--->suspend--->suspend_late--->suspend_noirq

唤醒resume_noirq--->resume_early--->resume--->complete

struct dev_pm_ops {
	int (*prepare)(struct device *dev);
	void (*complete)(struct device *dev);
	int (*suspend)(struct device *dev);
	int (*resume)(struct device *dev);
	int (*freeze)(struct device *dev);
	int (*thaw)(struct device *dev);
	int (*poweroff)(struct device *dev);
	int (*restore)(struct device *dev);
	int (*suspend_late)(struct device *dev);
	int (*resume_early)(struct device *dev);
	int (*freeze_late)(struct device *dev);
	int (*thaw_early)(struct device *dev);
	int (*poweroff_late)(struct device *dev);
	int (*restore_early)(struct device *dev);
	int (*suspend_noirq)(struct device *dev);
	int (*resume_noirq)(struct device *dev);
	int (*freeze_noirq)(struct device *dev);
	int (*thaw_noirq)(struct device *dev);
	int (*poweroff_noirq)(struct device *dev);
	int (*restore_noirq)(struct device *dev);
	int (*runtime_suspend)(struct device *dev);
	int (*runtime_resume)(struct device *dev);
	int (*runtime_idle)(struct device *dev);
};

static const struct dev_pm_ops goodix_ts_dev_pm_ops = {
	.suspend = goodix_ts_suspend,
	.resume = goodix_ts_resume,
};

类dpm函数的作用是按顺序执行相关的电源函数


上面有个suspend_ops的指针(cpu休眠时的动作),其定义在

kernel/drivers/cpuidle/lpm-levels.c

static int lpm_probe(struct platform_device *pdev)
{
	suspend_set_ops(&lpm_suspend_ops);
}

static const struct platform_suspend_ops lpm_suspend_ops = {
	.enter = lpm_suspend_enter,
	.valid = suspend_valid_only_mem,
	.prepare_late = lpm_suspend_prepare,
	.wake = lpm_suspend_wake,
};

kernel/kernel/power/suspend.c

void suspend_set_ops(const struct platform_suspend_ops *ops)
{
	suspend_ops = ops;	
}

参考的内核打印如下

    52.402471:   <6> PM: suspend entry 1970-01-01 00:13:08.409503329 UTC
    52.402486:   <2> PM: Syncing filesystems ... done.
    52.410354:   <6> Error: returning -512 value
    52.409207:   <2> Freezing user space processes ... (elapsed 0.005 seconds) done.
    52.415161:   <2> Freezing remaining freezable tasks ... (elapsed 0.002 seconds) done.
    52.418063:   <2> Suspending console(s) (use no_console_suspend to debug)
    52.451064:   <6> PM: suspend of devices complete after 31.502 msecs
    52.452177:   <6> PM: late suspend of devices complete after 1.102 msecs
    52.456733:   <6> PM: noirq suspend of devices complete after 4.546 msecs
    52.456743:   <2> Disabling non-boot CPUs ...
    52.458561:   <6> migrate_irqs: 1510 callbacks suppressed
    52.458564:   <6> IRQ32 no longer affine to CPU3
    52.458572:   <6> IRQ33 no longer affine to CPU3
    52.458579:   <6> IRQ34 no longer affine to CPU3
    52.458586:   <6> IRQ36 no longer affine to CPU3
    52.458593:   <6> IRQ37 no longer affine to CPU3
    52.458600:   <6> IRQ38 no longer affine to CPU3
    52.458608:   <6> IRQ40 no longer affine to CPU3
    52.458615:   <6> IRQ41 no longer affine to CPU3
    52.458622:   <6> IRQ42 no longer affine to CPU3
    52.458628:   <6> IRQ43 no longer affine to CPU3
    52.460298:   <6> CPU3: shutdown
    52.464728:   <6> CPU4: shutdown
    52.469291:   <6> CPU5: shutdown
    52.473567:   <6> CPU6: shutdown
    52.477904:   <6> CPU7: shutdown
    52.479231:   <6> CPU0:msm_cpu_pm_enter_sleep mode:3 during suspend


猜你喜欢

转载自blog.csdn.net/mike8825/article/details/80420213
今日推荐