Performance Problems in Libraries and SDKs

It’s difficult to imagine modern android apps that don’t implement some external libraries or SDKs. After all, most apps have to leverage some combination of network image loading, crash tracking, advertisement, or analytics libraries and SDKs. It makes sense - developers shouldn’t have to reinvent the wheel (several wheels, actually) every time they want to create an application. However, it turns out that many libraries and SDKs cause major startup delays and other performance issues. These delays can be hard to track down because developers typically have little to no knowledge of the library or SDK’s implementation.

Common Performance Problems in Libraries and SDKs

There are a couple of common problems that we’re constantly telling developers to look out for. It turns out that some of these problems persist in libraries and SDKs, which means it’s all the more important to be vigilant when it comes to using and understanding third party code.

  1. ClassLoader.getResourceAsStream is the most popular performance problem we see in libraries and SDKs. If a library or SDK is provided in JAR instead of AAR) format, ClassLoader.getResourceAsStream is the only way to load resources. Developers use JAR instead of AAR for a variety of reasons, the main one being that they want to distribute one package for both Java and Android.

  2. Hung methods in the main thread are another common problem found in libraries and SDKs. Libraries and SDKs often need to be initialized, so it is convenient for their developers to provide an initialization method that does a lot of the heavy lifting. For instance, an advertisement SDK may acquire the list of installed apps to avoid showing you an ad for an app you’ve already installed. An A/B testing SDK may load feature toggles from a remote server. If the developers are not careful and do this heavy work in the main thread, your app will suffer.

  3. Reflection is another common problem. Library and SDK developers often use reflection to make it easier for other developers to use their library or SDK. For instance, an app developer can create a REST client or a DAO object just by adding a few Java annotations. Unfortunately, when not used carefully, reflection can introduce huge overhead to any Android app.

Libraries and SDKs - Real-Word Examples With Top Apps

Performance problems are pervasive in libraries and SDKs. Here we describe the problems in the following 11 popular libraries and SDKs and the apps affected:

  1. Tapjoy
  2. Startapp
  3. Heyzap
  4. Yume
  5. Joda-Time
  6. OrmLite
  7. Activeandroid
  8. Jersey
  9. AWS Android SDK
  10. SLF4J
  11. Logback

Tapjoy  

Tapjoy suffers from the ClassLoader.getResourceAsStream problem. Here’s an example (textPlus 5.9.9):

tapjoy
1729ms for call com.tapjoy.TapjoyConnect.requestTapjoyConnect

Other affected apps include Bible 5.11.3, Akinator FREE 4.04, AlarmMon 6.1.8, Yokee 2.0.205, Keek 5.0.6, SimSimi 6.6.1.3, InstaFisheye 2.6.8, Jaumo 3.5.3, My Diet Coach 4.2.8, Talking Angela 2.4, and ZombieBooth 4.32.

Startapp  

Startapp suffers from both hung methods in the main thread and ClassLoader.getResource problems. Here’s an example (Lovely Photo Frames 4.0.2):

Startapp
698ms for call com.startapp.android.publish.StartAppAd.init

Other affected apps include Flash Alerts 2.2 and Voice Changer 29

Heyzap  

Heyzap also struggles with properly managing the main thread. Here’s an example (from Mackolik 3.3.6) in which Heyzap makes 3 calls of packageManager.getInstalledPackages(), which takes ~236ms:

Heyzap
241ms for call com.heyzap.sdk.ads.HeyzapAds.start

Yume  

Yume, like many of the SDKs already mentioned, perpetuates the ClassLoader.getResource problem. Here’s an example (Talking James Squirrel 3.26.0):

Yume
2152ms for call com.kauf.marketing.YuMe.init

Other affected apps include: Talking Babsy Baby: Baby Games 3.30.0

Joda-Time  

ClassLoader.getResource just wont stop cropping up. It shows up again in the Joda-Time library, as you can see here in this example (Yahoo Fantasy Sports 6.4.0):

Joda-Time
2259ms for call org.joda.time.DateTimeZone static initializer

Other affected apps include: TuneIn Radio - Radio & Music 13.6.1, My Pregnancy Today Tracker 1.17.1, LiveScore 2.1.4, Vevo - Watch HD Music Videos 2.1.8, Muslim Pro: Prayer Times Quran 7.0.6, and Timehop 3.1.1

OrmLite  

Ormlite, too, suffers from calls to ClassLoader.getResource. In this example (from Anghami 1.8.58), the call takes nearly an entire second:

ormlite
830ms for call com.j256.ormlite.android.apptools.OpenHelperManager.getHelper

Other affected apps include: Booking.com Hotel Reservations 8.4.2, Nike+ Running 1.7.3, Run with Map My Run 3.10.0, OLX Brasil - Comprar e Vender 10.1.3.28, and Kaave 1.8.0

Activeandroid  

ActiveAndroid’s reflection usage is a concern, as it can cause some serious app slowdown, as seen here in Myntra 2.4.0:

activeandroid
1421ms for call com.activeandroid.ActiveAndroid.initialize

Other affected apps include: Scribd - A World of Books 3.11

Jersey  

Jersey’s use of reflection is also pretty detrimental to app performance. It slows down Photobucket 3.3.6 (and a slew of other apps) significantly:

com.photobucket.android Iricle Graph
660ms for call com.photobucket.api.client.jersey.UserClient constructor

AWS Android SDK  

Yet again, ClassLoader.getResource finds its way into another SDK. AWS Android’s use of ClassLoader.getResource is exceptionally slow here in Moovit 4.2.7.137:

AWS
2371ms for call com.amazonaws.auth.CognitoCachingCredentialsProvider static initializer

SLF4J  

Unsurprisingly, SLF4J also suffers from ClassLoader.getResource:

slf4j
678ms for call org.slf4j.LoggerFactory.getLogger

Logback  

What’s wrong with Logback? You guessed it - ClassLoader.getResource. See how it affects Audible 1.9.0 here:

logback
1561ms for call org.slf4j.LoggerFactory.getLogger

Other affected apps include: Wiper 2.5, Marco Polo: PTT Video Chat 1.2.19, and Talkatone: FREE Texts & Calls 4.3

Recommendation: Profile the libraries and SDKs you use to avoid surprises