Loading page...Загружаем страницу...正在加载页面...
AtlasRepo

Cold start in a 4.5 MB FOSS Android app: measure it with adb, then fix what's actually slow

Description and use

The workflow demonstrates that measuring cold start accurately, inspecting the artifact, and targeting real runtime work yields measurable improvements. The author’s fixes reduced the 8.4 MB dex size, eliminated unnecessary IPC, and added AOT compilation, all contributing to a faster cold start.

Problem

Cold start times are hard to improve without measurement; the author demonstrates how to measure and identify real bottlenecks in a small Android app.

Outcome

The workflow demonstrates that measuring cold start accurately, inspecting the artifact, and targeting real runtime work yields measurable improvements. The author’s fixes reduced the 8.4 MB dex size, eliminated unnecessary IPC, and added AOT compilation, all contributing to a faster cold start.

Workflow

  • Force a cold start with adb: adb shell am force-stop dev.weavrik.wifiwarn && adb shell am start -W -n dev.weavrik.wifiwarn/.MainActivity and record the timing output.
  • Run the command ~10 times, discard the first run, and take the median of the remaining runs.
  • Unzip the APK and inspect classes.dex size with unzip -l wifiwarn-v1.0.apk | grep -E "classes|\.dex|resources\.arsc" to confirm the artifact weight.
  • Examine the app’s onCreate and onResume code to identify synchronous work on the main thread.
  • Apply fixes in impact order: (a) enable R8 and resource shrinking in build.gradle, (b) add a Baseline Profile via androidx.profileinstaller, (c) cache or remove duplicate IPC calls and guard migration logic, (d) avoid adding an Application subclass.
  • Re‑measure after each change to verify median improvement, reverting any change that does not improve the median.

Evidence

Force a cold start: adb shell am force-stop dev.weavrik.wifiwarn adb shell am start -W -n dev.weavrik.wifiwarn/.MainActivity

Source

unzip -l wifiwarn-v1.0.apk | grep -E "classes|\.dex|resources\.arsc" 8418928 classes.dex 982700 resources.arsc

Source

Config.migrateLegacy() reads SharedPreferences and, on the legacy path, parses and rewrites a JSON blob — on the main thread, before the first frame.

Source

getEnabledAccessibilityServiceList() and Settings.canDrawOverlays() are binder calls into system_server, and canDrawOverlays() is invoked twice per resume.

Source

(a) Turn on R8. The biggest single lever for a FOSS app that vendors Material.

Source

(b) Add a Baseline Profile. Without one, ART starts cold code in the interpreter and JITs it while your first screen draws.

Source

(c) Get IPC off the critical path. Cache canDrawOverlays() once in onCreate, delete the duplicate call inside refreshSwitches()...

Source

(d) Don't add an Application subclass casually. wifiwarn has none — good.

Source

  • Record date: 2026-11-02T05:14:28.969Z