android系统休眠与唤醒驱动流程详细分析

android系统休眠与唤醒驱动流程详细分析
android系统休眠与唤醒驱动流程详细分析

Android休眠与唤醒驱动流程分析

Android系统休眠和标准的Linux系统休眠有一些差异。就是在休眠机制上不同。他们的休眠过程如下:

标准linux休眠过程:

●power management notifiers are executed with PM_SUSPEND_PREPARE

●tasks are frozen

●target system sleep state is announced to the platform-handling code

●devices are suspended

●platform-specific global suspend preparation methods are executed

●non-boot CPUs are taken off-line

●interrupts are disabled on the remaining (main) CPU

●late suspend of devices is carried out (一般有一些BUS driver的动作进行)?

●platform-specific global methods are invoked to put the system to sleep

标准linux唤醒过程:

●t he main CPU is switched to the appropriate mode, if necessary

●early resume of devices is carried out (一般有一些BUS driver的动作进行)?

●interrupts are enabled on the main CPU

●non-boot CPUs are enabled

●platform-specific global resume preparation methods are invoked

●devices are woken up

●tasks are thawed

●power management notifiers are executed with PM_POST_SUSPEND

用户可以通过sys文件系统控制系统进入休眠:

查看系统支持的休眠方式:

#cat /sys/power/state

常见有standby(suspend to RAM)、mem(suspend to RAM)和disk(suspend to disk),只是standby耗电更多,返回到正常工作状态的时间更短。

通过#echo mem > /sys/power/state 让系统进入休眠。

Android休眠与唤醒

android是在传统的linux内核电源管理设计的基础上,结合手机设计的实际需求而进化出的一套电源管理系统,其核心内容有:wakelock 、early_suspend与late_resume。

wakelock在Android的电源管理系统中扮演一个核心的角色。wakelock是一种锁的机制,只要有人拿着这个锁,系统就无法进入休眠,可以被用户态程序和内核获得。这个锁可以是有超时的或者是没有超时的,超时的锁会在时间过去以后自动解锁。如果没有锁了或者超时了,内核就会启动休眠的那套机制来进入休眠。

当系统在启动完毕后,会自己去加一把名为“main“的锁,而当系统有意愿去睡眠时则会先去释放这把“main”锁,在android中,在early_suspend的最后一步会去释放“main”锁(wake_unlock: main)。释放完后则会去检查是否还有其他存在的锁,如果没有则直接进入睡眠过程。

它的缺点是,如果有某一应用获锁而不释放或者因一直在执行某种操作而没时间来释放的话,则会导致系统一直进入不了睡眠状态,功耗过大。

early_suspend:先与linux内核的睡眠过程被调用。一般在手机系统的设计中对背光的操作等采用此类方法,因为背光需要的能耗过大。当然此操作与late_resume是配套使用的。一些在内核中要预先进行处理的事件可以先注册上early_suspend函数,当系统要进入睡眠之前会首先调用这些注册的函数。

本文中,linux kernel版本为linux-2.6.29,android版本为android 2.1

与android休眠唤醒主要相关的文件主要有:

●linux_source/kernel/power/main.c

●linux_source/kernel/power/earlysuspend.c

●linux_source/kernel/power/wakelock.c

●linux_source/kernel/power/process.c

●linux_source/driver/base/power/main.c

●linux_source/arch/xxx/mach-xxx/pm.c或linux_source/arch/xxx/plat-xxx/pm.c

Android 休眠过程如下:

当用户读写/sys/power/state时,linux_source/kernel/power/main.c中的state_store()函数会被调用。其中,android的early_suspend会执行request_suspend_state(state); 而标准的linux休眠则执行error = enter_state(state);

static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,

const char *buf, size_t n)

{

#ifdef CONFIG_SUSPEND

#ifdef CONFIG_EARL YSUSPEND

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 = -EINV AL;

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_EARL YSUSPEND

if (state == PM_SUSPEND_ON || valid_state(state)) {

error = 0;

request_suspend_state(state);

#else

error = enter_state(state);

#endif

#endif

Exit:

return error ? error : n;

}

在request_suspend_state(state)函数中,会调用early_suspend_work的工作队列,从而进入early_suspend()函数中。

static DECLARE_WORK(early_suspend_work, early_suspend);

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_STA TE) {

struct timespec ts;

struct rtc_time tm;

getnstimeofday(&ts);

rtc_time_to_tm(https://www.360docs.net/doc/67658384.html,_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, https://www.360docs.net/doc/67658384.html,_nsec);

}

if (!old_sleep && new_state != PM_SUSPEND_ON) {

state |= SUSPEND_REQUESTED;

queue_work(suspend_work_queue, &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);

}

requested_suspend_state = new_state;

spin_unlock_irqrestore(&state_lock, irqflags);

}

在early_suspend()函数中,首先要判断当前请求的状态是否还是suspend,若不是,则直接退出了;若是,函数会调用已经注册的early_suspend的函数。然后同步文件系统,最后释放main_wake_lock。

static void early_suspend(struct work_struct *work)

{

struct early_suspend *pos;

unsigned long irqflags;

int abort = 0;

mutex_lock(&early_suspend_lock);

spin_lock_irqsave(&state_lock, irqflags);

if (state == SUSPEND_REQUESTED)

state |= SUSPENDED;

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) {

if (pos->suspend != NULL)

pos->suspend(pos);

}

mutex_unlock(&early_suspend_lock);

if (debug_mask & DEBUG_SUSPEND)

pr_info("early_suspend: sync\n");

sys_sync();

abort:

spin_lock_irqsave(&state_lock, irqflags);

if (state == SUSPEND_REQUESTED_AND_SUSPENDED)

wake_unlock(&main_wake_lock);

spin_unlock_irqrestore(&state_lock, irqflags);

}

在wake_unlock()中,删除链表中wake_lock节点,判断当前是否存在wake_lock,若wake_lock的数目为0,则调用工作队列suspend_work,进入suspend状态。

static DECLARE_WORK(suspend_work, suspend);

void wake_unlock(struct wake_lock *lock)

{

int type;

unsigned long irqflags;

spin_lock_irqsave(&list_lock, irqflags);

type = lock->flags & WAKE_LOCK_TYPE_MASK;

#ifdef CONFIG_WAKELOCK_STA T

wake_unlock_stat_locked(lock, 0);

#endif

if (debug_mask & DEBUG_WAKE_LOCK)

pr_info("wake_unlock: %s\n", lock->name);

lock->flags &= ~(W AKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);

list_del(&lock->link);

list_add(&lock->link, &inactive_locks);

if (type == WAKE_LOCK_SUSPEND) {

long has_lock = has_wake_lock_locked(type);

if (has_lock > 0) {

if (debug_mask & DEBUG_EXPIRE)

pr_info("wake_unlock: %s, start expire timer, "

"%ld\n", lock->name, has_lock);

mod_timer(&expire_timer, jiffies + has_lock);

} else {

if (del_timer(&expire_timer))

if (debug_mask & DEBUG_EXPIRE)

pr_info("wake_unlock: %s, stop expire "

"timer\n", lock->name);

if (has_lock == 0)

queue_work(suspend_work_queue, &suspend_work);

}

if (lock == &main_wake_lock) {

if (debug_mask & DEBUG_SUSPEND)

print_active_locks(WAKE_LOCK_SUSPEND);

#ifdef CONFIG_WAKELOCK_STA T

update_sleep_wait_stats_locked(0);

#endif

}

}

spin_unlock_irqrestore(&list_lock, irqflags);

}

在suspend()函数中,先判断当前是否有wake_lock,若有,则退出;然后同步文件系统,最后调用pm_suspend()函数。

static void suspend(struct work_struct *work)

{

int ret;

int entry_event_num;

if (has_wake_lock(W AKE_LOCK_SUSPEND)) {

if (debug_mask & DEBUG_SUSPEND)

pr_info("suspend: abort suspend\n");

return;

}

entry_event_num = current_event_num;

sys_sync();

if (debug_mask & DEBUG_SUSPEND)

pr_info("suspend: enter suspend\n");

ret = pm_suspend(requested_suspend_state);

if (debug_mask & DEBUG_EXIT_SUSPEND) {

struct timespec ts;

struct rtc_time tm;

getnstimeofday(&ts);

rtc_time_to_tm(https://www.360docs.net/doc/67658384.html,_sec, &tm);

pr_info("suspend: exit suspend, ret = %d "

"(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,

tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,

tm.tm_hour, tm.tm_min, tm.tm_sec, https://www.360docs.net/doc/67658384.html,_nsec);

}

if (current_event_num == entry_event_num) {

if (debug_mask & DEBUG_SUSPEND)

pr_info("suspend: pm_suspend returned with no event\n");

wake_lock_timeout(&unknown_wakeup, HZ / 2);

}

}

在pm_suspend()函数中,enter_state()函数被调用,从而进入标准linux休眠过程。

int pm_suspend(suspend_state_t state)

{

if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)

return enter_state(state);

return -EINV AL;

}

在enter_state()函数中,首先检查一些状态参数,再同步文件系统,然后调用suspend_prepare()来冻结进程,最后调用suspend_devices_and_enter()让外设进入休眠。

static 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]);

error = suspend_devices_and_enter(state);

Finish:

pr_debug("PM: Finishing wakeup.\n");

suspend_finish();

Unlock:

mutex_unlock(&pm_mutex);

return error;

}

在suspend_prepare()函数中,先通过pm_prepare_console();给suspend分配一个虚拟终端来输出信息,再广播一个系统进入suspend的通报,关闭用户态的helper进程,然后调用suspend_freeze_processes()来冻结进程,最后会尝试释放一些内存。

static int suspend_prepare(void)

{

int error;

unsigned int free_pages;

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

if (error)

goto Finish;

if (suspend_freeze_processes()) {

error = -EAGAIN;

goto Thaw;

}

free_pages = global_page_state(NR_FREE_PAGES);

if (free_pages < FREE_PAGE_NUMBER) {

pr_debug("PM: free some memory\n");

shrink_all_memory(FREE_PAGE_NUMBER - free_pages);

if (nr_free_pages() < FREE_PAGE_NUMBER) {

error = -ENOMEM;

printk(KERN_ERR "PM: No enough memory\n");

}

}

if (!error)

return 0;

Thaw:

suspend_thaw_processes();

usermodehelper_enable();

Finish:

pm_notifier_call_chain(PM_POST_SUSPEND);

pm_restore_console();

return error;

}

在suspend_freeze_processes()函数中调用了freeze_processes()函数,而freeze_processes()函数中又调用了try_to_freeze_tasks()来完成冻结任务。在冻结过程中,会判断当前进程是否有wake_lock,若有,则冻结失败,函数会放弃冻结。

static int try_to_freeze_tasks(bool sig_only)

{

struct task_struct *g, *p;

unsigned long end_time;

unsigned int todo;

struct timeval start, end;

u64 elapsed_csecs64;

unsigned int elapsed_csecs;

unsigned int wakeup = 0;

do_gettimeofday(&start);

end_time = jiffies + TIMEOUT;

do {

todo = 0;

read_lock(&tasklist_lock);

do_each_thread(g, p) {

if (frozen(p) || !freezeable(p))

continue;

if (!freeze_task(p, sig_only))

continue;

/*

* Now that we've done set_freeze_flag, don't

* perturb a task in TASK_STOPPED or TASK_TRACED.

* It is "frozen enough". If the task does wake

* up, it will immediately call try_to_freeze.

*/

if (!task_is_stopped_or_traced(p) &&

!freezer_should_skip(p))

todo++;

} while_each_thread(g, p);

read_unlock(&tasklist_lock);

yield(); /* Yield is okay here */

if (todo && has_wake_lock(WAKE_LOCK_SUSPEND)) {

wakeup = 1;

break;

}

if (time_after(jiffies, end_time))

break;

} while (todo);

do_gettimeofday(&end);

elapsed_csecs64 = timeval_to_ns(&end) - timeval_to_ns(&start);

do_div(elapsed_csecs64, NSEC_PER_SEC / 100);

elapsed_csecs = elapsed_csecs64;

if (todo) {

/* This does not unfreeze processes that are already frozen

* (we have slightly ugly calling convention in that respect,

* and caller must call thaw_processes() if something fails),

* but it cleans up leftover PF_FREEZE requests.

*/

if(wakeup) {

printk("\n");

printk(KERN_ERR "Freezing of %s aborted\n",

sig_only ? "user space " : "tasks ");

}

else {

printk("\n");

printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds "

"(%d tasks refusing to freeze):\n",

elapsed_csecs / 100, elapsed_csecs % 100, todo);

show_state();

}

read_lock(&tasklist_lock);

do_each_thread(g, p) {

task_lock(p);

if (freezing(p) && !freezer_should_skip(p))

printk(KERN_ERR " %s\n", p->comm);

cancel_freezing(p);

task_unlock(p);

} while_each_thread(g, p);

read_unlock(&tasklist_lock);

} else {

printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100,

elapsed_csecs % 100);

}

return todo ? -EBUSY : 0;

}

到现在,所有的进程(也包括workqueue/kthread) 都已经停止了,内核态进程有可能在停止的时候握有一些信号量,所以如果这时候在外设里面去解锁这个信号量有可能会发生死锁,所以在外设suspend()函数里面作lock/unlock锁要非常小心,建议不要在外设的suspend()里面等待锁。而且suspend的过程中,有一些log是无法输出的,所以一旦出现问题,非常难调试。

回到enter_state()函数中,再冻结进程完成后,调用suspend_devices_and_enter()函数让外设进入休眠。该函数中,首先休眠串口(之后不能再显示log,解决方法为在kernel配置选项

的cmd_line中,添加”no_console_suspend”选项),再通过device_suspend()函数调用各驱动的suspend函数。

当外设进入休眠后,suspend_ops->prepare()被调用,suspend_ops是板级的PM操作(本文中粉红色的函数,依赖于具体的平台),以s3c6410为例,其注册在linux_source/arch/arm/plat-s3c64xx/pm.c中,只定义了suspend_ops->enter()函数。

static struct platform_suspend_ops s3c6410_pm_ops = {

.enter = s3c6410_pm_enter,

.valid = suspend_valid_only_mem,

};

接下来,多CPU中的非启动CPU被关闭。

int suspend_devices_and_enter(suspend_state_t state)

{

int error;

if (!suspend_ops)

return -ENOSYS;

if (suspend_ops->begin) {

error = suspend_ops->begin(state);

if (error)

goto Close;

}

suspend_console();

suspend_test_start();

error = device_suspend(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;

if (suspend_ops->prepare) {

error = suspend_ops->prepare();

if (error)

goto Resume_devices;

}

if (suspend_test(TEST_PLA TFORM))

goto Finish;

error = disable_nonboot_cpus();

if (!error && !suspend_test(TEST_CPUS))

suspend_enter(state);

enable_nonboot_cpus();

Finish:

if (suspend_ops->finish)

suspend_ops->finish();

Resume_devices:

suspend_test_start();

device_resume(PMSG_RESUME);

suspend_test_finish("resume devices");

resume_console();

Close:

if (suspend_ops->end)

suspend_ops->end();

return error;

Recover_platform:

if (suspend_ops->recover)

suspend_ops->recover();

goto Resume_devices;

}

接下来suspend_enter()被调用,该函数首先关闭IRQ,然后调用device_power_down(), 它会调用suspend_late()函数, 这个函数是系统真正进入休眠最后调用的函数, 通常会在这个函数中作最后的检查,接下来休眠所有的系统设备和总线。最后调用suspend_pos->enter() 来使CPU进入省电状态。这时候,整个休眠过程完成,代码的执行也就停在这里了。

static int suspend_enter(suspend_state_t state)

{

int error = 0;

device_pm_lock();

#ifdef CONFIG_CPU_FREQ

cpufreq_get_cpufreq_name(0);

strcpy(governor_name, cpufreq_governor_name);

if(strnicmp(governor_name, userspace_governor, CPUFREQ_NAME_LEN)) {

cpufreq_set_policy(0, "performance");

}

#endif /* CONFIG_CPU_FREQ */

arch_suspend_disable_irqs();

BUG_ON(!irqs_disabled());

if ((error = device_power_down(PMSG_SUSPEND))) {

printk(KERN_ERR "PM: Some devices failed to power down\n");

goto Done;

}

error = sysdev_suspend(PMSG_SUSPEND);

if (!error) {

if (!suspend_test(TEST_CORE))

error = suspend_ops->enter(state);

sysdev_resume();

}

device_power_up(PMSG_RESUME);

Done:

arch_suspend_enable_irqs();

#ifdef CONFIG_CPU_FREQ

if(strnicmp(governor_name, userspace_governor, CPUFREQ_NAME_LEN)) {

cpufreq_set_policy(0, governor_name);

}

#endif /* CONFIG_CPU_FREQ */

BUG_ON(irqs_disabled());

device_pm_unlock();

return error;

}

在suspend_pos->enter()所对应的函数中,代码最终停止在pm_cpu_sleep();处。

static int s3c6410_pm_enter(suspend_state_t state)

{

……

s3c6410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));

s3c6410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));

s3c6410_pm_do_save(core_save, ARRAY_SIZE(core_save));

s3c6410_pm_do_save(sromc_save, ARRAY_SIZE(sromc_save));

/* Clear WAKEUP_STAT register for next wakeup -jc.lee */

/* If this register do not be cleared, Wakeup will be failed */

__raw_writel(__raw_readl(S3C_W AKEUP_STAT), S3C_WAKEUP_STAT);

#ifdef CONFIG_MACH_SMDK6410

/* ALL sub block "ON" before enterring sleep mode - EVT0 bug*/

__raw_writel(0xffffff00, S3C_NORMAL_CFG);

/* Open all clock gate to enter sleep mode - EVT0 bug*/

__raw_writel(0xffffffff, S3C_HCLK_GATE);

__raw_writel(0xffffffff, S3C_PCLK_GATE);

__raw_writel(0xffffffff, S3C_SCLK_GATE);

……

/* s3c6410_cpu_save will also act as our return point from when

* we resume as it saves its own register state, so use the return

* code to differentiate return from save and return from sleep */

if (s3c6410_cpu_save(regs_save) == 0) {

flush_cache_all();

pm_cpu_sleep();

}

/* restore the cpu state */

cpu_init();

__raw_writel(s3c_eint_mask_val, S3C_EINT_MASK);

/* restore the system state */

s3c6410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));

s3c6410_pm_do_restore(sromc_save, ARRAY_SIZE(sromc_save));

……

}

Android 唤醒过程如下:

如果在休眠中系统被中断或者其他事件唤醒,接下来的代码就从suspend完成的地方开始执行,以s3c6410为例,即pm.c中的s3c6410_pm_enter()中的cpu_init(),然后执行suspend_enter()的sysdev_resume()函数,唤醒系统设备和总线,使能系统中断。

static int suspend_enter(suspend_state_t state)

{

int error = 0;

device_pm_lock();

#ifdef CONFIG_CPU_FREQ

cpufreq_get_cpufreq_name(0);

strcpy(governor_name, cpufreq_governor_name);

if(strnicmp(governor_name, userspace_governor, CPUFREQ_NAME_LEN)) {

cpufreq_set_policy(0, "performance");

}

#endif /* CONFIG_CPU_FREQ */

arch_suspend_disable_irqs();

BUG_ON(!irqs_disabled());

if ((error = device_power_down(PMSG_SUSPEND))) {

printk(KERN_ERR "PM: Some devices failed to power down\n");

goto Done;

}

error = sysdev_suspend(PMSG_SUSPEND);

if (!error) {

if (!suspend_test(TEST_CORE))

error = suspend_ops->enter(state); //suspend过程完成处

sysdev_resume();

}

device_power_up(PMSG_RESUME);

Done:

arch_suspend_enable_irqs();

#ifdef CONFIG_CPU_FREQ

if(strnicmp(governor_name, userspace_governor, CPUFREQ_NAME_LEN)) {

cpufreq_set_policy(0, governor_name);

}

#endif /* CONFIG_CPU_FREQ */

BUG_ON(irqs_disabled());

device_pm_unlock();

return error;

}

然后回到suspend_devices_and_enter()函数中,使能休眠时候停止掉的非启动CPU,继续唤醒每个设备,使能终端。

int suspend_devices_and_enter(suspend_state_t state)

{

int error;

if (!suspend_ops)

return -ENOSYS;

if (suspend_ops->begin) {

error = suspend_ops->begin(state);

if (error)

goto Close;

}

suspend_console();

suspend_test_start();

error = device_suspend(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;

if (suspend_ops->prepare) {

error = suspend_ops->prepare();

if (error)

goto Resume_devices;

}

if (suspend_test(TEST_PLA TFORM))

goto Finish;

error = disable_nonboot_cpus();

if (!error && !suspend_test(TEST_CPUS))

suspend_enter(state); //suspend过程完成处

enable_nonboot_cpus();

Finish:

if (suspend_ops->finish)

suspend_ops->finish();

Resume_devices:

suspend_test_start();

device_resume(PMSG_RESUME);

suspend_test_finish("resume devices");

resume_console();

Close:

if (suspend_ops->end)

suspend_ops->end();

return error;

Recover_platform:

if (suspend_ops->recover)

suspend_ops->recover();

goto Resume_devices;

}

当suspend_devices_and_enter()执行完成后,系统外设已经唤醒,但进程依然是冻结的状态,返回到enter_state函数中,调用suspend_finish()函数。

static 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]);

error = suspend_devices_and_enter(state); //suspend过程完成处

Finish:

pr_debug("PM: Finishing wakeup.\n");

suspend_finish();

Unlock:

mutex_unlock(&pm_mutex);

return error;

}

在suspend_finish()函数中,解冻进程和任务,使能用户空间helper进程,广播一个系统从suspend状态退出的notify,唤醒终端。

static void suspend_finish(void)

{

suspend_thaw_processes();

usermodehelper_enable();

pm_notifier_call_chain(PM_POST_SUSPEND);

pm_restore_console();

}

当所有的唤醒已经结束以后,用户进程都已经开始运行了,但没点亮屏幕,唤醒通常会是以下的几种原因:

如果是来电,那么Modem会通过发送命令给rild来让rild通知WindowManager有来电响应,这样就会远程调用PowerManagerService来写”on”到/sys/power/state 来调用late resume(),执行点亮屏幕等操作。

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

当”on”被写入到/sys/power/state之后,同early_suspend过程,request_suspend_state()被调用,只是执行的工作队列变为late_resume_work。在late_resume函数中,唤醒调用了early_suspend的设备。

static DECLARE_WORK(late_resume_work, late_resume);

static void late_resume(struct work_struct *work)

{

struct early_suspend *pos;

unsigned long irqflags;

int abort = 0;

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)

pos->resume(pos);

if (debug_mask & DEBUG_SUSPEND)

pr_info("late_resume: done\n");

abort:

mutex_unlock(&early_suspend_lock);

}

关于wake_lock

在上文中,已经介绍了wakelock机制,下面从代码的角度进行介绍。

wakelock有3种类型,常用为W AKE_LOCK_SUSPEND,作用是防止系统进入睡眠。其他类型不是很清楚。

enum {

WAKE_LOCK_SUSPEND, /* Prevent suspend */

WAKE_LOCK_IDLE, /* Prevent low power idle */

WAKE_LOCK_TYPE_COUNT

};

Wakelock有加锁和解锁2种操作,加锁有2种方式,第一种是永久加锁(wake_lock),这种锁必须手动的解锁;另一种是超时锁(wake_lock_timeout),这种锁在过去指定时间后,会自动解锁。

void wake_lock(struct wake_lock *lock)

{

wake_lock_internal(lock, 0, 0);

}

void wake_lock_timeout(struct wake_lock *lock, long timeout)

{

wake_lock_internal(lock, timeout, 1);

}

对于wakelock,timeout = has_timeout = 0;直接加锁后,然后退出;

static void wake_lock_internal(

struct wake_lock *lock, long timeout, int has_timeout)

{

int type;

unsigned long irqflags;

long expire_in;

spin_lock_irqsave(&list_lock, irqflags);

type = lock->flags & WAKE_LOCK_TYPE_MASK;

BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);

BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));

#ifdef CONFIG_WAKELOCK_STA T

if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) {

if (debug_mask & DEBUG_WAKEUP)

pr_info("wakeup wake lock: %s\n", lock->name);

wait_for_wakeup = 0;

lock->stat.wakeup_count++;

}

if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) &&

(long)(lock->expires - jiffies) <= 0) {

wake_unlock_stat_locked(lock, 0);

lock->https://www.360docs.net/doc/67658384.html,st_time = ktime_get();

}

#endif

if (!(lock->flags & WAKE_LOCK_ACTIVE)) {

lock->flags |= WAKE_LOCK_ACTIVE;

#ifdef CONFIG_WAKELOCK_STA T

lock->https://www.360docs.net/doc/67658384.html,st_time = ktime_get();

#endif

}

list_del(&lock->link);

if (has_timeout) {

if (debug_mask & DEBUG_WAKE_LOCK)

pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n",

lock->name, type, timeout / HZ,

(timeout % HZ) * MSEC_PER_SEC / HZ);

lock->expires = jiffies + timeout;

lock->flags |= WAKE_LOCK_AUTO_EXPIRE;

list_add_tail(&lock->link, &active_wake_locks[type]);

} else {

if (debug_mask & DEBUG_WAKE_LOCK)

pr_info("wake_lock: %s, type %d\n", lock->name, type);

lock->expires = LONG_MAX;

lock->flags &= ~W AKE_LOCK_AUTO_EXPIRE;

list_add(&lock->link, &active_wake_locks[type]);

}

if (type == WAKE_LOCK_SUSPEND) {

current_event_num++;

#ifdef CONFIG_WAKELOCK_STA T

if (lock == &main_wake_lock)

update_sleep_wait_stats_locked(1);

else if (!wake_lock_active(&main_wake_lock))

update_sleep_wait_stats_locked(0);

#endif

if (has_timeout)

expire_in = has_wake_lock_locked(type);

else

expire_in = -1;

if (expire_in > 0) {

if (debug_mask & DEBUG_EXPIRE)

pr_info("wake_lock: %s, start expire timer, "

"%ld\n", lock->name, expire_in);

mod_timer(&expire_timer, jiffies + expire_in);

} else {

if (del_timer(&expire_timer))

if (debug_mask & DEBUG_EXPIRE)

pr_info("wake_lock: %s, stop expire timer\n",

lock->name);

if (expire_in == 0)

queue_work(suspend_work_queue, &suspend_work);

}

}

spin_unlock_irqrestore(&list_lock, irqflags);

}

而对于wake_lock_timeout,在经过timeout时间后,才加锁。再判断当前持有wakelock 时,启动另一个定时器,在expire_timer的回调函数中再次判断是否持有wakelock。

static void expire_wake_locks(unsigned long data)

{

long has_lock;

unsigned long irqflags;

if (debug_mask & DEBUG_EXPIRE)

pr_info("expire_wake_locks: start\n");

spin_lock_irqsave(&list_lock, irqflags);

if (debug_mask & DEBUG_SUSPEND)

print_active_locks(WAKE_LOCK_SUSPEND);

has_lock = has_wake_lock_locked(W AKE_LOCK_SUSPEND);

if (debug_mask & DEBUG_EXPIRE)

pr_info("expire_wake_locks: done, has_lock %ld\n", has_lock);

if (has_lock == 0)

queue_work(suspend_work_queue, &suspend_work);

spin_unlock_irqrestore(&list_lock, irqflags);

}

static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);

在wakelock中,有2个地方可以让系统从early_suspend进入suspend状态。分别是:

●在wake_unlock中,解锁之后,若没有其他的wakelock,则进入suspend。

●在超时锁的定时器超时后,定时器的回调函数,会判断有没有其他的wakelock,若没

有,则进入suspend。

Android系统的休眠不仅在要对底层Linux进行设置,在系统服务上也要进行设置,休眠之后,包括后台服务都要停止。

android系统开机启动流程分析

一,系统引导bootloader 加电,cpu执行bootloader程序,正常启动系统,加载boot.img【其中包含内核。还有ramdisk】 二,内核kernel bootloader加载kernel,kernel自解压,初始化,载入built-in驱动程序,完成启动。 内核启动后会创建若干内核线程,在后装入并执行程序/sbin/init/,载入init process,切换至用户空间(user-space) 内核zImage解压缩 head.S【这是ARM-Linux运行的第一个文件,这些代码是一个比较独立的代码包裹器。其作用就是解压Linux内核,并将PC指针跳到内核(vmlinux)的第一条指令】首先初始化自解压相关环境(内存等),调用decompress_kernel进行解压,解压后调用start_kernel启动内核【start_kernel是任何版本linux内核的通用初始化函数,它会初始化很多东西,输出linux版本信息,设置体系结构相关的环境,页表结构初始化,设置系 统自陷入口,初始化系统IRQ,初始化核心调度器等等】,最后调用rest_init【rest_init 会调用kernel_init启动init进程(缺省是/init)。然后执行schedule开始任务调度。这个init是由android的./system/core/init下的代码编译出来的,由此进入了android的代码】。 三,Init进程启动 【init是kernel启动的第一个进程,init启动以后,整个android系统就起来了】 init进程启动后,根据init.rc 和init. .rc脚本文件建立几个基本 服务(servicemanager zygote),然后担当property service 的功能 打开.rc文件,解析文件内容。【system/core/init/init.c】将service信息放置到service.list中【system/core/init/init_parser.c】。 建立service进程。【service_start(…) execve(…)】 在init.c中,完成以下工作 1、初始化log系统【解析/init.rc和init.%hardware%.rc文件,在两个 文件解析步骤2时执行“early-init”行动】 2、初始化设备【在/dev下创建所有设备节点,下载firmwares】 3、初始化属性服务器【在两个文件解析步骤2时执行“init”行动】

标准linux休眠和唤醒机制分析

标准linux休眠和唤醒机制分析 说明: 1. Based on linux 2.6.32, only for mem(SDR) 2. 有兴趣请先参考阅读:电源管理方案APM和ACPI比较.doc Linux系统的休眠与唤醒简介.doc 3. 本文先研究标准linux的休眠与唤醒,android对这部分的增改在另一篇文章中讨论 4. 基于手上的一个项目来讨论,这里只讨论共性的地方 虽然linux支持三种省电模式:standby、suspend to ram、suspend to disk,但是在使用电池供电的手持设备上,几乎所有的方案都只支持STR模式(也有同时支持standby模式的),因为STD模式需要有交换分区的支持,但是像手机类的嵌入式设备,他们普遍使用nand 来存储数据和代码,而且其上使用的文件系统yaffs一般都没有划分交换分区,所以手机类设备上的linux都没有支持STD省电模式。 一、项目power相关的配置 目前我手上的项目的linux电源管理方案配置如下,.config文件的截图,当然也可以通过make menuconfig使用图形化来配置: # # CPU Power Management # # CONFIG_CPU_IDLE is not set # # Power management options

# CONFIG_PM=y # CONFIG_PM_DEBUG is not set CONFIG_PM_SLEEP=y CONFIG_SUSPEND=y CONFIG_SUSPEND_FREEZER=y CONFIG_HAS_WAKELOCK=y CONFIG_HAS_EARLYSUSPEND=y CONFIG_WAKELOCK=y CONFIG_WAKELOCK_STAT=y CONFIG_USER_WAKELOCK=y CONFIG_EARLYSUSPEND=y # CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set # CONFIG_CONSOLE_EARLYSUSPEND is not set CONFIG_FB_EARLYSUSPEND=y # CONFIG_APM_EMULATION is not set # CONFIG_PM_RUNTIME is not set CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_NET=y 上面的配置对应下图中的下半部分图形化配置。。。,看来是直接在Kconfig文件中删除了配置STD模式的选项。

分析Android 开机启动慢的原因

开机启动花了40多秒,正常开机只需要28秒就能开机起来。 内核的启动我没有去分析,另一个同事分析的。我主要是分析从SystemServer启来到开机动画结束显示解锁界面的这段时间,也就是开机动画的第三个动画开始到结束这段时间,这是个比较耗时阶段,一般都在17秒左右(见过牛B的手机,只需5秒)。 SystemServer分两步执行:init1和init2。init1主要是初始化native的服务,代码在sy stem_init.cpp的system_init,初始化了SurfaceFlinger和SensorService这两个native的服务。init2启动的是java的服务,比如ActivityManagerService、WindowManagerService、PackageManagerService等,在这个过程中PackageManagerService用的时间最长,因为PackageManagerService会去扫描特定目录下的jar包和apk文件。 在开机时间需要40多秒的时,从Log上可以看到,从SurfaceFlinger初始化到动画结束,要27秒左右的时间,即从SurfaceFlinger::init的LOGI("SurfaceFlinger is starting")这句Log到void SurfaceFlinger::bootFinished()的LOGI("Boot is finished (%ld ms)", long(ns 2ms(duration)) ),需要27秒左右的时间,这显然是太长了,但到底是慢在哪了呢?应该在个中间的点,二分一下,于是想到了以启动服务前后作为分隔:是服务启动慢了,还是在服务启动后的这段时间慢?以ActivityManagerService的Slog.i(TAG, "System now ready")的这句Log为分割点,对比了一下,在从SurfaceFlinger is starting到System now read y多了7秒左右的时间,这说明SystemServer在init1和init2过程中启动慢了,通过排查,发现在init1启动的时候,花了7秒多的时间,也就是system_init的LOGI("Entered system _init()")到LOGI("System server: starting Android runtime.\n")这段时间用了7秒多,而正常情况是400毫秒便可以初始化完,通过添加Log看到,在SensorService启动时,用了比较长的时间。 不断的添加Log发现,在启动SensorService时候,关闭设备文件变慢了,每次关闭一个/dev/input/下的设备文件需要100ms左右,而SensorService有60~70次的关闭文件,大概有7s左右的时间。 调用流程是: frameworks/base/cmds/system_server/library/system_init.cpp: system_init->SensorServi ce::instantiate frameworks/native/services/sensorservice/SensorService.cpp: void SensorService::onFi rstRef()->SensorDevice& dev(SensorDevice::getInstance()) hardware/libsensors/SensorDevice.cpp: SensorDevice::SensorDevice()->sensors_open hardware/libsensors/sensors.cpp: open_sensors->sensors_poll_context_t sensors_poll_context_t执行打开每个传感器设备时,遍历/dev/input/目录下的设备文件,以匹配当前需要打开的设备,遍历文件是在 hardware/libsensors/SensorBase.cpp的openInput下实现,如果打开的设备文件不是正在打开的设备文件,会执行下面语句的else部分: if (!strcmp(name, inputName)) { strcpy(input_name, filename); break;

Android 开机启动流程

Android的开机流程 1. 系统引导bootloader 1) 源码:bootable/bootloader/* 2) 说明:加电后,CPU将先执行bootloader程序,此处有三种选择 a) 开机按Camera+Power启动到fastboot,即命令或SD卡烧写模式,不加载内核及文件系统,此处可以进行工厂模式的烧写 b) 开机按Home+Power启动到recovery模式,加载recovery.img,recovery.i mg包含内核,基本的文件系统,用于工程模式的烧写 c) 开机按Power,正常启动系统,加载boot.img,boot.img包含内核,基本文件系统,用于正常启动手机(以下只分析正常启动的情况) 2. 内核kernel 1) 源码:kernel/* 2) 说明:kernel由bootloader加载 3. 文件系统及应用init 1) 源码:system/core/init/* 2) 配置文件:system/rootdir/init.rc, 3) 说明:init是一个由内核启动的用户级进程,它按照init.rc中的设置执行:启动服务(这里的服务指linux底层服务,如adbd提供adb支持,vold提供SD卡挂载等),执行命令和按其中的配置语句执行相应功能 4. 重要的后台程序zygote 1)源码:frameworks/base/cmds/app_main.cpp等 2) 说明:zygote是一个在init.rc中被指定启动的服务,该服务对应的命令是/system/bin/app_process a)建立Java Runtime,建立虚拟机 b) 建立Socket接收ActivityManangerService的请求,用于Fork应用程序 c) 启动System Server 5. 系统服务system server 1)源码:frameworks/base/services/java/com/android/server/SystemServer.jav a 2) 说明:被zygote启动,通过SystemManager管理android的服务(这里的服务指frameworks/base/services下的服务,如卫星定位服务,剪切板服务等) 6. 桌面launcher 1)源码:ActivityManagerService.java为入口,packages/apps/launcher*实现 2) 说明:系统启动成功后SystemServer使用xxx.systemReady()通知各个服务,系统已经就绪,桌面程序Home就是在ActivityManagerService.systemReady()通知的过程中建立的,最终调用()启launcher 7. 解锁 1) 源码: frameworks/policies/base/phone/com/android/internal/policy/impl/*lock* 2) 说明:系统启动成功后SystemServer调用wm.systemReady()通知WindowManagerService,进而调用PhoneWindowManager,最终通过LockPatternKeyguardView显示解锁界面,跟踪代码可以看到解锁界面并不是一个Activity,这是只是向特定层上绘图,其代码了存放在特殊的位置

Linux+Kernel+and+Android+休眠与唤醒实现与优化

Linux Kernel and Android 休眠与唤醒(中文版) 四月 18th, 2010 0 Comments/1664 hits Table of Contents ?简介 ?国际化 ?版本信息 ?对于休眠(suspend)的简单介绍 ?Linux Suspend 的流程 o相关的文件: o准备, 冻结进程 o让外设进入休眠 o Resume ?Android 休眠(suspend) o涉及到的文件: o特性介绍 ?Early Suspend ?Late Resume ?Wake Lock o Android Suspend o Early Suspend o Late Resume o Wake Lock o Suspend o Android于标准Linux休眠的区别 简介 休眠/唤醒在嵌入式Linux中是非常重要的部分,嵌入式设备尽可能的进入休眠状态来延长电池的续航时间.这篇文章就详细介绍一下Linux中休眠/唤醒是如何工作的, 还有Android中如何把这部分和Linux的机制联系起来的. 国际化 ?English Version: link ?中文版: link 作者: zhangjiejing Date: 2010-04-07, https://www.360docs.net/doc/67658384.html,

版本信息 ?Linux Kernel: v2.6.28 ?Android: v2.0 对于休眠(suspend)的简单介绍 在Linux中,休眠主要分三个主要的步骤: 1.冻结用户态进程和内核态任务 2.调用注册的设备的suspend的回调函数 o顺序是按照注册顺序 3.休眠核心设备和使CPU进入休眠态冻结进程是内核把进程列表中所有的 进程的状态都设置为停止,并且保存下所有进程的上下文. 当这些进程被 解冻的时候,他们是不知道自己被冻结过的,只是简单的继续执行.如何让 Linux进入休眠呢?用户可以通过读写sys文件/sys /power/state 是实 现控制系统进入休眠. 比如 命令系统进入休眠. 也可以使用 来得到内核支持哪几种休眠方式. Linux Suspend 的流程 相关的文件: 你可以通过访问Linux内核网站来得到源代码,下面是文件的路径: ?linux_soruce/kernel/power/main.c ?linux_source/kernel/arch/xxx/mach-xxx/pm.c ?linux_source/driver/base/power/main.c 接下来让我们详细的看一下Linux是怎么休眠/唤醒的. Let 's going to see how these happens.

基于MT6752的 android 系统启动流程分析报告

基于MT6752的Android系统启动流程分析报告 1、Bootloader引导 (2) 2、Linux内核启动 (23) 3、Android系统启动 (23) 报告人: 日期:2016.09.03

对于Android整个启动过程来说,基本可以划分成三个阶段:Bootloader引导、Linux kernel启动、Android启动。但根据芯片架构和平台的不同,在启动的Bootloader阶段会有所差异。 本文以MTK的MT6752平台为例,分析一下基于该平台的Android系统启动流程。 1、Bootloader引导 1.1、Bootloader基本介绍 BootLoader是在操作系统运行之前运行的一段程序,它可以将系统的软硬件环境带到一个合适状态,为运行操作系统做好准备,目的就是引导linux操作系统及Android框架(framework)。 它的主要功能包括设置处理器和内存的频率、调试信息端口、可引导的存储设备等等。在可执行环境创建好之后,接下来把software装载到内存并执行。除了装载software,一个外部工具也能和bootloader握手(handshake),可指示设备进入不同的操作模式,比如USB下载模式和META模式。就算没有外部工具的握手,通过外部任何组合或是客户自定义按键,bootloader也能够进入这些模式。 由于不同处理器芯片厂商对arm core的封装差异比较大,所以不同的arm处理器,对于上电引导都是由特定处理器芯片厂商自己开发的程序,这个上电引导程序通常比较简单,会初始化硬件,提供下载模式等,然后才会加载通常的bootloader。 下面是几个arm平台的bootloader方案: marvell(pxa935) : bootROM + OBM + BLOB informax(im9815) : bootROM + barbox + U-boot mediatek(mt6517) : bootROM + pre-loader + U-boot broadcom(bcm2157) : bootROM + boot1/boot2 + U-boot 而对MT6752平台,MTK对bootloader引导方案又进行了调整,它将bootloader分为以下两个部分: (1) 第1部分bootloader,是MTK内部(in-house)的pre-loader,这部分依赖平台。 (2) 第2部分bootloader,是LK(little kernel的缩写,作用同常见的u-boot差不多),这部分依赖操作系统,负责引导linux操作系统和Android框架。 1.2、bootloader的工作流程 1.2.1 bootloader正常的启动流程 先来看启动流程图:

linux内核启动 Android系统启动过程详解

linux内核启动+Android系统启动过程详解 第一部分:汇编部分 Linux启动之 linux-rk3288-tchip/kernel/arch/arm/boot/compressed/ head.S分析这段代码是linux boot后执行的第一个程序,完成的主要工作是解压内核,然后跳转到相关执行地址。这部分代码在做驱动开发时不需要改动,但分析其执行流程对是理解android的第一步 开头有一段宏定义这是gnu arm汇编的宏定义。关于GUN 的汇编和其他编译器,在指令语法上有很大差别,具体可查询相关GUN汇编语法了解 另外此段代码必须不能包括重定位部分。因为这时一开始必须要立即运行的。所谓重定位,比如当编译时某个文件用到外部符号是用动态链接库的方式,那么该文件生成的目标文件将包含重定位信息,在加载时需要重定位该符号,否则执行时将因找不到地址而出错 #ifdef DEBUG//开始是调试用,主要是一些打印输出函数,不用关心 #if defined(CONFIG_DEBUG_ICEDCC)

……具体代码略 #endif 宏定义结束之后定义了一个段, .section ".start", #alloc, #execinstr 这个段的段名是 .start,#alloc表示Section contains allocated data, #execinstr表示Section contains executable instructions. 生成最终映像时,这段代码会放在最开头 .align start: .type start,#function /*.type指定start这个符号是函数类型*/ .rept 8 mov r0, r0 //将此命令重复8次,相当于nop,这里是为中断向量保存空间 .endr b 1f .word 0x016f2818 @ Magic numbers to help the loader

Android开机启动流程样本

Android的开机流程 1. 系统引导bootloader 1) 源码: bootable/bootloader/* 2) 说明: 加电后, CPU将先执行bootloader程序, 此处有三种选择 a) 开机按Camera+Power启动到fastboot, 即命令或SD卡烧写模式, 不加载内核及文件系统, 此处能够进行工厂模式的烧写 b) 开机按Home+Power启动到recovery模式, 加载recovery.img, recovery.img包含内核, 基本的文件系统, 用于工程模式的烧写 c) 开机按Power, 正常启动系统, 加载boot.img, boot.img包含内核, 基本文件系统, 用于正常启动手机( 以下只分析正常启动的情况) 2. 内核kernel 1) 源码: kernel/* 2) 说明: kernel由bootloader加载 3. 文件系统及应用init 1) 源码: system/core/init/* 2) 配置文件: system/rootdir/init.rc, 3) 说明: init是一个由内核启动的用户级进程, 它按照init.rc中的设置执行: 启动服务( 这里的服务指linux底层服务, 如adbd提供adb支持, vold提供SD卡挂载等) , 执行命令和按其中的配置语句执行相应功能 4. 重要的后台程序zygote 1) 源码: frameworks/base/cmds/app_main.cpp等 2) 说明: zygote是一个在init.rc中被指定启动的服务, 该服务对应的命令是/system/bin/app_process

Android系统启动过程详解

Android系统启动过程详解 Android系统启动过程 首先Android框架架构图:(来自网上,我觉得这张图看起来很清晰) Linux内核启动之后就到Android Init进程,进而启动Android相关的服务和应用。 启动的过程如下图所示:(图片来自网上,后面有地址)

下面将从Android4.0源码中,和网络达人对此的总结中,对此过程加以学习了解和总结, 以下学习过程中代码片段中均有省略不完整,请参照源码。

一Init进程的启动 init进程,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行, 并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。init始终是第一个进程。 启动过程就是代码init.c中main函数执行过程:system\core\init\init. c 在函数中执行了:文件夹建立,挂载,rc文件解析,属性设置,启动服务,执行动作,socket监听…… 下面看两个重要的过程:rc文件解析和服务启动。 1 rc文件解析 .rc文件是Android使用的初始化脚本文件(System/Core/Init/readm e.txt中有描述: four broad classes of statements which are Actions, Commands, Services, and Options.) 其中Command 就是系统支持的一系列命令,如:export,hostname,mkdir,mount,等等,其中一部分是linux 命令, 还有一些是android 添加的,如:class_start :启动服务,class_stop :关闭服务,等等。 其中Options是针对Service 的选项的。 系统初始化要触发的动作和要启动的服务及其各自属性都在rc脚本文件中定义。具体看一下启动脚本:\system\core\rootdir\init.rc 在解析rc脚本文件时,将相应的类型放入各自的List中: \system\core\init\Init_parser.c :init_parse_config_file( )存入到 action_queue、action_list、service_list中,解析过程可以看一下parse_config函数,类似状态机形式挺有意思。 这其中包含了服务:adbd、servicemanager、vold、ril-daemon、deb uggerd、surfaceflinger、zygote、media…… 2 服务启动 文件解析完成之后将service放入到service_list中。 文件解析完成之后将service放入到service_list中。 \system\core\init\builtins.c

android的休眠和唤醒

android休眠与唤醒驱动流程分析 标准linux休眠过程: ●power management notifiers are executed with PM_SUSPEND_PREPARE ●tasks are frozen ●target system sleep state is announced to the platform-handling code ●devices are suspended ●platform-specific global suspend preparation methods are executed ●non-boot CPUs are taken off-line ●interrupts are disabled on the remaining (main) CPU ●late suspend of devices is carried out (一般有一些BUS driver的动作进行)? ●platform-specific global methods are invoked to put the system to sleep 标准linux唤醒过程: ●t he main CPU is switched to the appropriate mode, if necessary ●early resume of devices is carried out (一般有一些BUS driver的动作进行)? ●interrupts are enabled on the main CPU ●non-boot CPUs are enabled ●platform-specific global resume preparation methods are invoked ●devices are woken up ●tasks are thawed ●power management notifiers are executed with PM_POST_SUSPEND 用户可以通过sys文件系统控制系统进入休眠: 查看系统支持的休眠方式: #cat /sys/power/state 常见有standby(suspend to RAM)、mem(suspend to RAM)和disk(suspend to disk),只是standby耗电更多,返回到正常工作状态的时间更短。 通过#echo mem > /sys/power/state 让系统进入休眠。 Android休眠与唤醒 android是在传统的linux内核电源管理设计的基础上,结合手机设计的实际需求而进化出的一套电源管理系统,其核心内容有:wakelock 、early_suspend与late_resume。 wakelock在Android的电源管理系统中扮演一个核心的角色。wakelock是一种锁的机制,只要有人拿着这个锁,系统就无法进入休眠,可以被用户态程序和内核获得。这个锁可以是有超时的或者是没有超时的,超时的锁会在时间过去以后自动解锁。如果没有锁了或者超时了,内核就会启动休眠的那套机制来进入休眠。 当系统在启动完毕后,会自己去加一把名为“main“的锁,而当系统有意愿去睡眠时则会先去释放这把“main”锁,在android中,在early_suspend的最后一步会去释放“main”锁(wake_unlock: main)。释放完后则会去检查是否还有其他存在的锁,如果没有则直接进入睡眠过程。 它的缺点是,如果有某一应用获锁而不释放或者因一直在执行某种操作而没时间来释放的话,则会导致系统一直进入不了睡眠状态,功耗过大。 early_suspend:先与linux内核的睡眠过程被调用。一般在手机系统的设计中对背光的操

Android SystemBar启动流程分析

Android SystemBar启动流程分析 SystemBars的服务被start时,最终会调用该类的onNoService()方法。 @Override public void start() { if (DEBUG) Log.d(TAG, "start"); ServiceMonitor mServiceMonitor = new ServiceMonitor(TAG, DEBUG, mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this); mServiceMonitor.start(); // will call onNoService if no remote service is found } @Override public void onNoService() { if (DEBUG) Log.d(TAG, "onNoService"); createStatusBarFromConfig(); // fallback to using an in-process implementation } private void createStatusBarFromConfig() { … mStatusBar = (BaseStatusBar) cls.newInstance(); … mStatusBar.start(); } BaseStatusBar是一个抽象类,故调用其子类的PhoneStatusBar的start 函数。 @Override public void start() { … super.start(); … } 子类的start又调用了父类的start public void start() { … createAndAddWindows(); … }

AndroidL系统启动及加载流程分析

Android L系统启动及加载流程分析 1、概述 Android L的启动可以分为几个步骤:Linux内核启动、init进程启动、native系统服务及java系统服务启动、Home启动,主要过程如下图: 图1 整个启动流程跟4.4及之前的版本相差不多,只是有个别不同之处,本文我们主要分析Linux内核启动之后的过程。

2、启动过程分析 2.1 init进程启动 当系统内核加载完成之后,会启动init守护进程,它是内核启动的第一个用户级进程,是Android的一个进程,进程号为1,init进程启动后执行入口函数main(),主要操作为: 图2 AndroidL上将selinux的安全等级提高了,设为了enforcing模式,4.4上是permissive模式。 解析rc脚本文件,即init.rc脚本,该文件是Android初始化脚本,定义了一系列的动作和执行这些动作的时间阶段e aryl-init、init、early-boot、boot、post-fs等阶段。init进程main 函数中会根据这些阶段进行解析执行。AndroidL上为了流程更清晰,增加了charger(充电开机)、ffbm(工厂模式)、以及late-init阶段,实际上这些阶段是对其他阶段的组合执行,比如late-init:

2.2 ServiceManager的启动 servicemanager的启动就是init进程通过init.rc脚本启动的: 源码在frameworks/native/cmds/servicemanager/service_manager.c中,servicemanager是服务管理器,它本身也是一个服务(handle=0),通过binder调用,为native和Java系统服务提供注册和查询服务的,即某个服务启动后,需要将自己注册到servicemanager中,供其他服务或者应用查询使用。AndroidL上servicemanger中在处理注册和查询动作之前添加了selinux安全检测相关的处理。 2.3 SurfaceFinger、MediaServer进程启动 Android4.4以前,surfacefinger的启动根据属性system_init.startsurfaceflinger,决定是通过init.rc启动还是systemserver进程启动,之后的版本包括AndoridL都是通过init.rc启动的: 启动后会向servicemanager进程注册服务中,该服务启动时主要功能是初始化整个显

Android休眠式快速开机设计讲座.doc

/ Android休眠式快速開機設計講座金融研訓院(台北市羅斯福路三段62號)/2011年9月9日/13:00-16:30 發票開立資料 公司抬頭統一編號 聯絡地址電話( ) 發票開立□兩聯式發票□三聯式發票團體報名是否 各別開立發票 □是□否 報名者資料 1 姓名部門職務 電話mail 2 姓名部門職務 電話mail Mail 3 姓名部門職務 電話mail 課程費用 □定價一人NT2,600元 9/1 (四)前報名享早鳥優惠價 □單人報名NT 2,200 ;□團體報名2人以上每人NT 2,000;□團體報名3人以上每人NT 1,800付款方式□ATM轉帳□匯款□支票□信用卡(請填寫信用卡授權單後傳真或MAIL) 付款資訊 .請於9/1(四) 前完成匯款 .戶名:遠播資訊股份有限公司 .銀行:國泰世華中山分行 .帳號:國泰世華013帳號042-03-500039-3匯款帳號末五碼匯款日期匯款金額 / / 課前問題 辦法希望講師說明之主題或問題(也可於報名後隨時來信提出) 問題填寫 零組件科技論壇VIP施行辦法 內容您是公司人事/教育訓練窗口嗎?可參加VIP計畫,取得同仁報名最低優惠價 勾選□我想參加VIP計畫,請寄合作方案給我□暫時不需要,謝謝□已參加聯絡人MAIL (請於此處填寫VIP合作方案寄送郵件地址) 報名注意事項 1.報名表填寫完畢請回寄至conny@https://www.360docs.net/doc/67658384.html,或傳真(02)2585-5519 2.研討會前三天寄發上課通知單,收到方完成報名手續,未收到請電洽(02)2585-5526 # 335 蔡岡陵小姐2.手開三聯式發票,當日於上課報到處領取

android开机启动流程简单分析

android开机启动流程简单分析 android启动 当引导程序启动Linux内核后,会加载各种驱动和数据结构,当有了驱动以后,开始启动Android系统同时会加载用户级别的第一个进程init(system\core\init\init.cpp)代码如下: int main(int argc, char** argv) { ..... //创建文件夹,挂载 // Get the basic filesystem setup we need put together in the initramdisk // on / and then we'll let the rc file figure out the rest. if (is_first_stage) { mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); mkdir("/dev/pts", 0755); mkdir("/dev/socket", 0755); mount("devpts", "/dev/pts", "devpts", 0, NULL); #define MAKE_STR(x) __STRING(x) mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)); mount("sysfs", "/sys", "sysfs", 0, NULL); } ..... //打印日志,设置log的级别 klog_init(); klog_set_level(KLOG_NOTICE_LEVEL); ..... Parser& parser = Parser::GetInstance(); parser.AddSectionParser("service",std::make_unique()); parser.AddSectionParser("on", std::make_unique()); parser.AddSectionParser("import", std::make_unique()); // 加载init.rc配置文件 parser.ParseConfig("/init.rc"); } 加载init.rc文件,会启动一个Zygote进程,此进程是Android系统的一个母进程,用来启动Android的其他服务进程,代码: 从Android L开始,在/system/core/rootdir 目录中有4 个zygote 相关的启动脚本如下图:

Android ninja 编译启动过程分析

Android ninja编译启动过程分析 ---make是如何转换到到ninja编译的 1.首先你的得对make的工作机制有个大概的了解: 运行的命令在要编译的目录下运行make,或者make target_name a.分析处理保存阶段(没有实际编译动作):它首先对当前目录下的Makefile文件的做一次扫描,语法分析,还有处理,主要是变量的保存,目标依赖列表生成,目标下的action列表的生成,然后记住 b.然后按记住的目标执行action列表动作(有实际编译动作). 编译启动的入口方式还是运行make: 2开始make-jxxx方式进入.....(xxx是本机cpu的数量) make开始做进行第一次扫描.... 目前USE_NINJA还是没有定义,估计以后很久很久才能启用的了! BUILDING_WITH_NINJA开始也是没定义的 看make扫描入口文件: Makefile: include build/core/main.mk 在build/core/main.mk: 在ninia之前都有include help.mk和config.mk 97include$(BUILD_SYSTEM)/help.mk 98 99#Set up various standard variables based on configuration 100#and host information. 101include$(BUILD_SYSTEM)/config.mk 说明make help//显示make帮助make config//当前显示配置 103relaunch_with_ninja:= 104ifneq($(USE_NINJA),false) 105ifndef BUILDING_WITH_NINJA<==第二次扫描不会到这里了 106relaunch_with_ninja:=true 107endif 108endif 116ifeq($(relaunch_with_ninja),true)<===第一次扫描入这里了 117#Mark this is a ninja build. 118$(shell mkdir-p$(OUT_DIR)&&touch$(OUT_DIR)/ninja_build) 119include build/core/ninja.mk//---进入ninja.mk 第一次扫描到此为止就结束掉了,因为在当前ifeq else endif后面没有代码了 120else#///!relaunch_with_ninja<===第二次扫描入这里了

Linux Kernel and Android休眠与唤醒

Linux Kernel and Android休眠与唤醒时间:2010-06-26 21:47:04来源:网络作者:未知点击:1767次 版本信息 Linux Kernel: v2.6.28 Android: v2.0 对于休眠(suspend)的简单介绍 在Linux中,休眠主要分三个主要的步骤: Android 休眠(suspend) 在一个打过android补丁的内核中, state_store()函数会走另外一条路,会进入到request_suspend_state()中, 这个文件在earlysuspend.c中. 这些功能都是android系统加的, 后面会对earlysuspend和late resume 进行介绍. 涉及到的文件: linux_source/kernel/power/main.c linux_source/kernel/power/earlysuspend.c linux_source/kernel/power/wakelock.c 特性介绍 Early Suspend Early suspend 是android 引进的一种机制, 这种机制在上游备受争议,这里不做评论. 这个机制作用在关闭显示的时候, 在这个时候, 一些和显示有关的设备, 比如LCD背光, 比如重力感应器, 触摸屏, 这些设备都会关掉, 但是系统可能还是在运行状态(这时候还有wake lock)进行任务的处理, 例如在扫描SD卡上的文件等. 在嵌入式设备中, 背光是一个很大的电源消耗,所以android会加入这样一种机制.

Late Resume Late Resume 是和suspend 配套的一种机制, 是在内核唤醒完毕开始执行的. 主要就是唤醒在Early Suspend的时候休眠的设备. Wake Lock Wake Lock 在Android的电源管理系统中扮演一个核心的角色. Wake Lock是一种锁的机制, 只要有人拿着这个锁, 系统就无法进入休眠, 可以被用户态程序和内核获得. 这个锁可以是有超时的或者是没有超时的, 超时的锁会在时间过去以后自动解锁. 如果没有锁了或者超时了, 内核就会启动休眠的那套机制来进入休眠. Android Suspend 当用户写入mem 或者standby到/sys/power/state中的时候, state_store()会被调用, 然后Android会在这里调用request_suspend_state() 而标准的Linux会在这里进入enter_state()这个函数. 如果请求的是休眠, 那么early_suspend这个workqueue就会被调用,并且进入early_suspend状态. 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(https://www.360docs.net/doc/67658384.html,_sec, &tm); pr_info("request_suspend_state: %s (%d->%d) at %lld " "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)",

相关文档
最新文档