您的位置:首页 > 移动开发 > Android开发

Debugging native framework code of Android Java applications

2016-04-09 09:27 721 查看
This article describes a way of debugging native libraries loaded by Android Java applications using Eclipse CDT. Android SDK applications and
Android Java framework services load various C/C++ libraries through JNI (i.e. Java Native Interface). Below are few scenarios where the technique described here comes in handy.

To debug Java security apis and Openssl integration code
To debug input dispatching logic in system_server framework process
To debug Android Java UI runtime and native UI stack integration

This article is meant for AOSP developers who like to debug native libraries in their fork of Android. This article is not meant for NDK developers.
They should use standard NDK debugging tools.


Android Java process

An Android system consists of many Java processes called with different names: Activities (i.e. UI Applications),
Services (i.e. daemon services running in background), NDK applications, framework services like Activity Manager, Input Manager etc. They are forked off
Zygote process. Command line applications like input, am, pm etc are Java applications as well.

All Java applications are launched using a native application called app_process.
You can think of this application as the Android counterpart to java application in Sun J2SE or JRE environment. Please
take a look at /system/bin/amshell script if you want to understand how it is invoked. Given below are its contents.

# Script to start "am" on the device, which has a very rudimentary

# shell.

#

base=/system

export CLASSPATH=$base/framework/am.jar

exec app_process $base/bin com.android.commands.am.Am "$@"


To debug native libraries loaded by Java applications, app_process is
the executable that should be used as target application in Eclipse debug configuration. Once that is in place, Debugging native code of Java applications is pretty much same as debugging pure native applications.


Setup

Please follow the native application debugging steps as described in Debugging
Android native applications article. When creating remote debug configuration as described in the article above, in step 2, select<aosproot>/out/target/product/mars/symbols/system/bin/app_process as
target application. The main tab should look like below.





Please follow all the other steps as is.

I am going to debug libhwui.so using the above debug configuration. libhwui.so is
one of core UI libs responsible for providing h/w accelerated APIs. It gets loaded by every Android UI application.

To build this library with debug symbols:

Launch a terminal window and change directory to <aosproot>.
Invoke envsetup.sh as below.

$. build/envsetup.sh


Change directory to ./frameworks/base/libs/hwui.
Edit Android.mk in this
directory and add "-O0 -g " where LOCAL_CFLAGS is
modified.
Invoke mm.

$mm -B LOCAL_STRIP_MODULE=false


Debugging session

OpenGLRenderer::prepareDirty(...) is one of the busy methods that gets called a lot
whenever a UI Activity changes something in its layout. Lets setup a breakpoint in this method and step through it.

Launch Eclipse and open Android native framework project.
Open libs/hwui/OpenGLRenderer.cpp from
eclipse. Set a breakpoint inOpenGLRenderer::prepareDirty() method.
Launch a terminal window and build libhwui.so with
debug symbols as described in previous section. Push this library to /system/lib directory on your device and reboot
the device. Wait until the device boots up.
Launch the UI application that you want to step through.
From terminal window, adb connect to your device. Setup port forwarding as below.

$adb forward tcp:10000 tcp:10000
Lets assume the UI application is ucboard. Find its pid and attach to it using gdbserver.

$adb shell ps | grep -i ucboard

app_16 2045 814 457284 33840 ffffffff 2ab7f6d8 S ucboard

$adb shell gdbserver :10000 --attach 2045

Attached; pid = 2045

Listening on port 10000

From Eclipse, Choose Run->Debug Configurations... and select "Native
Libs of Android Java apps"
remote c++ debug configuration created above.

Click Debug.
Eclipse should change to Debug perspective and the thread list shows all the threads in the UI application.
Do something in the UI app that makes it paint something on screen like changing focus from one field to other. You should see Eclipse hit the breakpoint created
above.





Please step through the code using the debug toolbar buttons in the oval annotation above.

When debugging pure native applications, you will have to change the target executable in debug configuration to the path of executable you are planning to debug. When debugging native code of Java applications,
you don't have to make any changes to debug configuration. Target executable is always app_process.

If you are planning to debug native code loaded by system_server (i.e. the Java app that hosts Activity Manager, Window Manager etc), don't use system_server executable under /system/bin. You need to use app_process
for this like other Java applications.

Posted 11th July 2014 by Video
Guy

Labels: android android-source app_process C/C++ debug eclipse gdb native
code NDK ndk-gdb system_server

0


Add a comment



JUL

3


Debugging
Android native applications

Android framework consists of multiple Java based services, native applications and native shared libraries. This article describes a way of
debugging native applications using Eclipse CDT. Applications that are implemented mainly in C/C++ are referred as native applications in this article. Examples of native applications are Surfaceflinger, Sensor service, tools like screenshot, bootanimation,
dumpsys etc.

NDK applications should be debugged using NDK tools. This article is not meant for NDK debugging. The audience of this article are developers
who like to debug or understand native applications that come with Android platform (i.e. AOSP).


Prerequisites

The tools described below are needed before you continue.


Eclipse CDT


Eclipse Kepler version on UBuntu is used to verify the steps described here.


gdbserver for target device

The android platform of target device should have gdbserver agent for remote debugging. You should see /system/bin/gdbserver on target device. If you don't find it, please use one from prebuilt directory. If the
device cpu is ARM based, you can use prebuilt/android-arm/gdbserver binary. If the device cpu is x86 based,prebuilt/android-x86/gdbserver should
be used. The binary needs to be copied to the device under/system/bin directory.


gdb host binary


gdb for host machine that understands the target device instruction set is needed. If you are planning to run Eclipse on x86 Linux box to debug
target device that uses ARM cpu, you need gdb compiled for x86 linux that understands ARM instruction set.

Android platform comes with prebuilt binaries for various host os, host cpu and target cpu combinations. For the above example, on AOSP 4.0.3 you will use arm-linux-androideabi-gdb located
under prebuilt/linux-x86/toolchain/arm-linux-androideabi-4.4.x/bin folder. If your AOSP build is using custom toolchain,
gdb from that toolchain should be used.

You can download the following binaries if your device is ARM based and host is x86 based Linux box. These are built with 7.3 version of gdb sources with multithreading patches. My debugging sessions are more predictable with them compared to the prebuilt binaries
that came with AOSP 4.0.3.

ARM
gdbserver

Linux
x86 gdb


Android SDK tools

Please install Android
SDK. Eclipse ADT is not needed. You can skip ADT installation. adb from SDK tools is needed to setup port forwarding, shell access to device.



Shadow AOSP directory

IDEs including eclipse tend to leave artifacts as you use them. Sometimes these artifacts under AOSP tree break AOSP builds. We need to create
a shadow directory of symlinks to sources under AOSP root mimicking its directory structure. The shadow directory will be used for eclipse projects.

Lets assume the AOSP sources are located at /home/videoguy/platform/mars folder.
This is the top level folder under which you should see frameworks, build, kernel etc sub directories. This folder is referred as <aosproot> in
the sections below. Lets assume the shadow folder is located at /home/videoguy/platform/ide/mars . This folder is
referred as <shadowroot> below.

Open a terminal window and change directory to <aosproot> .
Build the AOSP platform the way you normally do. You should see <aosproot>/out with
build artifacts after this. If you haven't created <shadowroot> yet, please create it before continuing. The directory
structure should look like below.





Change directory to <shadowroot>.

Invoke lndir command like below at command prompt.

$lndir ../../mars

This will make the shadow directory mimic the structure of <aosproot> with symlinks pointing to files under<aosproot> .
If you make changes to the files from Eclipse, the files under <aosproot> get changed and vice versa.


Eclipse project

The main goal of having eclipse project is to help with browsing, editing and debugging native code. It is not meant for
building code
from the IDE. Please use terminal window for building code you are planning to debug.

For this article, Surfaceflinger application is used as debuggee process. This process is responsible for compositing surfaces from foreground applications. Its sources are located under<aosproot>/frameworks/base/services/surfaceflinger folder.
Usually one would typically create project that includes the sources of specific module being debugged. Instead I suggest creating eclipse project that includes all the native code under frameworks/base.
This makes it easy navigating code using eclipse symbol help shortcuts.

Please follow the instructions below to create the project.

Launch Eclipse CDT.
Choose File->New->Project... menu option.

In the new project dialog, expand C/C++ category.

Select Makefile project with Existing Code. It looks like below.





Click Next.
Please configure new project.

Change Project Name to Android Native Framework.

Change Existing Code Location to <shadowroot>/frameworks/base.
Make sure you are using<shadowroot> tree for this.

Change Toolchain for Indexer settings to Linux GCC.





Click Finish. Please wait 30-40 secs for project parsing to complete.
Disable builds. As mentioned above, we do not want to use Eclipse for building native code.

Right click on Android Native Framework project and select Properties.

Select C/C++ Build.

Uncheck Use default build command.

Change Build command to dummymake. It should look like
below.



Press OK to close the dialog.

Now you have a project that can be used in remote debug configuration described later.


Native binaries with debug symbols

Native applications or libraries need to be built with debug symbols for source level debugging to work reliably. You can use lunch command to make a debug build as described at AOSP
Building and Running. You can make a debug or release build and flash your device with it. In either case, you can build specific components with debug symbols and debug that code. Remaining steps assume you already flashed the Android device with latest
and greatest AOSP platform build of your Android fork.

To build surfaceflinger library with debug symbols, please follow the steps below. You can use the same process for other libraries or applications.

Launch a terminal window and change directory to <aosproot>.
Invoke envsetup.sh as below.

$source build/envsetup.sh
Change directory to <aosproot>/frameworks/base/services/surfaceflinger.

$cd frameworks/base/services/surfaceflinger/
Invoke mm command as below.

$mm -B LOCAL_STRIP_MODULE=false LOCAL_CFLAGS=" -O0 -g "

The -B option will cause a clean build of current folder.

Passing LOCAL_CFLAGS like above would generate binary with debug symbols most of the times. If theAndroid.mk file
in current directory (i.e. where mm is invoked) redefines it, your build would fail. It is better to checkAndroid.mk file for this
scenario and edit the .mk file to include "
-O0 -g "
where LOCAL_CFLAGS is assigned. If you edited Android.mk file,
don't pass LOCAL_CFLAGS to mm.
Please note surfaceflinger .mk redefinesLOCAL_CFLAGS. Please plan to edit the file.

The generated unstripped binary (i.e. libsurfaceflinger.so) would be available at<aosproot>/out/target/product/mars/symbols/system/lib/libsurfaceflinger.so.

The binary has to be pushed to target device before debugging it.


Remote Debug Configuration

An eclipse debug configuration should be created to debug remote C/C++ applications. Before you do this using eclipse GUI, you need to create gdb script file that tells gdb where to find symbols for standard libraries
like C/C++ run time, openssl, OpenGL etc.

Create a file gdb4android.cmds with contents below under <aosproot> directory.
You need to substitute<aosproot> below with absolute path of your AOSP directory.

set solib-absolute-prefix <aosproot>/out/target/product/mars/symbols

set solib-search-path <aosproot>/out/target/product/mars/symbols/system/lib:<aosproot>/out/target/product/mars/symbols/system/bin


For the setup of this article, the file should look like below.

set solib-absolute-prefix /home/videoguy/platform/mars/out/target/product/mars/symbols

set solib-search-path[b]/home/videoguy/platform/mars
/out/target/product/mars/symbols/system/lib:/home/videoguy/platform/mars/out/target/product/mars/symbols/system/bin[/b]

The mars in out/target/product/mars/symbols/system/bin above
is the Android device you are building. You need to substitute mars with the device name of your AOSP configuration.

Now you should create debug configuration.

Launch eclipse and right click on Android Native Framework project. Choose Debug
As->Debug Configurations...
menu item.
Select C/C++ Remote Application.

Click on icon with + sign to add new debug configuration.

For C/C++ Application, browse to<aosproot>/out/target/product/mars/symbols/system/bin/surfaceflinger and
select it.

For Project, select Android Native Framework.

Enable the radio box Disable auto build. The dialog should look like below.





Select Debugger tab.

For GDB debugger, browse to gdb binary that matches your configuration as described in Prerequisites section.

For GDB command line, Browse and select <aosproot>/gdb4android.cmds file
that was created above.

Check Force thread list update on suspend checkmark.

Press Apply to save the configuration. The debugger tab should look like below.





Press Connection sub tab of Debugger tab.

Change Hostname or IPaddress to localhost.

Change port number to 10000.

Instead of localhost, you can use IP address of the device if device allows tcp connections from external clients. If you are connecting to the device over adb usb bridge,
localhost is the only option available.

Press Apply to save changes.

The Connection tab should look like below.





Press Close to close the dialog.

Having right gdb and gdb4android.cmds is crucial for debugging to work reliably. If debugger doesn't stop at the breakpoints you configured, first thing you should check is debugger
configuration in step 3 above.


Remounting root partition

In a typical debugging session, you make changes to sources; build; start a debugging session and stop it after tracing code of interest. You repeat this process until you are satisfied with the results of your changes.
This is the usual workflow when debugging desktop applications.

There are couple of wrinkles to iron out to have productive debugging sessions when debugging a native Android framework application (like Surfaceflinger). The application or library that you are planning to debug
needs to be copied to /system partition which is read-only. Flashing your device with new system image is not an option as it is time consuming process. The other option is to remount root partition as read-writeable and push new binaries to target device.
You might have to reboot your device if the changed binary affects core services like Surfaceflinger or system_server processes. That is still better than flashing your device. Given below are helper commands to do these tasks.

Assuming you have already connected to the device through ADB, Issue the following command to remount system partition as read-writable.

$adb shell mount -o rw,remount /system

If this doesn't work, try this one.

$adb shell mount -o rw,remount /

The way to verify if it worked is to look for root partition attributes in mount output. You should see rw (instead of ro) like red text below.

$adb shell mount
rootfs / rootfs rw 0 0

/dev/mmcblk0p5 / ext3 rw,relatime,errors=continue,barrier=0,data=ordered 0 0

tmpfs /dev tmpfs rw,nosuid,relatime,mode=755 0 0

devpts /dev/pts devpts rw,relatime,mode=600 0 0

proc /proc proc rw,relatime 0 0

sysfs /sys sysfs rw,relatime 0 0

tmpfs /mnt/asec tmpfs rw,relatime,mode=755,gid=1000 0 0

tmpfs /tmp tmpfs rw,relatime,mode=777,gid=1000 0 0

Then push new binary.

$adb push <aosproot>/out/target/product/mars/symbols/system/lib/libsurfaceflinger.so /system/lib

To reboot

$adb shell reboot

What we have done so far are one time configuration steps needed for debugging sessions. We have a project that has most of native sources we are planning to debug and
a debug configuration to debug a specific native application (i.e. Surfaceflinger). We have gone over adb helper commands to push new binaries to target device.


Debugging session

SurfaceFlinger::threadLoop() is a service method that gets invoked whenever there is a surface (aka layer) ready to be displayed. Lets setup a breakpoint
in this function and step through it.

Open frameworks/base/services/surfaceflinger.cpp from
eclipse project and set a breakpoint.

If you find breakpoint menu option is disabled, make sure you select Eclipse C/C++ perspective. Another possible reason for this is that the project is configured to use default build command (i.e. make instead of dummymake). Once eclipse parses the whole project,
you should be able to setup breakpoints.
Launch a separate terminal window and build surfaceflinger library with debug symbols as described above.
Connect to target device using adb. Push libsurfaceflinger.so to /system/lib directory as described in previous section.
Reboot the device (i.e. adb shell reboot)
Connect again using adb. Setup adb port forwarding.

$adb forward tcp:10000 tcp:10000
Launch gdbserver and attach to surfaceflinger process.

$adb shell ps | grep surfaceflinger

system 811 1 65484 30004 ffffffff 2aaf7850 S /system/bin/surfaceflinger

$adb shell gdbserver :10000 --attach 811

Attached; pid = 811

Listening on port 10000

The above command should be changed like below if you want gdbserver start an application on connection from client.

$adb shell gdbserver :10000 <path to application>
From Eclipse, Choose Run->Debug Configurations... and select Android
Native Framework
remote debug configuration. Click Debug.

Eclipse should connect to gdbserver and change to Debug perspective.

You should see something like below from gdbserver session.

Remote debugging from host 127.0.0.1

libthread_db:td_ta_new: Probing system for platform bug.

libthread_db:td_ta_new: Running as root, nothing to do.


You can ignore errors/warnings in gdb console about missing shared lib symbols.

You should see something like below in eclipse.



Interact with the device that results in UI update. It could be launching a different application or changing focus from one field to other. You should see eclipse
hit the breakpoint set above. It should look like below.



You can use the debug buttons from the toolbar with blue oval annotation to step through code. When done you can detach from gdbserver.

It is lot of steps to follow to get native debugging working. Don't be surprised if it doesn't work first time. You need to follow the steps carefully to get your first debugging session working. Please check the
following troubleshooting tips when you run into issues.


Troubleshooting


Eclipse debugger is failing during launch saying connection timeout

Make sure gdbserver is running waiting for connection. Or

Make sure adb forwarding was setup correctly to do port forwarding


Debuggee process is crashing with SIGINT

It is usually a symptom of using wrong gdb and gdbserver combination. Invoke "gdbserver --version" on device and "gdb --version" on host. Make sure the versions match. If you are building AOSP with custom toolchain
that has its own gdbserver and gdb, please use those versions.


Eclipse doesn't stop at breakpoints

Look for symptoms described in (2).


Breakpoints work in the beginning and stop working

Look for symptoms described in (2).


Debugger suspended the process, but step in/step over etc toolbar buttons are disabled

Make sure you selected one of the threads from thread list.

Posted 3rd July 2014 by Video
Guy

Labels: android android-source C/C++ debug eclipse gdb gdbserver native
code platform surfaceflinger

9


View comments



JUN

25


Debugging
Android Java framework services using Eclipse

Android provides rich SDK and developer environment to build applications targeted for Android devices. An application
developer can prototype, test and debug Android SDK applications using Eclipse ADT plugin or Android Studio. SDK
Debugging page explains various tools and ways of debugging applications. The debugging gets tricky if you are working on Android platform internals. This article explains a way of debugging Android platform services using Eclipse IDE.


Platform Services

Platform services are Android framework services like Activity manager, Window manager, Input manager, WiFi manager etc that run as part of system_process Linux process.





If you have modified framework classes and like to debug those changes on a live system, the technique described here comes in handy. If you are working
on a fork of Android platform and would like to understand different moving parts in Android framework, you can use this method to step through framework classes.

First you need to create an Eclipse project for Android platform. Please follow the instructions at Using
Eclipse to browse/edit AOSP code. You don't need Eclipse ADT plugin for this. The Java project created above is a standard J2SE style java project. What we are going to do is create a debug configuration to debug remote Java applications.


Remote Debug Configuration

Launch Eclipse and open Android platform project created above.

Select Run->Debug Configurations... menu option. Then select Remote Java Application from the list on left side.

Then press the icon with + sign from the popup toolbar to create new debug configuration. The port should be changed to 8700, host should be localhost and
the project should be Android platform as shown below.





Then press Apply to save the configuration.


Debug System_process

Android SDK is needed for remaining steps. If you haven't installed Android SDK, please install it following the instructions at Android
SDK installation.

Launch terminal window and add Android sdk tools directory to PATH.

Assuming Android SDK is installed at /opt/android/sdk folder,

$export PATH=/opt/android/sdk/tools:/opt/android/sdk/platform-tools:$PATH

Lets say the IP address of android device is 10.70.77.23. Connect to it using adb.

$adb connect 10.70.77.23

You don't need to do the above step if you are connecting to your device/emulator using USB.

Launch monitor application like below.

$monitor &

Find the process with name system_process and select it. You should see port 8700 tagged to system_process
as shown below.



That means JDWP debugging commands from the Eclipse debugger will be forwarded to the process tagged with port 8700. Minimize monitor application now.

If you are using ADT plugin, you can do the same from DDMS panel. Please keep in mind that you can have either DDMS or monitor running, but not both simultaneously.


Setup Breakpoints and Go!

Lets setup couple of breakpoints in one of platform services. Open WindowManagerService.java fromframeworks/base/services/java->com.android.server.wm package
in the Eclipse project.

Navigate to the method finishDrawingWindow and setup a line break point
on the first line in this method.

Choose Run->Debug Configurations... and select Android platform debug configuration created above. PressDebug button.

Eclipse shows an error popup that there were errors, please click OK to continue. This error is due to the fact that Eclipse failed to build the project which is expected
as our project is there merely for editing/browsing and debugging purposes.

Eclipse debugger should connect to system_process. Eclipse should transition to Java debug perspective. If it didn't, please pick that perspective. It should look like this.





Navigate to different application on your device. That will make system_service hit the breakpoint created above. It should look like this.





You can step through this method using the buttons inside the oval annotation above.

If you disconnect from system_process and then start debugging again, it might fail. Please make suresystem_process is the selected process
in DDMS/Monitor window (i.e. so that port 8700 traffic gets delivered to system_process).


Recap

A debug configuration was created to debug remote Java application at localhost:8700.

DDMS/Monitor application was used to proxy localhost:8700 traffic to debug agent of selected process on a device.

Standard Java debugging tools that ship with Eclipse JDT were used to connect to localhost:8700 and debug the target process.

This technique can also be used to debug any SDK application on an Android device.

Stay tuned for more debugging tips.

Posted 25th June 2014 by Video
Guy

Labels: android android-source debug eclipse framework system_process system_server

17


View comments

JUN

18


Using
Eclipse to browse and edit Android platform source code

Android platform consists of millions of lines of C, C++ and Java code. I am part of a team building an embedded device that
uses Android as OS. One of the challenges we have often faced as developers is how to navigate Android platform code (aka AOSP) easily.

Most IDEs like Eclipse, IntelliJ provide shortcuts to do this if the source code is managed through a project. Using
Eclipse page on AOSP site describes importing the source code into Eclipse. That doesn't work as expected. Following those instructions broke AOSP build because of artifacts left behind by the Eclipse project. This post describes a way to
accomplish this without breaking AOSP build.

Lets assume the AOSP sources are located at /home/videoguy/platform/mars folder.
This is the top level folder under which you should see frameworks, build, kernel etc sub directories. This folder is referred as <aosproot> in
the sections below. To keep this folder clean from IDE artifacts, we need to create a shadow folder. Lets assume the shadow folder is located at /home/videoguy/platform/ide/mars.
This folder is referred as<shadowroot> below.

Open a terminal window and change directory to <aosproot>.

Build the AOSP platform the way you normally do. You should see <aosproot>/outwith build artifacts after this. If
you haven't created <shadowroot> yet, please create it before continuing. The directory structure should look like below.





Change directory to <shadowroot>. Invoke lndir command
like below at command prompt.

$lndir ../../mars

This will make the shadow directory mimic the structure of <aosproot> with symlinks pointing to files under <aosproot>.
If you make changes to the files from Eclipse, the files under <aosproot> get changed and vice versa.
Copy development/ide/eclipse/.classpath to <shadowroot>.
The following command will do if invoked from <shadowroot> folder.

$cp development/ide/eclipse/.classpath .
Launch Eclipse. This procedure was tested using Kepler version of Eclipse running on UBuntu. Make sure you have 512MB of heap space set aside. On my box, eclipse is launched like
below.
$eclipse -vmargs -Xmx512M -Xms256M -XX:MaxPermSize=256M

Create a new Java Project. For this, Choose File->New->Java Project or right click in "Package Explorer" space and select
"New->Java Project" menu item.

For "Project Name", enter "Android Platform".

Uncheck "Use default location" and browse and select <shadowroot> directory.

The new project dialog should look like below.





Press "Next" button and wait. This step takes around 30 seconds.

Press "Finish" and wait. This takes around 10-20 seconds. You might see "Eclipse running out
of memory" error or "GC limit reached" error. If eclipse prompts you to close workbench, please do so. You can ignore these errors.
Close Eclipse and Relaunch. You should see "Android Platform" project like below when expanded.





This is a great way to edit platform Java code using IDE with source completion and other goodies.

Please keep in mind that this project is meant for browsing, editing and debugging Framework java code. It is not meant for building AOSP from eclipse. Please
use a terminal window to make builds manually.

In a future posting, I will show you how to debug framework service like window manager using this project.

原文地址: http://apienthusiast.blogspot.com/2014/07/debugging-native-framework-code-of.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: