文章一:
android休眠喚醒流程:
power按鍵事件上報給android系統,最終由windownmanager接收到,當有按鍵事件時判斷是否需要休眠後喚醒系統,然後調用powermanager系統服務去寫/sys/power/state節點.
此節點的寫函數裏判斷收到的內容,來執行android的休眠early_suspend/喚醒late_resume流程.
android層:
private int setScreenStateLocked(boolean on) 電源管理服務: frameworks/base/services/java/com/android/server/PowerManagerService.java
int err = Power.setScreenState(on);
在文件frameworks/base/core/java/android/os/Power.java定義
79 public static native int setScreenState(boolean on);
具體實現在:frameworks/base/core/jni/android_os_Power.cpp
static int setScreenState(JNIEnv *env, jobject clazz, jboolean on);
set_screen_state(on); 在文件hardware/libhardware_legacy/power/power.c中定義並實現
write(g_fds[REQUEST_STATE], buf, len); 寫/sys/power/state節點
內核層:
向節點寫內容會調用kernel/power/main.c的寫函數:
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n)
request_suspend_state(state); 調用此函數: 具體實現在./kernel/power/earlysuspend.c中
state: 爲休眠則調用early_suspend_work android early_suspen工作隊列
爲喚醒則調用late_resume_work android late_resume_work工作隊列
drivers/video/samsung/s3cfb_main.c中早已經註冊屏幕開關
register_early_suspend(&fbdev[i]->early_suspend);
所以
爲休眠則調用early_suspend_work中的屏幕休眠函數:
s3cfb_early_suspend()
backlight_on()---->s3cfb_backlight_on() 在文件arch/arm/plat-s5p/dev-fimd-s5p.c中定義 npd->backlight_on = s3cfb_backlight_on;
s3cfb_backlight_on中直接操作用來控制lcd的gpio關閉屏幕 arch/arm/mach-exynos/setup-fb-s5p.c
爲喚醒時調用late_resume_work中的屏幕喚醒函數:
s3cfb_late_resume()
backlight_off()---->s3cfb_backlight_off() 在文件arch/arm/plat-s5p/dev-fimd-s5p.c中定義 npd->backlight_off = s3cfb_backlight_off;
s3cfb_backlight_off中直接操作用來控制lcd的gpio使能屏幕
執行完所有的early_suspend後執行解鎖main_wake_lock,以便休眠.
wake_unlock(&main_wake_lock);
mod_timer(&expire_timer, jiffies + has_lock); 在文件/kernel/power/wakelock.c中
此函數將啓用expire_timer定時器,定時器內容即expire_wake_locks
340 static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
有四種方式可以引起休眠
①在wake_unlock()中, 如果發現解鎖以後沒有任何其他的wake lock了, 就開始休眠
②在定時器到時間以後, 定時器的回調函數會查看是否有其他的wake lock, 如果沒有, 就在這裏讓系統進入睡眠
③在wake_lock() 中, 對一個wake lock加鎖以後, 會再次檢查一下有沒有鎖, 剛加上鎖,爲什麼要檢查,有用嗎????
④按power鍵,調用earlysuspend.使系統或應用程序釋放鎖.從而調用上述三個函數進入休眠
if(has_lock ==0)
queue_work(suspend_work_queue,&suspend_work); 由DECLARE_WORK(suspend_work, suspend);知道,隊列中的內容即suspend函數.
suspend(); kernel/power/wakelock.c
pm_suspend(requested_suspend_state);
enter_state(state); kernel/power/suspend.c
suspend_devices_and_enter(state);
suspend_enter(state);
suspend_ops->enter(state); -->調用平臺相關的休眠函數,定義在中arch/arm/plat-samsung/pm.c:379:static const struct platform_suspend_ops s3c_pm_ops
即s3c_pm_enter
s3c_pm_arch_stop_clocks() --> 休眠時執行的的最後一個函數.系統停在此處,等待中斷或rtc等喚醒源喚醒.
從此處開始喚醒流程
enable_nonboot_cpus();
suspend_test_start(); ---------->kernel已經被喚醒,當按鍵或中斷來臨後可以執行中斷函數,上報喚醒事件.對於外部中斷來說,上報power按鍵事件.
pm_restore_gfp_mask(); kernel/power/suspend.c
enter_state(state);
pm_suspend(suspend_state_t state);
suspend(); kernel/power/wakelock.c
文章二:
Android系統關機或重啓的幾種實現方式:
(1)發送廣播方式
(2)通過init.rc啓動系統服務來運行sh文件
(3)Runtime調用Linux-shell
(4)PowerManager reboot以及反射調用PowerManagerService shutdown
具體說明:一. 發送廣播方式
Broadcast是Android的四大基本組件之一,也就是我們常說的廣播。Android系統本身就包含了許多廣播,時時刻刻在監聽着系統中註冊的每一個廣播並隨時準備響應操作。其中,就有關於關機或重啓的廣播:Intent.ACTION_REQUEST_SHUTDOWN和Intent.ACTION_REBOOT,通過發送這兩個廣播,Android就能自動接收廣播,並響應關機或重啓的操作。ACTION_REQUEST和ACTION_REBOOT是Intent.java是聲明的兩個字符串常量
public static final String ACTION_REBOOT =
"android.intent.action.REBOOT";
public static final String ACTION_REQUEST_SHUTDOWN = "android.intent.action.ACTION_REQUEST_SHUTDOWN";
Intent.java位於源碼/frameworks/base/core/java/android/content/Intent.java下面。具體實現方法如下
//廣播方式關機重啓
case R.id.shutdown_btn1:
Log.v(TAG, "broadcast->shutdown");
Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
//其中false換成true,會彈出是否關機的確認窗口
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
break;
case R.id.reboot_btn1:
Log.v(TAG, "broadcast->reboot");
Intent intent2 = new Intent(Intent.ACTION_REBOOT);
intent2.putExtra("nowait", 1);
intent2.putExtra("interval", 1);
intent2.putExtra("window", 0);
sendBroadcast(intent2);
break;
需要注意的幾點是:
第一,如前面所說,需要將APP提升至系統權限,具體做法是在AndroidMenifest.xml中添加如下代碼
android:sharedUserId="android.uid.system"
第二,同時需要添加關機權限
第三,在Eclipse中,代碼中的Intent.ACTION_REQUEST_SHUTDOWN 及 Intent.EXTRA_KEY_CONFIRM 在Eclipse IDE中報錯,還是和前面說的一樣,這兩個屬性不對上層開放,如果把項目放在源碼中進行編譯,是可以編譯通過的。
第四,由於需要在源碼中編譯項目,所以需要爲項目編寫mk文件,在項目根目錄下添加Android.mk文件,內容如下所示:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := PowerActionDemo
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
最後,將編譯生成的apk文件,通過adb push到機器上就可以驗證功能了。
二. 通過init.rc啓動系統服務來運行sh文件
Android啓動文件系統後調用的會調用第一個應用程序是/init,此文件一個很重要的內容就是解析了init.rc和init.xxx.rc,然後執行解析出來的任務。而init.rc,可以在系統的初始化過程中進行一些簡單的初始化操作。利用這一點,可以編寫簡單的關機或重啓的sh腳本文件,通過系統init解析,執行相應的關機或重啓操作。
1.首先,編寫關機和重啓的sh腳本。比如,新建
重啓腳本 system_reboot.sh,內容如下:
#!/system/bin/sh
reboot
關機腳本 system_shutdown.sh
#!/system/bin/sh
reboot -p
注意:此處關機命令並不是shutdown,而是reboot -p
2. 編寫Android.mk編譯腳本,目的是在源碼編譯的時候,將這兩個sh文件一起編譯到/system/bin目錄下
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PREBUILT_EXECUTABLES := system_shutdown.sh system_reboot.sh
LOCAL_MODULE_TAGS := optional
include $(BUILD_MULTI_PREBUILT)
3. init.rc添加關機和重啓的服務,打開init.rc文件,在最後面添加如下內容:
service system_shutdown /system/bin/system_shutdown.sh
oneshot
disabled
service system_reboot /system/bin/system_reboot.sh
oneshot
disabled
oneshot選項表示該服務只啓動一次,而如果沒有oneshot選項,這個可執行程序會一直存在--如果可執行程序被殺死,則會重新啓動。
disabled 表示禁用服務,此服務開機時不會自動啓動,但是可以在應用程序中手動啓動它。
4.新建一個目錄,比如poweraction, 將以上的Android.mk , system_shutdown.sh, system_reboot.sh放在這個目錄下,然後將poweraction這個目錄拷貝到Android系統中,比如device路徑下面。然後,編譯Android源碼,源碼編譯完成後, 查看生成的out/.../system/bin下面是不是包含system_shutdown.sh, system_reboot.sh兩個sh文件,如果有,則說明編譯成功。
5.最後,啓動系統服務,進行關機或重啓。
//啓動系統服務進行關機或重啓
case R.id.shutdown_btn2:
Log.v(TAG, "system service->shutdown");
SystemProperties.set("ctl.start", "system_shutdwon");
break;
case R.id.reboot_btn2:
Log.v(TAG, "system service->reboot");
SystemProperties.set("ctl.start", "system_reboot");
break;
三. Runtime調用Linux-shell
我們知道,Runtime這個Java類是可以用來調用並執行shell命令的,而Android虛擬機是支持Linux-shell語言的,基於這一點,可以利用Runtime來執行 關機或重啓的shell命令,這一點和上面介紹的方式二原理上大致相同。功能代碼如下:
//Runtime執行linux-shell
case R.id.shutdown_btn3:
try{
Log.v(TAG, "root Runtime->shutdown");
//Process proc =Runtime.getRuntime().exec(new String[]{"su","-c","shutdown"}); //關機
Process proc =Runtime.getRuntime().exec(new String[]{"su","-c","reboot -p"}); //關機
proc.waitFor();
}catch(Exception e){
e.printStackTrace();
}
break;
case R.id.reboot_btn3:
try {
Log.v(TAG, "root Runtime->reboot");
Process proc =Runtime.getRuntime().exec(new String[]{"su","-c","reboot "}); //關機
proc.waitFor();
}catch (Exception ex){
ex.printStackTrace();
}
break;
使用該方法需要注意的是,普通用戶是沒有權限執行reboot和shutdown的,自然而然也無法實現關機或重啓。使用的Android設備必須已經root過,上面的代碼加上su命令其實也就是爲了獲取管理員權限。另外一點,需要注意的是,該方法能夠奏效的前提是,你的android系統system/bin 目錄下存在reboot和shutdown文件(其實跟上面的原理一樣,也是調用bin目錄下的文件),聽說大部分設備存在reboot和shutdown這兩個文件,可使用的Android系統偏偏沒有shutdown文件,所以,無法直接使用
Runtime.getRuntime().exec(new String[]{"su","-c","shutdown"})
只能執行下面命令來進行關機(好神奇的p參數)
Runtime.getRuntime().exec(new String[]{"su","-c","reboot -p"});
四 . PowerManager reboot以及反射調用PowerManagerService shutdown
1. PowerManager提供了reboot等接口,因此,利用PowerManager實現重啓,就比較簡單。
PowerManager pManager=(PowerManager) getSystemService(Context.POWER_SERVICE); //重啓到fastboot模式
pManager.reboot("");
2. PowerManager類並沒有提供關機的shutdown接口,而是通過IBinder這種Android中特有的通信模式,與PowerManagerService 類進行通信。PowerManagerService是PowerManager 類中定義的接口的具體實現,並進一步調用Power 類來與下一層進行通信. 在PowerManagerService實現了shutdown接口,power服務實現了關機功能
PowerManager的實現通過IPowerManager來調用Power服務的接口。 IPowerManager是AIDL文件自動生成的類,便於遠程通信。IPowerManage.aidl文件目錄
framework/base/core/java/android/os/IPowerManage.aidl
IPowerManager實現了shutdown接口,所以,如果我們能夠獲得Power服務的IBinder,通過反射調用shutdown方法就能實現關機功能。
需要注意的是,ServiceManager管理着系統的服務程序,它保存着所有服務的IBinder,通過服務名就能獲取到這個服務的IBinder。
但ServiceManager這個類也是HIDE的,也需要反射進行調用。兩次,通過兩次反射調用,就能調用power服務實現的關機功能。
try {
//獲得ServiceManager類
Class> ServiceManager = Class
.forName("android.os.ServiceManager");
//獲得ServiceManager的getService方法
Method getService = ServiceManager.getMethod("getService", java.lang.String.class);
//調用getService獲取RemoteService
Object oRemoteService = getService.invoke(null,Context.POWER_SERVICE);
//獲得IPowerManager.Stub類
Class> cStub = Class
.forName("android.os.IPowerManager$Stub");
//獲得asInterface方法
Method asInterface = cStub.getMethod("asInterface", android.os.IBinder.class);
//調用asInterface方法獲取IPowerManager對象
Object oIPowerManager = asInterface.invoke(null, oRemoteService);
//獲得shutdown()方法
Method shutdown = oIPowerManager.getClass().getMethod("shutdown",boolean.class,boolean.class);
//調用shutdown()方法
shutdown.invoke(oIPowerManager,false,true);
} catch (Exception e) {
Log.e(TAG, e.toString(), e);
}
文章三:
Android 6.0變化之休眠模式
休眠:
Android 6.0最大變化之一就是加入了新的電量管理模式:休眠模式,當設備一段時間不用的時候,當屏幕關閉的時候,系統會自動進入休眠模式。這樣所有的App都將進入掛起模式,不能在接入 網絡等一些操作。
當然系統也會定期的退出休眠模式,來完成App延遲的工作,在這個空窗期(我暫且就這麼叫),系統會運行所有同步,工作,提醒等,並允許app接入網絡。
當過了空窗期後,系統會重新進入休眠期,App也會隨着掛起狀態,隨着時間的推移,空窗期越來越少,是爲了幫助沒有接入充電器的長期閒置的設備減少電池消耗。
只要用戶喚醒設備,打開屏幕或者接入電源,系統會自動退出休眠模式,所有的活動都會恢復正常狀態。
下面是當進入休眠期時的約束:
1. 延遲網絡請求;
2. 系統忽略喚醒鎖;
3. 標準的鬧鐘提醒(包括setExat()和setWindow())會被延時到下一個空窗期;
如果一定要在休眠期喚醒鬧鐘,可以用setAndAllowWhileIdle() 或者 setExactAndAllowWhileIdle();
鬧鐘設置setAlarmClock() 則繼續保持常態,在喚醒這個鬧鐘前系統推出休眠期一段時間;
4. 禁用wifi scan;
5. 不允許同步;
6. 禁用JobScheduler ;
休眠容易影響 AlarmManager alarms and timers manage,因爲當系統進入休眠狀態,鬧鐘在android5.1(API level 22)或者更低不會喚醒 ;
爲了幫助管理alarms,android 6.0(API level 23) 介紹了兩個方法: setAndAllowWhileIdle()和setExactAndAllowWhileIdle(). 這樣即使你再休眠期的時候 鬧鐘也會被喚醒;
PS: 即使這兩種方法,每個App每15分鐘喚醒次數也不能超過一次;
有了休眠,自然會影響我們的後臺服務,比如 推送,google 建議是用GMC( Google Cloud Messaging)。
App待機:
app Standby 允許系統決定一個app是否是空閒,當用戶不怎麼用的時候;系統是通過用戶一段時間內是否夠觸摸這個app來決定的,以下的幾點是不在考慮範圍的:
1、用戶退出了App;
2、app有一個前臺進程;
3、App生成一個用戶能夠在鎖屏或通知欄上看到的通知;
當用戶接入電源的時候,系統會釋放待機狀態,自動接入網絡,完成延遲工作。如果設備閒置很長一段時間,系統會大約一天允許連接一次網絡。
google建議使用GMC,可以省電。GMC的優先級要高於休眠模式和待機模式的,所以當處於休眠模式和待機模式的時候 是不會影響推送的。可以通過這個喚醒你的App,短時間內接通網絡,然後繼續回到休眠模式。並且不會影響其他app的待機模式。用GMC的高優先級消息。
PS:當然,爲了更好地兼容,google也提供了一個白名單,可以設置某些應用不會進入休眠和待機狀態。這些應用依然可以正常訪問網絡。不過也不是什麼都可以做,一些同步或其他工作還是不行的。
調用這個方法,即可查看是否加入白名單:isIgnoringBatteryOptimizations()
可以通過一些參數:
ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS、REQUEST_IGNORE_BATTERY_OPTIMIZATIONS 主動請求系統加入到白名單中。
PS : 詳情文檔:http://developer.android.com/intl/zh-cn/training/monitoring-device-state/doze-standby.html
不會所有的6.0系統的手機,都有這個毛病吧?
文章四:
linux下休眠/待機命令
if you
# cat /sys/power/state
mem disk
you can
echo “mem” > /sys/power/state 這相當於待機
echo “disk” > /sys/power/state 這相當於休眠
from http://Linux.chinaunix.NET/bbs/viewthread.PHP?tid=1057578
命令行中執行如下:
[root@fsc feng]# file /sys/power/state
/sys/power/state: ASCII text
[root@fsc feng]# cat /sys/power/state
standby mem disk
[root@fsc feng]# echo “mem”>/sys/power/state
/sys/power/state是個文本文檔,一個”mem”的導向就能使系統掛起到內存(待機)或硬盤(休眠),實在太神奇了,一定要深入學習瞭解一下其中原因!
—————————————–
關於Linux操作系統睡眠和休眠
from http://www.xxlinux.com/linux/article/accidence/technique/20080303/14073.html
在作之前,先檢查一下你的內核能支持哪些方式:
# cat /sys/power/state
standby disk
在實際項目中我執行後的結果爲:
# cat /sys/power/state
freeze mem
1. 睡眠 (sleep)
睡眠可能有兩種方式:mem和standby,這兩種方式都是suspend to RAM,簡稱STR,只是standby耗電更多一些,返回到正常工作方式時間更短一些而已。
只需要
# echo standby > /sys/power/state
就可以了。
2. 休眠 (hibernation)
休眠也有兩種方式:shutdown和platform。shutdown是通常的方式,比較可靠一些。如果你的系統上ACPI支持非常好,那就有機會支持platform方式。激活的方式稍有不同:
# echo platform > /sys/power/disk; echo disk > /sys/power/state
or
# echo shutdown > /sys/power/disk; echo disk > /sys/power/state
注意休眠有一個前提,就是在系統啓動時需要指定resume設備,也就是休眠的鏡像需要保存的分區。一般都用swap分區來做。
指定方式是:
kernel /boot/vmlinuz root=/dev/sda1 resume=/dev/sda2 vga=0×314 …
這樣在系統啓動時,內核會檢查resume中的內容,如果存在上次休眠的鏡像,那內核便會將鏡像讀入內存,恢復正常工作狀態。
文章五
系統掛起(Suspend)是電源管理(APM&ACPI)的一個特性,給用戶帶來了很大的方便。Linux在2.6系列核心中對電源管理有了較好的支持,下面就談談linux對系統掛起的支持情況。
Linux對系統掛起的支持
Linux同時提供了對APM和ACPI的支持,當時兩者是不兼容的,同一時刻只能有一種機制工作。由於ACPI的優越性,所以現在Linux將ACPI設爲缺省的電源管理方案。對於一些比較舊的主板,如果其BIOS中ACPI的實現在2000年以前,那麼Linux自動啓用APM(可以通過核心命令行參數acpi=force來強制啓用ACPI)。如果你下主板BIOS中對ACPI的支持有些問題導致Linux工作不正常,那麼還可以使用核心命令行參數acpi=off來強制禁用ACPI,這樣Linux會自動啓用APM電源管理。
Linux現在主要支持三種ACPI的節電方式:
S1:Stopgrant,即待機(standby)模式。顯示屏自動斷電,只是主機通電。這時敲任意鍵即可恢復原來狀態。待機模式
S2 S3:STR(Suspend To Ram),即掛起到內存。系統把當前信息儲存在內存中,只有內存等幾個關鍵部件通電,這時計算機處在高度節電狀態。此時系統不能從鍵盤喚醒。手工喚醒的方法只能是按前面板上的電源按鈕。喚醒後,計算機從內存中讀取信息很快恢復到原來狀態。
睡眠可能有兩種方式:mem和standby,這兩種方式都是suspend to RAM,簡稱STR,只是standby耗電更多一些,返回到正常工作方式時間更短一些而已。
S4:STD(Suspend To Disk),即掛起到硬盤,也即休眠。計算機自動關機,關機前將當前數據存儲在硬盤上,用戶下次按開關鍵開機時計算機將無須啓動操作系統,直接從硬盤讀取數據,恢復原來狀態。休眠模式
在Linux下查看核心支持ACPI情況的方法如下:
2.4核心下:
# cat /proc/acpi/sleep
S0 S1 S3 S4 S5
2.6核心下:
# cat /sys/power/state
standby mem disk
在實際項目中我執行後的結果爲:
# cat /sys/power/state
freeze mem上面的輸出可知,我們系統中核心同時支持三種節電模式。
在/sys/power目錄下還有一個文件:disk,文件的內容可以如下:
shutdown: 將系統狀態保存到磁盤,讓BIOS關閉計算機;
platform: 將系統狀態保存到磁盤,讓BIOS關閉計算機,並且點亮掛起指示燈;
firmware: 讓BIOS自己將系統狀態保存,並且關閉計算機,需要BIOS自己有掛起磁盤。大部分工作都由BIOS完成,對操作系統是透明的;
進入這三種節電模式的方法如下:
#echo standby > /sys/power/state ---->掛起(S1)
#echo mem > /sys/power/state ---->掛起到內存(S3)
#echo shutdown > /sys/power/disk; echo disk > /sys/power/state ---->掛起到磁盤(S4)#echo platform > /sys/power/disk; echo disk > /sys/power/state
Linux下的磁盤掛起(STD)是通過swsusp機制實現的:將系統當前狀態保存的內存後,再把內存內容寫入交換分區(swap)。這裏要求交換分區容量最好大於內存容量。系統掛起到磁盤後,下次啓動的時候需要向核心傳遞命令行參數resume=/dev/hdaX(/dev/hdaX是系統中的交換分區),這樣系統就能夠很快恢復到關機時的狀態。
還有一個非正式的核心補丁可以實現STD:Software Suspend 2。該項目是一個快速發展的項目,設計上教swsusp有一些優勢,但是還沒有集成到核心正式發佈中,實現方式與swsusp基本相同。
雖然Linux提供了系統掛起的機制,但是執行上面的掛起操作不一定能夠成功。一方面,這些操作除了需要BIOS支持以外,還需要外圍硬件設備能夠兼容,即設備支持節電狀態,支持從節電狀態或斷電狀態恢復;另一方面,這些設備驅動必須能夠接收電源管理指令。目前,系統掛起的主要障礙就是那些還不太完善的驅動程序,如USB、顯卡、聲卡驅動等。
當然,現在Linux核心對系統掛起的支持還有待改進,主要表現在:
1 不支持SMP系統。
2 不支持大內存(>4G)。
3 核心中許多模塊需要增加電源管理的支持。
4 缺少上層配置程序。
不過以放心,所有的問題內核黑客們都能夠解決!
Linux電源管理_Generic PowerManager 之Suspend功能--(一)
蝸窩科技,www.wowotech.net。中:
Linux電源管理(6)_Generic PM之Suspend功能
http://www.wowotech.net/linux_kenrel/suspend_and_resume.html
Linux電源管理(10)_autosleep
http://www.tuicool.com/articles/MvUf6v
Linux電源管理(5)_Hibernate和Sleep功能介紹
http://www.wowotech.net/linux_kenrel/std_str_func.html