ubuntu 在 R40e 上 還有 Debian 在 Sempron 2600 上

2011年5月4日 星期三

Worklog - android suspend

在 driver/input/keyboard/mxc_pwrkey.c 有 powerkey 專用的 keyboard driver。
2.6 的 driver, device architecture.

device 的部份在
arch/arm/mach-mx5/device.c
device 的 data 在
arch/arm/mach-mx5/mx51_babbage.c

大概就是 ..

PM_SUSPEND_XX 定義在: linux/suspend.h: #define PM_SUSPEND_ON ((__force suspend_state_t) 0) #define PM_SUSPEND_STANDBY ((__force suspend_state_t) 1) #define PM_SUSPEND_MEM ((__force suspend_state_t) 3) #define PM_SUSPEND_MAX ((__force suspend_state_t) 4) 對應的 /sys/power/state 內容字串定義在 kernel/power/suspend.c const char *const pm_states[PM_SUSPEND_MAX] = { #ifdef CONFIG_EARLYSUSPEND [PM_SUSPEND_ON] = "on", #endif [PM_SUSPEND_STANDBY] = "standby", [PM_SUSPEND_MEM] = "mem", };
在 kernel/power/main.c 有 compare, dispatch 的 code:
state_store( ) for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) { printk("state:%d %s\n",state,pm_states[state]); if (*s && len == strlen(*s) && !strncmp(buf, *s, len)){ printk("matched %d !!\n",state); break; } }
kernel/power 負責 suspend/wakeup 的流程,提工一組 function,讓其他 driver 能夠register 自己的 handler,在 suspend 前,會被一一呼叫到 : register_early_suspend.
register_late_suspend.

奇怪的是,dmesg的 log 只能看到 early_suspend( ) ,沒有辦法trace 到 early_suspend 之後的 printk message。

在 kernel/printk.c 中有 boot argument : console_suspend_enabled1變數,是用
__setup("no_console_suspend", console_suspend_disable); 和 no_console_suspend 關聯在一起。


好像有人鎖住wake_lock,,所以睡不下去...
wake_lock. wake_unlock..


看 log 是
wake_lock : PowerManagerService,
wake_unlock : alarm

印出上面 log 的 code 是在:
kernel/power/wakelock.c - wake_lock_internal()
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]); } 所以證明 lock 的人是 alarm 和 PowerMangerService.
用 cgrep wake_lock_init 可以找出 alarm 是 driver/rtc/alarm-dev.c。
但是找不出 PowerManagerService 是哪裡來的




"base/services/java/com/android/server/PowerManagerService.java" line 610
有: private void updateWakeLockLocked() { if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) { // keep the device on if we're plugged in and mStayOnWhilePluggedIn is set. mStayOnWhilePluggedInScreenDimLock.acquire(); mStayOnWhilePluggedInPartialLock.acquire(); } else { mStayOnWhilePluggedInScreenDimLock.release(); mStayOnWhilePluggedInPartialLock.release(); } } 證明 充電時是會保持 wakeup...

那個 acquire 是 PowerManagerService private class UsynchronizedWakeLock( ) 實做的 function. public void acquire() { if (!mRefCounted || mCount++ == 0) { long ident = Binder.clearCallingIdentity(); try { PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken, MY_UID, mTag); mHeld = true; } finally { Binder.restoreCallingIdentity(ident); } } } 所以是用 Binder 作的.

在 PowerManagerService 中的 WakeLock , Binder 操作,實做了一個 private class WakeLock: private class WakeLock implements IBinder.DeathRecipient {


原來 WakeLock 幾乎是 Android 的 PM (power management) 的代名詞。
一些 ref:

所以 cat /proc/wakelock 可以看到所有 wakelock 的統計資料

使用 dumpsys 可以列出 Android System 的狀態 (所有 Service 裡面有實做 dump( ) 的,都會被呼叫).
adb shell dumpsys | less就可以search "Power Manager State"

以下是 dumpsys , Battery Service 的部份: DUMP OF SERVICE battery: Current Battery Service state: AC powered: false USB powered: false status: 1 health: 0 present: false level: 0 scale: 100 voltage:0 temperature: 0 technology: null 對應的 code 是:
BatteryService.java :469 dump( ) pw.println("Current Battery Service state:"); pw.println(" AC powered: " + mAcOnline); pw.println(" USB powered: " + mUsbOnline); pw.println(" status: " + mBatteryStatus); pw.println(" health: " + mBatteryHealth); pw.println(" present: " + mBatteryPresent); pw.println(" level: " + mBatteryLevel); pw.println(" scale: " + BATTERY_SCALE); pw.println(" voltage:" + mBatteryVoltage); pw.println(" temperature: " + mBatteryTemperature); pw.println(" technology: " + mBatteryTechnology); 所以 AC powered 就是 mAcOnline

BatteryManager 提供的 isPowered(),是根據以下狀態: final boolean isPowered() { // assume we are powered if battery state is unknown so the "stay on while plugged in" option will work. return (mAcOnline || mUsbOnline || mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN); } 根據 dumpsys 的內容, mAcOnline = false, mUsbOnline = false, mBatteryStatus = 1.

BatteryManager.BATTERY_STATUS_UNKNOWN 的宣告:
/base/core/java/android/os/BatteryManager.java:89: public static final int BATTERY_STATUS_UNKNOWN = 1; 所以上述 isPowered( ) return 1 的原因是 mBatteryStatus.

=======> 把他 Mark 掉?

但是實際上是 Powered 沒錯,是不應該因為 Powered 就 stayOn,所以應該要改 PowerManagerService..(?)

dumpsys wakeup state 的 PowerManagerService 內容:
DUMP OF SERVICE power: Power Manager State: mIsPowered=true mPowerState=3 mScreenOffTime=327973 ms mPartialCount=1 mWakeLockState= mUserState=SCREEN_BRIGHT_BIT SCREEN_ON_BIT mPowerState=SCREEN_BRIGHT_BIT SCREEN_ON_BIT mLocks.gather= mNextTimeout=12961205 now=12948606 12s from now mDimScreen=true mStayOnConditions=0 mStayOnCondition=0.

ref PowerManagerService.java 610:
private void updateWakeLockLocked() { if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) { // keep the device on if we're plugged in and mStayOnWhilePluggedIn is set. mStayOnWhilePluggedInScreenDimLock.acquire(); mStayOnWhilePluggedInPartialLock.acquire(); } else { mStayOnWhilePluggedInScreenDimLock.release(); mStayOnWhilePluggedInPartialLock.release(); } } 所以不是這一段 code lock 住。

繼續看 dumpsys :
mBroadcastWakeLock=UnsynchronizedWakeLock(mFlags=0x1 mCount=0 mHeld=false) mStayOnWhilePluggedInScreenDimLock=UnsynchronizedWakeLock(mFlags=0x6 mCount=0 mHeld=false) mStayOnWhilePluggedInPartialLock=UnsynchronizedWakeLock(mFlags=0x1 mCount=0 mHeld=false) mPreventScreenOnPartialLock=UnsynchronizedWakeLock(mFlags=0x1 mCount=0 mHeld=false) mProximityPartialLock=UnsynchronizedWakeLock(mFlags=0x1 mCount=0 mHeld=false) mProximityWakeLockCount=0 內部lock 變數都不是在 mHeld 狀態。

還有:
mLocks.size=1: PARTIAL_WAKE_LOCK 'GpsLocationProvider' activated (minState=0, uid=1000, pid=2213) mPokeLocks.size=0: 有一個 mLock 是 activated..

使用者是: ./base/location/java/com/android/internal/location/GpsLocationProvider.java:255: private final static String WAKELOCK_KEY = "GpsLocationProvider"; 查GpsLocationProvider.java.. // Create a wake lock PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); .... ... // beware, the events can come out of order if ((mNavigating || mEngineOn) && !mWakeLock.isHeld()) { if (DEBUG) Log.d(TAG, "Acquiring wakelock"); mWakeLock.acquire(); } 所以到 Setting -- Location & Security ,把 GPS 功能關閉.
==> 結果一樣,無法 suspend。
用 dumpsys 看, PowerManagerService 的 mLock.size 還是 1.

重新開機.. dumpsys 看.. mLock.size 是 0.

將 CPU_SUSPEND_IN 拉 Low,, 還是無法 suspend,但是 suspend 後的log 變成: early_suspend++ early_suspend: call handlers wake_lock: PowerManagerService, type 0 mxcfb_early_suspend wake_lock: PowerManagerService, type 0 wake_lock: PowerManagerService, type 0 early_suspend: sync wake_lock: PowerManagerService, type 0 wake_unlock: PowerManagerService WAKE_LOCK_SUSPEND has_lock:-1 wake_unlock: main WAKE_LOCK_SUSPEND has_lock:-1 active wake lock android_usb wake lock mmc_delayed_work, expired early_suspend-- wake_lock: alarm, type 0, timeout 5.000 wake_lock: PowerManagerService, type 0 wake_unlock: alarm WAKE_LOCK_SUSPEND has_lock:-1 wake_unlock: PowerManagerService WAKE_LOCK_SUSPEND has_lock:-1 wake_lock: alarm, type 0, timeout 5.000 wake_lock: PowerManagerService, type 0 wake_unlock: alarm WAKE_LOCK_SUSPEND has_lock:-1 wake_unlock: PowerManagerService WAKE_LOCK_SUSPEND has_lock:-1 wake_lock: alarm, type 0, timeout 5.000 wake_lock: PowerManagerService, type 0 wake_unlock: alarm WAKE_LOCK_SUSPEND has_lock:-1 最後的 PowerMangerService 有 lock - unlock,所以應該不是 PowerManagerService。
往前看,有
active wake lock android_usb 猜是usb 連線,把 usb 斷開後, log 出現
suspend++ suspend: enter suspend 然後console 失效,wakeup 拉 high 也無法 wakeup.
重新開機,usb 不連接, gps default off, 開機後把 CPU_SUSPEND_IN 拉 low.. 進入 suspend:
state_store mem *p (null), len:3 state:0 on state:1 standby state:2 (null) state:3 mem matched 3 !! request_suspend_state: 3 request_suspend_state: mem (0->3) at 45862462003 (1970-01-01 00:00:42.936891626 UTC) put early_suspend_work into suspend_work_queue early_suspend++ early_suspend: call handlers mxcfb_early_suspend wake_lock: PowerManagerService, type 0 wake_lock: PowerManagerService, type 0 wake_lock: PowerManagerService, type 0 early_suspend: sync wake_lock: PowerManagerService, type 0 wake_unlock: PowerManagerService WAKE_LOCK_SUSPEND has_lock:-1 wake_unlock: main expired wake lock mmc_delayed_work WAKE_LOCK_SUSPEND has_lock:0 early_suspend-- suspend++ suspend: enter suspend pm_suspend suspend: enter_state PM: Syncing filesystems ... done. suspend_prepare Freezing user space processes ... (elapsed 0.02 seconds) done. Freezing remaining freezable tasks ... (elapsed 0.01 seconds) done. PM: Entering mem sleep suspend_devices_and_enter suspend_console++ Suspending console(s) (use no_console_suspend to debug) 電流由 1.2 A 降為 0.75A。

把 CPU_SUSPEND_IN 拉 High 後,resume.
suspend_console-- dpm_suspend_start PM: suspend of devices complete after 1235.924 msecs suspend_enter suspend wp cpu=800000000 dpm_suspend_noirq power_suspend_late return 0 PM: late suspend of devices complete after 0.661 msecs mx5_suspend_enter PM: early resume of devices complete after 0.559 msecs ppwrkey_event_handler_Keydown pwrkey_event_handler_Keyup IPU DMFC NORMAL mode: 1(0~1), 5B(4,5), 5F(6,7) wakeup wake lock: mmc_delayed_work wake_lock: mmc_delayed_work, type 0 wake_lock: mmc_delayed_work, type 0 ppwrkey_event_handler_Keyup ppwrkey_event_handler_Keydown pwrkey_event_handler_Keyup pwrkey_event_handler_Keydown wake_lock: mmc_delayed_work, type 0, timeout 0.500 wake_lock: mmc_delayed_work, start expire timer, 50 wake_unlock: mmc_delayed_work WAKE_LOCK_SUSPEND has_lock:0 wake_unlock: mmc_delayed_work, stop expire timer PM: resume of devices complete after 188.103 msecs PM: Finishing wakeup. suspend_finish Restarting tasks ... wake_lock: KeyEvents, type 0 wake_unlock: KeyEvents WAKE_LOCK_SUSPEND has_lock:0 wake_lock: KeyEvents, type 0 wake_lock: PowerManagerService, type 0 state_store on *p (null), len:2 state:0 on matched 0 !! wake_unlock: KeyEvents WAKE_LOCK_SUSPEND has_lock:-1 wake_lock: KeyEvents, type 0 done. suspend: exit suspend, ret = 0 (1970-01-01 00:04:44.101005456 UTC) suspend++ active wake lock KeyEvents active wake lock PowerManagerService request_suspend_state: 0 request_suspend_state: on (3->0) at 124256152052 (1970-01-01 00:04:44.115987198 UTC) wake_lock: main, type 0 put late_resume_work into suspend_work_queue wake_lock: PowerManagerService, type 0 suspend: abort suspend late_resume: call handlers wake_lock: PowerManagerService, type 0 wake_unlock: KeyEvents WAKE_LOCK_SUSPEND has_lock:-1 wake_lock: KeyEvents, type 0 mxc_ipu mxc_ipu: Channel already disabled 9 mxc_ipu mxc_ipu: Channel already uninitialized 9 wake_lock: PowerManagerService, type 0 wake_unlock: KeyEvents WAKE_LOCK_SUSPEND has_lock:-1 late_resume: done Ending connection mmc1: Starting deferred resume Ending connection mmc1: Deferred resume completed 螢幕出現 mode select,按下 HOME Key, 恢復。



所以: GPS ON 和 USB connect 會讓 系統無法 suspend.

1 則留言:

大頭鰱 提到...

版主你好!
我現在有一個很大的困擾, 就是我們開發的是android 2.2 我把 GPS的功能打開後. 就是點了 google map or gps test 的程式後再離開, 發現無法進入 suspend mode. 我看到你的文章有寫. GPS On 會使的系統無法進入 suspend mode . 那請問一下, 你有解法嗎 ? 可以幫我幫我嗎? 要改那一段程式呢?

標籤

網誌存檔