Category Archives: Performance

Disable Android ART ahead-of-time compilation to optimize debug deployment

Android ART

With the introduction of the ART runtime came ahead-of-time (AOT) compilation to replace the Dalvik just-in-time (JIT) compilation. This is achieved on app installation when a one time process is executed to convert the APKs DEX files into a compiled app optimized for the device it is running on. Devices running the old Dalvik VM use JIT compilation that is performed at run time and only on frequently executed parts of apps. This change is designed to increase execution performance of apps on the new ART runtime.

For developers AOT compilation can cause frustration as every time an app is changed it has to be reinstalled on the target device. The AOT compilation process can take anything from a second to well over 10 seconds, the more code in an app the longer the device compilation process takes.

The good news is that it is possible to disable this AOT compilation for your debug builds, although this will cause your app to revert to being interpreted as it is executed. Disabling AOT compilation reduces the total time taken to deploy the app to the device and as a developer if you are modifying code and executing the app time after time, any increase in deployment speed is a welcome improvement. The tradeoff is a reduction in performance, although you are not likely to notice this performance hit for most types of applications. You should also consider that if you are writing an app that performs intensive computations then you may find saving a couple of seconds on installation for a compromised runtime performance is a counter-productive optimization.

Disabling ART ahead-of-time compilation

Disabling the AOT compilation is as simple as adding the application attribute android:vmSafeMode in your AndroidManifest.xml. Here is an example:

<manifest
 package="com.testing.sample.myapp"
 xmlns:android="http://schemas.android.com/apk/res/android">

 <application
 android:icon="@mipmap/ic_launcher"
 android:label="@string/app_name"
 android:vmSafeMode="true">
 ...

It is important to understand that this is not an attribute that we want to override on our release builds. It is possible to apply the attribute to debug builds only by creating a new …/app/src/debug/AndroidManifest.xml file. In this new manifest file you don’t need to replicate your existing manifest and can simply include the attribute you wish to add:

<manifest
 xmlns:android="http://schemas.android.com/apk/res/android"> 
 <application android:vmSafeMode="true" />
</manifest>

Note: It is only possible to disable AOT compilation if you have a targetSdkVersion of 22+ and you’re running a device using the ART runtime.

Execution timing of ART ahead-of-time compilation

Before you make this change you should first identify that AOT is causing a significant delay to your deployment times. For small apps it is likely that you will save less than a second of installation time and this optimization is probably not required.

The device process that performs the ahead-of-time compilation is called dex2oat and outputs logging information that allows us to see the execution time elapsed. Filter your logcat for items containing dex2oat and you will see the execution time for the process.

Here is example output with AOT compilation enabled:

07-03 10:19:02.650  21326-21326/? I/dex2oat﹕ /system/bin/dex2oat --zip-fd=6 --zip-location=/data/app/com.testing.sample.myapp/base.apk --oat-fd=7 --oat-location=/data/dalvik-cache/arm/data@app@com.testing.sample.myapp-2@base.apk@classes.dex --instruction-set=arm --instruction-set-features=div --runtime-arg -Xms64m --runtime-arg -Xmx512m --swap-fd=8
07-03 10:19:03.989  21326-21326/? I/dex2oat﹕ dex2oat took 3.338s (threads: 4) arena alloc=107KB java alloc=2MB native alloc=4MB free=3MB

Output with AOT compilation disabled:

07-03 10:17:33.934  19031-19031/? I/dex2oat﹕ /system/bin/dex2oat --zip-fd=6 --zip-location=/data/app/com.testing.sample.myapp-1/base.apk --oat-fd=7 --oat-location=/data/dalvik-cache/arm/data@app@com.testing.sample.myapp-1@base.apk@classes.dex --instruction-set=arm --instruction-set-features=div --runtime-arg -Xms64m --runtime-arg -Xmx512m --compiler-filter=interpret-only --swap-fd=8
07-03 10:17:34.693  19031-19031/? I/dex2oat﹕ dex2oat took 1.258ms (threads: 4) arena alloc=0B java alloc=2MB native alloc=502KB free=7MB

Checking if manifest includes vmSafeMode

The logcat output of the dex2oat process also lets you check that the vmSafeMode attribute has been correctly applied. When vmSafeMode is set to true this process will be executed with the following argument:

/system/bin/dex2oat ... --compiler-filter=interpret-only

If you are seeing this option when installing your release APK then it is likely you have included vmSafeMode in your apps main AndroidManifest.apk rather than the debug only manifest.

Another method I found for determining if vmSafeMode is set for a given APK is to use the aapt.exe tool. You will find the aapt tool in the build-tools folder of the Android SDK, which differs in location based on your chosen OS. You will probably have several different versions installed and will find it in a location such as:

.../Android/sdk/build-tools/22.0.1/aapt.exe

Execute the list command:

aapt list -a myapkfile.apk

This should produce output including:

Android manifest:
N: android=http://schemas.android.com/apk/res/android
  E: manifest (line=17)
    A: android:versionCode(0x0101021b)=(type 0x10)0x1
    A: android:versionName(0x0101021c)="1.0" (Raw: "1.0")
    A: package="com.testing.sample.myapp" (Raw: "com.testing.sample.myapp")
    A: platformBuildVersionCode=(type 0x10)0x16 (Raw: "22")
    A: platformBuildVersionName="5.1.1-1819727" (Raw: "5.1.1-1819727")
    E: uses-sdk (line=22)
      A: android:minSdkVersion(0x0101020c)=(type 0x10)0x15
      A: android:targetSdkVersion(0x01010270)=(type 0x10)0x16
    E: application (line=26)
      A: android:label(0x01010001)=@0x7f0b0001
      A: android:icon(0x01010002)=@0x7f030000
      A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff
      A: android:vmSafeMode(0x010102b8)=(type 0x12)0xffffffff

Side effects of disabling AOT compilation

Without ahead-of-time compilation your app is going to run slower, it probably won’t be noticeable, but the runtime will have more work to do during execution. I have heard some developers have had major performance problems, such as execution of intensive processing experiencing a 10x increase in execution time. So keep an eye out for any performance problems.

So far I am happy to report that I have not run into any execution issues or unexpected behavior while testing this optimization.

References

Android ART:

https://source.android.com/devices/tech/dalvik/

Android Manifest vmSafeMode attribute:

http://developer.android.com/guide/topics/manifest/application-element.html#vmSafeMode

1 Comment

Filed under Android SDK, Performance

Using Battery Historian to tame your battery draining app

IMPORTANT: Battery Historian 2.0 has been released. This article includes instructions that relate to the initial version of Battery Historian.

Battery Historian is an open source python script released by Google to profile battery related events on your Android Device. It was conceived as part of Google’s Project Volta that also saw the introduction of the new JobScheduler API to give developers some tools to develop apps that are good citizens when it comes to battery consumption.

It is useful for developers to investigate the impact their app is having on battery life by displaying a time line of events where the state of the most battery hungry sensors and features of Android are graphed.

Some typical use cases for Battery Historian would be:

  • To show a wake lock is being acquired and released in the correct manner
  • To verify the GPS is being turned off when your app no longer requires it
  • To ensure your app isn’t constantly activating the mobile radio and preventing Android from entering a sleeping state

Prerequisites

There are a few prerequisites that are required to use Battery Historian.

  • An Android device running Android 4.4 or later
  • Battery Historian script. Available from https://github.com/google/battery-historian
  • ADB. You will need the Android Debug Bridge installed to issue commands to your Android device
  • Python 2.x. Battery Historian is actually just a python script that processes the information in a battery stats dump from your device and builds a document to graphically represent the data. The python script that is Battery Historian is written for Python 2.x, and as such is not compatible with the latest Python 3.x. versions.

Tip: Using the python convert script 2to3.py does not correctly upgrade the python source. You need to either run the script with Python 2.x or convert and debug the script manually.

 

Generating a Battery Historian chart

It is just a quick couple of steps to setup and generate the battery stats chart using Battery Historian. You need to clear the existing bugreport data in the device, then perform any operations on your app, download the new data to your computer and run it through the python script to produce a lovely colorful representation of what has happened on your device.

Step 1: Prerequisites

Ensure you have checked all the items listed in the prerequisites section.

Step 2: Reset battery stats data on your device

All existing battery stats data needs to be removed from your device before we try to capture the data while your app is being used. To reset existing data make the following command line call:

adb shell dumpsys batterystats --reset

Step 3: Disconnect your device from your computer

Step 4: Test your app

Perform all the steps you want to do to test your app while the battery stats monitoring is taking place. If you are not tracking a specific bug then you can just try to exercise the areas of your app that may be triggering and stopping battery intensive operations.

If you are tracking a specific bug you will need to understanding what is happening under the hood of your app and which calls to which APIs are happening.

Step 5: Reconnect your device to your computer

Step 6: Generate bugreport

To generate the bugreport data and download it to your device you need to issue the following ADB command:

adb bugreport > batterystats.txt

This may take a couple of minutes to generate as the data file produced can be quite large.

Step 7: Generate the Battery Historian report

To generate the battery historian report from the bugreport output execute the historian.py script

python historian.py batterystats.txt > batteryreport.html
Battery historian command line arguments

Battery historian command line arguments

If you execute this script using python 3.x you will see an error such as SyntaxError: Missing parentheses in call to ‘print’.

Generating this report may produce an out of memory error due to the bugreport captured being too large, if this happens return to step 2 and start again with a smaller duration of testing your app.

Interpreting the Battery Historian chart

Open the html report generated to view your data. You will see a report similar to the image below:

Battery historian chart

Battery historian sample chart

Take a look at the period of time when your app was running, it will be shown in the row labelled top. This shows the topmost app running at any given time. Follow the list of rows down to see what is happening at the time your app was visible and running on your Android device. You should see the state of the screen, wake locks, GPS, WiFi, mobile data and other battery hogging events.

Remember that all running services could be affecting these readings as this data is not just in the domain of your app. Also remember that it may be that your battery drain issues may be caused during the period when your app is no longer topmost. You need to have a deep understanding of your services, what they are doing, when they are doing it, and how they are initiated to correctly interpret these charts.

Fixing common battery drain issues

Knowing what the common battery drain issues are and how to fix them will go a long to helping you understand why your app is producing the results in your Battery Historian chart. This is a vast topic in itself but a couple of the more common scenarios are:

  • Explicit wake locks not being managed correctly. Don’t use explicit wake locks unless it is absolutely necessary. It is almost always not necessary to use them directly to keep the screen awake. As an alternative use LayoutParams.FLAG_KEEP_SCREEN_ON and remove this flag as soon as you no longer need the screen to remain on.
  • Executing battery draining non-urgent tasks at inopportune times. Tasks that can be deferred until the device is on WiFi and/or charge can now be delayed using the simple and powerful JobScheduler API in Android 5.0+.
  • Constant Polling of web services keeping the mobile radio alive. Take a look at a using SyncAdapter to reduce server polling or use inexact alarm schedules for tasks.
  • Third party libraries such as Mobile Advertising or Analytics SDKs. It is easy to add libraries to your app but you must give consideration to the effect that library has on battery performance. Any library that transfers data to and from the internet is going to come with some costs. If it is a poor quality library it could cause major battery drain. Be careful what you include and profiling using Battery Historian after adding that any library is a smart move.

Conclusion

Battery Historian is not quite the powerful, easy to use battery performance tuning panacea that was trumpeted as part of Project Volta. It has very little documentation and isn’t great tracking down events over large time periods, for example on repeating alarm events, or events that only happen under very specific circumstances. However it is a useful tool that can help track issues such as ensuring wake locks, GPS and other energy sapping functionality are being handled correctly.

Battery Historian is another tool to add to your arsenal, even if just to give you some piece of mind that your app is being kind to your user’s battery. The best bet is as always understanding the fundamentals for battery performance turning and ensuring you are not violating best practice. Finally, don’t forget about one of the other pillars of Project Volta, the JobScheduler API.

Take a look at the Google I/O session below for more information about Battery Historian and Project Volta.

Leave a comment

Filed under Performance

Static Code Analysis using FindBugs (Android Studio)

There are many techniques, procedures and tools that can contribute to the quality of the source code your team produces.  One of those techniques is static code analysis and if you are using Android Studio you are probably using at least one tool for this already, Android Lint.  Lint is an very high quality tool that will not only give your Java source code the once over, but also your XML files, including layouts. It has deep knowledge about Android development patterns and it evolves with each SDK release, it should be the first stop for static code analysis in Android.  Every developer should pay attention when Android Lint waves that little yellow flag at you.

No matter how good Android Lint is, it is always worthwhile having a second and third opinion from different tools.  FindBugs is not an alternative to Android Lint, but it can be used as a companion. It is an open source tool that performs static analysis of your Java bytecode to warn of potential bugs, defects, security and performance issues.  It knows nothing about Android and is not a panacea for poorly designed apps, but it can provide a little nudge in the direction of potential issues in your software. As with all tools in this space it will never have a 100% strike rate, but it does allow the developer to take another look and think twice about a piece of code.

When an issue arises you will get a warning that is placed into one of nine different buckets. They are:

  • Dodgy code
  • Malicious code vulnerability
  • Bad practice
  • Correctness
  • Internationalization
  • Security
  • Performance
  • Multi-threaded correctness
  • Experimental

Each of these can be disabled if not required and you can also configure the confidence level at which issues will be reported.

Using FindBugs in the Android Studio IDE

Android Studio is built from the IntelliJ Java IDE which allows it to use IntelliJ plugins.  This is how you can integrate FindBugs into your Android Studio environment.

To open the IDE plugins go to the settings page (File > Settings…), and find the Plugins menu.  From here you can browse plugin repositories and do a search for FindBugs, or you can download the FindBugs plugin and install it manually from file.  When searching for the plugin you may find references to the QA Plug plugin.  This is another plugin that includes FindBugs and another way to get access to FindBugs from within your IDE and as a bonus it also includes other code analysis tools such as CheckStyle and PMD.

Executing FindBugs Analysis

Your code must have been built before analysis as FindBugs operates on the generated bytecode.  You can start the FindBugs analysis from within Android Studio by going to the Analyze menu, selecting FindBugs and then selecting the scope of the analysis to perform.  If you are using FindBugs through the QA Plug, you can access it from the Tools menu.

Exclude filters for Android

On first run of FindBugs you may be quite disappointed with the results.  With the default confidence level and no filters set FindBugs will report many issues that are part of the automatically generated android code to support functionality such as accessing resources.  For example, you may get many warnings similar to the these:

The class name R$dimen doesn't start with an upper case letter
The class name R$drawable doesn't start with an upper case letter

Take a look at the FindBugs manual for the specification of the filter format and details how you can create an exclude filter. For a filter that stops the warnings from Android auto generated code use the following XML:

<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
    <Match>
        <!-- ignore all issues in resource generation -->
        <Class name="~.*\.R\$.*"/>
    </Match>
    <Match>
        <Class name="~.*\.Manifest\$.*"/>
    </Match>
</FindBugsFilter>

Another issue you may hit are FindBugs warnings for JUnit tests. This can also be handled in the exclude filter file by adding the following:

<!-- ignore all bugs in test classes, except for those bugs specifically relating to JUnit tests -->
<Match>
    <Class name="~.*\.*Test" />
    <!-- test classes are suffixed by 'Test' -->
    <Not>
        <Bug code="IJU" /> <!-- 'IJU' is the code for bugs related to JUnit test code -->
    </Not>
  </Match>

This filter can be added to your Gradle build file for the automated builds discussed later, but for manually executed analysis you can add the filter in Android Studio. Go to settings dialog (File > Settings…) and select FindBugs-IDEA. Here you can configure the plugin settings and add the exclude filter list from an XML file.

findbugs_options

Run FindBugs again and you will have no one to blame except your team for the issues that are reported.

Automating FindBugs

Like other parts of the development process you can automate this static analysis. Gradle has support for the FindBugs plugin. To create a Gradle task you can add the following to the gradle.build in your project:

apply plugin: 'findbugs'

task findbugs(type: FindBugs) {
    ignoreFailures = false
    effort = "default"
    reportLevel = "medium"
    excludeFilter = new File("${project.rootDir}/findbugs/findbugs-filter.xml")
    classes = files("${project.rootDir}/app/build/intermediates/classes")
    source = fileTree('src/main/java/')
    classpath = files()
    reports {
        xml.enabled = true
        html.enabled = true
        xml {
            destination "$project.buildDir/findbugs/findbugs-output.xml"
        }
        html {
            destination "$project.buildDir/findbugs/findbugs-output.html"
        }
    }
}

Visit https://gradle.org/docs/current/dsl/org.gradle.api.plugins.quality.FindBugs.html for more information about configuring FindBugs in Gradle.

Conclusion

If your team doesn’t enforce clean Android Lint builds for your projects then stop looking at other tools now.  It should be your first line of defence for code quality standards.  If your lint pane is boringly empty then maybe it is time for another tool to give its opinion.  This is not a must have tool for every Android developer, but it does have its value.  It may only need to pick up a lazy security flaw once to make the configuration and automation time worthwhile.

References

FindBugs home http://findbugs.sourceforge.net/

FindBugs Intellij Plugin https://plugins.jetbrains.com/plugin/3847?pr=idea

Gradle FindBugs Plugin https://gradle.org/docs/current/userguide/findbugs_plugin.html

5 Comments

Filed under Android SDK, Android Studio, Automation, Gradle, Performance, Security, Tools