welcom ! Handel home

顯示具有 Eclipse Android 標籤的文章。 顯示所有文章
顯示具有 Eclipse Android 標籤的文章。 顯示所有文章

2016年4月20日 星期三

RTOS Design software VM 系統架構規劃

** 語言對平台的延續性 慎選語言 要能跨平台 要相容 才能累積成果經驗 減少歸零的挫折
** 軟體技術分析文件 資料結構 演算法 狀態圖 流程圖 才是軟體的靈魂 找對工具軟體 建立標準的文件格式 建立資料
** 建立函數庫 累積資源 提升coding 效率 , 結構化物件化 的規劃 建立 功能導向 需求導向的 函數庫或物件庫 以此 在上層建立 軟體的演算法 資料結構 如此 軟體轉換平台時 只要針對 底層函數庫改寫 或重新編譯
** 軟體系統的分層架構規劃
L00:[HardHDL] 硬體層
L01:[BIOS] 基本io 驅動
L02:[DRIVE1_LOW] 低階驅動 庫
L03:[DRIVE2_HIGH] 高階驅動 庫
L04:[SYS_PUBLIB] 系統公用函數庫
L05:[APP_PUBLIB] 應用公用函數庫
L06:[USER_PUBLIB] 使用及含庫
L07:[APP] 應用程式
各階層的關聯限制 嚴格遵守 提高系統的穩定及高度移植效率
L07 LINK L06,L05,L04
L06 LINK L04,L04
L05 LINK L04,L03
L04 LINK L03,L02
L03 LINK L02,L01
L02 LINK L01,L00
L01 LINK L00
由此理論 應建構一個 理想化的軟體虛擬平台 VM
累積設計資源

2015年7月7日 星期二

Android Studio VS Eclipse Note

Android Studio系列教程



http://stormzhang.com/devtools/2014/11/25/android-studio-tutorial1/

Android Studio是Google於2013 I/O大會針對Android開發推出的新的開發工具
Android Studio VS Eclipse
相信目前國內用Eclipse的還是大多數,那麼首先就來說一下Studio的一些優點,比較才能更有說服力,才能說明為什麼我們要從Eclipse遷移到Studio。
·         1、Google推出的
毫無疑問,這個是它的最大優勢,Android Stuido是Google推出,專門為Android“量身訂做”的,是Google大力支持的一款基於IntelliJ IDEA改造的IDE,這個應該能說明為什麼它是Android的未來
·         2、速度更快
Eclipse的啟動速度、回應速度、記憶體佔用一直被詬病,相信大家這點應該深有體會,而且經常遇到卡死狀態。Studio不管哪一個方面都全面領先Eclipse
·         3、UI更漂亮
I/O上演示的那款黑色主題真是太棒了,極客範,Stuido自帶的Darcula主題的炫酷黑介面實在是高大上,相比而言Eclipse下的黑色主題太low了
·         4、更加智慧
提示補全對於開發來說意義重大, Studio則更加智慧,智慧保存,從此再也不用每次都 Ctrl + S了。熟悉Studio以後效率會大大提升。
·         5、整合了Gradle構建工具
Gradle是一個新的構建工具,自Studio亮相之處就支援Gradle,可以說Gradle集合了Ant和Maven的優點,不管是配置、編譯、打包都非常棒。
·         6、強大的UI編輯器
Android Studio的編輯器非常的智慧,除了吸收Eclipse+ADT的優點之外,還自帶了多設備的即時預覽,相對這對Android開發者來說簡直是神器啊。
·         7、內置終端
Studio內置終端,這對於習慣命令列操作的人來說簡直是福音啊,再也不用來回切換了,一個Studio全部搞定。
·         8、更完善的外掛程式系統
Studio下支持各種外掛程式,如Git、Markdown、Gradle等等,你想要什麼外掛程式,直接搜索下載。
·         9、完美整合版本控制系統
安裝的時候就自帶了如GitHub, Git, SVN等流行的版本控制系統,可以直接check out你的項目。


2014年7月9日 星期三

2014年6月24日 星期二

[Android] 休眠與喚醒驅動流程分析

android休眠與喚醒驅動流程分析
標準linux休眠過程:
l  power management notifiers are executed with PM_SUSPEND_PREPARE
l  tasks are frozen
l  target system sleep state is announced to the platform-handling code
l  devices are suspended
l  platform-specific global suspend preparation methods are executed
l  non-boot CPUs are taken off-line
l  interrupts are disabled on the remaining (main) CPU
l  late suspend of devices is carried out (一般有一些BUS driver的動作進行)‏
l  platform-specific global methods are invoked to put the system to sleep

標準linux喚醒過程:
l      the main CPU is switched to the appropriate mode, if necessary
l  early resume of devices is carried out (一般有一些BUS driver的動作進行)‏
l  interrupts are enabled on the main CPU
l  non-boot CPUs are enabled
l  platform-specific global resume preparation methods are invoked
l  devices are woken up
l  tasks are thawed
l  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休眠喚醒主要相關的檔主要有:
l  linux_source/kernel/power/main.c
l  linux_source/kernel/power/earlysuspend.c
l  linux_source/kernel/power/wakelock.c
l  linux_source/kernel/power/process.c
l  linux_source/driver/base/power/main.c
l  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_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);
            }
#else
#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_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;
            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);
    }
    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;
    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) {
            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_STAT
    wake_unlock_stat_locked(lock, 0);
#endif
    if (debug_mask & DEBUG_WAKE_LOCK)
            pr_info("wake_unlock: %s\n", lock->name);
    lock->flags &= ~(WAKE_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_STAT
                    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(WAKE_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(ts.tv_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, ts.tv_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 -EINVAL;
}

在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_PLATFORM))
            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_WAKEUP_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_PLATFORM))
            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種類型,常用為WAKE_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_STAT
    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->stat.last_time = ktime_get();
    }
#endif
    if (!(lock->flags & WAKE_LOCK_ACTIVE)) {
            lock->flags |= WAKE_LOCK_ACTIVE;
#ifdef CONFIG_WAKELOCK_STAT
            lock->stat.last_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 &= ~WAKE_LOCK_AUTO_EXPIRE;
            list_add(&lock->link, &active_wake_locks[type]);
    }
    if (type == WAKE_LOCK_SUSPEND) {
            current_event_num++;
#ifdef CONFIG_WAKELOCK_STAT
            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(WAKE_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狀態。分別是:
l  在wake_unlock中,解鎖之後,若沒有其他的wakelock,則進入suspend。
l  在超時鎖的計時器超時後,計時器的回呼函數,會判斷有沒有其他的wakelock,若沒有,則進入suspend。