Friday, May 29, 2009

connect G1 phone to adb on Ubuntu

You can find very detailed instructions on android page. But they missed one thing, that is adb needs to be run with root permission. So after you setup everything, do:
adb kill-server
sudo adb devices

Thursday, May 28, 2009

The mouse cursor issue

I did the mouse cursor support for X86 platforms. As matter fact, the same change should be able to run anyway.

But when I try to drag the screen to switch to next screen, I see the screen keeps flicking. It looks like a bug. In order to debug this problem, I wrote a small application to just draw lines on the screen. When I start to draw, I can see the lines keep jumping back to position 0,0 during the mouse cursor movement . It seems that the mouse cursor keeps sending out wrong mouse position.
After some debugging, I found out that it is cause by the batching mode of mouse event. Current mouse cursor tries to simulate the touch events, in order to do that, I have to convert the rel_x/y to abs_x/y and this conversion was never done for batched events. Because of this, both rel_x/y and abs_x/y are sent with touch events.
I have published the patch to
http://code.google.com/p/patch-hosting-for-android-x86-support/downloads/list

Friday, May 22, 2009

How to write Android native service by C contntinue

Here is some thing I did; first, I copied biner.c to my private directory and used it as a library to access kernel binder driver. And then, I wrote my service to use the functions in binder.c to talk to service manager.
In order to talk with service manager, we need following things:
1. an unique id for the service we are going to build. It is a string16
2. add permission for our service to service manager.

For the point 1, I create an uint16 array like
uint16_t svcmgr_id16[] = {
'B','i','n','d','e','r','.','T','e','s','t','.','I','B','i','n',
'd','e','r','t','e','s','t'
};

for the point 2, I'm kind of lazy, I add a new item to the allowd[] in servicemanager. It looks like this:
{10001, "Binder.Test.IBindertest"}

Ok, lets get something real, we need to do following steps to make everything to work:
1. connect to the binder by calling binder_open function. The binder_open function creates a shared memory with /dev/binder. I copied service manager code to create a 128K shared memory.
2.create an io block through bio_init function to talk with service manager through binder. You need to provide a buff to bio_init. I use an integer array with size of 128
3. fill in the target (servicemanager) and source(Binder.Test.IBindertest) by calling bio_put_string16_x
4. call binder_call with command SVC_MGR_ADD_SERVICE. It is a blocking call. You need to provide a binder_io object for the result.
5. if binder_call returns 0, call binder_loop with a message handler callback function to process messages sent from service client.

The message processing callback function:
The prototype of the message processing callback functions is:
static int binder_handler(struct binder_state *bs,
struct binder_txn *txn,
struct binder_io *msg,
struct binder_io *reply)

In the callback function, we at least need to handle INTERFACE_TRANSACTION so that our service client can find our service.
switch(txn->code) {
case INTERFACE_TRANSACTION:
bio_put_string16(reply,svcmgr_id16);
break;
case :
default:
error handling.

Monday, May 18, 2009

How to write Android native service by C

It is not as hard as I thought before I start. When I look into the frameworks/base/cmds/servicemanager, I realized that it should be an easy job. So I decide to give it a try. I will list what I do after I complete it.

Tuesday, May 12, 2009

How to build and use a shared libraries in Android

Actually, it is very simple to build and use your own shared library,

For the shared library, you need to create an Android.mk like this:

  LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
  LOCAL_SRC_FILES := hello.c
  LOCAL_CFLAGS :=
  LOCAL_C_INCLUDES :=
  LOCAL_SHARED_LIBRARIES := libc        <=== may be not required 
  LOCAL_MODULE := libhello
  include $(BUILD_SHARED_LIBRARY)

For the executable that needs use this shared library, the Android.mk needs to be written as :

  LOCAL_PATH:= $(call my-dir)
  include $(CLEAR_VARS)
  LOCAL_SRC_FILES := main.c
  LOCAL_SHARED_LIBRARIES := libc libhello
  LOCAL_MODULE := myprog          <=== the name of final executable 
  include $(BUILD_EXECUTABLE)


Besides makefile changes, we also need to change build/core/prelink-linux-arm.map. Android does prelink (a modified version), all the memory location of DSO are predefined. In order to build a shared library for Android, you need to define the address and size for the memory used by your DSO (before you start to build anything). For current example, I have added following lines at the end of .map file.

  libhello.so            0x9A100000
  The C code I'm using to build this example is
main.c
  #include "myprog.h"
  int main(void)
{
hello("World!");
return 0;
}


  Hello.c
#include
  void hello(const char* name)
{
printf("Hello %s!\n", name);
}

Saturday, May 9, 2009

Android Suspend and resume (the wakelock problem)

I enabled wakelock in my Android kernel today, after the wakelock is enabled on my PC, my machine failed to wake up. It seems that the machine gets back to suspend right after it is waken up.
I spent two hours to read the wakelock code and try to find out the reason for the problem. It seems that the wakelock.c checks a flag called entry_event_num during the machine resume process. The value of entry_event_num is saved before the machine goes into sleep, and wakelock checks it during the machine resume. If the value of entry_event_num did not changed since machine went to sleep, then wakelock will put the machine back to sleep again.
It looks like that the entry_event_num flag is used to verify whether the machnie is waken up from an expected event. If it is not, then machine will continue to sleep. To me this is more like a hack for a hardware bug.
So I hacked it to make my PC to sleep well and wake up on time :-). Here is the code I have changed:
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
index 7833d28..175f8a3 100644
--- a/kernel/power/wakelock.c
+++ b/kernel/power/wakelock.c
@@ -292,11 +292,13 @@ static void suspend(struct work_struct *work)
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
}
+#if 0
if (current_event_num == entry_event_num) {
if (debug_mask & DEBUG_SUSPEND)
pr_info("suspend: pm_suspend returned with no event\n");
wake_lock_timeout(&unknown_wakeup, HZ / 2);
}
+#endif
}
static DECLARE_WORK(suspend_work, suspend);


Actually, the wakelock is really not a good idea. From my current understanding, if one of the application hold a wakelock without timeout and dead, the machine may not be able to go to sleep forever until you reboot your machine.

Friday, May 8, 2009

Android on X86 Battery Service problem

Recently, I got this EeePC netbook, beside accessing e-mail and web, I leave it on my desk for most of the time. One day, I saw this web site which talks about running Android on EeePC 701, so I decided to give it a try. Normally I like to record steps and findings when I try something, so that's wh I created this blog to record my experience on Android.

Here you go with my first blog...

When running Android Eee_701 build on a real machine, the battery service will not show the correct battery status on the status bar. Depending on what your battery is, you may get a warning says battery level lower than 15% or simply a question mark with the battery icon.

There are two issues cause these problems:
  1. the power_supply sysfs paths used by the batteryservice jni layer are not correct. Current sysfs path for battery status is hardcoded inside com_android_server_BatteryService.cpp and it is for G1 only.
  2. The way how Android handles the content of battery status files in sysfs may not be right for your machine. For example, ACPI used by x86 has a different way to provide battery charging level. It is (charge_now/charge_full)*100. But G1 phone only has one parameter, and it is current charging level in a scale of 100.

Fixing these issues are not difficult, yet the hard part is how to make the fix portable, what about tomorrow you want the same code to work on a different platform?
It is for sure not a good idea to continue to hardcode for the sysfs path or content processing methods inside com_android_BatteryService.cpp again.

Here is my 2 cents:
We could put power_supply sysfs paths inside vendor/asus/eee_701/system.prop and then have com_android_BatteryService.cpp pick them up from system property during the run time. By doing this, you don't need to change any of your code, if you add new type of battery with different sysfs path, you don't even need to change your code.
Now, you may want to ask me what about processing the file contents differently? For that, we may need to do more works. We could create an abstract class that can be inherited by the real battery status class. The abstract class implements the battery status common interface and methods. The real battery status class will only need to implement the special parts for different battery. And the BatteryService jni layer calls the real battery status class to collect battery status. So when you have a new battery, only a minimum mount of the code need to be changed.

I have actually implemented the entire thing and the same code works on G1, EeePC and VirtualBox very well.