ubuntu 在 R40e 上 還有 Debian 在 Sempron 2600 上

2012年12月28日 星期五

suspend/resume 時 disable/enable Wifi.

Wifi 要修改成..suspend 前關閉,resume 後打開。

Android 原來的作法是 suspend 時,wifi module 也進入 wifi suspend mode。
系統 wake up 時,wifi 回到 full power mode。


這一項還跟 Wifi 的 Advance setting 有關,可以設定 suspend 時,wifi 是不是要開啟。
如果選不要,suspend 時,wifi moduel 會進入 idle mode (好像也是 suspend mode)

另外,會開啟 wifi module 的 wow (wake on wireless) -- wifi 有動作時會 wakeup 系統(?).

以上這些功能都要拿掉。

所以...

1.先改 WifiService.

原來 ACTION_SCREEN_ON/OFF 的 broadcastreceiver 在 wifi disable 就被 unregister 了,
enable 時才重新 register。

這樣不行,這樣 disable 後就收不到 SCREEN_ON 了。

所以修改一下,在 WifiService( ) Initiate 時就 register,在 disable/enable 時不做。
讓 SCREEN_ON/OFF 的 broadcastreceiver 永遠存在。


2.修改原有 mDeviceIdle 的行為

原來 mDeviceIdle 這個 private variable 會讓 wifi 進入 suspend,
現在改掉,讓 mDeviceIdle = true 時,會 disable wifi。

這段 code 在 WifiService 的 doUpdateWifiState( )

原來 : boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode;

加上.. boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode && !mDeviceIdle;


3. SCREEN_ON,OFF 的 action

原來是設一個 timer , delay,之後再把 wifi 進入 idle。
現在直接進入 idle。
-- follow MESSAGE_DEVICE_IDLE 的 code。


這樣做完後,有時候會發生 unload driver 還沒完全結束,就 suspend 了,然後 wakeup 還繼續作 suspend,
這樣就和 SCREEN_ON 的 動作衝突,導致 wakeup 時 load module fail。

所以參考 stop wifi 的 code,用 PowerManager 的 wakelock 來防止 系統太早 suspend.

就是在 doUpdateWifiState( ),最後,sendEnableMessage( ) 時,設定一個 3 sec 的 wakelock: sDriverStopWakeLock.acquire(); sWakeLock.acquire(); sendEnableMessage(false, false, ....); mWifiHandler.sendEmptyMessageDelayed(MESSAGE_RELEASE_WAKELOCK,3000); 其實這是猜 unload module 的時間不會超過 3 sec, 其實有點不好。

這樣做完後, suspend/wakeup 10 多次後,偶而會出現 Nullpointer Exception,
指出發生在 WifiStateTracker.java 裡..

+ synchronized (this) { if (mDhcpTarget != null) { + Log.d(TAG,"setCancelCallback"); mDhcpTarget.setCancelCallback(true); + Log.d(TAG,"removeMessges"); mDhcpTarget.removeMessages(EVENT_DHCP_START); } + }
猜是 mDhcpTarget 在中間被變更 release 掉了,所以才會有這個 Exception,
所以在這段 code 加上 synchronized( ) 。

同樣,在 release mDhcpTarget 的 code,也用 synchroinzed 包起來: // When supplicant dies, kill the DHCP thread + synchronized (this) { if (mDhcpTarget != null) { + Log.d(TAG,"set mDhcpTarget to null"); mDhcpTarget.getLooper().quit(); mDhcpTarget = null; } + }

這樣改改完,好像就沒發生了...

測試中...


總結大概是:
  • SCREEN_ON/OFF
  • 等 unload 完成
  • mDhcpTarget 的同步

測試結果是 fail,最後好像還是沒有 unload 完成就 suspend 了..
所以用 delay 的方式還是不可行,要用同步。
所以修改 wlan_tool,在 rmmod 時加上 wakelock:
 echo rmmodar6000 > /sys/power/wake_lock
 rmmod ar6000
 echo rmmodar6000 > /sys/power/wake_unlock

繼續測試..

還是 fail...



查 log,好像是在 wakeup 後,load driver 時,剛好跟 sdio host driver 衝突。

所以修改 wlan_tool, 的 loaddriver,sleep 2。

之後測試一個晚上 OK (on/off 次數超過前面幾次 fail 的次數)。
但是用 sleep 的方式不好,應該要 check sysfs 看看 sdio driver ready 了沒

沒有留言:

標籤

網誌存檔