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 這樣就可以了。

2012年11月30日 星期五

touch interface in framework

跟 kernel 介面 (/dev) 銜接的 code 好像是 /framework/base/libs/ui/EventHub.cpp

先 scanDir( ),把 /dev/input/ 下所有有效的 file 列出。
然後一一用 openDevice( ) 打開,看看屬於哪一種 input 類型 (keyboard, trackball, touch pad/singl,multi..)
然後決定要不要 monitor


在 frameworks/base/services/java/com/android/server/InputManager.java

kernel 所有的 input driver 都會在 /dev/input/event?

可以用 read



ref:
  • http://ray2501.blogspot.tw/2012/08/keyboard-and-touch-panel.html
  • http://download.farsight.com.cn/download/pdf/Farsight091114-linux-1.pdf
  • http://source.android.com/tech/input/touch-devices.html
  • http://www.kernel.org/doc/Documentation/input/multi-touch-protocol.t
  • http://blog.csdn.net/liwendovo/article/details/7903635
  • http://www.cnblogs.com/tnxk/archive/2012/10/26/2741326.html

2012年11月27日 星期二

platform-device, plat-form-drier : part II

以前寫過一篇: platform-device, platform-driver.

device 就是 hardware,
driver 就是 software。

hardware 是說 memory map 位址區域, irq number。
software 是說 裝置的啟動,偵測,操作,移除 等等動作。


系統上,同一個裝置可以有很多個,
例如:多組 eMMC port。

因為eMMC 的動作都一樣,所以只要寫一組 platform-driver 的 code。
但是每一個 eMMC port mapping 的 DMA, memory map region, irq, hardware detect pin 都不一樣。 所以每一個 eMMC port 都要有一個 platform-device。

platform-device 和 platform-driver 利用 name 來關連,
註冊時,kernel 會比較 name 字串。

所以當 platform-driver 註冊時,kernel 會找是不是有.name 的 device 已經註冊,
如果有找到,就呼叫 platform-driver 的 probe function。
並且把找到的 platform-device 當作參數傳給 probe( )。

2012年11月26日 星期一

繼續:suspend/wakeup, gpio state

iMX51 有 GPIO1-4 ,4 組 gpio port,每個 port 有 32 pin 。

GPIO 控制暫存器的位址是在:
  • 73F8-4000 : GPIO1
  • 73F8-8000 : GPIO2
  • 73F8-C000 : GPIO3
  • 73F9-0000 : GPIO4

2012年11月23日 星期五

linux , suspend/resume driver and kernel

driver/base/sys.c:
int sysdev_suspend(pm_message_t state) { .... list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { if (drv->suspend) { ret = drv->suspend(sysdev, state);
就 一一把 registered driver 的 suspend( ) 呼叫一次 (如果有的話)。

這個 function 是 kernel/power/suspend.c 的 suspend_enter( ) 呼叫的。
是在 kernel/printk.c 的 suspend_console() 之後,

所以printk 已經印不出 message 了。

如果要看到 message,就要在 boot argument 加上 no_console_suspend=1

2012年11月19日 星期一

iMX51 suspend 最後(底層)的 code

suspend 時,最後 callmx5_suspend_enter( )
會 call 到 suspend_in_iram(suspend_param1, NULL, NULL);

suspend_in_iram 是一個 function pointer. void (*suspend_in_iram)(void *param1, void *param2, void* param3) = NULL; 在 pm_init 時: suspend_param1 = cpu_is_mx51() ? (void *)SUSPEND_ID_MX51: (void *)SUSPEND_ID_MX53; memcpy(suspend_iram_base, cpu_do_suspend_workaround,SZ_4K); suspend_in_iram = (void *)suspend_iram_base; 也就是..把cpu_do_suspend_workaround 這塊區域copy 到 suspend_iram_base 中。
再把 suspend_iram_base 指定給 suspend_in_iram( )

這是因為suspend 時,dram 會disable, 進入 self-refresh,所以不能 access。

所以要把 dram 中的 code 先 copy 到 internal ram (iram) 中,才可以執行。


cpu_do_suspend_workaround 是 assembly code: suspend.S

parameter 1 是 chip ID, 因為這個 function 是mx50,mx51, mx53 共用的。
這段assembly code,作 invalid cache, set ddr to self-refresh mode.
set dd pin to high-z, 然後就進入 wait for interrupt 模式:
    /*
     * PLL1 workaround as the following: For mx51 only.
     * Before enter WFI
     *      (1) switch DDR and ARM to PLL2
     *      (2) Disable AREN bit to avoid PLL1 restart during MFN change)
     *      (3) set PLL1 to ~864Mhz with MFI = 8, MFN = 180, MFD = 179
     *          thus the equation |MFN/(MFD+1)|  < 1
     *      (4) Manual restart PLL1
     *      (5) Wait PLL1 lock
     * After CPU out of WFI
     *      (6) Set PLL1 to 800Mhz with only change MFN to 60, others keep
     *      (7) Wait MFN change complete by delay 4.6us,
     *      (8) Switch DDR and ARM back to PLL1
     */

atmel studio 6 -- project 有 C 和 assembly source

依照一般方法 New Project -- 選 C/C++ project, User Board。

這樣 就會產生 USER_APPLICATION1 的 project。
裡面已經有了main.C

接著在外面用編輯器新增一個 test.S 的 assembly source。
之後再拖拉到 project 的 src folder。

然後就可以 build 了。

2012年11月14日 星期三

atmel xmega : 減少 power down mode 的電流

依據 atmel 的 application note: AVR1010: Minimizing the power consumption of XMEGA devices

Power Reduction Registers

xmega有一組 Power Reduction Registers,可以分別開啟/關個別 component 的 clock,好達到 power reduction 的目的。

但是在 Power-Down Mode,因為 peripherial clk source 已經關掉,所以無論 Power Reduction Registers 的內容是如何,所有周邊都是關掉的。
也就是說,不用費心去設了



GPIO

另外文章有說到 gpio 的設置:

所以 io pin 都設定為 floating 避免影響到週邊,但是要注意,因為內部有 digitial input buffer。
會隨者 io pin 的 floating 電壓作 high/low 的變化,還是會消耗電流。
所以最好讓 io pin 有特定的 high/low 電壓,避免 switching 造成電流消耗。

如果 gpio pin 連接到 類比信號,即使他不是 configure 成 input,都應該要把那一個 pin 的 digital input buffer disable 掉,
-- 可以經由 PINnCTL 來設定。

要減小電流,把所有沒用到的 gpio pin 都enable pull-up 或 pull-down,並且把 digital input buffer disable 掉。


JTAG

JTAG 也可以 disable,好降低耗電,OCD (on chip debugging) 也一樣,
OCD 只能由 fuse disable,JTAG 可以用 software 的方式 disable/enable。

當使用 PDI 介面作 debugging 時,因為完全不需要用到 JTAG 介面,所以可以經由 FUSE 把 JTAG 功能關閉。


Flash & EEPROM

EEPROM 和 flash 也可以關掉,有一個 errata 說明有些裝置在 sleep mode 時,flash 還繼續耗電,
所以在 sleep 前,要手動把 flash 關掉。

2012年11月13日 星期二

subversion web interface : 指定看某個 rev

直接在 browser 上輸入 subversion repo link 的話,他顯示的是最新的狀態,
如果要指定是哪一個 revision ,就要:

在 repo root 後面加上 !svn/bc/<revision_number>/
要注意,是 repo link 的後面,不是整個的最後面。

以 這個 link 來說:
http://svn.yoya.com/PANDA/CVV-7AA0/branches/Charles/SystemController/CVV73AAY_ONOFF/
rev 就要寫成:
http://svn.yoya.com/PANDA/!svn/bc/36097/CVV-7AA0/branches/Charles/SystemController/CVV73AAY_ONOFF/



atxmega128a3 -- adc

xmega A3 有兩組adc 轉換器,
這兩組可以規劃成
  • 同時運作
  • 獨立運作
  • 同步運作


12bit 解析度, 2MHz sampling rate

輸入端可以選擇
  • sigle ended
  • differential
configure 成 differential 時,還有一個 內部 gain 可以選擇。


是 pipeline ADC

pipeline 的設計,把 ADC 的動作,分成很多獨立的 stage,
當第一個stage 完成,把結果交給下一個 stage 後,他就可以繼續下一個 adc 動作,
不用等待每個stage 都作玩。

這樣的設計,可以得到高 sampling rate。



ADC 可以由軟體觸發,或是經由其他的週邊裝置觸發,
ADC 將結果放在 4 個 result register 中的一個,供後續的動作使用。
所以可以利用 DMA 自動將 result 搬移到 memory。

2012年11月12日 星期一

sanyo 行動電源



買了行動電源 ,連著電池,我以為可以用來充電池 ,結果不行。

實際用 Nexus S 測試:

先把 他充飽.

Nexus S從 20% 開始充到 92%, 約 3hr.
-- 還是綠燈

然後用到19%,再繼續充,
充到 60%, 約 1.5hr,已經變成 "橘色" (還是紅色?)。
繼續充...到飽,還是橘色

Nexus S 從 60% 開始充,,充到 80%, 變紅色,繼續..
充到92%. 還沒斷電。

所以大概可以充 2.5 次 (每次 20% --> 90%).

2012年11月9日 星期五

avr-gcc, xmega

avr tool 好像包含在 debian 的標準套件中。
所以用 apt 安裝就可以。
#apt-get install gcc-avr

裝完後,可以用 avr-gcc --target-help 列出 support 的 avr chip.

現在要用的 atxmega128a3,所以可以把輸出用 grep 慮一下。
發現這一版有 support atxmega128a3

這樣 build 的時候就可以用 option: -mmcu=atxmega128a3


也有包含需要的 libc 和 peripherial register definition.

會安裝在 /usr/lib/avr

像 register 的定義,要直接用的話,就只要在 source code include avr/io.h

io.h 會依照 target mcu 的定義來 include 正確的 ioXXXX.h

在 windows 版也一樣, include avr/io.h 就好。
-- 實際上,include avr_compiler.h 就好,他會 include 需要的 io.h, interrupt.h, pgmspace.h .. etc

raspberry_pi, samba share

samba 的話,也跟一般 linux distro 一樣: #sudo apt-get install samba samba-common-bin 然後用 default 的 /etc/samba/smb.conf 就可以。 .. 或是修改,home share, browseable = yes readonly = false

之後要把 user 加進 sambs 中。
因為 default smb.conf 是 sync user account,所以只能加這個系統上有的 user。 $sudo smbpasswd -a pi
輸入 password 兩次後,再 run service samba reload 就可以了。

在 windows 機器上 file browser 輸入 \\ip-address\pi
就會出現 account login 畫面,使用 pi, raspberry 就可以 看到 /home/pi 目錄了。



配上前一篇,可以把 transmission-daemon 的 download path 改到 /hom/pi/downloads 中。


raspbere pi 壞了

不能開機了,ok燈不會亮,console 顯示的是
要Fsck 一下。
看來是sd card 壞掉。
便宜的sd 果然沒好貨。


這次使用標準系統再run 一次,看看還會不會有問題。

如果還有,就要隔開 root/system 和 download parition 了。
-- swap 搞不好也要開一個,不開的話,系統好像會在 /var 下開一個約 100M 的 swap file.


2012年11月8日 星期四

草稿:簡單的小系統 os .. 1

先作 schuduler 和 delay

就只有 8 個 task,每個數字代表一個 priority,每個 priority 只有一個 task。
task 0 是 reserverd system task,作 background task 使用。

這樣 scheduler 就很簡單: SAVECONTEXT; currtaski=0; for(i=7;i>0;i--) if(readytask[i]==true){ currtaski=i; break; } RESTORECONTEXT;
bool readytask[] 就是標示現在是 ready to run 的 task。



delay 要實做,要配合 timer

int delaytask[i];

timer 的 ISR:
for(i=1;i<8;i++) if(delaytask[i]>0){ delaytask[i]--; if(delaytask[i]==0){ readytask[i]=true; delaytask[i]=-1; // for safe } } ... 然後如果有改變,就要 call reschedule()

create task 就超簡單,stack 也是預先宣告好的 array..
createTask(int priority, (void *taskbody)(), int *stack);
task 都create 完,call start_scheduler( ) 就可以了。




download 下來包含 atmel studio 4, 6 的project 檔,可以 build OK (使用 native compileer , not winavr)

Atmel Xmega 架構說明

這個應該要參考 XMEGA D Manual (doc8210.pdf)

  • harvard architecture -- seperate program and data bus
  • single level pipeline, one executed, one pre-fetch (這樣不就是 2 level ?)
  • 是 8/16 bit risc microcontrollers (8/16 是什麼意思?)
  • 32 個8bit general purpose working registers.
  • 有 program memory (flash),EEPROM 和 SRAM
  • Stack in RAM
  • Stack pointer accessible in I/O memory space
  • direct addressing 16MB , both data and program memory
  • 16/24 bit I/O registers (?)
  • I/O status & control registers 位於 lowest 4KB data memory addess
  • SRAM 的位置是由 0x2000 開始
  • EEPROM 是 0x1000 到 0x1FFF
  • program memory 被分成兩部份:boot program section, application program section

跟 context switch 最有關係的是 stack 和 status register。

Status Register : SREG
  • 在 interrupt 發生時,cpu 並不會作 save-restore 的動作,需要寫出code來作
  • SREG 也被mapping 在 I/O memory space,所以可以自由存取

Stack & Stack Register : SP
  • Stack Register 的size 是兩個 byte,一樣mapping 到 I/O memory 的位置,佔兩個位址
  • 和一般 Stack 一樣,初始在高位址,push 時減少address。
  • CPU reset 時,SP 的初始值是 SRAM 的最高位址
  • SP 也可以由軟體更改,但是必須要在0x2000 以上
  • 執行中斷和call指令時,return address 會自行 push 到 stack,同樣的 RET, RETI 指令會自動 pop
  • 執行 中斷, call, RET, RETI 命令時,每次push/pop 的size 隨裝置的program memory 大小而有不同,program memory 小於 128k 的裝置,每次 push/pop 2 個 byte,大於 128k 的,每次三個 byte
  • 值行單純的 push, pop 命令時,每次只能對 1 個 byte 操作
  • 當變更 SPL (SP 內容) 時,會自動 disable interrupt 4 個 instruction cycle



這樣的架構是可以support rtos 的,
這篇文章有說明在 interrupt routine 中,preserve/restore context 的code:
Preserving sreg in AVR interrupts

在avrfreak 有一篇 freeRTOS , atxmega128a1 port 的code,
這段是寫在 include/FreeRTOS v6.1.0/ISR_Support.h 中。

2012年11月7日 星期三

bootloader for atxmega

Xmega_bootloader 是一個給 atmel xmega 系列的 bootloader,

從他的 readme 可以知道,這個 bootloader 藉由 某一pin 的狀態,決定是 normal boot 還是進入 programming mode。

一旦進入 programming mode 後,他就會從 serial port 收取資料,
program 自己的 program memory , eepron..

serial port 的 protocol 是 AVR9001。

2012年11月2日 星期五

16g sd 開始運作

pchome 買的,兩片600.


2012年11月1日 星期四

Raspberry pi -- ssh 檔案名稱亂碼

上次用 transmission-daemon download 下來的檔案,有些是亂碼,導致在 ssh 下 無法刪除。
這是因為 locale 沒設定正確。

所以 follow 這一篇,設定 : #dpkg-reconfigure locales
我好像只有選中文, 中文 utf8,和簡體,簡體 utf8。
然後 default 選中文 utf8。

之後就可以在 ssh 中正常顯示了。

然後發現每次 apt-get install 都會有 error message 出現,用 locale 看一下也有 error message: locale: Cannot set LC_CTYPE to default locale: No such file or directory locale: Cannot set LC_MESSAGES to default locale: No such file or directory locale: Cannot set LC_ALL to default locale: No such file or directory LANG=en_US.utf8 LANGUAGE= LC_CTYPE="en_US.utf8" LC_NUMERIC="en_US.utf8" LC_TIME="en_US.utf8" LC_COLLATE="en_US.utf8" LC_MONETARY="en_US.utf8" LC_MESSAGES="en_US.utf8" LC_PAPER="en_US.utf8" LC_NAME="en_US.utf8" LC_ADDRESS="en_US.utf8" LC_TELEPHONE="en_US.utf8" LC_MEASUREMENT="en_US.utf8" LC_IDENTIFICATION="en_US.utf8" LC_ALL= 所以重新 run dpkg-reconfigure locales
把 en_US.utf8 加進來。這樣就可以了。

2012年10月31日 星期三

framwork code trace : go to sleep

只有查到 Framework 中,最後被 call 的是 com.android.server.PowerManagerService.gotoSleep(PowerManagerService.java:2449)
但是找不到 call 這個 function 的 java code.

找一下 c code,果然還有一堆,像: ./base/services/jni/com_android_server_PowerManagerService.cpp:40: jmethodID goToSleep; ./base/services/jni/com_android_server_PowerManagerService.cpp:104:void android_server_PowerManagerService_goToSleep(nsecs_t eventTime) { ./base/services/jni/com_android_server_PowerManagerService.cpp:108: env->CallVoidMethod(gPowerManagerServiceObj, gPowerManagerServiceClassInfo.goToSleep, ./base/services/jni/com_android_server_PowerManagerService.cpp:110: checkAndClearExceptionFromCallback(env, "goToSleep"); ./base/services/jni/com_android_server_PowerManagerService.cpp:167: GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleep, gPowerManagerServiceClassInfo.clazz, ./base/services/jni/com_android_server_PowerManagerService.cpp:168: "goToSleep", "(J)V"); ./base/services/jni/com_android_server_PowerManagerService.h:30:extern void android_server_PowerManagerService_goToSleep(nsecs_t eventTime); ./base/services/jni/com_android_server_InputManager.cpp:899: android_server_PowerManagerService_goToSleep(when);
最後 com_android_server_InputManager.cpp 可能就是處理的地方 (因為 power button 被 implement 成一個 key)

這個 code 是.. void NativeInputManager::interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId, int32_t action, int32_t &flags, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) { ... ... if (wmActions & WM_ACTION_GO_TO_SLEEP) { android_server_PowerManagerService_goToSleep(when); } ...

所以找賦予 wmAction WM_ACTION_GO_TO_SLEEP 值的 code..
這個 const WM_ACTION_GO_TO_SLEEP 的定義有點糟,jni 和 java 都要定義一次,而且要確保一樣: ./base/core/java/android/view/WindowManagerPolicy.java:106: public final static int ACTION_GO_TO_SLEEP = 0x00000004; .. ./base/services/jni/com_android_server_InputManager.cpp:873: const int32_t WM_ACTION_GO_TO_SLEEP = 4;

到這邊就有點麻煩..

上面 com_android_server_InputManager.cpp 的 interceptKeyBeforeQueueing( ) 中,先去 call java : JNIEnv* env = jniEnv(); jint wmActions = env->CallIntMethod(mCallbacksObj, gCallbacksClassInfo.interceptKeyBeforeQueueing, when, action, flags, keyCode, scanCode, policyFlags, isScreenOn); 這段code的 interceptKeyBeforeQueueing 是..
FIND_CLASS(gCallbacksClassInfo.clazz, "com/android/server/InputManager$Callbacks"); GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz, "interceptKeyBeforeQueueing", "(JIIIIIZ)I");
是 InputManager.java 的 interceptKeyBeforeQueuing

print current stack backtrace -- android

在 trace android framework 時,常常迷失掉。
可以在 framwork source 中,加入 dumpStack( ),這樣就可以找出 caller..

舉例來說,想知道 短按 power button 時,system suspend 的動作是誰 call 的。
只知道最後 作 setScreenState( ) 是實際寫入 kernel interface 的 function。

所以在 PowerManagerService.javasetScreenStateLocked() 加入: import java.lang.Thread; .... Thread.currentThread().dumpStack();
然後suspend 時,logcat 就會有: /System.err( 2417): java.lang.Throwable: stack request_suspend_state: mem (0->3) at 98046449377 (1970-01-02 00:26:25.141454751 UTC) dump W/System.err( 2417): at java.lang.Thread.dumpStack(Thread.java:577) W/System.err( 2417): at com.android.server.PowerManagerService.setScreenStateLocked(PowerManagerService.java:1629) W/System.err( 2417): at com.android.server.PowerManagerService.screenOffFinishedAnimatingLocked(PowerManagerService.java:1817) W/System.err( 2417): at com.android.server.PowerManagerService.access$4300(PowerManagerService.java:82) W/System.err( 2417): at com.android.server.PowerManagerService$BrightnessState.finishAnimationLocked(PowerManagerService.java:2079) W/System.err( 2417): at com.android.server.PowerManagerService$BrightnessState.stepLocked(PowerManagerService.java:2062) W/System.err( 2417): at com.android.server.PowerManagerService$BrightnessState.run(PowerManagerService.java:2088) W/System.err( 2417): at android.os.Handler.handleCallback(Handler.java:587) W/System.err( 2417): at android.os.Handler.dispatchMessage(Handler.java:92) W/System.err( 2417): at android.os.Looper.loop(Looper.java:130) W/System.err( 2417): at android.os.HandlerThread.run(HandlerThread.java:60) I/PowerManagerService( 2417): setScreenStateLocked0
這樣就知道,是



ref : java: printing current backtrace

2012年10月29日 星期一

netlink -- event interface between userland & kernel

這是 imx3 的 source code。
-- 只在 mc13783 這個 driver 有用到,和 battery, power 相關的 code。

為了一些 hardware 的 event 寫了一個 driver (mxc_hw_event),提供一個 netlink 的 interface,讓 kernel event 可以傳送到 user program。

mxc_hw_evnet 只在 /sys/..../ 下開一個 mxc_hw_event 的 netlink nod。

然後 export 一個 hw_event_send 給其他 kernel module 用。

其他 driver 的使用方法是..(以 pmic_battery 來看.):

當偵測到 充電器插入時...
t_sensor_bits sensor; struct mxc_hw_event event = { HWE_BAT_CHARGER_PLUG, 0 }; pr_debug("In callback_chg_detect\n"); /* get sensor values */ pmic_get_sensors(&sensor); pr_debug("Callback, charger detect:%d\n", sensor.sense_chgdets); if (sensor.sense_chgdets) event.args = 1; else event.args = 0; /* send hardware event */ hw_event_send(HWE_DEF_PRIORITY, &event); 經由 mxc_hw_event 這個 netlink node 送出訊息。

這樣 user program 可以monitor mx_hw_event,得到 charger plug event。
不必一直polling,或是像以前一樣,經過 /dev 的 ioctrl 送自己的 pid,作 signal handler。

2012年10月26日 星期五

Dev AVR on Windows -- Atmel Studio & WINAVR

  1. 去 winavr 網站 download winavr. 安裝
  2. 去 atmel 網站 download atmel studio (現在是 6.0)。
  3. 一樣,download service pack, 安裝
打開後,選 File -- import , import studio 4 project (aps)。
選一個 studio 4 的 aps 檔,他會自己 convert 成 6 的 project 檔。

點一下tool bar 的 device - Atxmega128A3。
會開啟 這個 device 的相關 page (datasheet & tool..etc)
可以看到 tool 有兩個可以選:
  1. Native
  2. As4_gcc
Native 那個好像是 Atmel 自己附的,Nsc 那個好像就是 winavr。

可以 follow 這一頁的說明,到 Tool-Option ,.. 去看/更改。
就是:
  • 安裝 winavr,假設是在 C:\Winavr
  • 開啟 avr studio, tools - options - toolchain - flavour configuration
  • Add Flavour
  • Name : winavr
  • Toolchain Path : C:\winavr\bin
  • Make Path : C:\winavr\utils\bin
  • 之後,開啟的 project,按下 toolbar 上 device 那個icon (chip icon ATxmega128A3),就會出現一堆頁面,Advanced -- Toolchain Flavour 選 winavr

接上 JTAG MKII 後,會自己找 driver install,然後在 atmel studio 開啟就找得到了。
-- 現在用的是 PDI 介面。

然後就可以 build project, debug - run 了。

2012年10月25日 星期四

正式服役 raspberry pi, B, 256M

Torrent download server.



我好像花了1800 買的。
賣家好像是自己要用,但是為了分攤運費,所以多買了幾片。

2012年10月24日 星期三

Android : power key to suspend, again..

參考前面兩篇文章: 一堆地方有goToSleep(),最後call 到的是...
./base/services/java/com/android/server/PowerManagerService.java
裡面的
    private void goToSleepLocked(long time, int reason) {
這個 function 最後 call 的是..
            setPowerState(SCREEN_OFF, false, reason);
這個function 剛好 follow ref.1 的內容。

原來的 code 寫法,短按 Power 就是 suspend,
長按則出現 PowerDialog,讓你選擇關機。

短按的動作,會讓 interceptKeyBeforeQueueing 傳回 含有
result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
的return code。

2012年10月23日 星期二

ra0 occurred replay counter different in Key Handshaking

ra0 Pairwise Key Handshaking timeout

ra0 occurred MIC different in Key Handshaking

2012年10月22日 星期一

Raspberry Pi : Minimal system & preparation

只是要作一個 bt download server.
又因為沒有 dvi/hdmi moditor,所以只能用 ssh.


1. dd minimal system

先到 這裡 download armhf 的 minimal debian distribution. (without X).

dd 完後,開機,果然 sshd 就自動啟動了。
但是這只有 root account,password 是 raspberry
-- 沒有原來的那個 pi 帳號。


2. resize/enlarge the root partition

因為download 的 image 是 2G 系統,所以使用 4G SD 的話,會有 2G 沒用到,

follow 這一篇,resize 的作法就是用 fdisk 把最後一個 partition 砍掉 (p3/swap),然後把 p2(root) 砍掉再重新new 一個包含整個剩下區域的 partition。(root+swap)

-- 很有趣,這樣resize (new) 完後,重新開機 (shutdown -r now)。 再作 resize2fs 就可以了。
-- 東西竟然不會不見。

嗯,沒錯,沒有留 partition。

3. 安裝, config transmission-daemon

就 follow 上一篇就可以囉。

!! 真的動了!!
結果ip 是 20

*接下來就要開啟samba囉...



後來system 有死掉一次,不知道是不是這個 minimum 系統的原因,所以用回標準系統。
標準系統啟動後,會自動 run raspi-config。
讓你從選單作 systemconfig。

  • 先 expand_rootfs, 然後 reboot
  • 再手動叫起 sudo raspi-config
  • change_timezone
  • memory_split (16)
  • ssh (enable)
  • boot_behaviour (boot into console)
然後就可以 run apt-update, apt-upgrade。
之後再 run dpkg-reconfigure locales



這個版本也沒有 enale uart login

要 enable 的話,要改 /etc/inittab , 加上(uncomment 掉):
#Spawn a getty on Raspberry Pi serial line
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

2012年10月19日 星期五

Raspberry Pi:Torrent client --- transmission-daemon

當作 torrent client 的話,可以用 transmission-daemon 這個 package。
用 apt-get install 完後,他會自動修改 init.d/ 還有 /etc/group 。
增加啟動的命令和新增一個 user group : transmission-daemon,並且啟動 daemon。

但是要稍微修改一下設定:/etc/transmission-daemon/settings.json:
  • "rpc-authentication-required": false, 這樣web interface 就不會要求密碼
  • "rpc-whitelist-enabled": false, 這樣所有 ip 都可以access web interface

然後就可以重新啟動 transmission-daemon: service transmission-daemon reload
要用 reload, 不可以用 restart,因為 現在 transmission-daemon 還有 bug,在 /etc/transmission-daemon/README.json: Currently transmission overwrites the settings.json configuration file on exit. The daemon can be instructed to reload the config with a SIGHUP, or # invoke-rc.d transmission-daemon reload Otherwise changes made manually to the file while the daemon is running will be silently overwritten on exit.

試試看在 pc 的 browser 開啟 http://raspberry-pi-ip:9091
就會出現 web 介面了。



另外 有說到如果遇到 down load 時當機的情況,就要修改 settings.json,加上:
  • "peer-limit-global": 100,
  • "peer-limit-per-torrent": 30,
限制download 時 track 的數量。

另外,download 的位置也寫在 settings.json 中。

預設是: "download-dir": "/var/lib/transmission-daemon/downloads",
未完成的位置是在: "incomplete-dir": "/root/Downloads",
可以另外安裝 samba server。


ref:

另外,這個 image 比較小,只有500MB,pure command line,沒有 X

USB HUB supplied power

usb 2-1.3: new high speed USB device using fsl-ehci and address 3
usb 2-1.3: New USB device found, idVendor=0403, idProduct=6011
usb 2-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 2-1.3: Product: Quad RS232-HS
usb 2-1.3: Manufacturer: FTDI
usb 2-1.3: rejected 1 configuration due to insufficient available bus power
usb 2-1.3: no configuration chosen from 1 choice

'usb 2-1.3: rejected 1 configuration due to insufficient available bus power'

找到印出這個 message 的 code,在比較式把 value 印出來, 結果是: bMaxPower:250 *2, bus_mA: 100
代表hub report 只有100mA 的輸出能力,但是 device claim 250mA。

查一下 hub 的 datasheet,,知道 hub 有兩種模式:
  • bus_powered: 從 upstream 取得電源,所以downstream 只允許有 100mA,而且所有 down stream 的總和不得超過 500mA
  • self_powered: 自己有電源(adaptor),每個 downstream 都可以有 500mA

所以猜是 hub 的 configuration 錯了。

hub 的 configuration 是由 configureation pin SEL0-2 決定,
剛好有決定是 bus-power 或 self-power mode。

改掉成 self-power mode 後,就 OK 了。

2012年10月17日 星期三

Raspberry: initial config & set proxy for apt-get

接上 monitor, keyboard 開機後。第一次會出現 config 選單。
選了把 root partition 加大。還有開啟 ssh server 後就可以重開。

... 然後開機就會是 expand root partition 的 message。

然後出現 login prompt
username : pi password : raspberry
接上網路線後,ifconfig 就可以看到 ip 了。

然後 follow 這一篇: Connect Raspi to a Proxy

在 /etc/apt/apt.conf.d 下新增一個檔案:02proxy

內容是;
Acquire::http::Proxy "http://yourproxyaddress:proxyport";

如果是 uart 開機,又是 minimum image, 開機就不會自己出現 config,
要手動:raspi-config

2012年10月15日 星期一

Raspberry Pi : enable sshd server & config network for default booting

買了一堆cable 後,最後還是用 hdmi-dvi cable 才成功的看到 boot 畫面。

其實,不一定要用 monitor,可以用網路 ssh server,像 這一篇:

Raspberry Pi quickstart: headless setup (no monitor)

就有說明修改 SD image,開啟 sshd server 的方法,

原來燒入 sd card 的 image 會有兩個 partition,把他門 mount 近來看就可以修改了。


一樣,然後 這一篇 就可以啟動 VNC Server,然後用 VNC client 來控制。


2013.09.24:

光改 static ip 這招好像沒效。
因為一開機就會出現一個 choose combo,要你選,沒選的話,網路部會起來。
所以還是要 monitor + keyboard。

179

因為種種原因...要用 firefox..,所以啟動了 vnc
就 follow 上面的 link,裝了 tightvnc,並且在 系統啟動就 enable。
結果 好像沒啟動,手動啟動後,要我給一個 password,所以就輸入了 跟 login 一樣的。

之後client 端就用 tightvncviewer 成功。

$xtightvncviewer 192.168.1.179:1

再安裝 icesweal
也 OK.



另外。command line 設定 Wifi 的方法: http://www.penguintutor.com/news/raspberrypi/rpi-wireless-cli

get source for building aosp - framework & ..

承上篇,android 不含kernel 的部份。

其實 android 的 framework 已經把 prebuild 的 kernel 包含在 devices/product 下。
所以不修改 kernel 的話,就不用 download kernel source。

取得 source code 的方法就跟網頁說得一樣: Download the source

repo init -u https://android.googlesource.com/platform/manifest -b android-4.1.2_r1
-- 這個 branch (android-4.1.2_r1 有在 kernel source 中).

然後一樣作 sync... (文章 mirror 的作法,我做起來會 fail,好像是因為 dalvik2 這個 folder.)

這個 branch , device 下才有 samsung/crespo 這個 folder,才能 buils Nexus S 的 image。

之後還要拿 close source 的 bin 檔。

大概就是去 aosp download 對應版本的 一堆 tgz 檔,解開後會變成 sh。
到 aosp 的目錄去run 他,他就會顯示license 讓你確認,並且檢查 source code正不正確,然後 create vendor folder,放到裡面。

都做完後,就可以 回去 follow Build 的 step。 run envsetup, lunch 和 make 了。

我lunch 選的是 8 : full_crespo-userdebug

也可以用 full_crespo-eng,這個沒列在選單中,要自己 key,,

get source for building aosp --kernel

kernel: 重要的是 kernel,並不是每一個 build 都有。
所以要去你自己的機器的 device 去看,有那幾個 build。

所有 git project 的列表在: android google source


以 Nexus S 來看,就是 :

device/samsung/crespo Files specific to Samsung crespo hardware, a.k.a. Nexus S.

以現在這個時間,最後release 的版本是 android-4.1.2_r1

所以 整個 repo branch:
repo init -u https://android.googlesource.com/platform/manifest -b android-4.1.2_r1

這樣 device/samsung/ 下就會有 crespo



然後才follow aosp kernel 說明 :
http://source.android.com/source/building-kernels.html

在 device/samsung/crespo 目錄,command : git log kernel:
commit c181cc132d5077ea28ffeb9d0be656665f5319c6 Author: Dmitry Shmidt Date: Mon Sep 10 14:17:56 2012 -0700 crespo: Kernel prebuilt (DO NOT MERGE) 5894150 net: wireless: bcmdhd: Report proper mcs rate mask 5ad899a netfilter: xt_qtaguid: report only uid tags to non-privileged processes 782ca40 netfilter: xt_IDLETIMER: Rename INTERFACE to LABEL in netlink notification b/7103180 Change-Id: If9ac23da68669087761dfd4f80d1c08f2fd99a49 Signed-off-by: Dmitry Shmidt

log 裡有寫對應的 kernel build SHA1 code. -- 5894150

這個 SHA1 code 就是 kernel 的 rev。



接著自己把 samsung 的 kernel clone 下來...
一樣,在 剛剛的頁面,有 samsung 的 kernel git project...
git clone https://android.googlesource.com/kernel/samsung.git
clone 完,到 samsung 目錄下,沒有檔案,是 empty commit ..

所以先看看 server 端的 branch 有哪些: git branch -r origin/HEAD -> origin/master origin/android-samsung-2.6.35-gingerbread origin/android-samsung-3.0-ics-mr1 origin/android-samsung-3.0-jb origin/android-samsung-3.0-jb-mr0 origin/master
然後一一用 git log remote-branch-name 找到剛剛的 SHA1 commit...
-- 找到,是在 origin/android-samsung-2.0-jb-mr0 ..

其實直接 checkout SHA1 number 就可以: git checkout 5894150

* 這就是 aosp 說明頁的那一句: git checkout <commit_from_first_step>


ref:

2012年10月12日 星期五

about mirrorlink or terminal mode

Mirrorlink 就是把手機 panel (和 audio) 的延伸。
目前好像只有在車用系統上有用。

經由 MirrorLink,利用車用影音系統的lcd/touch 來控制手機。

目標是希望降低車用影音系統的成本,刪除掉與手機重複的功能。
同時又保有較大的螢幕和比較方便的操作。

mirrorlink 有一個專門的協會在運作。
規定了使用的 protocol。

但是好像沒有很嚴格,所以各家手機各有自己的 implement。

目前看來,好像是用 vnc。

在手機上 run VNC server。
再經由 usb cdc/ncm profile 傳送。


實際上 mirrorlink 要作到三件事:
  1. lcd screen mirror
  2. phone audion mirror
  3. touch event to phone
前兩項可以用 mdhi。這樣可以減少 phone 的 overhead,還有一些hardware 相容性問題 (hardware codec not always output to framebuffer)

touch event 就比較麻煩,他的需求有:
  1. absoulte pos , 而不是像 mouse 一樣的 move/relative pos
  2. system contol permission
這兩項是 couple 在一起的。

要把touch event 注入系統,通常都需要system permission。
如果使用系統support 的輸入裝置則不需要,像 bt/usb hid device

但是這些系統 support 的輸入裝置都是 relative posistion,沒有 absoult position。




google 一下 vnc server on android,會有一些application。
一樣,這些大多要求 root 權限。

即使不需要 root 權限 (例如:VMLite VNC server),
也需要 user 先將手機連上 pc,利用 pc 來開啟 vnc server。

這個動作應該是利用 adb 啟動 vnc server,因為 adb 有 system 權限。


猜測解決方法:

大概有兩種,
第一種就是把 adb command 內建,當手機連上時,用 adb command 啟動 手機上的 server。
第二種就是利用內建的 hid 裝置,加上一個校正動作,把touch 的 絕對位置 轉為 相對位置,送到手機。


一堆 inject Event 的 api 在後面的 android 版本都被刪除了,所以只剩下對 /dev/input/event 寫入的方法。
adb shell 有 shell 權限,測試 cat , echo pipe command,好像有對 /dev/input/event 讀寫的權限 -- shell ?
Android 4.0 以後 /system/bin 有 adb 命令,所以已經內建 adb client 端。

adb 可以重導到 tcp,所以可以經過 wifi,不必經過 usb..
-- 這個或許不需要,因為 mhl 可以同時使用 mhl , usb 功能。

所以 mirror link 有關 touch 的實做方法大概是:
  • user 開啟 'usb debug 功能', 接上 車機
  • 車機 接通手機的 adb shell,event 一個 c program 對 /dev/input/event 寫入 touch event

Sony 的車用系統有 mirrorlink,下面是手機的support list:
http://www.sony-asia.com/support/compatibility/499547

-- 大概就是 SONY, NOKIA (Symbian), Samsung 三家有 support。而且SONY, Samsung 是只有最新的一款有 support 而已。

XDA 有 release XAV601 的內容,這個 thread 有提到 sony release 的 library: http://forum.xda-developers.com/showthread.php?t=1686535&page=2
sony : http://www.sony.net/Products/Linux/Audio/XAV-701BT.html


PIONEER 用的是另一種方法:Display + app control。
用 HDMI, MHL 把手機螢幕,聲音顯示出來,至於控制的部份,再用 自己的 app 來作,手機上安裝 PIONEER 的 app,讓車用音響控制。
所以 google play 上有一堆 PIONEER 的 app。
https://play.google.com/store/apps/developer?id=PIONEER+CORPORATION

另外,基於 PIONEER 的 appradio ,有人寫出另一個軟體,讓 車用音響直接控制 android phone:(arliberator) https://play.google.com/store/apps/details?id=com.kyle.arliberator&feature=nav_result#?t=W251bGwsMSwyLDNd
-- 但是,這個軟體需要 root。
-- 從 FAQ 可以看到,root 是為了 inject touch event,還有是利用 BT 連接。

結果:最偷懶的作法是 HID,加上龜零。
每次點擊都當作mouse 從(0,0) 移動到點擊處,然後按下button。
這樣就可以避免mouse 只送相對 move 資料的問題。

當然,還要配上設定解析度,HID 裝置要先知道phone 的螢幕解析度。

2012年10月11日 星期四

ADV7180 support for BSP10.4

這是 freescale 官方(?) 的修改。
讓 android 可以 support interlaced input。
但是。還是不support錄影。

Patch to support adv7180 TVin chip for Freescale Android R10.4 BSP on iMX53

2012年10月8日 星期一

找到 android core dump 的 位置

這一篇有說明如何從 core dump 找到當機的 source code:
http://kobablog.wordpress.com/2011/05/14/how-to-read-crash-dump-of-android/

大概就是..從 out/target/product/XXX/ 下的 symbols folder,有 not stripped version 的檔案。

利用 objdump 列出位址與 source code。
配合 core dump 的內容就可以找出來了。



馬上來照著做好了,sample 是會發生 core dump 的XXXX..
內容大概是.. I/DEBUG ( 2333): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000 I/DEBUG ( 2333): r0 bee91054 r1 00000000 r2 bee9105a r3 00000000 I/DEBUG ( 2333): r4 bee91030 r5 bee91054 r6 80204c50 r7 0000abd8 I/DEBUG ( 2333): r8 bee91288 r9 4850cc70 10 0000abd8 fp aca9f368 I/DEBUG ( 2333): ip 80204c7c sp bee91028 lr 80201ec9 pc afd20856 cpsr 60000030 I/DEBUG ( 2333): #00 pc 00020856 /system/lib/libc.so I/DEBUG ( 2333): #01 pc 00001ec4 /data/data/com.Xingtek/lib/libhashkey.so I/DEBUG ( 2333): #02 pc 00011e34 /system/lib/libdvm.so I/DEBUG ( 2333): #03 pc 000436e0 /system/lib/libdvm.so I/DEBUG ( 2333): #04 pc 00048e62 /system/lib/libdvm.so I/DEBUG ( 2333): #05 pc 00017034 /system/lib/libdvm.so I/DEBUG ( 2333): #06 pc 0001c0e4 /system/lib/libdvm.so I/DEBUG ( 2333): #07 pc 0001afdc /system/lib/libdvm.so I/DEBUG ( 2333): #08 pc 00059dde /system/lib/libdvm.so I/DEBUG ( 2333): #09 pc 00061b52 /system/lib/libdvm.so I/DEBUG ( 2333): #10 pc 00017034 /system/lib/libdvm.so I/DEBUG ( 2333): #11 pc 0001c0e4 /system/lib/libdvm.so I/DEBUG ( 2333): #12 pc 0001afdc /system/lib/libdvm.so I/DEBUG ( 2333): #13 pc 00059c40 /system/lib/libdvm.so I/DEBUG ( 2333): #14 pc 00046126 /system/lib/libdvm.so I/DEBUG ( 2333): #15 pc 0003194e /system/lib/libandroid_runtime.so I/DEBUG ( 2333): #16 pc 000327fa /system/lib/libandroid_runtime.so I/DEBUG ( 2333): #17 pc 00008cca /system/bin/app_process I/DEBUG ( 2333): #18 pc 00014b52 /system/lib/libc.so 所以去查一下 libc.so 的 20856 ..
用 arm-eabi-objdump -S libc.so 之後,找 20856:


可以看到是strcat( ) 中的... 20856: 5ccc ldrb r4, [r1, r3]
應該是 r1 是 00000000,也就是 strcat 的 pointer 有一個是 0導致。

去看一下 bionic/libc/string/strcat.c:

char * strcat(char *s, const char *append) { char *save = s; for (; *s; ++s); while ((*s++ = *append++) != '\0'); return(save); } 果然沒有檢查,
所以加上 null pointer 檢查。

奇怪的是,如果直接在 code 用 s, append 檢查,會被 optimize 掉,
所以要另開 function..
int isnotvalid(int a, int b) { if((a==0)||(b==0)) return 1; else return 0; } 然後在 strcat 壹開始用 isnotvalid( ) cheeck s, append 才不會被 optimize 掉,
兒這樣,那個 XingTek 的 apk 也可以執行了 (雖然沒值...)



附帶提一點(或許對其他人來說,已經是 common sense ..)

libc.so 好像是啟動就cache 住,所以用 adb sync 把修改過的 lib.so sync 到 target,再啟動XingTek app
他也不會使用新的 lib.so,

adb sync 玩 libc.so 後,要 system reboot 才行。

山寨機的問題

以我這台經jetrom 加持過的超Low end 7 ips a9 2 core pad  icou7 來說,大概有以下問題
  • 無線超不穩,連一下就斷
  • 電池指示是壞的 ,常常保持100, 然後用一陣子就突然斷電。
  • Touch很頓,和飄,中間和四周差很大,反應很慢。
  • 軟體相容性很差,很多 game 都不能玩。一些 google ap 升級後就 fail..
  • 用不到半年,問題越來越多:
    • 竟然出現不會 suspend/sleep 的奇異現象,按下 power 鍵,螢幕是關了,再按 power 鍵恢復,但是不是所動畫面,後來發現 系統根本沒關,所以電池一下就耗盡了。
    • panel 不定期出現一些白帶
    • download 的東西一多,系統設定好像變得奇怪,猜是 內部 nand/emmc? partition 問題,要 會恢復原廠狀態 (format partition)才會恢復
所以山寨之所以便宜,就是便宜在這,,他的function 都是時好時壞。

2012年10月4日 星期四

2012年10月2日 星期二

init: untracked pid 2981 exited
ping: sendto: Network is unreachable
ADDRCONF(NETDEV_UP): wlan0: link is not ready
# channel hint set to 2437
wmi_control_rx() : Unknown id 0x103b
ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready
init: no such service 'iprenew_wlan0:wlan0'
init: untracked pid 3060 exited
ADDRCONF(NETDEV_UP): wlan0: link is not ready
channel hint set to 2437
wmi_control_rx() : Unknown id 0x103b
ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready
init: no such service 'iprenew_wlan0:wlan0'
init: untracked pid 3119 exited
ADDRCONF(NETDEV_UP): wlan0: link is not ready
channel hint set to 2437
wmi_control_rx() : Unknown id 0x103b
ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready
init: no such service 'iprenew_wlan0:wlan0'
init: untracked pid 3179 exited
ADDRCONF(NETDEV_UP): wlan0: link is not ready
...

2012年9月27日 星期四

根據 config file 來 mount storage 裝置,並且在各狀態適當的送出 message。

config file 長得: ####################### ## Regular device mount ## ## Format: dev_mount


實際的 code,設計一個 DirectVolume class 來對應每一個 volume directory (也就是 config file 中的一行)。

前面的 label, mount_point, part 在 新 DirectoryVolume 物件生成時傳進去: dv = new DirectVolume(vm, label, mount_point, atoi(part));

後面的 sysfs_path 再一個一個的加進剛剛生成的 DirectVolume 物件中..
(所以一個 label 可以有很多個 sysfs_path ?)
while((sysfs_path = strsep(&next, " \t"))) { if (dv->addPath(sysfs_path)) { SLOGE("Failed to add devpath %s to volume %s", sysfs_path, label); goto out_fail; } }

2012年9月25日 星期二

suspend power button

EIM_A27 -- GPIO2_2_21

static struct power_key_platform_data pwrkey_data = { .key_value = KEY_F4, .register_pwrkey = mxc_register_powerkey, .get_key_status = mxc_pwrkey_getstatus, }; 所以 report key value 是 KEY_F4

然後 KEY_F4 是: ./include/linux/input.h:185:#define KEY_F4 62

2012年9月21日 星期五

android screencast

分為兩部份: agent (run 在 android device),和 screencast 本體 (pc)。

agent 在 pc 程式啟動後,會用 adb push 到 device,然後啟動。

agent 和 screencast program 會建立通道, screen cast 會把 key, mouse event 傳給 agent,
agent 再把 這些command 用 : if(type.equals("pointer")) { wm.injectPointerEvent(getMotionEvent(paramList), false); return; }
把動作輸入到系統。

至於android device 的螢幕,經由另一個 thread,. 抓 fb 的資料傳到 pc... Process p = Runtime.getRuntime().exec("/system/bin/cat /dev/graphics/fb0"); InputStream is = p.getInputStream(); System.out.println("Starting sending framebuffer"); OutputStream os = s.getOutputStream(); byte[] buff = new byte[336*512*2]; while(true) { int nb = is.read(buff); if(nb < -1) break; System.out.println("val "+nb); os.write(buff,0,nb); Thread.sleep(10); } is.close();

2012年9月18日 星期二

__init 只有在開機時需要用到的空間

kernel 升級後,proc 下的某個 module variable 竟然被清成 0 了。

後來發現那個 variable 有 __init 宣告。

所以只有在剛開機時,值還在,開完後就被清掉了。




ref: http://adrianhuang.blogspot.tw/2010/01/linux-kernel-init-initdata.html

所以以前能動真是奇蹟 ...

2012年9月17日 星期一

Nexus s 開始服役

中古機,NT 4500 買的。已經是 jelly bean.

感想,相機真是糟呀,,,

2012年9月14日 星期五

open fail on the 2nd pl2303 cable

接兩個 pl2303,第二條 (ttyUSB1) open 時會有 error。

猜是 kernel 的問題。

看一下,10.4 的 kernel 是2.6.35.3
我把 driver/usb/serial/ 下有用到的 source 都改為 linux-2.6.30.y 的版本
還有 include/linux/usb/serial.h 和一些source 要加上 include slab.h
後,還是一樣不OK。

有一篇說是因為 pl2303 是 1.1,接在 2.0 的 hub/port 上,interrupt 的時間比較長。
沒辦法 match 2.0 的 spec。

所以街一個 1.1 的 hub 再接 pl2303 就可以。

有一篇甚至用 company command echo 1 > ....ehci/company 就可以work!

另一篇有說改 pl2303 用的 interrupt_in_urb 的 structure,把 interrupt 從 1 改 32 就可以,,
這個 interrupt_in_urb 的 structure 好像是在 usb-serial.c 中,,,

所以去修改一下 usb-serial,把 bInterval 增加一下:

在 usb_serial_probe 中..
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 3a38054..3ebe5d0 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1005,7 +1005,7 @@ int usb_serial_probe(struct usb_interface *interface, endpoint->bEndpointAddress), port->interrupt_in_buffer, buffer_size, serial->type->read_int_callback, port, - endpoint->bInterval); + endpoint->bInterval+2); } } else if (num_interrupt_in) { dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined");

2012年9月13日 星期四

Add a new entry in Settings. --- save and restore

系統啟動後,Wifi AP Config, restore 的動作好像是在WifiService 作的。

AP Config 好像是存成檔案,不是用 sql 存的。

WifiService 啟動的時候,在 生成函數 WifiService( ) 最後就有: //Initiate a read of Wifi Ap configuration Message.obtain(mWifiHandler, MESSAGE_READ_WIFI_AP_CONFIG).sendToTarget();

對應的 MESSAGE_READ_WIFI_AP_CONFIG 的 handler 是: private class WifiHandler extends Handler { ... ... case MESSAGE_READ_WIFI_AP_CONFIG: readWifiApConfigBlocked(); break;

readWifiApConfigBlocked( ) 是:
DataInputStream in = null; try { WifiConfiguration config = new WifiConfiguration(); in = new DataInputStream(new BufferedInputStream(new FileInputStream( WIFIAP_CONFIG_FILE))); int version = in.readInt(); if (version != 1) { Slog.e(TAG, "Bad version on hotspot configuration file, set defaults"); setDefaultWifiApConfiguration(); return; } config.SSID = in.readUTF(); int authType = in.readInt(); config.allowedKeyManagement.set(authType); if (authType != KeyMgmt.NONE) { config.preSharedKey = in.readUTF(); } synchronized (mWifiApConfigLock) { mWifiApConfig = config; } } catch (IOException ignore) { setDefaultWifiApConfiguration(); } finally {
其中的 WIFI_AP_CONFIG_FILE 是在: private static final String WIFIAP_CONFIG_FILE = Environment.getDataDirectory() + "/misc/wifi/softap.conf";
這個 file 要在 WifiService 只少啟動一次後,才會產生。



系統的其他 component 要得到 wifi ap configuration 要靠 WifiConfiguration 這個 class。
然後是用 Parcel (Android 的 serialize) 作傳送。

所以讀入 config 後,還要修改 WifiConfiguration Parcel 的內容,把 Channel Number 加進去。

2012年9月12日 星期三

Add a new entry in Settings.

設定中一些都是預先寫好的設定輸入格式 class。
source code 都在;

frameworks/base/core/java/android/preference:

 CheckBoxPreference.java
 DialogPreference.java
 EditTextPreference.java
 GenericInflater.java
 ListPreference.java


Preference 的每一頁。的每個 entry 排列,都是寫在 xml 裡。

每一頁的 class 的 onCreate( ),就是作: addPreferencesFromResource(R.xml.wifi_advanced_settings);
把 layout load 進來。
 R.xml.wifi_advanced_settings 對應到 xml/wifi_advanced_settinfgs.xml 

xml 的內容就是 class name, title。


所以要在 wifi_ap mode 新增一個 channel setting,就是:

先在 xml/wifi_ap_settings.xml 新增一個 entry: <ListPreference android:key="wifi_ap_chanell_num" android:title="@string/wifi_ap_channel_num_text" android:persistent="false" />
然後在 字串定義的 xml 把新增個@string/wifi_ap_channel_num_text 定義出來:

values/strings.xml:
<string name="wifi_ap_channel_num_text">Channel Number</string>

光是作這兩個,在 ap setting 最後就可以多一個 Channel Number 的設定選項。

接著作 code 的部份...,


2012年9月11日 星期二

wifi hostspot / hostap channel

Android 的 hotspot 沒有可以設 channel 的地方,找一下..

hotspot 的 daemon 是 /external/hostapd

查了一下有設定 channel 的code。
是啟動時,從 argument 給的 (當然也可以吃 config)。

... 先 JUMP OUT 一下...

在 /system 下找一下 hostap ---- /net/SoftapController.cpp
/* * Arguments: * argv[2] - wlan interface * argv[3] - softap interface * argv[4] - SSID * argv[5] - Security * argv[6] - Key * argv[7] - Channel * argv[8] - Preamble * argv[9] - Max SCB */ int SoftapController::setSoftap(int argc, char *argv[]) {

這個 function 依照 argv[] 寫好 /data/wifi/hostapd.conf,然後用 prop start hostapd。

所以包含設定和啟動。

呼叫這個 function 的是..netd/CommandListener.cpp

int CommandListener::SoftapCmd::runCommand(SocketClient *cli, int argc, char **argv) { ,,,, } else if (!strcmp(argv[1], "set")) { rc = sSoftapCtrl->setSoftap(argc, argv);

簡單來說,就是..如果是 set command,就把所有 argument 包好,交給 setSoftap( )

runCommand( ) 是 CommandListener,是 Android 的一種 Service。

是利用 socket 作 IPC 的 server。
這種 server 用的都是 plain text 。所以找一下 SoftapCmd 的 comand string 是...

CommandListener::SoftapCmd::SoftapCmd() : NetdCommand("softap") { }
所以是 "softap"

之後就是 framework 的 client 端 (呼叫端),找一下 framework...

services/java/com/android/server/NetworkManagementService.java

public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface) throws IllegalStateException { .... .... else { /** * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8] * argv1 - wlan interface * argv2 - softap interface * argv3 - SSID * argv4 - Security * argv5 - Key * argv6 - Channel * argv7 - Preamble * argv8 - Max SCB */ String str = String.format("softap set " + wlanIface + " " + softapIface + " %s %s %s", convertQuotedString(wifiConfig.SSID), wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ? "wpa2-psk" : "open", convertQuotedString(wifiConfig.preSharedKey)); mConnector.doCommand(str); } mConnector.doCommand(String.format("softap startap"));
這段code就是從 WifiConfig 取出 參數值,包裝成 argv[]傳給 softap set

找到!!

code 只有作到參數 arg5,後面 6,7,8 都是用 default。

所以要可以設 hotspot channel,就可以把 argv6 加上去..

所以要作:
  • WifiConfig 新增 softap_channel
  • 設定增加一個 item 設定 softap_channel (1-11)
  • 這段code,增加一個 argument,把 WifiConfig.softap_channel 拿出來

2012年9月3日 星期一

把 ehci-arc.c 和 ehci-hub.c 的 function 都加上 entry message,發現即使平時沒事,都會有:
ehci_watchdog
ehci_work
timer_action
反覆出現。

2012年8月31日 星期五

iMX51 的 USB Host Controller 幾乎跟 EHCI 一樣。
-- 可能是為了確保 sw 相容。
只有一些地方不一樣。

以 Port Status/Control Register 來看: * Port Owner : 這本是決定 ehci 或是 companion controller 用,但是 51 沒有 companion controller ,所以這個 bit always 1

arm 的 writel( )

arm 的 writel( ) arch/arm/include/asm/io.h: #define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); })
然後同一個 source file: #define writel_relaxed(v,c) ((void)__raw_writel((__force u32) \ cpu_to_le32(v),__mem_pci(c)))
一樣,上面... #define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))
所以 v 是 value, c 是 address。

2012年8月30日 星期四

心得 -- 山寨平板

網路無法連 ,清除為原廠設定還是不行 把Ap重開才OK

網路真的是死穴,一堆平板的wifi都不好,Tf101,iconia a100都一樣,沒辦法長時間連線。,
往回
無線非常不穩,連一陣子就要手動關掉重開,不然就會卡住。
一堆Gameloftㄉㄜ˙game不能玩。
山寨版就是週邊的效能和 系統穩定問題。
這些都是試用是不出來的。
起碼要用一個禮拜才會有感覺。
但是作為媒體播放器還真是沒話說。 外接姆指碟。rmvb也都播得很順。

2012年8月28日 星期二

usb : implement the "componion" attr on TDI type controller

usb 2.0 一般使用 ehci controller
一般會有一個 1.1 的 controller 叫 companion controller,跟 ehci 一起,接在 usb 末端的 TT (Tansition Transistor) 後面。

然後 programmer 可以控制這個 TT ,讓他接到 componion controller 上,就變成 1.1。
接到 ehci 上,就變成 2.0。

linux 也 follow 這個,在 usb device 的 sys filesystem 裡,實做一個 "componion" attribute file。

把數字寫進這個 componion file,該 port (--) 的 TT 就會接到 componion controll 上。
要恢復的話,就把port number 的負值寫到 componion 上 (e.g: -4),TT 就會接回 ehci controller 。
藉此,可以分別控制 各個 ehci 的速度。



但是有些 controller 把 1.0 的功能也作在 ehci 裡,同時內建 TT,這樣,就沒有 companion controller 了。 == source code 叫這種 controller 是 TDI , structure 中用 has_tt 來代表。

這樣,就沒辦法強制工作在 1.1 了。




但是,這邊有一個 patch,是利用這類 controller 的 : +#define PORT_PFSC (1<<24) /* port force full-speed connect */
強制讓 ehci 工作在 full speed,來模擬 componion 的作用。

ref : http://permalink.gmane.org/gmane.linux.usb.general/14891

printk all out - debug console log level

不是所有的 printk 都會印到 console 上,會有 level 的限制。

系統啟動後,在 /proc/sys/kernel/printk 可以用來控制輸出的level。
$ cat /proc/sys/kernel/printk 7 4 1 7 這是說 printk level 小/等 於 7 的,才會被印到 console。

這四個數值是寫在 /kernel/printk.c 中。
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */ /* We show everything that is MORE important than this.. */ #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */ int console_printk[4] = { DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */ DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */ MINIMUM_CONSOLE_LOGLEVEL, /* minimum_console_loglevel */ DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */ };

然後在 include/linux/kernel.h 中分別定義: extern int console_printk[]; #define console_loglevel (console_printk[0]) #define default_message_loglevel (console_printk[1]) #define minimum_console_loglevel (console_printk[2]) #define default_console_loglevel (console_printk[3])
在系統啟動以後,可以: $ cat "8 4 1 4" > /proc/sys/kernel/printk 改變 console level。

但是如果是連 kernel boot time 都要的話,就只有改 console_printk[] 了。

把 DEFAULT_CONSOLE_LOGLEVEL 定義成 8 就可以。

2012年8月27日 星期一

driver/host/Kconfig:
config USB_EHCI_ARC
 bool "Support for Freescale controller"
 depends on USB_EHCI_HCD && (ARCH_MXC || ARCH_STMP3XXX || ARCH_MXS)
 select USB_OTG_UTILS
 ---help---
    Some Freescale processors have an integrated High Speed
    USBOTG controller, which supports EHCI host mode.

    Say "y" here to add support for this controller
    to the EHCI HCD driver.


實際上.config:
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ARC=y
CONFIG_USB_EHCI_ARC_OTG=y
CONFIG_USB_EHCI_FSL_UTMI=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y




然後在 driver/usb/host...

然後 CONFIG_USB_EHCI_HCD::
drivers/usb/host/Makefile:obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o

CONFIG_USB_EHCI_ARC, _OTG 的:
arch/arm/mach-mx5/usb_h1.c:#ifdef CONFIG_USB_EHCI_ARC
arch/arm/mach-mx5/usb_dr.c:#ifdef CONFIG_USB_EHCI_ARC_OTG
arch/arm/mach-mx5/usb_dr.c:#endif /* CONFIG_USB_EHCI_ARC_OTG */
arch/arm/mach-mx5/usb_dr.c:#ifdef CONFIG_USB_EHCI_ARC_OTG
arch/arm/mach-mx5/usb_h2.c:#ifdef CONFIG_USB_EHCI_ARC
drivers/usb/host/ehci-hcd.c:#ifdef CONFIG_USB_EHCI_ARC
drivers/usb/otg/fsl_otg.c:  "CONFIG_USB_EHCI_ARC_OTG\n"



所以主要的好像就只有 driver/usb/host/ehci-hcd.c

然後這個 source include 很多其他的 .c
#include "ehci-dbg.c"
#include "ehci-hub.c"
#include "ehci-sched.c"
#include "ehci-arc.c"
#define PLATFORM_DRIVER  ehci_fsl_driver
以上就是實際compile 的 source code.

2012年8月26日 星期日

這樣看來,Nexus 7會是不錯的產品

為什麼不給一個後 相機呀?

果然很兩光,用這會被氣死。 輸入法一直當機,其他的也不能用。 結果1024x600還是不夠用。 先寫這些好了。

2012年8月24日 星期五

CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_ARC=y CONFIG_USB_EHCI_ARC_OTG=y CONFIG_MXC_OTG=y

2012年8月22日 星期三

hotspot (wifiap) 的 dhcp lease time

hotspot 的 dhcp,dns 等動作是交給 dnsmasq 這個程式來作。

netd 的 TetherController.cpp 是負責叫起 dnsmasq 動作的部份。

dnsmasq 跟一般的 command 一樣,是由 command argument 決定動作。
argument 也由 TetherController.cpp 負責。

dhcp 的 lease time 也由 argument 決定。

以下就是準備好 argument,然後用execv( ) 啟動 dnsmasq 的 code: int num_processed_args = 4 + (num_addrs/2) + 1; // 1 null for termination char **args = (char **)malloc(sizeof(char *) * num_processed_args); args[num_processed_args - 1] = NULL; args[0] = (char *)"/system/bin/dnsmasq"; args[1] = (char *)"--no-daemon"; args[2] = (char *)"--no-resolv"; args[3] = (char *)"--no-poll"; int nextArg = 4; for (int addrIndex=0; addrIndex < num_addrs;) { char *start = strdup(inet_ntoa(addrs[addrIndex++])); char *end = strdup(inet_ntoa(addrs[addrIndex++])); asprintf(&(args[nextArg++]),"--dhcp-range=%s,%s,1h", start, end); } if (execv(args[0], args)) { LOGE("execl failed (%s)", strerror(errno)); }

其中 : "--dhcp-range=%s,%s,1h" 最後一項就是 lease_time: 1h。


dnsmasq 啟動後,會由 read_opts( ) 負責 parsing argument, update parameter.



修改後,client 端可以用 showlease wlan0 這個 command 來看收到的 dhcp server 傳來的 lease time 是多少。

2012年8月21日 星期二

/external/dhcpcd/ 有一個 showlease ,可以用來看 dhcpcd 拿到的 ip lease time。

dhcp server 則是 netd 的 dnsmasq
system 下的 vold, netd 有類似的架構。
都是用 CommandListener.


netd 也負責 Tethering ,叫起 dnsmasq,這同時負責 dhcp (竟然不是獨立的 dhcp 程式)。

netd 負責很多事: class CommandListener : public FrameworkListener { static TetherController *sTetherCtrl; static NatController *sNatCtrl; static PppController *sPppCtrl; static PanController *sPanCtrl; static SoftapController *sSoftapCtrl; static UsbController *sUsbCtrl; static RouteController *sRouteCtrl;



CommandListenener 繼承 FrameworkListener。
FrameworkListener 是用 unix socket 作為溝通的 interface。

使用的 unix socket,要先 create 好 (init.rc:) service netd /system/bin/netd socket netd stream 0660 root system 然後在 netd 啟動的時候,告訴 FrameworkListener,要 listen 哪一個 unix socket (CommandListener.cpp) : CommandListener::CommandListener() : FrameworkListener("netd") { registerCmd(new InterfaceCmd()); registerCmd(new IpFwdCmd()); registerCmd(new TetherCmd()); registerCmd(new NatCmd()); registerCmd(new ListTtysCmd()); registerCmd(new PppdCmd()); registerCmd(new PanCmd()); registerCmd(new SoftapCmd()); registerCmd(new UsbCmd()); registerCmd(new RouteCmd());
command 的內容好像是用 plain text。

command 本身也是,所以每個 command 都有一個 "name" (CommandListener.cpp): CommandListener::TetherCmd::TetherCmd() : NetdCommand("tether") { }
FrameworkListener 從 netd socket 收到 command 後,在 dispatchCommand ( ) parsing 一下,
把command 整理成: command, argc, argv[],之後,比對 command 字串,
然後 call 比對到的 runCommand(cli, argc, argv)

2012年8月9日 星期四

usb auto_suspend & wakeup

奇怪,一個 usb hub 在 xp 下可以正常動作,在 7 下就 fail。

-- 發現只要 hub 上一直有插著裝置,就OK。

一旦 hub 空了,3,4 sec 後, hub 上的clk 就停了。
在 xp 上,即使 hub 空了,clk 也不會停。



大概是因為 7 的 usb driver 有 auto suspend 吧。
hub 支援 auto-suspend,所以 7 在問 hub 時,知道他可以 auto-suspend。
所以當 hub 上沒東西的時候,過一段時間, 7 就、把他 suspend 了。

為了配合,還要有 wakeup 功能。
一旦 suspend 後,只要有東西插入 hub,hub 就會發出 interrupt,通知 7。

這個wakeup function 在 linux source code 是(以 imx51 為例):
arch/arm/mach-mx5/usb_dr.c

2012年8月8日 星期三

debian-multimedia ---- deb-multimedia

www.debian-multimedia.org 改為 www.deb-multimedia.org 了
所以 apt update 會 fail..

ref : http://www.deb-multimedia.org/

2012年8月3日 星期五

NativeDaemonConnector
配合
INativeDaemonConnectorCallback

可以用來實做:程式中,需要用 Thread 來完成的動作。

任何 object 都可以用來同步。
任何 Handler 都可以用來作 message 傳遞。

?

obtainMessage, new Messasge

from http://www.cnblogs.com/android007/archive/2012/05/10/2494766.html

Android 中 SendMessage( ) 時,Message 主體都是用: msg = obtainMessage( ..)
然後再用 sendMessasge(msg) 送出去。

不用 General 的: msg = new Message( ) 的原因,是因為 obtainMessage 會從 message pool 中拿出來,
new 的話,就要請系統作記憶體管理,new object 出來。
所以 obtainMessage( ) 比較快。

2012年8月1日 星期三

unmount fail 的原因是因為沒有 任何一個 external storage 是 MOUTED,
所以 UNMOUNT 都沒作,
所以沒有 UNMOUNT DONE event,
所以 observer 沒有被 call 到.....

2012年7月27日 星期五

I/AudioService( 2563): AudioFocus abandonAudioFocus(): removing entry for android.media.AudioManager@2acbae28com.android.music.MediaPlaybackService$3@2acf7c78 E/JavaBinder( 2563): *** Uncaught remote exception! (Exceptions are not yet supported across processes.) E/JavaBinder( 2563): java.util.ConcurrentModificationException E/JavaBinder( 2563): at java.util.AbstractList$SimpleListIterator.next(AbstractList.java:64) E/JavaBinder( 2563): at android.media.AudioService.removeFocusStackEntry(AudioService.java:2214) E/JavaBinder( 2563): at android.media.AudioService.requestAudioFocus(AudioService.java:2331) E/JavaBinder( 2563): at android.media.IAudioService$Stub.onTransact(IAudioService.java:296) E/JavaBinder( 2563): at android.os.Binder.execTransact(Binder.java:320) E/JavaBinder( 2563): at com.android.server.SystemServer.init1(Native Method) E/JavaBinder( 2563): at com.android.server.SystemServer.main(SystemServer.java:730) E/JavaBinder( 2563): at java.lang.reflect.Method.invokeNative(Native Method) E/JavaBinder( 2563): at java.lang.reflect.Method.invoke(Method.java:507) E/JavaBinder( 2563): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) E/JavaBinder( 2563): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) E/JavaBinder( 2563): at dalvik.system.NativeStart.main(Native Method) I/AudioService( 2563): Remote Control registerMediaButtonEventReceiver() for ComponentInfo{com.android.music/com.android.music.MediaButtonIntentReceiver}

2012年7月25日 星期三

Muscic 的暫停與繼續..

Music 的 MediaPlaybackService.java :

logcat -s MediaPlaybackService 來看..

可以看到,Music 在background 繼續播放,在收到 AudioManger 的通之後,才會停止: case FOCUSCHANGE: // This code is here so we can better synchronize it with the code that // handles fade-in // AudioFocus is a new feature: focus updates are made verbose on purpose switch (msg.arg1) { case AudioManager.AUDIOFOCUS_LOSS: Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS"); if(isPlaying()) { mPausedByTransientLossOfFocus = false; } pause(); break;

但是其他的 event: AUDIOFOCUS_GAIN, AUDIOFOCUSE_LOSS_TRANSIENT 都沒收到。

從 code 來看, 這兩個 message 應該是在有電話進來的時候會有,先收到 LOSS_TRANSIENT。
等電話掛斷後,收到 AUDIOFOCUS_GAIN。




另外,BroadcastReceiver( ) 也有針對 play, pause, next, prev 的 cmd 操作,可以把 debugLog 修改一下: Log.v(LOGTAG,"mIntentReceiver.onReceive " + action + " / " + cmd);

這個 command 是給 Music app 自己用的 - 因為宣告成 class private variable.

上面的messasge 出來的是: V/MediaPlaybackService( 2610): mIntentReceiver.onReceive com.android.music.musicservicecommand / pause V/MediaPlaybackService( 2610): pause V/MediaPlaybackService( 2610): mIntentReceiver.onReceive com.android.music.musicservicecommand / pause V/MediaPlaybackService( 2610): pause V/MediaPlaybackService( 2610): onStartCommand

在 framework 裡找到用這個command(Intent) 的 code:

frameworks/base/core/java/android/widget/VideoView.java: private void openVideo() { if (mUri == null || mSurfaceHolder == null) { // not ready for playback just yet, will try again later return; } // Tell the music playback service to pause // TODO: these constants need to be published somewhere in the framework. Intent i = new Intent("com.android.music.musicservicecommand"); i.putExtra("command", "pause"); mContext.sendBroadcast(i);

Official UNIX tool for Windows

MS 官方的 unix tool: http://www.microsoft.com/en-us/download/details.aspx?id=2391

還有 nfs server for windows system 喔。

2012年7月20日 星期五

BandLuxe C331

log after eject /dev/sr1 (CDROM) [ 1980.712292] usb 2-1.1.4.2: USB disconnect, address 9 [ 1991.773362] usb 2-1.1.4.2: new high speed USB device using ehci_hcd and address 10 [ 1991.883062] usb 2-1.1.4.2: New USB device found, idVendor=1a8d, idProduct=2006 [ 1991.883068] usb 2-1.1.4.2: New USB device strings: Mfr=3, Product=2, SerialNumber=4 [ 1991.883072] usb 2-1.1.4.2: Product: BandLuxe 3.5G HSPA Adapter [ 1991.883075] usb 2-1.1.4.2: Manufacturer: BandRich [ 1991.883078] usb 2-1.1.4.2: SerialNumber: EE45B741112F4E2CB3F00AF0444EE4D1F1B8C491 [ 1991.883233] usb 2-1.1.4.2: configuration #1 chosen from 1 choice [ 1991.884062] cdc_acm 2-1.1.4.2:1.1: ttyACM0: USB ACM device [ 1991.884909] cdc_acm 2-1.1.4.2:1.3: ttyACM1: USB ACM device [ 1991.886971] eth1: register 'cdc_ether' at usb-0000:00:1d.0-1.1.4.2, CDC Ethernet Device, 00:26:fa:ee:45:b7 [ 1991.887235] scsi11 : SCSI emulation for USB Mass Storage devices [ 1991.887369] usb-storage: device found at 10 [ 1991.887373] usb-storage: waiting for device to settle before scanning [ 1996.883439] usb-storage: device scan complete [ 1996.883961] scsi 11:0:0:0: CD-ROM BandRich CDROM 0001 PQ: 0 ANSI: 0 [ 1996.884421] scsi 11:0:0:1: Direct-Access BandRich CDROM 0001 PQ: 0 ANSI: 0
browsers/BrowserProvider.java
提供的幫助有: private static final String[] SUGGEST_PROJECTION = new String[] { "_id", "url", "title", "bookmark", "user_entered" }; ... 發現這個好像是指.."在網址列輸入" 的部份...

Browser : Clear Search History -- Part I

找一下 "的網頁指出" ..
結果在:

base/core/res/res/values-zh-rTW/strings.xml:

使用者是:
base/core/java/android/webkit/CallbackProxy.java





猜是 confirm dialog:



所以是在處理 javascript 的 alert。

其中有 mWebChromeClient 不是 null 時,才會處理。

在 browser/Tab.java 中,有使用 setWebChromeClient..

所以... setWebViewClient( ) 和 setWebChromeClient( ) 的不同處是...?

ref: http://stackoverflow.com/questions/2835556/whats-the-difference-between-setwebviewclient-vs-setwebchromeclient

setWebChromeClient( ) 會處理 JS Alert。

拿 http://www.mkyong.com/tutorials/android-tutorial/ 的 WebView Example code 來測試這個 javascript alert 頁面。


試著拿掉 setWebChromeClient( ) 這行,執行時,就不會出現 dialog

標籤

網誌存檔