For last few weeks I’ve been working for a client and one of the major issue that we were facing was the Slow Cold Start or Slow TTID (Time to initial Display). You can see the Slow Cold Start Metric for your app in Play Console’s Android Vitals section.
Definition taken directly from the Play Console:
Slow Cold Start – The percentage of daily sessions in which users experienced at least one cold start-up time of more than five seconds. This is measured as the time taken from when a user launches your app, to when the first frames appear on the screen. A daily session refers to a day during which your app was used.
Before we start looking at the issue let’s revise some of the history. Before Android 12 there was no unified way of implementing Splash screen. Developers used to have dedicated activity/fragment with custom theme having background, or custom theme having background applied to the application or in worst case just an activity/fragment without a theme having background (this leads to blank screen being visible before the app draws it’s first frame).
But with Android 12 Google introduced Splash Screen API which provided a uniform way of implementing the Splash Screen so every single app on your device shows similar experience on launching the app. Also there is no way for you to avoid this migration as starting Android 12, the system always applies the new Splash Screen for all apps.
If you look at the migration part in the official docs it seems like a very simple process but there is a catch which is not visible unless you read the docs very carefully or you understand the internal implementation.
In our case before migrating to this Splash Screen API our Slow Cold Start metric was very similar to our peers (as reported by Play Console). But after migrating to the Splash Screen API our Slow Cold Start metric spiked up by a huge margin 😢.
NOTE: Based on your selection of the app category, Play Console shows you the relative comparison of most of the metrics like ANR, App Size & App Startup issues with your peers in the Android Vitals section.
After we saw the results on the Play Console there was a Panic among the developers as even during the release testing we didn’t found any issues. So to verify the metric we took all the devices we had in our inventory and started measuring the time taken to render the Home Screen, but even after that we didn’t see any problem and that is where we were wrong.
What we were measuring was the TTFD (Time to full Display) and not the TTID. What Play Console reports is TTID, which is captured by the Android OS automatically. For an example Android OS prints below log for actual Play Store app.
Displayed com.android.vending/.AssetBrowserActivity: +1s39ms
So we also started looking at the logs for our app on different devices and verified that the metrics reported by Play console were correct. This made us think that we must have done some mistake in our migration to Splash Screen API and the metrics got derailed.
After this we re-looked at all the steps mentioned on the official documentation multiple times to see if we missed something but we found no issue in our implementation. Then we started looking at the docs even more carefully and we caught a glimpse of a very important clue i.e. A
SplashScreen is a Window and therefore occludes an Activity.
The clue hinting that SplashScreen uses Window directly
This helped us in connecting the dots as for TTID the app has to draw it’s first frame but since the Splash Screen API directly uses a Window the first frame draw is essentially delayed till some View rendering happens using Activity, Fragment or Dialog.
To give you some background, earlier we had a dedicated SplashActivity where we were rendering our brand logo and tagline which ensured that the first frame gets rendered on the SplashActivity itself. So even if we do some network call or some other setup before User reaches HomeActivity the time TTID time is very short because SplashActivity has started rendering view via setContentView(). But after the migration our first frame rendering was happening on the HomeActivity, which becomes visible after the SplashActivity finishes its job, which made TTID time a lot longer. This was happening because we were not calling setContentView() on SplashActivity anymore as the SplashScreen API already renders the content directly on the window.
We also checked the API implementation to know how exactly it works and we found that first of all it has 2 implementations, one fore API 31+ (Android 12+) and other for the lower Android APIs.
Another very important implementation detail is the setKeepOnScreenCondition() which acts as a boundary toggle between the SplashScreen and your own UI rendering via Activity, Fragment or Dialog, as this blocks UI rendering as long as the condition predicate evaluates to true.
Finally having the knowledge of the internals of SplashScreen API we refactored our code such that our TTID metric reverted back to previous value 🙂.
Reference Material Links and Credits:
- Improving App Startup: Facebook App – https://android-developers.googleblog.com/2021/11/improving-app-startup-facebook-app.html
- Official Documentation of Splash Screen API – https://developer.android.com/develop/ui/views/launch/splash-screen
- Splash Screen API Migration Guide – https://developer.android.com/develop/ui/views/launch/splash-screen/migrate
Hope you liked reading the article. Please feel free to reach me on Twitter. Thank You!
This article was originally published on proandroiddev.com