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 就是 mAcOnlineBatteryManager 提供的 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 . 那請問一下, 你有解法嗎 ? 可以幫我幫我嗎? 要改那一段程式呢?
張貼留言