Making Your Android App Crash

As the title points out, this post will help you make your application crash and detect if there are any performance issues in it.

Julián Falcionelli
Major League
Published in
8 min readApr 25, 2018

--

The Android ecosystem is huge. There are lots of Android versions to test, a variety of screen sizes, and different scenarios to move in.

Great Changes Are Ahead

The good news for developers (in my opinion) is that Google is planning to be more restrictive regarding target API Levels supported by our apps. In short:

  • In August 2018 new apps will be required to target API level 26 (Android 8.0) or higher.
  • In November 2018 updates to existing apps will be required to target API level 26 or higher.
  • From 2019 and onward each year the target SdkVersion requirement will advance. Within one year following each Android dessert release, new apps and app updates will need to target the corresponding API level or higher.

More info: https://android-developers.googleblog.com/2017/12/improving-app-security-and-performance.html

My minimum SDK version recommend for now is 21 — NOT LESS since lot of functionalities are not supported on pre 21, and the development process will be affected and always try to target the max SDK version available, to be able to use latest SDK features and prevent problems at the moment to publish your application in the PlayStore.

Having this in mind, during your development process you need to test your app depending on your min API LVL and Target SDK version. It would be great if you can try your app on different Android distributions like MIUI (for Xiaomi), OxigenOS, Huawei EMUI, CyanogenMod, LineageOS, etc.

If you are writing Instrumentation Tests you can use Firebase Test Labs to easily test your application in different devices.

Testing Your App's Life

An easy way to ensure that all Life Cycle's methods of our Activities/Fragments are being executed is forcing them to re-instantiate by enabling the Settings > System > Developer options > Don’t keep activities option.

This will help you test the complete Life Cycle of our Activities, since sometimes it is difficult to execute some Life Cycle events like OnSavedInstance.

Forcing Network Latencies

In order to do this you need to go to an elevator and try the application inside it

Just joking. The Android Emulator allows us to change the Network Type and the Signal Strength.

If you don't want to use it, because you want to test your app in real devices, there are a few applications that can be very useful like Charles which is very easy to use.

When using Charles, you can change the connectivity settings in Proxy > Throttle Settings… to simulate different kinds of connections, latencies and more.

Simulating Low Memory

You need to test your application in extreme situations. In this case, when the devices are low on resources.

The best way to test this is by creating a Virtual Device with a Custom Hardware Profile setting low RAM values.

If you know that you are able to manually release resources from your application, in those extreme situations you can register your Context to be notified about changes in the memory status by calling the registerComponentCallbacks and implementing the ComponentCallbacks2 interface. This makes sense only when you know that your application is effectively performing tasks that require a lot of processing.

To test those callbacks you can trigger the onTrimMemory callbacks by running the following adb command:

$ adb shell am send-trim-memory <packagename> <mode>

Mode can be HIDDEN|RUNNING_MODERATE|BACKGROUND|RUNNING_LOW|MODERATE|RUNNING_CRITICAL|COMPLETE.

e.x.

$ adb shell am send-trim-memory com.example.myapp RUNNING_CRITICAL

Detecting Long Operations in the UI Thread

If you want to be notified when long operations are made on the UI Thread enable the Settings > System > Developer options > Strict mode enabled option.

By doing this, every time a long operation is performed on the UI Thread you will get a red blink border alert. Don’t panic if you get blinks each time a new screen is rendered, just check it and pay more attention on blinks that happen repeatedly in a short time, maybe you are doing unnecessary view’s refreshing, not using ViewHolders on RecyclerViews, rendering big images or doing I/O events on the UI Thread.

Performing Random UI Interactions

There is a useful and funny adb command that allows us to quickly perform X number of random events like user taps, enable/disable Wi-Fi/ Bluetooth / Airplane Mode, move your App to Background, resume it and so on.

To do this run:

$ adb shell monkey [options] <event-count>

e.g.

$ adb shell monkey -p com.example.myapp -v 10000

Running this will start your application and perform 10000 random events.

Running Mockey on the PlayStore App — To see the end check https://vimeo.com/266355246

Detecting Memory Leaks

In order to do this, you can use this LeakCanary which detects Memory Leaks and lists them into a separated app. You will able to check the origin of those leaks.

https://github.com/square/leakcanary/blob/master/assets/screenshot.png

Also you can use the Android Profiler to detect memory leaks by looking the Memory Graph and checking if it constantly increases as you use the app and never goes down.

https://developer.android.com/studio/profile/android-profiler.html

The most common memory leaks are related to static references of the Context on singleton instances, no-longer valid references on background threads and more.

Detecting HTTP Errors with Chuck

Chuck is a great library that intercepts all HTTP requests that our application makes and helps you analyze them through a friendly UI instead of logging all of your networking information in the Logcat.

https://github.com/jgilfelt/chuck/blob/master/assets/chuck.gif

Totally recommended, takes 2 lines of code to implement it and is really useful. It doesn’t just help the Android Team but also the QA and backend teams, so they can quickly check how the backend is working without installing Android stuff in their environment.

Detecting Wakelocks

Wakelocks are power-managing software mechanisms, which make sure that your Android device doesn’t go into deep sleep (which is the state that you should strive for), because a given app needs to use your system resources. That’s a pretty substantial prerequisite for anomalous battery drain.

How can apps cause this? For example, those who persistently request information from the web (the so-called “polling” for new events) cause subsequent wake-locks.

If you need to detect those undesirable wake-locks, you can use to use the BatteryStats tool. While using it, you can generate a history of your device during an X period of time with the information of all the processes that ran there.

To use it follow these steps:

  1. Connect your device with the application installed.
  2. Make sure that your device is connected. To do this, you can run adb devices and verify if your device is displayed on the devices list.
  3. You can quickly check for the existing Wakelocks on your devices by running:
$ adb shell dumpsys power | grep WAKE_LOCK

4. Run the following command to enable all history information.

$ adb shell dumpsys batterystats --enable full-wake-history

5. Run the following command to reset and clear old battery history stats and the report will be generated from scratch after you disconnect your device (and the battery starts to drain).

$ adb shell dumpsys batterystats —-reset

6. Finally, in order to get the Battery History during the time the devices was disconnected run:

$ adb bugreport

After the command finish to run a zip file will be generated in the root folder of your project.

Make sure that during that time you’ve triggered all services that your application has and keep your device disconnected for at least 10 minutes.

Now upload the generated file with the BatteryStats tool. You can download it as the Official Documentation explains or you can just use https://bathist.ef.lc/ which has hosted that tool and works great.

Here is one Battery Graph history that I’ve generated:

There is a lot of information there but for now just focus on the Long Wakelocks section. As we can see, during the complete period (like 10 minutes) there were a few Wakelocks coming from my application, com.example.myapp, more specifically they comes from the DownloadManagerJobService and DownloadNotificationsJobService.

Since Oreo, IntentServices aren’t allowed to be executed in background, only in the foreground, developers are forced to use other Android components to deal with long background operations. One of the reasons for this restriction was that developers were using indefinite services that were excessively causing these famous Wakelocks and therefore, undesired battery drains.

One alternative is using JobSchedulers. Actually, they are very easy to use but they are not Wakelock-Free, since you can use them and never call the jobFinished method causing long periods of execution and therefore Wakelocks.

How can we fix this? Just by making sure that we call the jobFinished to release the resources that our service is using, avoiding infinite polling functionalities like querying indefinitely our database.

Last But Not Least

After going through these processes, you will able to determine if your app is ready to be published and the min requirements that Android devices need to have in order to run your application. This is very important to prevent bad reviews in the PlayStore. So, if your App is working great on most devices but there is a specific device model which has some issues running your app, I recommend you to disable that specific device from the PlayStore Console.

Also, you can define exclusion rules according to the minimum RAM required and Chipset Model from the PlayStore Console. So, if your app has high resource requirements, for example, something with AR, you can use these rules to block installs on devices with low-old resources and prevent them from getting bad reviews for bad performance.

Google Play Console — Exclusion Rules

If you have any tips or advice that can be useful to check our application’s quality please comment here. Sometimes obvious things for us are not that obvious for others!

And finally, I want to thank all the creators and contributors of all of these great tools that I mention that help us develop efficient apps.

--

--