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 了沒

新詐騙嗎? 0970662557

0970662557 詐騙電話,說是台哥大,要送中華電信用戶 手機。 問我要宅配到哪裡...

2012年12月25日 星期二

android sdk : create oem addon.

OEM 變更 framework api 的比較好的作法是把 修改的 api 用另外的名子包裝起來。
這樣才不會影響到 framework 的 標準。

然後再把這些api wrapper 放到 addon,
再 build 一個 sdk-addon,讓customer 使用。


這個動作,參考 :
Android source 有 sample。
在 device/sample/

大部分的說明都是從這裡開始。
README.txt:
To build the add-on:
 make -j8 PRODUCT-sample_addon-sdk_addon


真的就是下command PRODUCT...
我本來以為 PRODUCT 要改成自己的 product,結果是 make 的 reserve word,
其實就像是 build 完整 image 一樣.. 後面的 'sample_addon 才是 product name。
sdk_addon 是 target。

product name 就是 printconfig 顯示的:
TARGET_PRODUCT=imx53_loco

build 完以後,follow 這一篇(http://stackoverflow.com/questions/14729793/configure-eclipse-to-use-my-own-android-sdk-framework-jar) 把 sdk 裝在 eclipse 中..

2012年12月24日 星期一

變更 usb 裝置的 access attribute

像 ttyUSB, hid,, wifi 之類的pnp 裝置。
標準 linux 系統好像是由 usbd _ rules 負責。

android 是由 init 負責。
ystem/root/init/ueventd.c

一開始,吃設定檔: get_hardware_name(hardware, &revision); ueventd_parse_config_file("/ueventd.rc"); snprintf(tmp, sizeof(tmp), "/ueventd.%s.rc", hardware); ueventd_parse_config_file(tmp);

所以設定檔就是 /ueventd.hardwarename.rc
以 imx5x 為例, hardwarename 是 freescale,所以是 ueventd.freescale.rc


這個設定檔的內容是:
/dev/ttymxc2              0600   bluetooth  bluetooth
/dev/pmem_gpu             0660   system     graphics
/dev/pmem_adsp*           0666   system     audio
/dev/snd/*                0664   system     audio
/dev/ttyUSB*              0640   radio      radio
/dev/ttyACM*              0640   radio      radio
/dev/video0               0660   system     camera
/dev/video1               0660   system     camera


所以,要把 ttyUSB 的權限改成所有program 都可以read/write,就要改:
/dev/ttyUSB*        0666   radio    radio

一個 thread 對 uart_port 作 select。
另一個 thread 在 suspend 時,會對 uart_port 作 close。

從一篇文章說, select 的 file 被 close 時,會立刻 return -1,error 是 EBADR。

所以就利用這個機制避免select 永久 block。

所以要注意的就剩下... 正常情況下 select return 後, read 到一半被close。

worklog -- 碎碎唸 - gps & suspend wakeup

gps port 使用 usb-serial。
所以 suspend 時要先 close,resume 後再 open。
-- 這部份最好作到 transparent。
framework jvm 部份可以由 ACTION_SCREEN_OFF/ON 知道 suspend/wakeup 的時機。
c standalone program 可以由 /sys/power/wait_fb_suspend/wakeup 知道。



但是,

usb-serial 在 resume 後,需要2 sec 的時間,krenel module 才會被 probe, ttyUSB 才會出現。
-- 這個比 ACTION_SCREEN_ON, wait_fb_wakeup 的時間晚。

gps 的應用有點問題:
ap 可以各自在 system wakeup 時,作 startNavigating, 和 enable gps 的動作。
不一定經由哪一個 api 來作。




所以.

suspend/wakeup 的 close, open 動作可以作在 jni, hardware lib 的部份:是 C code。
也可以坐在 framework 的 GpsLocationProvider.java 裡。

作在 C code 比較乾淨,可以作到讓上面的 framework 都不知道有作這個動作。

但是

他要自己經由 /sys/power/wait_fb_suspend.wakeup 來作。
這樣架構有點醜,

因為 jni code 是跟 framework code 是 link 在一起的, framework 的 LocationManager 已經有 monitor SCREEN_ON/OFF 了,
這裡還重作一次,而且是 monitor 不一樣的地方,
--- 所以很醜..

如果作在 LocationManger,會要處理一堆 ap 不統一的 , 在 wakeup 時的 enable/startNaigating 動作。
用一個 flag 來檔的話,code 的架構也很醜。


如果在 LocationManager 收到 SCREEN_ON/OFF 時,改 call jni function 作,
這樣,就要增加 jni interface -- 好像 break 了 framework 的 interface。




最後還是開 thread 在 libhardware 的 jni 裡... (醜1).

2012年12月19日 星期三

wait_event_xx, wake_up

以前在看 wait_event_xx 的時候就有一個疑問 wait_event(queue, condition)

這麼 cool,竟然可以任意寫 condition,而不是 function pointer。

後來看到,原來這是 macro (include/linux/wait.h) :
#define __wait_event(wq, condition) \ do { \ DEFINE_WAIT(__wait); \ \ for (;;) { \ prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE); \ if (condition) \ break; \ schedule(); \ } \ finish_wait(&wq, &__wait); \ } while (0)
所以可以寫 condition。

然後就忘了這個 macro。


幾年之後又看到後:這樣是一個 condition 的話,不就要一直檢查,不然 kernel 怎麼會知道這個 condition 相關的變數變更的時機。

後來又再看一次 macro,
才知道 prepare_to_wait( ) 後,就被掛起來了。
一定要有人叫起他,才有辦法再作 condition 檢查。

所以 誰叫醒他 (wq) ?
是 wake_up (wq...), wake_up(wq) 會叫醒所有 wq 裡面掛起的 task。

這樣 task 就會起來作 condition check。好決定是繼續睡,還是起來工作了。


所以 誰決定 那裡要 call wake_up( ) ?

--- 就是寫 wait_event_xx(wq,cond) 的人。

在 其他 task 中,讓 condition 變更時,就叫 wake_up,讓所有相關的 task 起來。

--- 所以這個 wait_event, wake_up 的同步機制,有點手動的感覺。

android : get suspend wakeup event in C code

在 android framework, app 中要知道 suspend/wakeup 的 時機,就收 SCREEN_OFF,SCREEN_OFF 這兩個 broadcast intent 就可以。

但是 C program (大部分是 daemon, service),要知道 suspend/wakeup 的時機,好像就沒有 signal 之類的方法。


base/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp

看到一個方法。

就是去讀 /sys/power/wait_for_fb_sleep, 和 wait_for_fb_wake

這兩個 sysfs 的 node 是 kernel/power/fbearlysuspend.c 提供的:
static ssize_t wait_for_fb_sleep_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { char *s = buf; int ret; ret = wait_event_interruptible(fb_state_wq, fb_state != FB_STATE_DRAWING_OK); if (ret && fb_state == FB_STATE_DRAWING_OK) return ret; else s += sprintf(buf, "sleeping"); return s - buf; }
其中有 wait_event_interruptible( ),
所以在 read /sys/power/wait_for_fb_sleep 時,會被 block 住,直到 fb_state != FB_STATE_DRAWING_OK 時,才會 恢復執行 。

看看 surfaceblinger 的 code:
static char const * kSleepFileName = "/sys/power/wait_for_fb_sleep"; ... ... fd = open(kSleepFileName, O_RDONLY, 0); do { err = read(fd, &buf, 1); } while (err < 0 && errno == EINTR); close(fd); LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno)); if (err >= 0) { sp<urfaceFlinger> flinger = mFlinger.promote(); LOGD("About to give-up screen, flinger = %p", flinger.get()); if (flinger != 0) { mBarrier.close(); flinger->screenReleased(0); mBarrier.wait(); } } 在 read( wait_for_fb_sleep ) 時,會被 block 住,直到 kernel run 到earlysuspend 後,才會繼續,

earlysuspend 的時機是在 call driver suspend 之前,所以在 logcat 可以看到:
InputManager-JNI 在 call android_server_PowerManagerService_goToSleep 後,會有:
libharware jni code, set_screen_state 0


然後就是
/D/SurfaceFlinger(2401): About to give-up screen, flinger = 0x8c830
對照上面的 code,就是 read( ) 之後。


SurfaceFlinger 在做完 suspend 要作的事後,就要等 wakeup 了,
所以接著的 code 就是: static char const * kWakeFileName = "/sys/power/wait_for_fb_wake"; ... ... fd = open(kWakeFileName, O_RDONLY, 0); do { err = read(fd, &buf, 1); } while (err < 0 && errno == EINTR); close(fd); LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno)); if (err >= 0) { sp<SurfaceFlinger> flinger = mFlinger.promote(); LOGD("Screen about to return, flinger = %p", flinger.get()); if (flinger != 0) flinger->screenAcquired(0); } return true;
馬上 read ( wait_for_fb_wake )

在 kernel 中,這個 attrib 是: ret = wait_event_interruptible(fb_state_wq, fb_state == FB_STATE_DRAWING_OK); if (ret && fb_state != FB_STATE_DRAWING_OK) return ret; else s += sprintf(buf, "awake"); return s - buf;
一樣,是等 fb_state == FB_STATE_DRAWING_OK

所以在 system logcat,libhardware power jni 設完 set_screen_state 1 後,
就是
D/SurfaceFlinger (2401): Screen about to return, flinger = 0x8c830




仿照 Surfaceflinger 的 code,這樣就可以得到 suspend/ wakeup 的時間:

2012年12月18日 星期二

GpsLocationProvider : Enable, Disable

一樣,是用 Binder Message 傳送。
private final class ProviderHandler extends Handler { @Override public void handleMessage(Message msg) { int message = msg.what; switch (message) { case ENABLE: if (msg.arg1 == 1) { handleEnable(); } else { handleDisable(); } break;

是用第一個 argument 來通知 Enable/Disable。

Enable 時,執行的是: private void handleEnable() { if (DEBUG) Log.d(TAG, "handleEnable"); if (mEnabled) return; mEnabled = native_init();
也就是 call native_init -- jni 的 function。

Disable 時,執行的是: private void handleDisable() { if (DEBUG) Log.d(TAG, "handleDisable"); if (!mEnabled) return; mEnabled = false; stopNavigating(); // do this before releasing wakelock native_cleanup();
也就是 call native_cleanup()


這兩個 native function 分別是: static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj) { const GpsInterface* interface = GetGpsInterface(env, obj); 就是 GetGpsInterface( ),沒有 call Open( )..
所以在 GetGpsInterface( ) 就要 open ..

然後 cleanup 是..
static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj) { const GpsInterface* interface = GetGpsInterface(env, obj); if (interface) interface->cleanup(); }
所以知道這是一個類似 Sigletone 的 code,每次 call interface api 時,都要由 GetGpsInterface( ) 取得 handle 後,再判斷是否OK, 再 call ref function。
static const GpsInterface* sGpsInterface = NULL; static const GpsInterface* GetGpsInterface(JNIEnv* env, jobject obj) { // this must be set before calling into the HAL library if (!sGpsInterface) { sGpsInterface = get_gps_interface(); if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) { sGpsInterface = NULL; return NULL; } } return sGpsInterface; }
GetGpsInterface function 其實是確保在第一次 new interface 時,會 call init( )




簡單的說,
  • Enable -- init
  • Disable -- cleanup

所以只要在 這兩個 native function 上實做 open, cloase com port 就可以

.. 但是看起來..又像是 start, stop.
這兩個分別對應到 startNavigating(), stopNavigating().

應該是作在 start(), stop()

kref_put , kernel object ref and release

問題出現在 usb-serial 上,當 suspend 時 device suspend -- disconnect
當 resume 時, 重新 probe。

結果.. 有些跳過順序: # first boot -- 0.1.2.3 # suspend and resume -- 0.1.3.4 跳過 2

發現 disconect 時,call usb_serial_put( ),
void usb_serial_put(struct usb_serial *serial) { kref_put(&serial->kref, destroy_serial); }

call 的就是 kref_put( ):
/** * kref_put - decrement refcount for object. * @kref: object. * @release: pointer to the function that will clean up the object when the * last reference to the object is released. * This pointer is required, and it is not acceptable to pass kfree * in as this function. * * Decrement the refcount, and if 0, call release(). * Return 1 if the object was removed, otherwise return 0. Beware, if this * function returns 0, you still can not count on the kref from remaining in * memory. Only use the return value if you want to see if the kref is now * gone, not present. */ int kref_put(struct kref *kref, void (*release)(struct kref *kref)) { WARN_ON(release == NULL); WARN_ON(release == (void (*)(struct kref *))kfree); if (atomic_dec_and_test(&kref->refcount)) { release(kref); return 1; } return 0; }

也就是 decrease refcount, 如果是 0, 就 call 傳進來的 function : release()

參考 kref_get( ) , 在 usb-serial port 有人 open 時,就會呼叫。
也就是說,一定要所有 open 的人都 close 了, refcount 才會是 0

2012年12月17日 星期一

request_irq, free_irq

一般(沒有特別依照 arch 作) 的 request_irq 是 implement 在
include/linux/interrupt.h
request_thread_irq 和 request_irq 互相為wrapper.-- 由 CONFIG_GENERIC_HARDIRQS 有否定義決定。
im5x 有 define,所以 request_irq( ) call request_thread_irq.

後者implement 在:
kernel/irq/manage.c
裡面也有 disable_irq( ) 和 disable_irq_nosync( ) 的實做。

基本上 disable_irq( ) 就是: disable_irq_nosync(); irq_sync( ); 其中 irq_sync( ) 就是 check 有沒有 pending 的 irq, 如果有,就去執行 handler。

2012年12月13日 星期四

prop : init value when system boot

Android 的 prop 系統。
是由 system/core/init/property_service.c 負責的,包括系統 prop 的初始,之後回答app 的詢問,設定/變更 prop。

init.c 的 main 啟動後,create, setup 好需要的 system folder。
之後,就先: void property_init(void) { init_property_area(); load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT); }

然後再 call
void start_property_service(void) { int fd; load_properties_from_file(PROP_PATH_SYSTEM_BUILD); load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT); load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE); /* Read persistent properties after all default values have been loaded. */ load_persistent_properties();
所以 prop 讀取,設定的順序是:
  • PROP_PATH_RAMDISK_DEFAULT : /default.prop
  • PROP_PATH_SYSTEM_BUILD : /system/build.prop
  • PROP_PATH_SYSTEM_DEFAULT : /system/default.prop
  • PROP_PATH_LOCAL_OVERRIDE : /data/local.prop
  • PERSISTENT_PROPERTY_DIR/persist.*
從 /data/local.prop 可以知道,如果是自己想要更改 system 的 prop,
應該要放在 /data/local.prop,這樣使用 factory reset 後,自己的設定會被刪掉。
真正的恢復出廠狀態。

要是想要增加自己的 prop 設定檔,可以修改 property_service.c ,
y 增加一個 load_properties_from_file(PROP_PATH_MYPROP);

* 以上的 path 定義在 /bionic/libc/include/sys/_system_properties.h



現在產品的作法是改 Makefile..

2012年12月12日 星期三

Messge.java

Message.java

在這個 class 裡,實做了一個小小的 Messge cache.

當你 new 一個 Messge,用完,把他 recycle,不是 free 掉,
這樣,下一個需要 new Message 時,就直接從 recycle pool 拿,不用 free 掉。

2012年12月10日 星期一

android, Wifi Service -- code reading,

SystemServer.java 啟動 connectivity = ConnectivityService.getInstance(context); ServiceManager.addService(Context.CONNECTIVE_SETVICE,connectvity); ConnectivityService 啟動時,會從 resource load 進這個 device 所有的 NetworkAttributes[]


然後一一將他門生出來..例如 Wifi
case ConnectivityManager.TYPE_WIFI: Slog.d(TAG, "Starting Wifi Service."); WifiStateTracker wst = new WifiStateTracker(context, mHandler); WifiService wifiService = new WifiService(context, wst); ServiceManager.addService(Context.WIFI_SERVICE, wifiService); wifiService.startWifi(); mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst; wst.startMonitoring(); break;


WifiStateTracker 被傳入 WifiServer 中,同時也被 ConnectivityService 紀錄在要照顧的 mNetTrackers[] 陣列中。


不直接在 WifiServer 中實做 WifiStateTracker (介面?) 的原因大概是因為 WifiStateTracker 不是 interface,而是 Abstract Class。
又 java 不允許多重繼承的原因。
而 NetworkStateTracker 又是一個 abstract class, 不是 interface。

.. 問題反而變成 NetworkStateTracker 為什麼是 abstract class, not interface


2012年12月7日 星期五

Enable/Disable Wifi 最後是call WifiService.java -- setWifiEnabledBlocking()

這是private function ,只有 WifiHandler 使用:
  • MESSAGE_ENABLE_WIFI
  • MESSAGE_DISABLE_WIFI
以上都是靠 sendEnableMessage 傳遞。
-- 也是 private
call sendEnableMessage( ) 的 有:
  • private : doUpdateWifiState
  • public : setWifiEnabled

doUpdateWifiState( ) 一樣,也是在 message handler MESSAGE_UPDATE_STATE 中呼叫,
--private : updateWifiState()

updateWifiState( ) 在:
  • Broadcast Receiver: ACTION_AIRPLANE_MODE_CHANGED
  • Broadcast Receiver: ACTION_TETHER_STATE_CHANGED
  • Receiver SCREEN_OFF inteent
  • private : acquireWifiLockLocked
  • private : releaseWifiLockLocked

2012年12月6日 星期四

D/WifiService( 2388): sendEnableMessae false
D/WifiService( 2388): MESSAGE_DISABLE_WIFI
D/WifiService( 2388): setWifiEnabledBlockingdisable
I/wpa_supplicant( 2739): wlan0: CTRL-EVENT-TERMINATING - signal 15 received
I/wpa_supplicant( 2739): wlan0: CTRL-EVENT-TERMINATING - signal 0 received
V/WifiMonitor( 2388): Event [CTRL-EVENT-TERMINATING - signal 15 received]
D/WifiStateTracker( 2388): notifySupplicantLost
D/WifiStateTracker( 2388): EVENT_SUPPLICANT_DISCONNECT
I/wpa_supplicant( 2739): wlan0: CTRL-EVENT-STATE-CHANGE id=1 state=0 BSSID=00:00:00:00:00:00
D/        ( 2388): enter Cmd: L
D/WifiStateTracker( 2388): updateBatteryWorkSourceLocked
V/WifiStateTracker( 2388): Connection to supplicant lost
D/NetworkStateTracker( 2388): setDetailed state, old =CONNECTED and new state=DISCONNECTED
D/WifiStateTracker( 2388): Reset connections and stopping DHCP
D/ConnectivityService( 2388): NetworkStateTracker.EVENT_STATE_CHANGED
D/ConnectivityService( 2388): ConnectivityChange for WIFI: DISCONNECTED/DISCONNECTED
D/ConnectivityService( 2388): getMobileDataEnabled returning true
D/ConnectivityService( 2388): wifi disc, recover mobile data
D/ConnectivityService( 2388): enableMobileDataAgain
D/ConnectivityService( 2388): getMobileDataEnabled returning true
D/WifiService( 2388): stopSupplicant
D/ConnectivityService( 2388): Attempting to switch to mobile
D/ConnectivityService( 2388): Attempting to switch to ETHERNET
D/Tethering( 2388): MasterInitialState.processMessage what=3
D/MYGPS   ( 2388): gps_get_extension(agps_ril)
D/ConnectivityService( 2388): Attempting to switch to PPPOE
D/dhcpcd  ( 2746): received SIGTERM, stopping
D/dhcpcd  ( 2746): deleting route 0.0.0.0/0 via 192.168.204.254
D/dhcpcd  ( 2746): deleting IP address 192.168.204.180/24
D/dhcpcd  ( 2746): executing `/system/etc/dhcpcd/dhcpcd-run-hooks', reason STOP
D/ConnectivityService( 2388): enable again : Mobile data state: DISCONNECTED
init: untracked pid 2746 exited
init: untracked pid 2739 exited
D/WifiStateTracker( 2388): Disabling interface
D/WifiService( 2388): resetConnection
I/wlan_tool( 2793): wifi unloading
debug_hdr_ptr: 0x5429a0
 Attempting to reset target on instance destroy....
W/Netd    ( 2326): No subsystem found in netlink event
D/NetlinkEvent( 2326): Unexpected netlink message. type=0x11
E/Tethering( 2388): attempting to remove unknown iface (wlan0), ignoring
D/WifiService( 2388): unloadDriver
D/WifiService( 2388): Wakelock disable

2012年12月5日 星期三

source flow -- key, interceptKeyBeforeQueueing

NativeInputManager 是 JNI library
屬於 SystemServer 的一部分。

SystemServer 在 JNI_OnLoad 時, 就會call NativeInputManager 的 一堆 initital, start, register function .

nativeInit

NativeInputManager 物件生成時,會 new 一個 EventHub 物件,並且傳入 InputManager 的生成function 中。(同時也把自己 NativeInputManager 當作參數傳入)
eventHub = new EventHub(); mInputManager = new InputManager(eventHub, this, this);
nativeStart

就是開始執行 InputManager 的 Thread:
gNativeInputManager->getInputManger()->start();

所以實際的 Thread 是 InputManager( ) 的 Thread.

-- 跳 N 步 --

這個 Thread 執行的 code 就是: void InputReader::loopOnce(){ mEventHub->getEvent(& rawEvent); process(& rawEvent); } process 就會找到 event 來自 KeyboardInputMapper Device,請他 run process
就是 processKey( ),

然後就是getDispatcher, notifyKey
mPolicy, interceptKeyBeforeQueueing


mPolicy 是在 InputDispatcher( ) 生成時,傳入的 InputDispatcherPolicyInterface 參數物件。
也就是當初傳入 InputManager 生成函數 的 NativeInputManager 物件 (他有繼承 InputDispatcherPolicyInterface).


所以由 inputReader 的 Thread 由 EventHub 取得 linux kernel input 的資料,
一路交給 NativeInputManager 的 interceptKeyBeforeQueueing( ) 來處理。

這一整段,都沒有用到 java code


在 NativeInputManager 的 interceptKeyBeforeQueueing( ) 裡面,才有用 java call back function 去 call InputManager.java 的 function.



那個 power key 的處理,就是在 NativeInputManager 的 interceptKeyBeforeQueueing( ) 處理的。

他先把 key 交給 java 的 .. pwrkey_event_handler_Keyup D/InputReader( 2240): loopOnce D/InputReader( 2240): consumeEvent D/InputReader( 2240): process D/InputReader( 2240): processKey D/InputDispatcher( 2240): notifyKey D/InputManager-JNI( 2240): interceptKeyBeforeQueueing -- about to call callback function W/System.err( 2240): java.lang.Throwable: stack dump W/System.err( 2240): at java.lang.Thread.dumpStack(Thread.java:577) W/System.err( 2240): at com.android.internal.policy.impl.PhoneWindowManager.interceptKeyBeforeQueueing(PhoneWindowManager.java:1868) W/System.err( 2240): at com.android.server.WindowManagerService$InputMonitor.interceptKeyBeforeQueueing(WindowManagerService.java:5324) W/System.err( 2240): at com.android.server.InputManager$Callbacks.interceptKeyBeforeQueueing(InputManager.java:385) W/System.err( 2240): at dalvik.system.NativeStart.run(Native Method) D/InputManager-JNI( 2240): interceptKeyBeforeQueueing WM_ACTION_GO_TO_SLEEP D/PowerManagerService-JNI( 2240): android_server_PowerManagerService_goToSleep request_suspend_state: mem (0->3) at 81038317625 (1970-01-02 07:31:38.609208250 UTC) mxc_ipu mxc_ipu: Channel already disabled 10 mxc_ipu mxc_ipu: Channel already uninitialized 10 I/power ( 2240): *** set_screen_state 0 D/SurfaceFlinger( 2240): About to give-up screen, flinger = 0x1dfb38 PM: Syncing filesystems ... done. PhoneWindowManager.java 在return 一個包含 ACTION_GO_TO_SLEEP 的 flag.
然後 NativeInputManager.c 處理這個 flag, call android_server_PowerManagerService_goToSleep

android framework 中,jni 多使用 自訂 mapping 的方式 (自己 implement JNI_OnLoad( ), 註冊 java - C function name 對應)

在 framework/base 下 cgrep 一下 JNI_OnLoad 就有很多。

framework 下的一堆 service

2012年12月4日 星期二

wifi 控制的底層好像是 hardware/libhardware_legacy/wifi ..
跟著 driver loading 的 code..

wifi.c : wifi_load_driver()

framework/base/core/jni/android_net_wifi_Wifi.cpp : static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject clazz) { return (jboolean)(::wifi_load_driver() == 0); } ... { "loadDriver", "()Z", (void *)android_net_wifi_loadDriver }, ... 這段 在 java 的 介面是: ./wifi/java/android/net/wifi/WifiNative.java:45: public native static boolean loadDriver();
在 ./wifi/java/android/net/wifi/WifiStateTracker.java 中再包裝一次。

然後就是 ./services/java/com/android/server/WifiService.java 呼叫 WifiStateTracker:
private boolean setWifiEnabledBlocking(boolean enable, boolean persist, int uid) {

這 funciton 是在 WifiService 的 handleMessge 處理的 public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_ENABLE_WIFI: setWifiEnabledBlocking(true, msg.arg1 == 1, msg.arg2); if (mWifiWatchdogService == null) { mWifiWatchdogService = new WifiWatchdogService(mContext, mWifiStateTracker); } sWakeLock.release(); break; case MESSAGE_START_WIFI: reportStartWorkSource(); mWifiStateTracker.setScanOnlyMode(msg.arg1 == WifiManager.WIFI_MODE_SCAN_ONLY); mWifiStateTracker.restart(); mWifiStateTracker.setHighPerfMode(msg.arg1 == WifiManager.WIFI_MODE_FULL_HIGH_PERF); sWakeLock.release(); break;

對應的function : private void sendEnableMessage(boolean enable, boolean persist, int uid) { Message msg = Message.obtain(mWifiHandler, (enable ? MESSAGE_ENABLE_WIFI : MESSAGE_DISABLE_WIFI), (persist ? 1 : 0), uid); msg.sendToTarget(); } private void sendStartMessage(int lockMode) { Message.obtain(mWifiHandler, MESSAGE_START_WIFI, lockMode, 0).sendToTarget(); }
suspend 時,好像會送 SCREEN_OFF

為了避免有些 ap 沒有處理 SCREEN_OFF
可以在 處理 suspend 的地方,改為 launch dialog/activity,讓所有 activity 退出,
然後再作 suspend。

2012年12月3日 星期一

java native interface : jni

Java call c function 的歸定。
就是在 C 寫 function 讓 java call

要作 java call C function ,有兩種方法:
  • 利用javah 產生的 header,實做 c function 。 -- 這是用 java vm 的標準 mapping 方式
  • 自己在 c function 寫 JNI_OnLoad( ), 在裡面寫明 mapping 方式。

ref:
  • http://www.xyplot.com/jni.simple.htm
  • http://hi.baidu.com/jfojfo/item/1011ac02d8e0cd813d42e27b
  • http://en.wikipedia.org/wiki/Java_Native_Interface


第一種方法,javah, 標準方式

在 Wiki 寫得很清楚,有嚴格的function name , argument mapping 的規定,
甚至 c 的 header file 都是由 java toolchain 產生的。

可以follow wiki 的 example 作法。

步驟是
  • 先寫 java code,c 的function 要加上 native
  • 用 javac compile 出 class
  • 用 javah 從 class 產生 c 的 header
  • follow c header,新開一個 c source, implement function
  • 用 gcc compile c files


照著作時發生兩個問題:

1. compile c code 時,出現 error
error: jni_md.h: No such file or directory
這個google 一下就可以知道,是 jni_md.h 的位置,是在 include/linux 下,不是 include 下,所以把 include/linux 也加到 include path 就可以。

gcc -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -shared libHelloWorld.c -o libHelloWorls.so
然後是..

2.-fPIC

relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
解決方法就和 error 的說明一樣,compile option 加 -fPIC就可以:
gcc -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -shared libHelloWorld.c -o libHelloWorld.so 這樣就可以了。

標籤

網誌存檔