>set path=%ProgramFiles%\Java\jdk1.6.0_17\bin;%PATH%
|
>java
Natives.java
|
>javah -classpath bin -jni game.emulator.util.Natives
|
>javap -classpath bin -s -p game.emulator.util.
Natives
|
>set path=%ProgramFiles%\Java\jdk1.6.0_17\bin;%PATH%
|
>java
Natives.java
|
>javah -classpath bin -jni game.emulator.util.Natives
|
>javap -classpath bin -s -p game.emulator.util.
Natives
|
so,
(1) i add it to frameworks/base/tat.
(2) modify build/core/pathmap.mk
like this:
FRAMEWORKS_BASE_SUBDIRS := \
$(addsuffix /java, \
core \
graphics \
im \
location \
media \
opengl \
sax \
telephony \
wifi \
tat \
)
(3) make and make sdk. (successfully).
but i don't find tat in android.jar that generated just now.
What need i to do else?
Pls give me some advice.
Thanks in advance.
프로필 보기
추가 옵션 11월25일, 오후4시42분
You will not need to create any more symlinks if you plan on installing any recent JF update as he has done this for you.
P.S. If you have adb running you can paste this in to do all of the previous commands at once (much faster).
If you've read the previous posts, you should have Busybox running on the phone. That means a proper shell (Ash), and plenty of Unix utilities to play with. Good.
But that's still not quite what we are looking for. We'd like to be able to store our aliases in a .profile startup file. We'd like to add our own stuff to the startup process. We'd like to feel at $HOME on our Android.
So we're going to do just that ! But as we've seen already, Android is not built to do that out of the box : no/etc/passwd, no $HOME, and a strange startup script. Let's have a look.
First thing : we should add a passwd and a group file in /etc. The problem, as you might have noticed, is that etc is not in your ramdisk directory. It is not in ramdisk.img, but rather in system.img. Actually, /etc is just a symlink to /system/etc(talk about crazy file system hierarchy !). Since modifying system.img is a bit more difficult than building a cpio archive, we too are going to play the symlink game.
Let's put our files somewhere (I've chosen /usr/share), and symlink to them from /etc.
cd my_ramdisk_dir mkdir -p usr/share cd usr/share echo root::0:0:root:/home:/bin/ash > passwd echo root::0: > group cd ../.. find usr >> ramdisk_listIn order to make all our symlinks, we have to modify the startup script. This script is called init.rc, and is part of the ramdisk. Let's edit this init.rc file. The % … % comments are mine, and I'll show you the context of my edits, so you can patch :
% Let's add a tmp and home directory. Home should be in a "permanent" storage place, in /data. /tmp should not. % # Backward compatibility symlink /system/etc /etc symlink /data/local /home symlink /cache /tmp % Modify these mount commands to have everything in rw, not ro % mount rootfs rootfs / rw remount mount yaffs2 mtd@system /system rw remount % Add this before the "on boot" block. This creates the symlinks % # add special persistent config files symlink /usr/share/passwd /system/etc/passwd symlink /usr/share/group /system/etc/groupAn finally, let's create our own rc startup script, to be run at the end of all other scripts. At the end of the init.rc file, add this line :
service rc /bin/rcAndroid startup shell comes with some global variables that should be carried over to our shell. We should also configure$PATH. So we are going to create a profile file in /etc. In your ramdisk dir, in usr/share, create a file named profile with this content :
export ANDROID_ROOT=/system export LD_LIBRARY_PATH=/system/lib export PATH=/bin:/sbin:/system/sbin:/system/bin:/system/xbin export BOOTCLASSPATH=/system/framework/core.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar export ANDROID_BOOTLOGO=1 export ANDROID_ASSETS=/system/app export EXTERNAL_STORAGE=/sdcard export ANDROID_DATA=/data export ANDROID_PROPERTY_WORKSPACE=9,32768Only PATH is important here. All the other variables were already set up in the Android shell (you can check by typing setafter connecting with adb shell). I've found that the network does not work if ANDROID_PROPERTY_WORKSPACE is not set up properly. Check that the number I give is the same as the one you have.
Then add a line in init.rc to create the symlink. And add usr/share/profile to ramdisk_list.
You will also be able to create your own .profile file in your $HOME directory on Android. You can strore your aliases and variables there, since /home has been symlinked to a /data subdirectory, and is persistent across reboots.
You can now rebuild the mydisk.img ramdisk, using cpio. Then start the emulator with this ramdisk. Log in with adb shell. If everything went fine, you should be able to login using /bin/login. The username is root, no password (you can change your /etc/passwd file if you want one).
Voila ! a real login shell, with properly set up variables and a $HOME to live in.
Today, Gentle Reader, we will examine the Bionic library, a slim libc developed by Google for use in the Android mobile software platform. Bionic is clearly tailored for supporting the Android system, but it is interesting to see what might be done with it in other embedded system contexts.
Google's stated goals for Bionic include:
In this article we'll delve into the Bionic libc via source inspection, retrieved from the git repository in October 2008. The library is written to support ARM CPUs, though some x86 support is also present. There is no support for other CPU architectures, which makes it a bit inconvenient as all of my current systems are PowerPC or MIPS. Nonetheless I'll concede that for the mobile phone market which Bionic targets, ARM is the only architecture which matters.
As one might expect for a BSD-licensed libc, a significant amount of code is sourced from OpenBSD, NetBSD, and FreeBSD. Additional BSD-licensed bits come from Sun and public domain code like the time zone package. There is also a significant amount of new code written by Google, particularly in the pthread implementation.
So what is different about the Bionic libc versus glibc? The most striking differences are in the C++ support, as detailed in the CAVEATS file:
Lack of exceptions is obviously a big deal for C++ programmers, but nonetheless we'll push on.
The pthread implementation appears to be completely new and developed by Google specifically for Android. It is, quite deliberately, not a complete implementation of POSIX pthreads. It implements those features necessary to support threads in the Dalvik JVM, and only selectively thereafter.
In other embedded Linux environments, the pthread library is crucial. There are a large number of developers in this space from a vxWorks background, to whom threads are simply the way software should be written. So we'll spend a bit more time delving into libpthread.
I haven't drawn a final conclusion of the Bionic pthread implementation yet. It is pleasingly simple, but lack of pthread_atfork() is troublesome and use of a magic address for the TLS map may make porting to other architectures more difficult. I need to get this puppy running on a PowerPC system and see how well it works.
In the course of digging through the library I generated a number of other notes, which don't really clump into categories. So I'm simply going to dump it all upon the Gentle Reader, in hopes that some of it is useful.
Bionic is certainly interesting, and pleasingly small. It also represents a philosophical outlook of keeping the GPL some distance away from the application code.
Bionic is a BSD-based libc with support for Linux system calls and interfaces. If the lack of C++ exceptions or other limitations prove untenable, the syscall and pthread mutex implementation could be repurposed into the heavier FreeBSD/NetBSD/OpenBSD libc, though handling thread cancellation using the Bionic mutexes could require additional work.
If you don't understand the reference in the title of this article, don't fret: you have simply not watched enough bad 1970's American television.
Update: In the comments, Ahmed Darwish points out another Android-related article discussing the kernel and power management interfaces Google added.
Update2: Embedded Alley is working on a MIPS port of the Android software.
Update3: In the comments Shuhrat Dehkanov points out an interview with David Turner, who works at Google on the Bionic implementation. Shuhrat also notes that you might have to log in to Google Groups to see the attachment. "Here is an overview by David Turner (though non-official) which answers some of the questions/unclear parts in your article."
DIAL out a phone call: (MO call)
from top UI to bottom,
[App] Phone Application ---> [App Framework] Telephony Manager (GSM) --->
[App Framework] Telephony Manager (RIL) ---> [Libraries] Telephony Manager
---> [Libraries] rild ---> [Libraries] libril.so ---> [Kernel Driver] Baseband
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
D/RILJ ( 85): [0053]> DIAL
D/RIL ( 22): onRequest: DIAL
D/AT ( 22): AT> ATD5556;
D/AT ( 22): AT< OK
D/GSM ( 85): [GSMConn] update: parent=DIALING, hasNewParent=false, wasConnectingInOrOut=true,
wasHolding=false, isConnectingInOrOut=true, changed=false
D/RILJ ( 85): [UNSL]< CALL_STATE_CHANGED
D/AT ( 22): AT< RING
D/RILJ ( 85): [UNSL]< CALL_STATE_CHANGED
D/RILJ ( 85): [0059]> SET_MUTE false
D/RIL ( 22): onRequest: SET_MUTE
D/RILJ ( 85): [0059]< SET_MUTE error: com.android.internal.telephony.gsm.CommandException:
REQUEST_NOT_SUPPORTED
D/RILJ ( 85): [0060]> GET_CURRENT_CALLS
D/RIL ( 22): onRequest: GET_CURRENT_CALLS
D/AT ( 22): AT> AT+CLCC
D/AT ( 22): AT< +CLCC: 1,0,3,0,0,"5556",129
D/AT ( 22): AT< OK
D/RILJ ( 85): [0124]< GET_CURRENT_CALLS [id=1,mo,ACTIVE,voice,norm,129,0]
D/GSM ( 85): [GSMConn] update: parent=ACTIVE, hasNewParent=false, wasConnectingInOrOut=
false, wasHolding=false, isConnectingInOrOut=false, changed=false
D/RILJ ( 85): WAKE_LOCK_TIMEOUT mReqPending=0 mRequestList=1
D/RILJ ( 85): 0: [14] SET_NETWORK_SELECTION_AUTOMATIC
D/GSM ( 85): [CallTracker] hangupForegroundResumeBackground
D/RILJ ( 85): [0125]> HANGUP_FOREGROUND_RESUME_BACKGROUND
D/RIL ( 22): onRequest: HANGUP_FOREGROUND_RESUME_BACKGROUND
D/AT ( 22): AT> AT+CHLD=1
D/AT ( 22): AT< OK
[First written by Steve Guo, please keep the mark if forwarding.]
Assume your target board's IP address is 192.168.1.101. Your host dev machine's IP address is 192.168.1.100. Your Android source code is in ~/mydroid.
In the target board, you should do the following things.
1. Make sure you have replaced libc.so with the version containing symbol information. (You should copy ~/mydroid/out/target/XXX/symbols/system/lib/libc.so), otherwise you will met issue when debugging multi-thread app. Because libthread_db.so depends on a _thread_created_hook symbol in libc.so.
2. Copy ~/mydroid/prebuilt/android-arm/gdbserver/gdbserver into board rootfs.
3. You can launch gdbserver by the following two commands:
#gdbserver 192.168.1.101:5544 --attach $(PID)
#gdbserver 192.168.1.101:5544 $(YOUR_APP)
The first command is to debug an already run process, the second command is to debug a new process. 5544 is a random port you can use any.
In the host develop machine, you should do the following things.
1. Add ~/mydroid/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin into $PATH so that you can directly use arm-eabi-gdb.
$export PATH=$PATH:~/mydroid/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin
2. launch arm-eabi-gdb and in the gdb shell environment, type the following commands:
(gdb) set solib-search-path ~/mydroid/out/target/product/avlite/symbols/system/lib:~/mydroid/out/target/product/avlite/symbols/system/bin
(gdb) target remote 192.168.1.101:5544
3. The remaining things is how you use gdb, it's not covered in this topic.
Note:
There are the following know issues now:
1. n and s does not work now for multi-thread app.
2. p does not work correctly for C++ symbol.
export ANDROID_HOME=(안드로이드 소스가 설치되어 있는 루트 디렉토리) cd $(ANDROID_HOME) . build/envsetup.sh lunch htc_dream-eng 또는 lunch generic-eng
cd $(ANDROID_HOME) make
cd vendor/htc/dream-open ./extract-files.sh
make
Contents[hide] |
The Android Development Tools (ADT) plugin for Eclipse adds powerful extensions to the Eclipse integrated development environment. It allows you to create and debug Android applications easier and faster. Details on ADT can be obtained from http://developer.android.com/guide/developing/eclipse-adt.html.
It is assumed that ADT plugin has already been setup to work with Eclipse environment as described http://developer.android.com/sdk/1.1_r1/installing.html#installingplugin.
Step 1: Unpon installing the ADT plugin for eclipse, Dalvik Debug Monitor Service (DDMS) should have been setup. DDMS configuration should be changed as in below:
Click on Window->Preferences; Select Android -> DDMS Change - ADB debugger base port: 8700; Logging Level: Verbose Click on Apply
Step 2: DDMS perspective can now be opened from the eclipse menu via:
Window -> Open Perspective -> Other -> DDMS; Click on OK
Step 3: Get Eclipse to attach to your Zoom2 board.
Bootup the zoom2 board and find the IP address of the board. NOTE: If you boot via NFS, then uboot will typically print out the board's IP address to console. Alternatively, from the command shell this can be gathered from /system/bin/netcfg utility.
On the host machine run the following commands from terminal shell:
export ADBHOST=<IP_ADDRESS_OF_YOUR_ZOOM2_BOARD> adb kill-server adb start-server
Check if you are now connected to the Zoom2 device by running the following command on the Host Terminal console:
adb devices
It should output something like:
emulator-5554 device
This confirms that Zoom2 board is connected. With this setup, you should be able to use Android Debug Bridge, Logcat, DDMS and other tools directly from Eclipse ADT environment for creating your applications for Android on Zoom2.
Step 4: Troubleshooting:
ADB is not in the path, where should I find it?
ADB command line tool is found at: <MYDROID_PATH>/out/host/linux-x86/bin/
The user space programs can be debugged using various debug commands). Here are some gnu apps that can be used to ease the debugging of binary files on the android platform. GDB, allows you to see what is going on `inside' another program while it executes -- or what another program was doing at the moment it crashed.
Following are the instructions to enable GDB on Android:
1. Obtain the IP address of the target. This can be found by adding “ip=dhcp” in the bootargs, which will obtain and print the IP automatically during boot. Alternatively if you have the busybox command line tools available on the target you can type "ifconfig eth0" to obtain the IP address of the target.
2. On the host, perform the following (once per new console window): Go to mydroid directory and run
source build/envsetup.sh setpaths export ADBHOST=<ip addr of target obtained above>
Ensure that above setup works by running
adb kill-server ; adb shell
You should see a command prompt of the target on your host. Verify this by running "ps" or similar commands. Exit the adb shell by typing “exit”
3. Start GDB using the following command
gdbclient <executable name> <port number> <task name> executable name: file name in system/bin dir port number: default is :5039 (need the colon before the number) task name: obtained by running "ps" on the target. GDB uses it to identify the PID internally.
E.g. for video playback, use (note the space after mediaserver and colon):
gdbclient mediaserver :5039 mediaserver
Then you can run commands like “info threads”, “break”, “step” etc.
For a full listing of GDB commands refer to: http://www.yolinux.com/TUTORIALS/GDB-Commands.html
You may have to run the following after each target reboot:
adb kill-server
DDD is a graphical front-end for GDB and other command-line debuggers like GDB.
Following are the instructions to enable DDD on Android:
The steps are almost same as GDB:
1. Obtain the IP address of the target. This can be found by adding "ip=dhcp" in the bootargs, which will obtain and print the IP automatically during boot. Alternatively if you have the busybox command line tools available on the target you can type "ifconfig eth0" to obtain the IP address of the target.
2. Install DDD: in the shell run:
sudo apt-get install ddd3
3. Add the following function to build/envsetup.sh:
function dddclient() { local OUT_ROOT=$(get_abs_build_var PRODUCT_OUT) local OUT_SYMBOLS=$(get_abs_build_var TARGET_OUT_UNSTRIPPED) local OUT_SO_SYMBOLS=$(get_abs_build_var TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED) local OUT_EXE_SYMBOLS=$(get_abs_build_var TARGET_OUT_EXECUTABLES_UNSTRIPPED) local PREBUILTS=$(get_abs_build_var ANDROID_PREBUILTS) if "$OUT_ROOT" -a "$PREBUILTS"?; then local EXE="$1" if "$EXE"? ; then EXE=$1 else EXE="app_process" fi local PORT="$2" if "$PORT"? ; then PORT=$2 else PORT=":5039" fi local PID local PROG="$3" if "$PROG"? ; then PID=`pid $3` adb forward "tcp$PORT" "tcp$PORT" adb shell gdbserver $PORT --attach $PID & sleep 2 else echo "" echo "If you haven't done so already, do this first on the device:" echo " gdbserver $PORT /system/bin/$EXE" echo " or" echo " gdbserver $PORT --attach $PID" echo "" fi echo >|"$OUT_ROOT/gdbclient.cmds" "set solib-absolute-prefix $OUT_SYMBOLS" echo >>"$OUT_ROOT/gdbclient.cmds" "set solib-search-path $OUT_SO_SYMBOLS" echo >>"$OUT_ROOT/gdbclient.cmds" "target remote $PORT" echo >>"$OUT_ROOT/gdbclient.cmds" "" ddd --debugger arm-eabi-gdb -x "$OUT_ROOT/gdbclient.cmds" "$OUT_EXE_SYMBOLS/$EXE" else echo "Unable to determine build system output dir." fi }
4. On the host, perform the following (once per new console window): Go to mydroid directory and run
source build/envsetup.sh setpaths export ADBHOST=<ip addr of target obtained above>
Ensure that above setup works by running
adb kill-server ; adb shell
You should see a command prompt of the target on your host. Verify this by running "ps" or similar commands. Exit the adb shell by typing “exit”
5. Start DDD using the following command
dddclient <executable name> <port number> <task name> executable name: file name in system/bin dir port number: default is :5039 (need the colon before the number) task name: obtained by running "ps" on the target. GDB uses it to identify the PID internally.
E.g. for video playback, use (note the space after mediaserver and colon):
dddclient mediaserver :5039 mediaserver
For the DDD manual, refer to: http://www.gnu.org/manual/ddd/html_mono/ddd.html
You may have to run the following after each target reboot:
adb kill-server
Lauterbach could be used to debug bootloaders, kernel and user space. Instructions on using Lauterbach Trace32 for debugging on Zoom2:
Install Lauterbach Trace 32 software on your PC (the below screenshot is from Oct 10 2008 release). Connect emulator cable to J5 (20 pin header) on Zoom2 debug board and power the emulator. Connect USB cable from the emulator to PC
Run zoom2_startup.cmm script to select your target as OMAP3430 and attach from File -> Run Batchfile. If the script is not run, some of the settings will have to be manually selected from CPU -> System Settings
Ensure that the emulator is “running” by the green status indicator (seen at the bottom of the below screenshot) before exercising any use cases that need to be debugged.
Run the use case (ex: audio/video playback) Halt the processor by clicking on the “pause” button and view registers (View -> Registers), list source (View -> List Source) etc.
Make sure to load the symbols for files that you’re interested in debugging and set source path recursively for source code correlation to work correctly. Also you may have to ensure that options such as –g is added during compiling your code to generate symbolic debugging directives. In some instances consider reducing the level of optimization used as the compiler will re-arrange instructions and hence it may be difficult to match the order of execution in the source code.
Examples of setting the source search path and loading symbols:
symbol.SOURCEPATH.SETRECURSEDIR "V:\mydroid\kernel\" data.load.elf V:\mydroid\kernel\vmlinux /nocode
These commands can be directly entered from either the debugger command prompt or by using a *.cmm script.
For user space debugging, T32 needs some help as it needs to be told where some of the modules you're interested in debugging are loaded. To do this you will have to run "ps" on the target and get PIDs for the application.
Then run "cat /proc/PID/maps > logfile" where PID is the process ID retrieved from "ps" in the above step. There is an avplayback_symbols.cmm file attached that exhibits how to do this. Below screenshot demonstrates being halted in user space during running of an AV playback use case.
zoom2_startup.cmm
avplayback_symbols.cmm
This could be used to debug bootloaders. Previous versions of CCS (v3.3 and older) did not contain Linux awareness but it is currently being added to CCSv4 which is in the beta phase. It should be possible to debug the kernel and user space once CCSv4 is released. See Linux_Aware_Debug for more information.
OProfile is a system-wide profiler for Linux systems, capable of profiling all running code at low overhead. It consists of a kernel driver and a daemon for collecting sample data, and several post-profiling tools for turning data into information
OProfile is optional component during KERNEL build. It may have been enabled by default. You can confirm that the kernel has OProfile support, by looking for following lines in the <mydroid_folder>/kernel/.config file
CONFIG_OPROFILE_OMAP_GPTIMER=y CONFIG_OPROFILE=y CONFIG_HAVE_OPROFILE=y
Hardware Configuration
The Hardware Configuration required to execute the test cases includes:
Linux machine (can be with your favorite distro) TCP/IP configuration on Zoom2 board Zoom2 Board
Software Configuration
The Software Configuration required to execute the test cases includes:
Tera Term (or any terminal program) Graphviz on Linux machine (Use this command on Host terminal $ sudo apt-get install graphviz GPROF2DOT python script (Copy the script to any location in your path (e.g. in ~/bin of your Linux machine); Ensure that ~/bin is exported in the PATH Run the following command - $ cd ~/bin && chmod 777 gprof2dot.py
Installation
This step should be done after the android file system has been built.
$MYDROID is the location where the android SDK is installed. eg: export MYDROID=/home/$user/Lxx.x/mydroid
Edit the $MYDROID/external/oprofile/opimport_pull script as follows:
Remove the python version number from the first line eg. change #!/usr/bin/python2.4 -E to #!/usr/bin/python -E Append the following lines at the end of the file to generate cpuloads.txt and callgraph.png for further analysis os.system(oprofile_event_dir + "/bin/opreport --session-dir=. >> cpuloads.txt") os.system(oprofile_event_dir + "/bin/opreport --session-dir=. -p $OUT/symbols -l -t 0.1 >> cpuloads.txt") os.system(oprofile_event_dir + "/bin/opreport -cg --session-dir=. -p $OUT/symbols > callgraph.txt") os.system("cat callgraph.txt | gprof2dot.py -s -w -f oprofile -n 1 -e 1 | dot -Tpng -o callgraph.png") Since we perform the post-processing on host, we don't need the actual vmlinux file (~40 MB) on target. Make sure that you create a dummy file named "vmlinux" in the root directory to satisfy opcontrol arguments. #echo 0 > /vmlinux
Execution
Set-up OProfile directories
Make sure that you have created an empty file and named it vmlinux as described in above section. Run the following command on the target # opcontrol --setup By default there should be no output. In case you see, "Cannot create directory /dev/oprofile: File exists do_setup failed#", it means that, OProfile is not built in the Kernel. Verify that you have selected OProfile in make menuconfig step of Kernel build (Refer Configuration Section)
Initialize the OProfile daemon
The kernel range start and end addresses need to be verified on the setup for each release using: # grep " _text" /proc/kallsyms c0030000 T _text # grep " _etext" /proc/kallsyms c03e1000 A _etext Note: You need busybox installed for this command to work. Refer here if you havent set-up busybox Using the above addresses, run the following command # opcontrol --vmlinux=/vmlinux --kernel-range=0xC0030000,0xC03e1000 --event=CPU_CYCLES:64 You should see the following output on your terminal Cannot open /dev/oprofile/1/enabled: No such file or directory Cannot open /dev/oprofile/2/enabled: No such file or directory Using 2.6+ OProfile kernel interface. Reading module info. Using log file /data/oprofile/samples/oprofiled.log # init: untracked pid 914 exited Increase the Back trace depth, so that more details can be captured in the log # echo 16 > /dev/oprofile/backtrace_depth To ensure that everything is ready, you can run the following command # opcontrol --status The following output should be seen. Note that the PID will change depending on your system. Driver directory: /dev/oprofile Session directory: /data/oprofile Counter 0: name: CPU_CYCLES count: 64 Counter 1 disabled Counter 2 disabled oprofiled pid: 915 profiler is not running 0 samples received 0 samples lost overflow
Starting and Stopping the profiler
Run the following command to start the profiler # opcontrol --start and use the command below to stop the profiler # opcontrol --stop
Generating the Results
We need to run the following steps on the Host machine (that has android SDK/build) to generate the results.
On command prompt of Host machine (that has android SDK/build), do the following $ cd $MYDROID $ source build/envsetup.sh $ setpaths $ export ADBHOST=<ip address of ZOOM2 board> The IP address of the ZOOM2 board can be found during boot-up phase e.g. : IP-Config: Got DHCP answer from 0.0.0.0, my address is 128.247.79.152
Post-process OProfile results
This needs to be done from the PC where Android SDK is installed. Go to the terminal on host PC and do the following: $ cd $MYDROID/external/oprofile/ $ ln -s $MYDROID/kernel/android-2.6.27/vmlinux $OUT/symbols/vmlinux $ opimport_pull <new_dir_to_store_dump_and_results_on_Linux_machine> The following files and the Callgraph image can be referred for OProfile results. They will be generated in the <new_dir_to_store_dump_and_results_on_Linux_machine> in step above cpuloads.txt callgraph.txt
Part Four of a Series of Posts about Android Mobile Application Development.
In three prior blog posts, Developing An Android Mobile Application , Android Software Development Tools – What Do I Need? and Android Native Development on Ubuntu 9.04 (Jaunty Jackalope), I discussed our approach for choosing Android as the next platform for our company’s mobile application, Aton Connect. Once I identified which platform was most suitable, I needed to decide on development tools that would allow us to develope our mobile application rapidly. Because the Aton Connect software architecture combines native and managed code, I am looking for ways to include native C/C++ code in our Android version.
There are now two primary sets of tools that can be used to develop Android applications that include native C/C++ native code. The original, and still unsupported way, is to leverage the tools built into the Android Open Source Project to build Android applications. The intent of the Android Open Source Project is to provide the means to port the Android operating system to hardware devices, ranging from cell phones, to netbooks, to set top boxes, etc.
Developing Android applications that include native code by using the Android Open Source Project allows the developer full access to every aspect of the operating system. Because the operating system is currently under development, the Android team will be changing various aspects of the operating system source. If you develop an Android application that happens to utilize one of the features that have changed, then your application may very well break when run on a device with a newer release of Android.
For this reason, the Android team has recently released the Android NDK or Android Native Development Kit. The goal of the NDK is to allow native code libraries to be incorporated into an Android Java application. A secondary goal is to limit access of native code to selected API’s and libraries that are considered mature, and thus are guaranteed to be supported in future releases of the Android OS. The Android NDK is available here: http://developer.android.com/sdk/ndk/1.5_r1/index.html.
In this post, I will be working with the Android Open Source Project (OSP) to build Android applications that utilize native code. In a later post, I will address the NDK, with its advantages and limitations. Using the OSP is useful where you are building applications for a custom port of Android. It is also helpful if you need access to API’s and libraries that are not included in the current release of the NDK and you are willing to accept that those API’s and libraries may change in future releases of the Android OS.
As our first example, I will build a non-trivial, but still simple C language application that does not involve Java. I will do this by cloning the classic “ping” application used to test TCP/IP connectivity in Android.
It is important to note that using the OSP for native development requires that I respect the file structure of the OSP. To do otherwise can generate a prohibitive amount of work to get the build system to perform properly.
In this discussion I will be referring to the environment variable $ANDROID_HOME, which is based on the instructions I presented in previous posts is equivalent to $HOME/mydroid. The descriptions below are for Ubuntu 9.04.
Applications that support the OS, such as “ping” reside in the folder $ANDROID_HOME/external. To avoid collisions with the rest of the OSP, I will create a folder for our native applications at $ANDROID_HOME/external/myapps.
The first step is to copy the folder and contents $ANDROID_HOME/external/ping to $ANDROID_HOME/external/myapps/ping. Then, to identify our modified code and to avoid overwriting the original ping command files, rename the folder $ANDROID_HOME/external/myapps/ping to $ANDROID_HOME/external/myapps/myping. In this folder, rename ping.c to my_ping.c and ping_common.h to my_ping_common.h. Use a text editor to change ping_common.h to my_ping_common.h in the #include statement in “my_ping.c”. You should also change “ping” to “my_ping” in the text prompt and error message strings to help identify the output as actually coming from this modified application.
Finally I need to adjust the Android.mk file in the folder $ANDROID_HOME/external/myapps/myping to reflect our other changes here. Note that this file is quite compact, reflecting only differences from the standard make procedures buried in the Android OS build system. The build system is very powerful and elegant, but quite complex if you choose to burrow into the details of how it actually works.
In the Android.mk file, make the following edits.
Change the line LOCAL_SRC_FILES:= ping.c to LOCAL_SRC_FILES:= my_ping.c.
Change the line LOCAL_MODULE := ping to LOCAL_MODULE := my_ping.
Note that the existing Android.mk file specifies static libraries with this line:
LOCAL_STATIC_LIBRARIES := libcutils libc
Next, open a terminal window and change the directory to $ANDROID_HOME/external/myapps/myping.
To setup the build environment use this command: source $ANDROID_HOME/build/envsetup.sh
Then enter the command “mm”. This simple command initiates a complex set of events that will build the application “my_ping” in about a minute. The terminal session output will look something like this:
cawilde@android:~$ cd $ANDROID_HOME/external/myapps/myping cawilde@android:~/mydroid/external/myapps/myping$ source $ANDROID_HOME/build/envsetup.sh cawilde@android:~/mydroid/external/myapps/myping$ mm make: Entering directory `/home/cawilde/mydroid' build/core/product_config.mk:261: WARNING: adding test OTA key ============================================ TARGET_PRODUCT=generic TARGET_BUILD_VARIANT=eng TARGET_SIMULATOR= TARGET_BUILD_TYPE=release TARGET_ARCH=arm HOST_ARCH=x86 HOST_OS=linux HOST_BUILD_TYPE=release BUILD_ID= ============================================ target thumb C: my_ping <= /home/cawilde/mydroid/external/myapps/myping/my_ping.c /home/cawilde/mydroid/external/myapps/myping/my_ping.c: In function 'fill': /home/cawilde/mydroid/external/myapps/myping/my_ping.c:136: warning: pointer targets in initialization differ in signedness /home/cawilde/mydroid/external/myapps/myping/my_ping.c: In function '__schedule_exit': /home/cawilde/mydroid/external/myapps/myping/my_ping.c:315: warning: comparison betIen signed and unsigned /home/cawilde/mydroid/external/myapps/myping/my_ping.c:320: warning: comparison betIen signed and unsigned /home/cawilde/mydroid/external/myapps/myping/my_ping.c: In function 'setup': /home/cawilde/mydroid/external/myapps/myping/my_ping.c:533: warning: pointer targets in initialization differ in signedness /home/cawilde/mydroid/external/myapps/myping/my_ping.c: In function 'gather_statistics': /home/cawilde/mydroid/external/myapps/myping/my_ping.c:725: warning: comparison betIen signed and unsigned /home/cawilde/mydroid/external/myapps/myping/my_ping.c: At top level: /home/cawilde/mydroid/external/myapps/myping/my_ping.c:958: warning: missing initializer /home/cawilde/mydroid/external/myapps/myping/my_ping.c:958: warning: (near initialization for 'cmsg.ipi.ipi_spec_dst') /home/cawilde/mydroid/external/myapps/myping/my_ping.c: In function 'receive_error_msg': /home/cawilde/mydroid/external/myapps/myping/my_ping.c:1017: warning: comparison betIen signed and unsigned /home/cawilde/mydroid/external/myapps/myping/my_ping.c: In function 'parse_reply': /home/cawilde/mydroid/external/myapps/myping/my_ping.c:1179: warning: comparison betIen signed and unsigned /home/cawilde/mydroid/external/myapps/myping/my_ping.c:1183: warning: comparison betIen signed and unsigned /home/cawilde/mydroid/external/myapps/myping/my_ping.c: In function 'main': /home/cawilde/mydroid/external/myapps/myping/my_ping.c:2038: warning: comparison betIen signed and unsigned /home/cawilde/mydroid/external/myapps/myping/my_ping.c:2046: warning: comparison betIen signed and unsigned target Executable: my_ping (out/target/product/generic/obj/EXECUTABLES/my_ping_intermediates/LINKED/my_ping) target Non-prelinked: my_ping (out/target/product/generic/symbols/system/bin/my_ping) target Strip: my_ping (out/target/product/generic/obj/EXECUTABLES/my_ping_intermediates/my_ping) Install: out/target/product/generic/system/bin/my_ping Finding NOTICE files: out/target/product/generic/obj/NOTICE_FILES/hash-timestamp Combining NOTICE files: out/target/product/generic/obj/NOTICE.html gzip -c out/target/product/generic/obj/NOTICE.html > out/target/product/generic/obj/NOTICE.html.gz make: Leaving directory `/home/cawilde/mydroid'
cawilde@android:~/mydroid/external/myapps/myping$
The build lists a number of warnings related to signed/unsigned variable mismatches which exist in the source file. These can be ignored for purposes of this demonstration. The build listing also describes where the various types of build outputs are located. These are close to the end of the session:
target Executable: my_ping (out/target/product/generic/obj/EXECUTABLES/my_ping_intermediates/LINKED/my_ping) (61 KB) target Non-prelinked: my_ping (out/target/product/generic/symbols/system/bin/my_ping) (61 KB) target Strip: my_ping (out/target/product/generic/obj/EXECUTABLES/my_ping_intermediates/my_ping) (27 KB) Install: out/target/product/generic/system/bin/my_ping (27 KB)
The build outputs of interest are described by the lines:
Install: out/target/product/generic/system/bin/my_ping (no symbols) target Executable: out/target/product/generic/obj/EXECUTABLES/my_ping_intermediates/LINKED/my_ping (includes debug symbols)
These lines mean the build outputs are located at $ANDROID_HOME at the paths given above.
Start a new terminal window and point it to the Android SDK development tools directory, located where you installed it. For example:
$HOME/android-sdk-linux_x86-1.5_r2/tools.
You may have a different location or SDK revision number.
You can determine the names of the emulator skins or AVD instances by using the command: “android list avds”. If you have not set up your AVD, refer to this page for instructions: http://developer.android.com/guide/developing/tools/avd.html
You can then start the emulator with this command: emulator -avd <avd_name> where avd_name is the name you gave the AVD when you created it, and is listed by the command: “android list avds”. Note that the “.avd” extension is not included as part of <avd_name>.
Once the Android emulator has booted up, you can try out your new my_ping application using the following procedure:
After a few pings on localhost are executed, type control C into the shell session to terminate the ping command. The output of my_ping in the shell session should look like this:
PING localhost (127.0.0.1) 56(84) bytes of data. 64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=1.79 ms 64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.166 ms 64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.153 ms 64 bytes from localhost (127.0.0.1): icmp_seq=4 ttl=64 time=0.151 ms ^C --- localhost my_ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3026 msrtt min/avg/max/mdev = 0.151/0.566/1.794/0.709 ms
If you want to make a change to Android.mk, for example to change a compilation or link option, you need to use the “touch my_ping.c” command to cause the rebuild to occur. If I do not touch a source file, the build system thinks nothing is to be done, even though I modified the Android.mk file.
So, how do you install a pure native application into the Android phone?
If you are a device manufacturer, you can build it into the full Android image for your device. Otherwise, you need a Java application as a wrapper. The Java wrapper application will provide the AndroidManifest.xml file and META-INF folder required by the Android package installer. There are other good reasons to use a Java wrapper, including access to framework libraries and easy design of GUI elements.
The use of a pure native application is also useful for debugging native shared libraries used with Java applications. I will describe this in a later post.
The next step is to debug your native application. I do not have the assistance of the Eclipse CDT GUI here, so I need to work with the classic GDB command line debug tool. I could build and load a version of GDB directly onto the Android platform and operate it through a terminal window, but this approach has problems. A major issue is building and debugging GDB itself on the Android platform. GDB is a fairly large program and resources on Android are limited. So, a better approach is to use a remote debugging strategy.
Because I am debugging on a different platform from our workstation I need a tool on the Android platform that will interact with the GDB debugger running on the workstation. This tool is named gdbserver, and is included in the Android 1.5 emulator in the folder “/system/bin”.
The setup and use of gdb with gdbserver is a bit complex. There is a function named gdbclient in the shell library $ANDROID_HOME/build/envsetup.sh which is used to startup both gdbserver and then gdb itself. I have adapted the gdbclient function into a shell script used for debugging our my_ping application instead of its original purpose of debugging the Android kernel code. This adaptation is covered by the Android license (Apache) as shown here: http://www.apache.org/licenses/LICENSE-2.0.
Create a shell file named “debug” in the myping folder that contains this text:
source $ANDROID_HOME/build/envsetup.sh
setpaths
OUT_ROOT=$ANDROID_HOME/$(get_build_var PRODUCT_OUT)
echo “OUT_ROOT = $OUT_ROOT”
OUT_SYMBOLS=$ANDROID_HOME/$(get_build_var TARGET_OUT_UNSTRIPPED)
echo “OUT_SYMBOLS = $OUT_SYMBOLS”
OUT_SO_SYMBOLS=$ANDROID_HOME/$(get_build_var TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED)
echo “OUT_SO_SYMBOLS = $OUT_SO_SYMBOLS”
OUT_EXE_SYMBOLS=$ANDROID_HOME/$(get_build_var TARGET_OUT_EXECUTABLES_UNSTRIPPED)
echo “OUT_EXE_SYMBOLS = $OUT_EXE_SYMBOLS”
PREBUILTS=$ANDROID_HOME/$(get_build_var ANDROID_PREBUILTS)
echo “PREBUILTS = $PREBUILTS”
LOCAL_EXE=”$1″
if [ -z "$LOCAL_EXE" ] ; then
echo “usage: debug local_exe remote_exe arguments”
exit
fi
REM_EXE=”$2″
if [ -z "$REM_EXE" ] ; then
echo “usage: debug local_exe remote_exe arguments”
exit
fi
ARG_LIST=”$3″
if [ -z "$ARG_LIST" ] ; then
echo “usage: debug local_exe remote_exe arguments”
exit
fi
PORT=”:5039″
adb forward “tcp$PORT” “tcp$PORT”
echo “PORT = $PORT, LOCAL_EXE = $LOCAL_EXE, REM_EXE = $REM_EXE, ARG_LIST = $ARG_LIST”
adb shell gdbserver $PORT $REM_EXE $ARG_LIST &
sleep 2
echo >|”$OUT_ROOT/gdbclient.cmds” “set solib-absolute-prefix $OUT_SYMBOLS”
echo >>”$OUT_ROOT/gdbclient.cmds” “set solib-search-path $OUT_SO_SYMBOLS”
echo >>”$OUT_ROOT/gdbclient.cmds” “target remote $PORT”
echo >>”$OUT_ROOT/gdbclient.cmds” “”
arm-eabi-gdb -silent -x “$OUT_ROOT/gdbclient.cmds” “$OUT_EXE_SYMBOLS/$LOCAL_EXE”
To use this for debugging “my_ping” you will need to recompile my_ping using the appropriate debugger options. Add this line to Android.mk immediately after the “LOCAL_SRC_FILES:= my_ping.c” line:
LOCAL_CFLAGS:=-O0 –g
The –O0 option disables GCC compiler optimizations and the –g option outputs additional debug information into the linked output. Without these two options, the GDB debugger operation can be very erratic. As mentioned above, you need to use the “touch my_ping.c” command to cause the rebuild to occur. If I do not touch a source file, the build system thinks nothing is to be done, even though I modified the Android.mk file. The rebuilt outputs are somewhat bigger, reflecting the reduced optimization and additional debug information.
Next, start up the emulator as described above.
You can then start the emulator with this command: emulator -avd <avd_name> where avd_name is the name you gave the AVD when you created it, and is listed by the command: “android list avds”. Note that the “.avd” extension is not included as part of <avd_name>.
With the emulator started, you can copy the build outputs to the correct locations. Use this command to copy the “symbols stripped” output to the emulator:
adb push $ANDROID_HOME/out/target/product/generic/system/bin/my_ping /data/tmp
Then, use this command to copy the output with symbols to the local folder for use by the GDB debugger:
cp $ANDROID_HOME/out/target/product/generic/obj/EXECUTABLES/my_ping_intermediates/LINKED/my_ping ./
Now you are ready to initiate a debug session using GDB on your workstation communicating with gdbserver on the Android emulator:
./debug my_ping /data/tmp/my_ping localhost
The initial output of the debug session looks like this:
OUT_ROOT = /home/cawilde/mydroid/out/target/product/generic
OUT_SYMBOLS = /home/cawilde/mydroid/out/target/product/generic/symbols
OUT_SO_SYMBOLS = /home/cawilde/mydroid/out/target/product/generic/symbols/system/lib
OUT_EXE_SYMBOLS = /home/cawilde/mydroid/out/target/product/generic/symbols/system/bin
PREBUILTS = /home/cawilde/mydroid/prebuilt/linux-x86
PORT = :5039, LOCAL_EXE = my_ping, REM_EXE = /data/tmp/my_ping, ARG_LIST = localhost
Process /data/tmp/my_ping created; pid = 695
Listening on port 5039
Remote debugging from host 127.0.0.1
gdb: Unable to get location for thread creation breakpoint: requested event is not supported
__dl__start () at bionic/linker/arch/arm/begin.S:35
35 mov r0, sp
gdb: Unable to get location for thread creation breakpoint: requested event is not supported
Current language: auto; currently asm
(gdb)
The debug session starts the Android loader for /data/tmp/my_ping and the initial debug location is in the Android loader, not our application. The loader is not configured to operate with GDB and so errors are displayed. Single stepping at this point will simply walk through the assembly code rendition of the Android loader. It is much more useful to set a breakpoint at the beginning of our application and then continue to the breakpoint, as follows:
(gdb) b my_ping.c:main
Breakpoint 1 at 0xe120: file /home/cawilde/mydroid/external/myapps/myping/my_ping.c, line 1673.
(gdb) c
Continuing.
warning: .dynamic section for “/home/cawilde/mydroid/out/target/product/generic/symbols/system/lib/libc.so” is not at the expected address (wrong library or version mismatch?)
[New Thread 695]
warning: .dynamic section for “/home/cawilde/mydroid/out/target/product/generic/symbols/system/lib/libstdc++.so” is not at the expected address (wrong library or version mismatch?)
warning: .dynamic section for “/home/cawilde/mydroid/out/target/product/generic/symbols/system/lib/libm.so” is not at the expected address
warning: difference appears to be caused by prelink, adjusting expectations
warning: .dynamic section for “/home/cawilde/mydroid/out/target/product/generic/symbols/system/lib/liblog.so” is not at the expected address
warning: difference appears to be caused by prelink, adjusting expectations
warning: .dynamic section for “/home/cawilde/mydroid/out/target/product/generic/symbols/system/lib/libcutils.so” is not at the expected address (wrong library or version mismatch?)
[Switching to Thread 695]
Breakpoint 1, main (argc=2, argv=0xbeaead84)
at /home/cawilde/mydroid/external/myapps/myping/my_ping.c:1673
1673 {
Current language: auto; currently c
(gdb) l
1668 “ [ -T timestamp option ] [ -Q tos ] [hop1 ...] destinationn”);
1669 exit(2);
1670 }
1671
1672 int main(int argc, char *argv[])
1673 {
1674 struct hostent *hp;
1675 int ch, hold, packlen;
1676 int socket_errno;
1677 u_char *packet;
(gdb) l
1678 char *target, hnamebuf[MAXHOSTNAMELEN];
1679 char rspace[3 + 4 * NROUTES + 1]; /* record route space */
1680
1681 icmp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
1682 socket_errno = errno;
1683
1684 /* if I Ire setuid root, undo that */
1685 if (setuid(getuid())) return -1;
1686
1687 source.sin_family = AF_INET;
I can then single step code and examine variables in the usual GDB fashion:
(gdb) n
1681 icmp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
(gdb) n
1682 socket_errno = errno;
(gdb) p socket_errno
$1 = 32768
(gdb) n
1685 if (setuid(getuid())) return -1;
(gdb) n
1687 source.sin_family = AF_INET;
(gdb) n
1689 preload = 1;
(gdb) p preload
$2 = 0
(gdb) n
1690 while ((ch = getopt(argc, argv, COMMON_OPTSTR “bRT:”)) != EOF) {
(gdb) p preload
$3 = 1
(gdb) n
1769 argc -= optind;
… etc ….
If you are not familiar with the GDB debugging tool, there are many references available on the Internet and a condensed guide is available here:http://www.yolinux.com/TUTORIALS/GDB-Commands.html.
My preference is using an integrated GUI development environment, and the command line GDB, although quite useful, is a long way from that. Ideally the CDT add-on for Eclipse could be reconciled with the Android OSP build environment. This would take more development time to accomplish than I have available, so I will continue to use GDB for Android native debugging tasks.
In the next post, I will detail how to build native shared libraries for use with a Java wrapper or Java GUI application.
* * * * * * * *
With 20+ years as a top software and firmware developer, Charles Wilde has acquired a combination of proven business smarts, mobile development skills and device engineering expertise that is hard to match. Charles is available to consult with you and your team about native code development in Android, Windows Mobile or Windows CE. Just email him at AtonMail@aton.com.