When debugging and profiling apps with native code, it’s often useful to use debugging tools that need to be enabled at process startup. This requires that you run your app in a fresh process rather than cloning from the zygote. Examples include:
- Tracing system calls with strace.
- Finding memory bugs with malloc debug or Address Sanitizer (ASan).
- Profiling with Simpleperf.
Using the wrap shell script
wrap.sh is easy:
- Compile a custom debuggable APK that packages the following:
- Install the debuggable APK on a device.
- Launch the app.
Creating the wrap shell script
When you launch a debuggable APK that contains
wrap.sh, the system executes
the script and passes the command to start the app as arguments. The script is
responsible for starting the app, but can make any environment or argument
changes. The script should follow
MirBSD Korn shell (mksh) syntax.
The following snippet shows how to write a simple
wrap.sh file that just
starts the app:
#!/system/bin/sh exec "$@"
wrap.sh, you would include the following line:
#!/system/bin/sh LIBC_DEBUG_MALLOC_OPTIONS=backtrace logwrapper "$@"
To take advantage of
wrap.sh, your APK must be debuggable. Make sure that the
android:debuggable=”true”setting is configured in the
element in your Android manifest.
It's also necessary to set
This is the default, but if you explicitly set it to
script will not work.
You must package the
wrap.sh script with the native libraries of the app. If
your app does not contain native libraries, add the lib directory manually to
your project directory. For each architecture that your app supports, you must
provide a copy of the wrap shell script under that native library directory.
The following example shows the file layout to support both the x86 and ARMv8 architectures:
# App Directory |- AndroidManifest.xml |- … |- lib |- x86 |- ... |- wrap.sh |- arm64-v8a |- ... |- wrap.sh