Dalvik In this document - Android Platform Developer's Guide

There are two general categories of work: porting to a Linux system with a previously unseen CPU architecture, and porting to a different operating system. This document covers the former.
The core libraries pull in code from many other projects, including OpenSSL, zlib, and ICU. These will also need to be ported before the VM can be used.
The code lives in dalvik/vm/arch/*, with the FFI-based version in the "generic" directory. There are two source files for each architecture. One defines the call bridge itself:
void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc, const u4* argv, const char* signature, void* func, JValue* pReturn)
The role of dvmPlatformInvoke is to convert the values in argv into C-style calling conventions, call the method, and then place the return type into pReturn (a union that holds all of the basic JNI types). The code may use the method signature (a DEX "shorty" signature, with one character for the return type and one per argument) to determine how to handle the values.
The other source file involved here defines a 32-bit "hint". The hint is computed when the method's class is loaded, and passed in as the "argInfo" argument. The hint can be used to avoid scanning the ASCII method signature for things like the return value, total argument size, or inter-argument 64-bit alignment restrictions.
The fast interpreter uses hand-coded assembly fragments. If none are available for the current architecture, the build system will create an interpreter out of C "stubs". The resulting "all stubs" interpreter is quite a bit slower than the portable interpreter, making "fast" something of a misnomer.
The fast interpreter is enabled by default. On platforms without native support, you may want to switch to the portable interpreter. This can be controlled with the dalvik.vm.execution-mode system property. For example, if you:
and reboot, the Android app framework will start the VM with the portable interpreter enabled.
Mterp Interpreter Structure
There may be significant performance advantages to rewriting the interpreter core in assembly language, using architecture-specific optimizations. In Dalvik this can be done one instruction at a time.
The simplest way to implement an interpreter is to have a large "switch" statement. After each instruction is handled, the interpreter returns to the top of the loop, fetches the next instruction, and jumps to the appropriate label.
An improvement on this is called "threaded" execution. The instruction fetch and dispatch are included at the end of every instruction handler. This makes the interpreter a little larger overall, but you get to avoid the (potentially expensive) branch back to the top of the switch statement.
Dalvik mterp goes one step further, using a computed goto instead of a goto table. Instead of looking up the address in a table, which requires an extra memory fetch on every instruction, mterp multiplies the opcode number by a fixed value. By default, each handler is allowed 64 bytes of space.
Not all handlers fit in 64 bytes. Those that don't can have subroutines or simply continue on to additional code outside the basic space. Some of this is handled automatically by Dalvik, but there's no portable way to detect overflow of a 64-byte handler until the VM starts executing.
The choice of 64 bytes is somewhat arbitrary, but has worked out well for ARM and x86.
In the course of development it's useful to have C and assembly implementations of each handler, and be able to flip back and forth between them when hunting problems down. In mterp this is relatively straightforward. You can always see the files being fed to the compiler and assembler for your platform by looking in the dalvik/vm/mterp/out directory.
The interpreter sources live in dalvik/vm/mterp. If you haven't yet, you should read dalvik/vm/mterp/README.txt now.
At this point you have an "all stubs" interpreter. You can see how it works by examining dalvik/vm/mterp/cstubs/entry.c. The code runs in a loop, pulling out the next opcode, and invoking the handler through a function pointer. Each handler takes a "glue" argument that contains all of the useful state.
Your goal is to replace the entry method, exit method, and each individual instruction with custom implementations. The first thing you need to do is create an entry function that calls the handler for the first instruction. After that, the instructions chain together, so you don't need a loop. (Look at the ARM or x86 implementation to see how they work.)
Once you have that, you need something to jump to. You can't branch directly to the C stub because it's expecting to be called with a "glue" argument and then return. We need a C stub "wrapper" that does the setup and jumps directly to the next handler. We write this in assembly and then add it to the config file definition.
To see how this works, create a file called dalvik/vm/mterp/myarch/stub.S that contains one line:
Then, in dalvik/vm/mterp/config-myarch, add this below the handler-size directive:
Regenerate the sources with ./rebuild.sh, and take a look inside dalvik/vm/mterp/out/InterpAsm-myarch.S. You should see 256 copies of the stub function in a single large block after the dvmAsmInstructionStart label. The stub.S code will be used anywhere you don't provide an assembly implementation.
Note that each block begins with a .balign 64 directive. This is what pads each handler out to 64 bytes. Note also that the ${opcode} text changed into an opcode name, which should be used to call the C implementation (dvmMterp_${opcode}).
The actual contents of stub.S are up to you to define. See entry.S and stub.S in the armv5te or x86 directories for working examples.
If you're working on a variation of an existing architecture, you may be able to use most of the existing code and just provide replacements for a few instructions. Look at the armv4t implementation as an example.
It is possible to customize the set of "optimized" instructions for your platform. This is possible because optimized DEX files are not expected to work on multiple devices. Adding, removing, or redefining instructions is beyond the scope of this document, and for simplicity it's best to stick with the basic set defined by the portable interpreter.
Once you have written a handler that looks like it should work, add it to the config file. For example, suppose we have a working version of OP_NOP. For demonstration purposes, fake it for now by putting this into dalvik/vm/mterp/myarch/OP_NOP.S:
This tells the generation script to use the assembly version from the myarch directory instead of the C version from the c directory.
Execute ./rebuild.sh. Look at InterpAsm-myarch.S and InterpC-myarch.c in the out directory. You will see that the OP_NOP stub wrapper has been replaced with our new code in the assembly file, and the C stub implementation is no longer included.
As you implement instructions, the C version and corresponding stub wrapper will disappear from the output files. Eventually you will have a 100% assembly interpreter.
When a debugger attaches, or a profiling feature is enabled, the VM will switch interpreters at a convenient point. This is done at the same time as the GC safe point check: on a backward branch, a method return, or an exception throw. Similarly, when the debugger detaches or profiling is discontinued, execution transfers back to the "fast" or "portable" interpreter.
Your entry function needs to test the "entryPoint" value in the "glue" pointer to determine where execution should begin. Your exit function will need to return a boolean that indicates whether the interpreter is exiting (because we reached the "bottom" of a thread stack) or wants to switch to the other implementation.
See the entry.S file in x86 or armv5te for examples.
This will run test 003 on an attached device or emulator. You can run the test against your desktop VM by specifying --reference if you suspect the test may be faulty. You can also use --portable and --fast to explictly specify one Dalvik interpreter or the other.
Some instructions are replaced by dexopt, notably when "quickening" field accesses and method invocations. To ensure that you are testing the basic form of the instruction, add the --no-optimize option.
There is no in-built instruction tracing mechanism. If you want to know for sure that your implementation of an opcode handler is being used, the easiest approach is to insert a "printf" call. For an example, look at common_squeak in dalvik/vm/mterp/armv5te/footer.S.
At some point you need to ensure that debuggers and profiling work with your interpreter. The easiest way to do this is to simply connect a debugger or toggle profiling. (A future test suite may include some tests for this.)
$ adb shell am instrument -w com.google.android.frameworktest/.tests.FrameworkInstrumentationTestRunner
INSTRUMENTATION_RESULT: test results:=.......F.......
1) testSetUpConditions(com.google.android.frameworktest.tests.focus.RequestFocusTest)junit.framework.AssertionFailedError: requestFocus() should work from onCreate.
at com.google.android.frameworktest.tests.focus.RequestFocusTest.testSetUpConditions(RequestFocusTest.java:66)
at android.test.InstrumentationTestSuite.runTest(InstrumentationTestSuite.java:73)
at android.test.InstrumentationTestSuite.runTest(InstrumentationTestSuite.java:73)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:151)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1088)
to continue
INSTRUMENTATION_CODE: -1
$
All Tests with Default TestRunner behavior
If no class or package is passed in to run, InstrumentationTestRunner will automatically find and run all tests under the package of the test application (as defined by the android:targetPackage attribute of the instrumentation defined in its manifest file).
$ adb shell am instrument -w \
com.android.samples.tests/android.test.InstrumentationTestRunner
INSTRUMENTATION_RESULT: Test results for InstrumentationTestRunner=..........
Time: 2.317
OK (10 tests)
INSTRUMENTATION_CODE: -1
Running all Tests Under Single Package
If you have many tests under one package, use the -e package
option to run all tests under that package without having to manually create a test suite.
$ adb shell am instrument -w \
-e package com.android.samples.view \
com.android.samples.tests/android.test.InstrumentationTestRunner
INSTRUMENTATION_RESULT: Test results for InstrumentationTestRunner=........
Time: 1.587
OK (8 tests)
Running a Single Test Suite
If you prefer to explicitly state which tests comprise all of your tests, you can define a test suite and run that directly. By convention, all test packages in your system should have at least one suite called AllTests (see AllTests.java). To run all of the tests using the AllTests suite for the api demos test app:
$ adb shell am instrument -w \
-e class com.android.samples.AllTests \
com.android.samples.tests/android.test.InstrumentationTestRunner
INSTRUMENTATION_RESULT: Test results for AllTests=..........
Time: 2.286
OK (10 tests)
INSTRUMENTATION_CODE: -1
A Single Test Case
$ adb shell am instrument -w \
-e class com.android.samples.view.Focus2ActivityTest \
com.android.samples.tests/android.test.InstrumentationTestRunner
INSTRUMENTATION_RESULT: Test results for Focus2ActivityTest=....
Time: 1.359
OK (4 tests)
INSTRUMENTATION_CODE: -1
A Single Test
$ adb shell am instrument -w \
-e class com.android.samples.view.Focus2ActivityTest#testGoingLeftFromRightButtonGoesToCenter \
com.android.samples.tests/android.test.InstrumentationTestRunner
INSTRUMENTATION_RESULT: Test results for Focus2ActivityTest=.
Time: 0.51
OK (1 test)
INSTRUMENTATION_CODE: -1
Attaching a debugger to your test
In order to debug your test code, instruct the controller to stop and wait for the debugger by adding -e debug true to your command line. This causes the test runner to stop and wait for the debugger just before calling your setUp() method. For example,
$ adb shell am instrument -w \
-e debug true \
com.android.samples.tests/android.test.InstrumentationTestRunner
Writing Tests
When writing tests, refer to the ApiDemos tests as models (located at //device/samples/ApiDemos). This section provides an overview of the test structure with ApiDemos.
Location of Files
Test packages should use the following structure and include Android.mk, AndroidManifest.xml, AllTests.java, and a src directory that mirrors the src directory of the tested application.
Files are located within a tests directory found in the root directory:
$ find samples/ApiDemos/tests
samples/ApiDemos/tests
samples/ApiDemos/tests/Android.mk
samples/ApiDemos/tests/AndroidManifest.xml
samples/ApiDemos/tests/src
samples/ApiDemos/tests/src/com
samples/ApiDemos/tests/src/com/google
samples/ApiDemos/tests/src/com/google/android
samples/ApiDemos/tests/src/com/google/android/samples
samples/ApiDemos/tests/src/com/google/android/samples/AllTests.java
samples/ApiDemos/tests/src/com/google/android/samples/ApiDemosTest.java
samples/ApiDemos/tests/src/com/google/android/samples/os
samples/ApiDemos/tests/src/com/google/android/samples/os/MorseCodeConverterTest.java
samples/ApiDemos/tests/src/com/google/android/samples/view
samples/ApiDemos/tests/src/com/google/android/samples/view/Focus2ActivityTest.java
samples/ApiDemos/tests/src/com/google/android/samples/view/Focus2AndroidTest.java
Contents of makefile
The contents of the makefile are similar to a normal application with the addition of a LOCAL_INSTRUMENTATION_FOR declaration.
# Add appropriate copyright banner here
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
# We only want this apk build for tests.
LOCAL_MODULE_TAGS := tests
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
# Notice that we don't have to include the src files of ApiDemos because, by
# running the tests using an instrumentation targeting ApiDemos, we
# automatically get all of its classes loaded into our environment.
LOCAL_PACKAGE_NAME := ApiDemosTests
LOCAL_INSTRUMENTATION_FOR := ApiDemos
include $(BUILD_PACKAGE)
Content of Manifest
Use the following example to create an AndroidManifest.xml file that declares the instrumentation. Specify that the framework supplied Instrumentation TestRunner targest the package of your application, allowing the tests that are run with the instrumentation to get access to all of the classes of your application without having to build the source into the test app. The name of the test application is typically the same as your target application with .tests appended.
# Add appropriate copyright banner here
package="com.android.samples.tests">
This declares that this app uses the instrumentation test runner targeting
the package of com.android.samples. To run the tests use the command:
"adb shell am instrument -w com.android.samples.tests/android.test.InstrumentationTestRunner"
-->
android:targetPackage="com.android.samples"
android:label="Tests for Api Demos."/>
The following snippet will prefix the /android.test.InstrumentationTestRunner when running tests from the command line:
$ adb shell am instrument -w \
com.android.samples.tests/android.test.InstrumentationTestRunner
New Instrumentation TestRunner
Create a class that derives from this class. You must override two abstract methods; one that returns the class loader of the target package, and another that defines all of the tests within the package. For example, the snippet below displays the test runner for the framework tests.
public class FrameworkInstrumentationTestRunner extends InstrumentationTestRunner {
Debugging with GDB
In this document
Debugging
Just-In-Time Debug Feature
The current version of envsetup.sh has a gdbclient command that handles much of the setup. For example, to attach the already-running globaltime application, execute the following, making sure that: 1) you do this from the same window used to build the software on the device you are debugging and 2) verify that the symbols in the object files in the build tree match up with what is installed on the device or emulator.
gdbclient app_process :5039 globaltime
Debugging
Short Instructions
Android runs gdbserver on the device and an ARM aware gdb, named arm-eabi-gdb, on the desktop machine.
First you need to run gdbserver on the device:
gdbserver :5039 /system/bin/executable
The :5039 tells gdbserver to listen on port 5039 on the localhost, which adb bridges from the host to the device. executable represents the command to debug, a common one being runtime -s which starts the entire system all running in a single process.
Launch gdb on the desktop. This can be done easily with the following command in the shell from which you built:
gdbclient executable
At this point gdb will connect with your device and you should be able to enter c to have the device start executing inside of the desktop gdb session.
Detailed Instructions
If the short instructions don't work, these detailed instructions should:
On the device, launch a new command:
gdbserver :5039 /system/bin/executable
or attach to an existing process:
gdbserver :5039 --attach pid
On your workstation, forward port 5039 to the device with adb:
adb forward tcp:5039 tcp:5039
Start a special version of gdb that lives in the "prebuilt" area of the source tree:
prebuilt/Linux/toolchain-eabi-4.2.1/bin/arm-eabi-gdb (for Linux)
prebuilt/darwin-x86/toolchain-eabi-4.2.1/bin/arm-eabi-gdb (for Darwin)
If you can't find either special version of gdb, run find prebuilt -name arm-eabi-gdb in your source tree to find and run the latest version:
prebuilt/Linux/toolchain-eabi-4.2.1/bin/arm-eabi-gdb out/target/product/product-name/symbols/system/bin/executable
Where product-name is the name of the device product that you're building (for example, sooner), and executable is the program to debug (usually app_process for an application).
Make sure to use the copy of the executable in the symbols directory, not the primary android directory, because the one in the primary directory has been stripped of its debugging information.
In gdb, Tell gdb where to find the shared libraries that will get loaded:
set solib-absolute-prefix /absolute-source-path/out/target/product/product-name/symbols
set solib-search-path /absolute-source-path/out/target/product/product-name/symbols/system/lib
absolute-source-path is the path to your source tree; for example, /work/device or /Users/hoser/android/device.
product-name is the same as above; for example, sooner.
Make sure you specify the correct directories—gdb may not tell you if you make a mistake.
Connect to the device by issuing the gdb command:
target remote :5039
The :5039 tells gdb to connect to the localhost port 5039, which is bridged to the device by adb.
You may need to inspire gdb to load some symbols by typing:
shared
You should be connected and able to debug as you normally would. You can ignore the error about not finding the location for the thread creation breakpoint. It will be found when the linker loads libc into your process before hitting main(). Also note that the gdb remote protocol doesn't have a way for the device to tell the host about newly created threads so you will not always see notifications about newly created threads. Info about other threads will be queried from the device when a breakpoint is hit or you ask for it by running info thread.
Just-In-Time Debug Feature
If you see the red LED flashing it means a process is in that new state (crashed and waiting for GDB connection). If this happens to the system process, most likely your device will be frozen at this point. Do not press the home key. Bring the device to someone who can debug native crashes and ask for advice. If you're in the field and just want your device to continue as it would have without this feature (like cylonning), press home (a tombstone will be recorded as usual). To enable a process to be debugged this way, you need to set a property:
adb shell setprop debug.db.uid 10000
and all processes with a uid <= 10000 will be trapped in this manner. When one of them crashes, the tombstone is processed as usual, an explicit message is printed into the log, and the red LED starts flashing waiting for the Home key to be depressed (in which case it continues execution as usual).
I/DEBUG ( 27): ********************************************************
I/DEBUG ( 27): * process 82 crashed. debuggerd waiting for gdbserver
I/DEBUG ( 27): *
I/DEBUG ( 27): * adb shell gdbserver :port --attach 82 &
I/DEBUG ( 27): *
I/DEBUG ( 27): * and press the HOME key.
I/DEBUG ( 27): ********************************************************
When you see the entry above, make sure adb is forwarding port 5039 (you only need to do this once, unless the ADB server dies) and execute:
% adb forward tcp:5039 tcp:5039
Execute the line shown in the debug output, substituting 5039 for the proper port:
% adb shell gdbserver :5039 --attach 82 &
If the crashing process is based off zygote (that is, system_server and all applications), the default values for the gdbclient command, app_process binary and port 5039, are correct, so you can execute:
% cd
% gdbclient
Otherwise you need to determine the path of the crashing binary and follow the steps as mentioned above (for example, gdbclient hoser :5039 if the hoser command has failed).
Debugging Native Code
In this document
Capturing logs
Debug Scenarios
Capturing logs
To capture log output:
Produce a process list with ps (ps -t if you want verbose thread feedback).
Dump kernel messages with dmesg.
Get verbose log messages with logcat '*:v' & (running in bg with & is important).
Debug Scenarios
# command to device shell (via adb)
% command to host pc shell
Crash but no exit...stuck
In this scenario, the GTalk app crashed but did not actually exit or seems stuck. Check the debug logs to see if there is anything unusual:
# logcat &
...
E/WindowManager( 182): Window client android.util.BinderProxy@4089f948 has died!! Removing window.
W/WindowManager( 182): **** WINDOW CLIENT android.view.WindowProxy@40882248 DIED!
W/ActivityManager( 182): **** APPLICATION com.google.android.gtalk DIED!
I/ServiceManager( 257): Executing: /android/bin/app_process (link=/tmp/android-servicemanager/com.google.android.gtalk, wrapper=/tmp/android-servi
cemanager/com.google.android.gtalk)
I/appproc ( 257): App process is starting with pid=257, class=android/activity/ActivityThread.
I/ ( 257): java.io.FileDescriptor: class initialization
I/SurfaceFlinger.HW( 182): About to give-up screen
I/SurfaceFlinger.HW( 182): screen given-up
I/SurfaceFlinger.HW( 182): Screen about to return
I/SurfaceFlinger.HW( 182): screen returned
I/SurfaceFlinger.HW( 182): About to give-up screen
I/SurfaceFlinger.HW( 182): screen given-up
I/SurfaceFlinger.HW( 182): Screen about to return
...
The logs indicate that the system launched a replacement GTalk process but that it got stuck somehow:
# ps
PID PPID VSIZE RSS WCHAN PC NAME
257 181 45780 5292 ffffffff 53030cb4 S com.google.andr
GTalk's PC is at 53030cb4. Look at the memory map to find out what lib is 0x53......
# cat /proc/257/maps
...
51000000-5107c000 rwxp 00000000 1f:03 619 /android/lib/libutils.so
52000000-52013000 rwxp 00000000 1f:03 639 /android/lib/libz.so
53000000-53039000 rwxp 00000000 1f:03 668 /android/lib/libc.so
53039000-53042000 rw-p 53039000 00:00 0
54000000-54002000 rwxp 00000000 1f:03 658 /android/lib/libstdc++.so
...
Disassemble libc to figure out what is going on:
% prebuilt/Linux/toolchain-eabi-4.2.1/bin/arm-elf-objdump -d out/target/product/sooner/symbols/android/lib/libc.so
00030ca4 <__futex_wait>:
30ca4: e1a03002 mov r3, r2
30ca8: e1a02001 mov r2, r1
30cac: e3a01000 mov r1, #0 ; 0x0
30cb0: ef9000f0 swi 0x009000f0
30cb4: e12fff1e bx lr
Blocked in a syscall
In this scenario, the system is blocked in a syscall. To debug using gdb, first tell adb to forward the gdb port:
% adb forward tcp:5039 tcp:5039
Start the gdb server and attach to process 257 (as demonstrated in the previous example):
# gdbserver :5039 --attach 257 &
Attached; pid = 257
Listening on port 5039
% prebuilt/Linux/toolchain-eabi-4.2.1/bin/arm-elf-gdb out/target/product/sooner/system/bin/app_process
(gdb) set solib-absolute-prefix /work/android/device/out/target/product/sooner/symbols
(gdb) set solib-search-path /work/android/device/out/target/product/sooner/symbols/android/lib
(gdb) target remote :5039
Remote debugging using :5039
0x53030cb4 in ?? ()
Current language: auto; currently asm
Don't let other threads get scheduled while we're debugging. You should "set scheduler-locking off" before issuing a "continue", or else your thread may get stuck on a futex or other spinlock because no other thread can release it.
(gdb) set scheduler-locking on
Ignore SIGUSR1 if you're using JamVM. Shouldn't hurt if you're not.
(gdb) handle SIGUSR1 noprint
(gdb) where
#0 __futex_wait () at system/klibc/android/atomics_arm.S:88
#1 0x53010eb8 in pthread_cond_timedwait (cond=0x12081c, mutex=0x120818, abstime=0xffffffff)
at system/klibc/android/pthread.c:490
#2 0x6b01c848 in monitorWait (mon=0x120818, self=0x6b039ba4, ms=0, ns=0) at extlibs/jamvm-1.4.1/src/lock.c:194
#3 0x6b01d1d8 in objectWait (obj=0x408091c0, ms=0, ns=0) at extlibs/jamvm-1.4.1/src/lock.c:420
#4 0x6b01d4c8 in jamWait (clazz=0xfffffffc, mb=0x0, ostack=0x2e188) at extlibs/jamvm-1.4.1/src/natives.c:91
#5 0x6b013b2c in resolveNativeWrapper (clazz=0x408001d0, mb=0x41798, ostack=0x2e188) at extlibs/jamvm-1.4.1/src/dll.c:236
#6 0x6b015c04 in executeJava () at extlibs/jamvm-1.4.1/src/interp.c:2614
#7 0x6b01471c in executeMethodVaList (ob=0x0, clazz=0x40808f20, mb=0x12563c, jargs=0xbe9229f4)
at extlibs/jamvm-1.4.1/src/execute.c:91
#8 0x6b01bcd0 in Jam_CallStaticVoidMethod (env=0xfffffffc, klass=0x0, methodID=0x12563c)
at extlibs/jamvm-1.4.1/src/jni.c:1063
#9 0x58025b2c in android::AndroidRuntime::callStatic (this=0xfffffffc,
className=0xbe922f0a "android/activity/ActivityThread", methodName=0x57000b7c "main")
at libs/android_runtime/AndroidRuntime.cpp:215
#10 0x57000504 in android::app_init (className=0xbe922f0a "android/activity/ActivityThread")
at servers/app/library/app_init.cpp:20
#11 0x000089b0 in android::sp::~sp ()
#12 0x000089b0 in android::sp::~sp ()
Previous frame identical to this frame (corrupt stack?)
(gdb) info threads
7 thread 263 __ioctl () at system/klibc/syscalls/__ioctl.S:12
6 thread 262 accept () at system/klibc/syscalls/accept.S:12
5 thread 261 __futex_wait () at system/klibc/android/atomics_arm.S:88
4 thread 260 __futex_wait () at system/klibc/android/atomics_arm.S:88
3 thread 259 __futex_wait () at system/klibc/android/atomics_arm.S:88
2 thread 258 __sigsuspend () at system/klibc/syscalls/__sigsuspend.S:12
1 thread 257 __futex_wait () at system/klibc/android/atomics_arm.S:88
(gdb) thread 7
[Switching to thread 7 (thread 263)]#0 __ioctl () at system/klibc/syscalls/__ioctl.S:12
12 movs r0, r0
(gdb) bt
#0 __ioctl () at system/klibc/syscalls/__ioctl.S:12
#1 0x53010704 in ioctl (fd=-512, request=-1072143871) at system/klibc/android/ioctl.c:22
#2 0x51040ac0 in android::IPCThreadState::talkWithDriver (this=0x1207b8, doReceive=true) at RefBase.h:83
#3 0x510418a0 in android::IPCThreadState::joinThreadPool (this=0x1207b8, isMain=false)
at libs/utils/IPCThreadState.cpp:343
#4 0x51046004 in android::PoolThread::threadLoop (this=0xfffffe00) at libs/utils/ProcessState.cpp:52
#5 0x51036428 in android::Thread::_threadLoop (user=0xfffffe00) at libs/utils/Threads.cpp:1100
#6 0x58025c68 in android::AndroidRuntime::javaThreadShell (args=0x105ffe28) at libs/android_runtime/AndroidRuntime.cpp:540
(gdb) thread 6
[Switching to thread 6 (thread 262)]#0 accept () at system/klibc/syscalls/accept.S:12
12 movs r0, r0
(gdb) bt
#0 accept () at system/klibc/syscalls/accept.S:12
#1 0x6b0334e4 in jdwpAcceptConnection (state=0xfffffe00) at extlibs/jamvm-1.4.1/jdwp/JdwpNet.c:213
#2 0x6b032660 in jdwpThreadEntry (self=0x4d020) at extlibs/jamvm-1.4.1/jdwp/JdwpMain.c:37
#3 0x6b022c2c in shell (args=0x4d960) at extlibs/jamvm-1.4.1/src/thread.c:629
(gdb) thread 5
[Switching to thread 5 (thread 261)]#0 __futex_wait () at system/klibc/android/atomics_arm.S:88
88 bx lr
(gdb) bt
#0 __futex_wait () at system/klibc/android/atomics_arm.S:88
#1 0x53010f48 in pthread_cond_timeout (cond=0x6b039b64, mutex=0x6b039b60, msecs=0) at system/klibc/android/pthread.c:513
#2 0x6b01c8d0 in monitorWait (mon=0x6b039b60, self=0x4d400, ms=1000, ns=272629312) at extlibs/jamvm-1.4.1/src/lock.c:183
#3 0x6b022084 in threadSleep (thread=0x4d400, ms=1000, ns=272629312) at extlibs/jamvm-1.4.1/src/thread.c:215
#4 0x6b00d4fc in asyncGCThreadLoop (self=0x4d400) at extlibs/jamvm-1.4.1/src/alloc.c:1179
#5 0x6b022c2c in shell (args=0x4d480) at extlibs/jamvm-1.4.1/src/thread.c:629
(gdb) thread 4
[Switching to thread 4 (thread 260)]#0 __futex_wait () at system/klibc/android/atomics_arm.S:88
88 bx lr
(gdb) bt
#0 __futex_wait () at system/klibc/android/atomics_arm.S:88
#1 0x53010eb8 in pthread_cond_timedwait (cond=0x6b039934, mutex=0x6b039930, abstime=0x0)
at system/klibc/android/pthread.c:490
#2 0x6b00b3ec in referenceHandlerThreadLoop (self=0x4d360) at extlibs/jamvm-1.4.1/src/alloc.c:1247
#3 0x6b022c2c in shell (args=0x4d960) at extlibs/jamvm-1.4.1/src/thread.c:629
(gdb) thread 3
[Switching to thread 3 (thread 259)]#0 __futex_wait () at system/klibc/android/atomics_arm.S:88
88 bx lr
(gdb) bt
#0 __futex_wait () at system/klibc/android/atomics_arm.S:88
#1 0x53010eb8 in pthread_cond_timedwait (cond=0x6b03992c, mutex=0x6b039928, abstime=0x0)
at system/klibc/android/pthread.c:490
#2 0x6b00b1dc in finalizerThreadLoop (self=0x4d8e0) at extlibs/jamvm-1.4.1/src/alloc.c:1238
#3 0x6b022c2c in shell (args=0x4d960) at extlibs/jamvm-1.4.1/src/thread.c:629
(gdb) thread 2
[Switching to thread 2 (thread 258)]#0 __sigsuspend () at system/klibc/syscalls/__sigsuspend.S:12
12 movs r0, r0
(gdb) bt
#0 __sigsuspend () at system/klibc/syscalls/__sigsuspend.S:12
#1 0x6b023814 in dumpThreadsLoop (self=0x51b98) at extlibs/jamvm-1.4.1/src/thread.c:1107
#2 0x6b022c2c in shell (args=0x51b58) at extlibs/jamvm-1.4.1/src/thread.c:629
Crash in C / C++ code
If it crashes, connect with aproto and run logcat on the device. You should see output like this:
I/ActivityManager( 188): Starting activity: Intent { component=com.android.calendar.MonthScreen }
I/ActivityManager( 188): Starting application com.android.calendar to host activity com.android.calendar.MonthScree
n
I/ServiceManager( 417): Executing: /android/bin/app_process (link=/android/bin/app_process, wrapper=/android/bin/app_process)
I/DEBUG: -- observer of pid 417 starting --
I/appproc ( 417): App process is starting with pid=417, class=android/activity/ActivityThread.
I/DEBUG: -- observer of pid 417 exiting --
I/DEBUG: -- observer of pid 420 starting --
I/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG: pid: 373, tid: 401 >>> android.content.providers.pim <<<
I/DEBUG: signal 11 (SIGSEGV), fault addr 00000000
I/DEBUG: r0 ffffffff r1 00000000 r2 00000454 r3 002136d4
I/DEBUG: r4 002136c0 r5 40804810 r6 0022dc70 r7 00000010
I/DEBUG: r8 0020a258 r9 00000014 10 6b039074 fp 109ffcf8
I/DEBUG: ip 6b039e90 sp 109ffc0c lr 580239f0 pc 6b0156a0
I/DEBUG: #01 pc 6b0156a0 /android/lib/libjamvm.so
I/DEBUG: #01 lr 580239f0 /android/lib/libandroid_runtime.so
I/DEBUG: #02 pc 6b01481c /android/lib/libjamvm.so
I/DEBUG: #03 pc 6b0148a4 /android/lib/libjamvm.so
I/DEBUG: #04 pc 6b00ebc0 /android/lib/libjamvm.so
I/DEBUG: #05 pc 6b02166c /android/lib/libjamvm.so
I/DEBUG: #06 pc 6b01657c /android/lib/libjamvm.so
I/DEBUG: #07 pc 6b01481c /android/lib/libjamvm.so
I/DEBUG: #08 pc 6b0148a4 /android/lib/libjamvm.so
I/DEBUG: #09 pc 6b0235c0 /android/lib/libjamvm.so
I/DEBUG: #10 pc 5300fac4 /android/lib/libc.so
I/DEBUG: #11 pc 5300fc5c /android/lib/libc.so
I/DEBUG: -- observer of pid 373 exiting --
I/DEBUG: -- observer of pid 423 starting --
If debugging output indicates an error in C or C++ code, the addresses aren't particularly useful, but the debugging symbols aren't present on the device. Use the "stack" tool to convert these addresses to files and line numbers, for example:
pid: 373, tid: 401 >>> android.content.providers.pim <<<
signal 11 (SIGSEGV), fault addr 00000000
r0 ffffffff r1 00000000 r2 00000454 r3 002136d4
r4 002136c0 r5 40804810 r6 0022dc70 r7 00000010
r8 0020a258 r9 00000014 10 6b039074 fp 109ffcf8
r8 0020a258 r9 00000014 10 6b039074 fp 109ffcf8
ADDR FUNCTION FILE:LINE
6b0156a0 executeJava extlibs/jamvm-1.4.1/src/interp.c:2674
580239f0 android_util_Parcel_freeBuffer libs/android_runtime/android_util_Binder.cpp:765
6b01481c executeMethodVaList extlibs/jamvm- 1.4.1/src/execute.c:91
6b0148a4 executeMethodArgs extlibs/jamvm-1.4.1/src/execute.c:67
6b00ebc0 initClass extlibs/jamvm-1.4.1/src/class.c:1124
6b02166c resolveMethod extlibs/jamvm- 1.4.1/src/resolve.c:197
6b01657c executeJava extlibs/jamvm-1.4.1/src/interp.c:2237
6b01481c executeMethodVaList extlibs/jamvm-1.4.1/src/execute.c:91
6b0148a4 executeMethodArgs extlibs/jamvm- 1.4.1/src/execute.c:67
6b0235c0 threadStart extlibs/jamvm-1.4.1/src/thread.c:355
5300fac4 __thread_entry system/klibc/android/pthread.c:59
5300fc5c pthread_create system/klibc/android/pthread.c:182
Or you can run logcat without any parameters and it will read from stdin. You can then paste output into the terminal or pipe it. Run logcat from the top of the tree in the environment in which you do builds so that the application can determine relative paths to the toolchain to use to decode the object files.
Debugging with tcpdump and other tools
Installing tcpdump
Running tcpdump
Other network debugging commands
Installing tcpdump
Pushing the binary to an existing device
Download tcpdump from http://www.tcpdump.org/, then execute:
adb root
adb remount
adb push /wherever/you/put/tcpdump /system/xbin/tcpdump
adb shell chmod 6755 /data/local/tmp/tcpdump
Including tcpdump in the build image
If you are running your own build, execute:
mmm external/tcpdump # install the binary in out/.../system/xbin
make snod # build a new system.img that includes it
Flash the device as usual, for example, fastboot flashball.
If you want to build tcpdump by default, add CUSTOM_TARGETS += tcpdump to your buildspec.mk.
Running tcpdump
You need to have root access on your device.
Batch mode capture
The typical procedure is to capture packets to a file and then examine the file on the desktop, as illustrated below:
adb shell tcpdump -i any -p -s 0 -w /sdcard/capture.pcap
# "-i any": listen on any network interface
# "-p": disable promiscuous mode (doesn't work anyway)
# "-s 0": capture the entire packet
# "-w": write packets to a file (rather than printing to stdout)
... do whatever you want to capture, then ^C to stop it ...
adb pull /sdcard/capture.pcap .
sudo apt-get install wireshark # or ethereal, if you're still on dapper
wireshark capture.pcap # or ethereal
... look at your packets and be wise ...
You can run tcpdump in the background from an interactive shell or from Terminal. By default, tcpdump captures all traffic without filtering. If you prefer, add an expression like port 80 to the tcpdump command line.
Real time packet monitoring
Execute the following if you would like to watch packets go by rather than capturing them to a file (-n skips DNS lookups. -s 0 captures the entire packet rather than just the header):
adb shell tcpdump -n -s 0
Typical tcpdump options apply. For example, if you want to see HTTP traffic:
adb shell tcpdump -X -n -s 0 port 80
You can also monitor packets with wireshark or ethereal, as shown below:
# In one shell, start tcpdump.
adb shell "tcpdump -n -s 0 -w - | nc -l -p 11233"
# In a separate shell, forward data and run ethereal.
adb forward tcp:11233 tcp:11233 && nc 127.0.0.1 11233 | ethereal -k -S -i -
Note that you can't restart capture via ethereal. If anything goes wrong, you will need to rerun both commands.
For more immediate output, add -l to the tcpdump command line, but this can cause adb to choke (it helps to use a nonzero argument for -s to limit the amount of data captured per packet; -s 100 is sufficient if you just want to see headers).
Disabling encryption
If your service runs over https, tcpdump is of limited use. In this case, you can rewrite some service URLs to use http, for example:
vendor/google/tools/override-gservices url:calendar_sync_https_proxy \
https://www.google.com/calendar rewrite http://android.clients.google.com/proxy/calendar
Other network debugging commands
On the device:
ifconfig interface: note that unlike Linux, you need to give ifconfig an argument
netcfg: lists interfaces and IP addresses
iftop: like top for network
route: examine the routing table
netstat: see active network connections
nc: netcat connection utility
On the desktop:
curl: fetch URLs directly to emulate device requests