From Android developer website, they said Android 2.0 provides two new Bluetooth profiles: Object Push Profile (OPP) and Phone Book Access Profile (PBAP). Seeing is believing. Where is the meat? ha, I found they finally released their Bluetooth application source code. Therefore, I tried to verify OPP in Beagle board. :D As usual, I read Build-from-Scratch wiki page and download code from 0xdroid project with beagle-eclair branch. LIke beagle-donut, I can use USB mouse, keyboard, mount a SD sdcard, use USB networking, and then I turn Bluetooth on. It's very easy to set up the working environment with 0xdroid. Check Bluetooth application source code and install it in Beagleboard cd packages/apps git clone git://android.git.kernel.org/platform/packages/apps/Bluetooth.git cd Bluetooth git checkout -b eclair remotes/origin/eclair git pull source ../../../build/envsetup.sh mm adb install ../../../out/target/product/beagleboard/system/app/Bluetooth.apk
Trace related logWhen we saw the log like below, it means it provides OPP service in RFCOMM channel 12 and PBAP service in RFCOMM channel 19. I/bluedroid( 736): Starting hciattach daemon I/bluedroid( 736): Starting bluetoothd deamon
I/bluetooth_ScoSocket.cpp( 797): Listening SCO socket... V/BtOpp Service( 933): Service onCreate
V/BtOpp Service( 933): Starting RfcommListener in 9 seconds V/BtOpp Service( 933): Service onStartCommand
V/BluetoothPbapService( 933): Pbap Service onCreate V/BluetoothPbapService( 933): Starting PBAP service V/BluetoothPbapService( 933): Pbap Service onStartCommand
D/BluetoothService( 736): Registering hfag record D/BluetoothService( 736): Registering opush record D/BluetoothService( 736): Registering pbap record
V/BluetoothPbapService( 933): Handler(): got msg=1 V/BluetoothPbapService( 933): Pbap Service startRfcommSocketListener V/BluetoothPbapService( 933): Pbap Service initSocket V/BluetoothPbapService( 933): Succeed to create listening socket on channel 19
V/BtOpp Service( 933): start RfcommListener V/BtOpp Service( 933): RfcommListener started I/BtOppRfcommListener( 933): Accept thread started on channel 12
Receiving and sending out data via BluetoothCurrently, it only accepts few media types, like image, video, audio, text/plain and text/html and it should have the extension name. It cannot accept vcard and vcalendar. But we can modify few lines in 'Bluetooth/src/com/android/bluetooth/opp/Constants.java ', then it can store vcard files. One more problem, there is no matched application can view *.vcf file. I guess I can reference with previous beagle-donut code to fix it. All incoming files are stored in /sdcard/bluetooth folder. Also, there is a db file to record all Bluetooth application actions. # cd /sdcard/bluetooth # ls 08042009068.jpg 08042009068-1.jpg
# cd /data/data/com.android.bluetooth/databases # ls btopp.db # sqlite3 btopp.db SQLite version 3.5.9 Enter ".help" for instructions sqlite> .tables android_metadata btopp sqlite> select * from btopp; 1||08042009068.jpg||image/jpeg|1|00:18:C5:42:18:78|1|1|493|394450||946685154325|0 2|content://media/external/images/media/1|08042009068.jpg|/sdcard/bluetooth/08042009068.jpg|image/jpeg|1|00:18:C5:42:18:78|1|1|200|394450|394450|946685200379|1 3||olv.vcf|/sdcard/bluetooth/olv.vcf|text/x-vcard|1|00:18:C5:42:18:78|1|1|200|68|68|946685305125|2 4|file:///sdcard/bluetooth/08042009068.jpg|08042009068.jpg||image/jpeg|0|00:18:C5:42:18:78|1|2|200|394450|394450|946685368037|0 5||btopp_vcard.vcf|/sdcard/bluetooth/btopp_vcard.vcf|text/x-vcard|1|00:22:A5:B8:AD:65|1|1|496|168||946685701894|0 6||btopp_vcard.vcf|/sdcard/bluetooth/btopp_vcard.vcf|text/x-vcard|1|00:22:A5:B8:AD:65|1|1|200|168|168|946685806848|2 7||08042009068.jpg||image/jpeg|1|00:18:C5:42:18:78|1|4|490|394450||946698435289|0 8||08042009068.jpg||image/jpeg|1|00:18:C5:42:18:78|1|4|490|394450||946698501841|0 9|content://media/external/images/media/1|08042009068.jpg|/sdcard/bluetooth/08042009068.jpg|image/jpeg|1|00:18:C5:42:18:78|1|1|200|394450|394450|946698554454|1 10|content://media/external/images/media/2|08042009068-1.jpg|/sdcard/bluetooth/08042009068-1.jpg|image/jpeg|1|00:18:C5:42:18:78|1|1|200|394450|394450|946698717592|1 11|file:///sdcard/bluetooth/08042009068-1.jpg|08042009068-1.jpg||image/jpeg|0|00:22:A5:B8:AD:65|1|2|495|394450|0|946698901473|0 12|content://media/external/images/media/2|08042009068-1.jpg||image/jpeg|0|00:18:C5:42:18:78|1|2|200|394450|394450|946699019695|0
Screenshots from beagle-eclair
* Turn Bluetooth On * Pair with Nokia N73 phone * Receive an image from N73 to Beagle board via BT * Send an image from Beagle board to N73 via BT
There is a very friendly and pretty cool project called ' Sikuli' and the authors are from Taiwan too. What is Sikuli? I copy these texts from its website. Sikuli is a visual technology to search and automate graphical user interfaces (GUI) using images (screenshots). The first release of Sikuli contains Sikuli Script, a visual scripting API for Jython, and Sikuli IDE, an integrated development environment for writing visual scripts with screenshots easily. Sikuli Script automates anything you see on the screen without internal API's support. You can programmatically control a web page, a desktop application running on Windows/Linux/Mac OS X, or even an iphone application running in an emulator. How I use Sikuli for Android? Since we can catch things from screenshots, it means we can run Android emulator in my Ubuntu machine. Furthermore, I can run a vnc server in Android device, then run a vnc viewer in Ubuntu. Therefore, I can see Android HOME screen in my Desktop. What it can do for me? ha, it can run automated tests and then we don't need SQA to verify phone basic functionalities. Like detect GSM signal, dial out a phone call, enable Bluetooth, connect to WiFi hotspot....etc. Launch Sikuli IDE editor in Ubuntu wget http://sikuli.org/dl/Sikuli-IDE-linux-20100104.zip unzip Sikuli-IDE-linux-20100104.zip sh Sikuli-IDE/sikuli-ide.sh
Launch Android in UbuntuThere is another tool " androidscreencast" I am using for this automated test. It can allow me to control my Android Dev phone remotely. We can have keyboard and mouse input! This is very important for Sikuli scripts, coz I can say "Click" something or "type" something. :) wget http://androidscreencast.googlecode.com/svn/trunk/AndroidScreencast/dist/androidscreencast.jnlp javaws androidscreencast.jnlp
 Let's write some examples! Please check these draft videos! Build Sikuli in Ubuntu 9.10 (64 bit) 1. download the source code (you'll need to install bzr, if you don't have it) > bzr branch lp:sikuli 2. check java version (use java-6-sun) erin@midnight:~/code/sikuli$ file /etc/alternatives/java /etc/alternatives/java: symbolic link to `/usr/lib/jvm/java-6-sun/jre/bin/java' erin@midnight:~/code/sikuli$ file /etc/alternatives/javac /etc/alternatives/javac: symbolic link to `/usr/lib/jvm/java-1.5.0-sun/bin/javac' 3. install some libraries tesseract-ocr - Command line OCR tool tesseract-ocr-dev - Development files for the tesseract command line OCR tool maven2 - Java software project management and comprehension tool libcv1 - computer vision library libcvaux1 - computer vision extension library libhighgui1 - computer vision GUI library 4. build code>cd sikuli-script >make g++ ScreenMatchProxy.o ocr-matcher.o template-matcher.o myocr.o screendiff.o -o ../../../target/lib/libScreenMatchProxy.so `pkg-config --libs opencv` -shared -L/usr/local/lib -I/usr/lib/jvm/java-6-sun/lib -ltesseract_full -ltiff /usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/4.4.1/../../../../lib/libtesseract_full.a(libtesseract_full.o): relocation R_X86_64_32 against `BLOCK_zapper(ELIST_LINK*)' can not be used when making a shared object; recompile with -fPIC /usr/lib/gcc/x86_64-linux-gnu/4.4.1/../../../../lib/libtesseract_full.a: could not read symbols: Bad value collect2: ld returned 1 exit status make[1]: *** [../../../target/lib/libScreenMatchProxy.so] Error 1 how i solved: i removed -ltesseract_full, then rebuilt it! >cd src/main/native/ >g++ ScreenMatchProxy.o ocr-matcher.o template-matcher.o myocr.o screendiff.o -o ../../../target/lib/libScreenMatchProxy.so `pkg-config --libs opencv` -shared -L/usr/local/lib -I/usr/lib/jvm/java-6-sun/lib -ltiff >make install-jar (it would build sikuli-script.jar, that is what we need!) >make release (it would build for all platforms, then zip to a file.) erin@midnight:~/project/sikuli/sikuli-script$ make release mkdir -p target/sikuli-script rm -rf target/sikuli-script/* cp target/sikuli-script.{bat,sh} target/sikuli-script cp: cannot stat `target/sikuli-script.{bat,sh}': No such file or directory make: *** [release] Error 1 how i solved: modify two lines in sikuli-script/Makefile and mkdir ../release cp target/sikuli-script.bat target/sikuli-script.sh $(RELEASE_TMP_PATH) cp -r $(LIB_PATH)/win32 $(LIB_PATH)/tmplib $(RELEASE_TMP_PATH) Done! you will find a zip file 'Sikuli-Script-all-20100128.zip' in release directory. >cd sikuli-ide >make install-jar >make major-release Done! you will find a zip file 'Sikuli-IDE-linux-20100128.zip' in release directory. This one is like we download from Sikuli website for linux version.
 If you noticed the source code in Eclair branch, you will find few differences in Bluetooth function. There are three new git repositories for bluetooth. "bluez", "glib" and "hcidump", all of them are located in /external/bluetooth folder, not /external/bluez anymore. bluez
android source: git://android.git.kernel.org/platform/external/bluetooth/bluez.git Eclair is using bluez version 4.47 and the big difference would be bluez API. Since it has a lot of changes between bluez3 (android 1.6) and bluez4 (Android 2.0), we can tell from the documents in doc folder. Or we can use dbus-send to get the detailed information.
# dbus-send --system --type=method_call --print-reply --dest=org.bluez / org.bluez.Manager.DefaultAdapter method return sender=:1.2 -> dest=:1.3 object path "/org/bluez/932/hci0"
# dbus-send --system --type=method_call --print-reply --dest=org.bluez /org/bluez/932/hci0 org.freedesktop.DBus.Introspectable.Introspect
Also, bluetooth service name is changed in Eclair. It's "bluetoothd" now. Check init.rc in /system/core/rootdir. service bluetoothd /system/bin/bluetoothd -d -n socket bluetooth stream 660 bluetooth bluetooth socket dbus_bluetooth stream 660 bluetooth bluetooth # init.rc does not yet support applying capabilities, so run as root and # let bluetoothd drop uid to bluetooth with the right linux capabilities group bluetooth net_bt_admin misc disabled
glibandroid source: git://android.git.kernel.org/platform/external/bluetooth/glib.git When we build bluez library, it would build glib as a static library. GLib provides the core application building blocks for libraries and applications written in C. It provides the core object system used in GNOME, the main loop implementation, and a large set of utility functions for strings and common data structures. If you are interested in how bluez use glib, you can trace bluez source code. new Bluetooth API
http://developer.android.com/guide/topics/wireless/bluetooth.html About Bluetooth, Android website has a very good document. It lists the functions and example code. Bluetooth * Turn on/off Bluetooth * Device and service discovery * Connect to a remote device using RFCOMM and send/receive data * Advertise RFCOMM services and listen for incoming RFCOMM connection
Bluetooth Chat applicationWhat I am curious? It's related to using RFCOMM and send/receive data. In the beginning, I am not quite understand and I thought it's OBEX. After running Bluetooth Chat application, I know what it means now. I installed 0xlab experimental eclair image in Beagle board and installed Bluetooth chat example from Android. I also run a python script in my ubuntu machine and it's from pybluez. Then, I can chat between Beagle board and my laptop via Bluetooth. When we start to run Bluetooth Chat application, it would create a RFCOMM socket and set it to listen mode. We can retrieve the information from sdptool. Then other BT devices can connect to Android using RFCOMM protocol and set channel to the same one. # sdptool browse local Browsing FF:FF:FF:00:00:00 ... Service Name: BluetoothChat Service RecHandle: 0x10005 Service Class ID List: UUID 128: fa87c0d0-afac-11de-8a39-0800200c9a66 Protocol Descriptor List: "L2CAP" (0x0100) "RFCOMM" (0x0003) Channel: 30
年終了。 最近幾個月不知道為什麼,沒辦法專心工作。利用上 ptt 跟看漫畫的空檔,把說很久的特效弄出可以 demo 的樣子 感謝 Erin 的幫忙,這段影片展示了 Cube 跟 Fire 特效。 WindowManagerService 允許的地方都可以接特效,但現在只有接在程式啟動時。 目前的進展可以在 gitorious 上取得。不過很顯然地,還有很多東西要弄。
Sometime I feel like I need to slow down my pace and my mind and now the time it is. Either for quiet thinking, intending to watch more or thinking about changing something. As you can see, I am a lazy blogger and not a good writer. Passion is the momentum for anything you want to do and it's the best gift.
Here are something about my work recently. Write it down here for arrangement. It's about 0xdroid project. I have done implementing Camera HAL for usb camera. For this, I need to have some concept about V4L2 in kernel. It's related to V4L2 Video In. Though camera is more complicated cause it can be greatly performance related when it comes to embedded device. For most product design, the camera sensor module is connected with the camera interface of the SOC. Thus in this manner, most cases there will be closed library provided by the SOC vendor for doing some effect control and performance related tasks.
When doing video recording with the camera, colorspace conversion for encoding and for preview on the screen to make the acceptable frame rate is really critical, especially when the resolution is high. Better situation will be more task can be handled by hardware. For taking picture, it would be better if the hardware can do scaling and jpeg encoding, etc. For previewing and video recording, it also would be cool if we don't need to do heavy colorspace conversion in host software side by hardware conversion(YUYV to YUV420(sp) or RGB) and Overlay support.
Overlay is cooperated with V4L2 video out part. Overlay verifying and could be used by Camera HAL or multimedia video playback is important.
More ahead. Though I need to let myself know what's the value and getting prepared.
Off topic here in this post, most importantly, Glad and excited that we have a third release, beagle-donut-0x3.
So exciting is our brand new release called ' 0xdroid beagle donut-0x3' that we forgot all about the coming bad weather in Taipei (raining, humid, and chill). This is our third released image for Beagle board in Android and it's based on Donut branch. If you have a beagle board on hand, you may give it a try. We provide a ' Happy installer' tool and it could give you a 'no pain no tears' good experiences on installing Android. Here is a 2 minutes video in youtube based on real booting time! If you don't have any beagle board to see our work, you could take it a look from our released videos in youtube. What kind of meat we have this time? Easy access to Internet through USB OTG network routed via host- Ethernet support + USB OTG network with default static IP configurations ...
Performance improvements- Dalvik VM + JIT compiler for ARMv7 ...
- ARM NEON optimizations for PixelFlinger ...
Theme Flexibility- Theme selector introduced ...
- Flexible resolution support for Launcher ...
More and better peripheral support- External GSM modem for functional Android Telephony/RIL ...
- Bluetooth OBEX OPush and FTP support ...
- Motion sensor support ...
- Camera capture / recording ...
Stability improvements with several issues fixed- Dalvik stability fix ...
- Wifi signal strength with Linux Wireless Extension fix ...
- Mouse stability fix ...
Here is our Roadmap about all these releases. If you have interest on particular item, you could get more information from our issue tracker. Furthermore, we welcome your feedback or any suggestion on 0xlab-devel mailing list! Frankly speaking, my favorite feature in this released image is neither Bluetooth Obex nor GSM modem, what I like most is our theme launcher. It has a Christmas theme inside. This theme is our best wishes. Wish everyone have a Merry Christmas and a Happy New Year!  
If you saw my previous post, it was mentioned my next step is to integrate this 3-axis accelerometer into Android. To prove my implementation could work flawlessly, I ask my colleague, Jeremy to record the following clip. The demo application is called 3D Level. The HAL implementation could be found here: http://gitorious.org/0xdroid/hardware_libhardwareIt's based on Michael's porting on Android for Openmoko GTA02.
Android 2.0 (Eclair) 原始程式碼已於一個月前釋出,在目錄 system/core 下有個 libacc 的子項目,這是開發者修改自 Fabrice Bellard 的大作 OTCC (Obfuscated Tiny C Compiler),以 C++ 與 Android 的執行時期函式庫重寫。libacc 的功能是提供給 Android 2.0 的 RenderScript 一個 C-like 語法的描述,如此一來,開發者可撰寫高效能的視覺效果與動畫,不過這部份並未完成,詳情可參考 " Android renderscript, more info' and an example application" 一文。 關於 libacc 的整合部份,可參考 frameworks/base/libs/rs 目錄下的兩個檔案: - rsScriptC.cpp
- rsScriptC_Lib.cpp
筆者準備了一份可單獨執行於 GNU/Linux 環境的套件:" libacc.tar.bz2",除去 Android 的相依性並補上 Makefile,測試方式如下: libacc$ make g++ -I./include -DHAVE_PTHREADS -c acc.cpp gcc -I./include -DHAVE_PTHREADS -c hashmap.c gcc -I./include -DHAVE_PTHREADS -c logd_write.c g++ -I./include -DHAVE_PTHREADS -c tests/main.cpp g++ -I./include -DHAVE_PTHREADS -c tests/runtimeTest.cpp g++ -o main \ acc.o \ hashmap.o \ logd_write.o \ main.o \ -ldl g++ -o runtimeTest \ acc.o \ hashmap.o \ logd_write.o \ runtimeTest.o \ -ldl
libacc 的 Code generator 支援以下硬體架構: 以 IA32 的環境為例,可透過測試程式來驗證 libacc: (參數 -R 表示作執行的動作) libacc$ ./main -R tests/data/hello.c Executing compiled code: Hello, world result: 0
其中 tests/data/hello.c 的內容為: libacc$ cat tests/data/hello.c int main() { printf("Hello, world\n"); return 0; }
若平台是 ARM 的話,還可以支援反組譯輸出,libacc 是 RenderScript 背後很重要的基礎建設,允許動態編譯 Android Graphics 的 RenderScript,輸出成機械碼並執行。參考檔案 tests/runtimeTest.cpp 可得知 RenderScript 的寫法,整個 libacc 可內嵌於程式中,比方說: const char* text = "void op_int(int a);\n" "void op_float12(float a, float b, float c, float d,\n" " float e, float f, float g, float h,\n" " float i, float j, float k, float l);\n" "void script() {\n" " globalVar += 3;\n" " op_int(123);\n" " op_float12(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0);\n" "}\n";
這個字串經過 libacc 的函式呼叫後,可得到以下的編譯與執行結果: libacc$ ./runtimeTest Executing script: op_int(123) op_float12(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) After script globalVar = 20
目錄 tests 還包含可在 Android 環境執行的自動測試 Python script。
First of all, I would like to thanks Jerry, who is the project manager from STMicroelectronic Taiwan branch. He sponsored 0xlab couple chips of LIS302DL, which is a 3-axis accelerometer device. And Neo (YOSUN's FAE) provides me a fixture for this device. So everything is ready for me to make it work on the Beagleboard. - LIS302DL You probably feel it is looked familiar. Yes, this chip is the same motion sensor as Openmoko Freerunner used. The only difference is that its interface would be adopted I2C instead of 3-wire SPI for Beagleboard. - Power source for LIS302DL If you probe the schematic of Beagleboard, the expansion header (J3) reserved DC 5v and VIO 1v8 respectively. You can leverage these as the power source for your own devices. Unfortunately, the range of Vdd for LIS302DL is located between 2v16 and 3v6. DC 5v is not fulfilled for this case. So tinker DC 5v is needed. Zerner diode can regulator the voltage as you want. In this case, one reistor and one zerner diode are required. - TSX0102 It's very Beagleboard specific or you can say it's TI specific. If you want to add an external device on the Beagleboard, a voltage level translator might be necessity. Since most of current devices, the least signaling I/O would be around 2v6. But Beagleboard only provides 1v8 voltage as I/O signaling. The real reason behind this I don't know about it. Maybe for the power consumption issue. Or can I call it's a kind of "product placement"? :p - Interrupt Basically, all the I/O to the host controller, Beagleboard, are based on 1v8 signaling. The I2C communication is through TXS0102 to talk between host and device. But there is one more line for one-directional signaling, that is interrupt from LIS302DL to host. My former colleague, Dkay, suggested a simple approach to reslove this. A diode and two pull high resistors would be enough  . - Kernel driver The corresponding kernel driver is put here: http://gitorious.org/0xlab-kernel/kernel Edit your kernel config with CONFIG_INPUT_ST_MOTION_SENSOR=y. The following picture is the overall picture for this work. Although it's not pretty, but it works perfectly. With evtest utility, I can retrieve input events from LIS302DL device.  # ./evtest /dev/input/event1 Input driver version is 1.0.0 Input device ID: bus 0x18 vendor 0x0 product 0x0 version 0x0 Input device name: "LIS302DL Motion Sensor" Supported events: Event type 0 (Sync) Event type 3 (Absolute) Event code 0 (X) Value 3 Min 0 Max 0 Event code 1 (Y) Value 245 Min 0 Max 0 Event code 2 (Z) Value 56 Min 0 Max 0 Testing ... (interrupt to exit) Event: time 12.269714, type 3 (Absolute), code 0 (X), value 4 Event: time 12.269989, type 3 (Absolute), code 1 (Y), value 245 Event: time 12.270233, type 3 (Absolute), code 2 (Z), value 55 Event: time 12.270233, -------------- Report Sync ------------ Event: time 12.273864, type 3 (Absolute), code 0 (X), value 3 Event: time 12.274200, type 3 (Absolute), code 2 (Z), value 56 Event: time 12.274200, -------------- Report Sync ------------ Event: time 12.284332, type 3 (Absolute), code 0 (X), value 4 Event: time 12.284545, type 3 (Absolute), code 1 (Y), value 244 Event: time 12.284698, -------------- Report Sync ------------ Event: time 12.294403, type 3 (Absolute), code 0 (X), value 3 Event: time 12.294799, type 3 (Absolute), code 2 (Z), value 55 Event: time 12.294799, -------------- Report Sync ------------ Event: time 12.304840, type 3 (Absolute), code 1 (Y), value 245 Event: time 12.305023, -------------- Report Sync ------------ Event: time 12.315063, type 3 (Absolute), code 1 (Y), value 244 Event: time 12.315277, type 3 (Absolute), code 2 (Z), value 56
So, what's the next? Making it integrated into Android would be a good idea.
About providing Bluetooth FTP & OPP profile issue, I've merged all related source code to 0xdroid begle-donut branch. I verified these two services in both Beagle board and Android Dev phone. It looks good now. When we turn BT on, we start ' obex-client' service in the background. It would register a record to SDP server in bluez and then other BT devices can find we provide this service. How it looks like? We provide channel 7 for FTP. Other BT device can browse our file system using rfcomm. They can pull data from us, modify file name, delete file, or push data to us. Below it's FTP record in SDP database: Service Name: File Transfer server Service RecHandle: 0x10003 Service Class ID List: "OBEX File Transfer" (0x1106) Protocol Descriptor List: "L2CAP" (0x0100) "RFCOMM" (0x0003) Channel: 7 "OBEX" (0x0008) Profile Descriptor List: "OBEX File Transfer" (0x1106) Version: 0x0100
 Let's explain it and trace the source code. Eg. CreateSession method call in obex-client dbus APIHow we connect obex-client with Bluetooth UI? [using JNI, aidl, and d-bus] We register a FTP service from AndroidRuntime. We also create few methods and it's based on obex client API document. Below texts are related source code: AndroidRuntime.cpp REG_JNI(register_android_server_BluetoothFtpService),
android_server_BluetoothFtpService.cpp int register_android_server_BluetoothFtpService(JNIEnv *env) { jclass clazz = env->FindClass("android/server/BluetoothFtpService");
method_onCreateSessionComplete = env->GetMethodID( clazz, "onCreateSessionComplete", "(Ljava/lang/String;Ljava/lang/String;Z)V" ); method_onChangeFolderComplete = env->GetMethodID( clazz, "onChangeFolderComplete", "(Ljava/lang/String;Ljava/lang/String;Z)V" ); return AndroidRuntime::registerNativeMethods(env, "android/server/BluetoothFtpService", sMethods, NELEM(sMethods)); }
Below text is the sequence from UI to native code and then back to UI. RemoteFileManagerActivity.java (Pick up one device from remote tab in Bluetooth UI) public boolean onOptionsItemSelected(MenuItem item) { // Intent intent; switch (item.getItemId()) { case MENU_SELECT_SERVER: if (mFTPClient.isConnectionActive()) { Toast.makeText(this, R.string.error_ftp_connect_timeout, Toast.LENGTH_LONG).show(); } else { /* Connect to Server */ handleServerSelect(); }
public void handleServerSelect() { mDirectoryButtons.removeAllViews(); currentDirectory = "/"; if (mContext.isBluetoothEnabled()) { Intent intent = new Intent(getApplicationContext(), BluetoothDevicePicker.class); intent.setAction(BluetoothAppIntent.ACTION_SELECT_BLUETOOTH_DEVICE); intent.putExtra(BluetoothAppIntent.PROFILE, BluetoothAppIntent.PROFILE_FTP); intent.setData(Uri.parse("file://" + currentDirectory)); try { startActivityForResult(intent, SUBACTIVITY_PICK_BT_DEVICE); } catch (ActivityNotFoundException e) { Log.e(TAG, "No Activity for : " + BluetoothAppIntent.ACTION_SELECT_BLUETOOTH_DEVICE, e); } } }
protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) { case SUBACTIVITY_PICK_BT_DEVICE: if (resultCode == RESULT_OK && data != null) { /* Obtain the Server name and Address */ String serverAddress = data.getStringExtra(BluetoothDevicePicker.ADDRESS); String serverName = data.getStringExtra(BluetoothDevicePicker.NAME); if (mFTPClient != null) { mFTPClient.setAddress(serverAddress); mFTPClient.setName(serverName); mServerConnectButtonLayout.setVisibility(View.GONE); if(mFTPClient.createSession() != true) { String szStr = getResources().getString(R.string.ftp_connect_failed, mFTPClient.getName()); Toast.makeText(this, szStr, Toast.LENGTH_LONG).show(); updateServerStatus(); } else { String szStr = getResources().getString(R.string.ftp_connect_device, mFTPClient.getName()); showBusy(mFTPClient.getName(), szStr); } } } break; } } /* onActivityResult */
BluetoothFtpService.java (handle from Android Frameworks) public synchronized boolean createSession(String address, IBluetoothFtpCallback callback) { /* * Need to register callback before calling native code * (which could potentially call callback) */ BluetoothObexDatabase.SessionDbItem dbItem = mSessionDb.new SessionDbItem(address,null,callback); mSessionDb.insert(dbItem);
boolean ret = createSessionNative(address);
if (!ret) { mSessionDb.deleteByAddress(address); }
return ret; }
android_server_BluetoothFtpService.cpp (use JNI and send a dbus method call to obex-client) static jboolean createSessionNative(JNIEnv* env, jobject object, jstring address ) { DBusMessage *msg = dbus_message_new_method_call(OBEXD_DBUS_CLIENT_SVC, OBEXD_DBUS_CLIENT_PATH, OBEXD_DBUS_CLIENT_IFC, OBEXD_DBUS_CLIENT_CREATE);
pending = (dbus_async_call_t *) malloc(sizeof(dbus_async_call_t)); if (pending) { DBusPendingCall *call; char *context_address = (char *) calloc(BTADDR_SIZE, sizeof(char)); strlcpy(context_address, c_address, BTADDR_SIZE); // for callback pending->env = env; pending->user_cb = onCreateSessionComplete; pending->user = context_address; pending->nat = nat; dbus_bool_t reply = dbus_connection_send_with_reply(nat->conn, msg, &call, 10*1000);
/external/obexd/client/main.c (handle from obex-client) static DBusMessage *create_session(DBusConnection *connection, DBusMessage *message, void *user_data) { if (session_create(source, dest, target, create_callback, data) == 0) return NULL;
/external/obexd/client/session.c (use rfcomm to connect with specific channel ) int session_create(const char *source, const char *destination, const char *target, session_callback_t function, void *user_data) { if (session->channel > 0) { err = rfcomm_connect(&session->src, &session->dst, session->channel, rfcomm_callback, callback);
android_server_BluetoothFtpService.cpp (we get the callback!) static void onCreateSessionComplete(DBusMessage *msg, void *user, void *nat_cb) { char* c_address = (char *)user; JNIEnv *env = NULL; nat->vm->GetEnv((void**)&env, nat->envVer); jstring address = env->NewStringUTF(c_address);
env->CallVoidMethod(nat->me, method_onCreateSessionComplete, obj_path, address, is_error);
BluetoothFTPClient.java (handle from Bluetooth UI) public void onCreateSessionComplete(boolean isError) { Message msg = Message.obtain(); msg.what = TYPE_CREATE_SESSION_COMPLETE; Bundle b = new Bundle(); b.putBoolean("isError", isError); msg.obj = b; mHandler.sendMessage(msg); }
RemoteFileManagerActivity.java (device is connected, going to refresh panel to display Remote file system) public void onCreateSessionComplete(boolean isError) { mSessionCreated = !isError; hideBusy(); if (mFTPClient != null) { if (isError == false) { mContext.onServerConnected(); goHomeDir(); } else { String szStr = getResources().getString(R.string.ftp_connect_failed, mFTPClient.getName()); Toast.makeText(this, szStr, Toast.LENGTH_LONG).show(); } } updateServerStatus(); refreshDirectoryPanel(); }

There is a Radio Layer Interface in Android and it is about telephony service. Like my previous article, I was working on using an external GSM modem in Beagle board. Currently, I am using it to verify telephony service and I can trace the whole log between framework (Telephony service) and ril-daemon. It is the real GSM network and then I can trace the traffic between modem and GSM base station. Here is some RIL information from Android Platform Development Kit.  RIL InitializationAndroid initializes the telephony stack and the Vendor RIL at startup as described in the sequence below: RIL daemon reads rild.lib path and rild.libargs system properties to determine the Vendor RIL library to use and any initialization arguments to provide to the Vendor RIL - these arguments are from /system/build.propeg. rild.libpath=/system/lib/libreference-ril.so rild.libargs=-d /dev/pts/0 RIL daemon loads the Vendor RIL library and calls RIL_Init to initialize the RIL and obtain a reference to RIL functions - open modem device - connect with telephony service (Android Frameworks) RIL daemon calls RIL_register on the Android telephony stack, providing a reference to the Vendor RIL functions - start listen socket (SOCKET_NAME_RIL = rild) - set ril event to listenCallback function  Below text is from radio log and we can see the sequence: I/RIL ( 954): Opening tty device /dev/pts/0 D/AT ( 954): entering mainLoop() I/RILJ ( 820): Connected to 'rild' socket I/RILC ( 954): libril: new connection D/RILC ( 954): [UNSL] UNSOL_RESPONSE_RADIO_STATE_CHANGED {RADIO_UNAVAILABLE} D/RILJ ( 820): Radio OFF @ init D/RILJ ( 820): [UNSL] UNSOL_RESPONSE_RADIO_STATE_CHANGED RADIO_UNAVAILABLE I/RILC ( 954): RIL Daemon version: android reference-ril 1.0 D/AT ( 954): AT AT-Command Interpreter ready D/RILC ( 954): [UNSL] UNSOL_RESPONSE_RADIO_STATE_CHANGED {RADIO_OFF} D/AT ( 954): AT> ATE0Q0V1 D/AT ( 954): ATE0Q0V1 D/RILB ( 820): Notifying: radio available
RIL InteractionThere are two forms of communication that the RIL handles: Solicited commands: Solicited commands originated by RIL lib, such as DIAL and HANGUP. The vendor RIL must provide the functions described in the table below to handle solicited commands. The RIL solicited command request types are defined in ril.h with the RIL_REQUEST_ prefix. Check the header file for details. eg. ask GSM network signal strength Send a request from framework (telephony service) to GSM modem (ril-daemon) D/GSM ( 791): EVENT_POLL_SIGNAL_STRENGTH D/RILJ ( 791): [0048]> SIGNAL_STRENGTH D/RILJ ( 791): send rr to ril-daemon... D/RILJ ( 791): [0048]> SIGNAL_STRENGTH D/RILJ ( 791): EVENT_SEND 001 V/RILJ ( 791): writing packet: 8 bytes D/RILC ( 943): [0048]> SIGNAL_STRENGTH D/RIL ( 943): onRequest: SIGNAL_STRENGTH D/AT ( 943): AT> AT+CSQ D/AT ( 943): AT+CSQ D/AT ( 943): +CSQ: 20,99 D/AT ( 943): OK D/AT ( 943): AT +CSQ: 20,99 D/AT ( 943): AT OK D/RILC ( 943): [0048] SIGNAL_STRENGTH {[ 20 99]} V/RILJ ( 791): Read packet: 40 bytes D/RILJ ( 791): [0048] SIGNAL_STRENGTH {20, 99, 0, 0, 0, 0, 0} D/GSM ( 791): EVENT_GET_SIGNAL_STRENGTH D/GSM ( 791): [PhoneNotifier] notifySignalStrength D/GSM ( 791): GSMPhone getSignalStrength
Unsolicited responses: Unsolicited responses that originate from the baseband, such as CALL_STATE_CHANGED and NEW_SMS. eg. Receive an incoming call (from ril-daemon to telephony service) D/AT ( 943): RING D/AT ( 943): AT RING D/RILC ( 943): [UNSL] UNSOL_RESPONSE_CALL_STATE_CHANGED V/RILJ ( 791): Read packet: 8 bytes D/RILJ ( 791): [UNSL] UNSOL_RESPONSE_CALL_STATE_CHANGED D/GSM ( 791): [GsmCallTracker] checkNoOperationsPending: pendingOperations=0 D/RILJ ( 791): [0283]> GET_CURRENT_CALLS D/RILJ ( 791): send rr to ril-daemon... D/RILJ ( 791): [0283]> GET_CURRENT_CALLS D/RILJ ( 791): EVENT_SEND 001 V/RILJ ( 791): writing packet: 8 bytes D/RILC ( 943): [0283]> GET_CURRENT_CALLS D/RIL ( 943): onRequest: GET_CURRENT_CALLS D/AT ( 943): AT> AT+CLCC D/AT ( 943): AT+CLCC D/AT ( 943): +CLCC: 1,1,4,0,0,"0952123687",129,"808 D/AT ( 943): 42C771F" D/AT ( 943): OK D/AT ( 943): AT +CLCC: 1,1,4,0,0,"0952123687",129,"80842C771F" D/AT ( 943): AT OK D/RILC ( 943): [0283] GET_CURRENT_CALLS {[id=1,INCOMING,toa=129,norm,mt,als=0,voc,noevp,0952082687,cli=0,name='(null)',0} V/RILJ ( 791): Read packet: 88 bytes D/RILJ ( 791): InCall VoicePrivacy is disabled D/RILJ ( 791): [0283] GET_CURRENT_CALLS [id=1,INCOMING,toa=129,norm,mt,0,voc,noevp,,cli=1,,0]
PS. tag information RIL: /hardware/ril/reference-ril/refereince-ril.c AT: /hardware/ril/reference-ril/atchannel.c RILD: /hardware/ril/rild/rild.c RILC: /hardware/ril/libril/ril.cpp RILJ: /frameworks/base/telephony/java/com/android/internal/telephony/gsm/RIL.java GSM: /frameworks/base/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
最近 mesa3d-dev mailing list 有一個討論串在討論 bit counting,也就是在算一個 unsigned int 裡有幾個 bit 是 1。 假設 unsigned int 有 32 bits 寬,最簡單的算法就是一個迴圈跑 32 次,一個一個 bit 去看。想當然這不是有效率的算法。事實上,只要做 簡單的修改,就可以讓迴圈跑的次數降到跟 bit 為 1 的 bit 數相同。換句話說,如果 unsigned int 裡只有 3 個 bit 為 1,迴圈只要跑三次就可以。不過像這麼基礎的運算,一定有不少人下過功夫在找最快的算法。一個問題,工程師會去尋找更好的方法;但是身為鄉民,我們感興趣的只有最好的方法,而且我們從不自己找!很幸運地,在最開頭提到的討論串裡頭,就有人提出一個號稱最快的算法。 討論串中提到的方法經過簡化可以寫成 int bitcount(unsigned int v) { v = v - ((v >> 1) & 0x55555555); v = (v & 0x33333333) + ((v >> 2) & 0x33333333); v = (v + (v >> 4)) & 0x0f0f0f0f; return (v * 0x01010101) >> 24; } 在深入去看這段程式碼前,最好可以用抽像點的方式看它想做的事  上圖中,v0 是使用者的輸入。展開成二進位表示法,每個 bit 的值不是 1 就是 0。如果有一個方法可以讓所有的 bit 變成兩個兩個一組 (v1)、4 個 4 個一組 (v2)、8 個 8 個一組 (v3)、一直到 32 個 bit 自己成一組 (v5),那 v5 的值剛好就是我們要的結果。從 v4 看起,假設我們已經有 v4 了,那麼應該不難發現 v5 = (v4 & 0xffff) + (v4 >> 16); 以此類推,很快就可以發現我們需要的是 int bitcount2(unsigned int v) { v = (v & 0x55555555) + ((v >> 1) & 0x55555555); /* v1 */ v = (v & 0x33333333) + ((v >> 2) & 0x33333333); /* v2 */ v = (v & 0x0f0f0f0f) + ((v >> 4) & 0x0f0f0f0f); /* v3 */ v = (v & 0x00ff00ff) + ((v >> 8) & 0x00ff00ff); /* v4 */ v = (v & 0x0000ffff) + ((v >> 16) & 0x0000ffff); /* v5 */ return v; } 這時再回過頭去看 bitcount,可以注意到雖然算法不完全相同,但它前三行在做的也是求 v1、v2 與 v3。但它接下來不是求 v4,而是把 v3 乘上 0x01010101。透過四則運算,這個乘法可以改寫成加法 v = (v3 24) + (v3 16) + (v3 8) + v3 把 v3 的展開式代入,會發現  將這個結果向右 shift 24 bits 得到的也是 v5。這就是 bitcount 的做法。 如果把寫死的 magic number 換成適當型別的除法與補數運算,這個 bitcount 函數對 32/64/128-bits 寬的 unsigned int 都可以適用。寬度的限制是來自於 v4' 的第一個小括號,它不能大於或等於 2^8。不過如果 bitcount 求到 v4 再來做乘法,這個限制也可以被放寬。
|