Savitar 2.0: Incremental Android Compilation Solution – Design, Features, and Performance
Savitar 2.0 is an incremental Android compilation system that combines a GUI plugin, a dynamically updatable Runner, a Gradle project‑support plugin, and external tools to compile only changed code, achieving 15‑second builds with over 92% success, saving more than 535 hours, while adding one‑click, MultiDex, and Kotlin internal support and addressing dependency issues, with plans for CLI, offline mode, and open‑source release.
Android compilation speed has long been a hot topic in the industry. After the 2019 Youzan Mobile Salon, the article "Youzan Android Incremental Compilation Roadmap – Savitar" introduced the Savitar solution for compilation acceleration. In 2020, Savitar was refined into version 2.0.
1. Design of Savitar
Savitar consists of four main parts:
GUI plugin : All capabilities are integrated into a plugin button, including automatic Runner updates, various checks, and compilation script execution.
Runner : A JAR containing the core logic for fetching modifications, generating scripts, and executing compilation. It can be dynamically updated and used in CLI environments.
Project support : A Gradle plugin that obtains project information and injects product-loading code with zero intrusion.
External dependencies : Tools required for the whole process, such as watchman for file monitoring, javac, kotlinc, etc.
The overall workflow is based on hot‑fix technology: changed code is compiled into patches, which are then loaded by the app to achieve faster builds.
2. Usage Data
Since June 2019, Savitar has been used over 18,000 times (averaging >30 times per day), saving a substantial amount of compilation time. The key statistics are:
Metric
Value
Success Rate
92.4%
Average Success Time
13.63 s
Average Usage Time
13.74 s
Cumulative Saved Time*
535+ h
*Based on the retail Android project, where the average full compile‑install time before acceleration was 120 s.
With incremental compilation, build time no longer scales with project size; it correlates only with the amount of code changed. Typical incremental builds complete within 15 s, including loading and running.
3. New Features in Savitar 2.0
3.1 One‑Click Support
In version 1.0, developers had to run the standard Android Studio (AS) build once before using Savitar. Savitar 2.0 removes this requirement: clicking the Savitar run button automatically decides whether to perform accelerated compilation or fall back to the normal AS build, supporting flavor switching.
3.2 MultiDex Support
MultiDex issues arise when the number of method references exceeds 64 K, causing compilation failures such as:
trouble writing output: Too many field references to fit in one dex file: 86151; max is 65536.The dx tool can handle MultiDex with the following parameters:
dx ... --min-sdk-version=xx --multi-dex --main-dex-list={path_to_main_dex_list.txt}The critical argument is path_to_main_dex_list.txt , which specifies classes to include in the main dex. For SDK ≥ 5.0, an empty list suffices because Savitar’s output is loaded dynamically.
3.3 Kotlin internal Keyword Support
Kotlin’s internal modifier makes members visible within the same module. In incremental builds, separate compilation can break this visibility, producing errors such as:
// B calls A's internal method sayHello()
error: cannot access 'sayHello': it is internal in 'A'The solution is to use the compiler option -Xfriend-paths to expose internals of friend modules:
value = "-Xfriend-paths"
valueDescription = "
"
description = "Paths to output directories for friend modules (whose internals should be visible)"By supplying the appropriate friend paths, internal members become accessible during incremental compilation.
4. Issues in Version 1.0 and Their Solutions
Version 1.0 focused on drastically reducing compile time by only recompiling modified files. This introduced two main problems:
Class dependency compilation : Changing a public API (e.g., method signature) without recompiling dependent classes can cause runtime NoSuchMethodException . Example:
// Original method
public void sayHello()
// Modified method
public String sayHello()Solution: Analyze file changes and locate direct dependents for recompilation.
File‑change analysis determines whether a modification requires dependent recompilation (e.g., public constant changes do, internal logic changes do not). Direct dependent detection is performed using ASM bytecode analysis during a full build, recording class metadata in ClassInfo objects:
public class ClassInfo {
public int access;
public String name;
public String superName;
public Set
interfaces;
public Set
importClass;
public List
fields;
public List
methods;
// ...
}After a change, the new ClassInfo is compared with the old one to identify affected dependents, which are then recompiled.
The analysis function signature is:
Set
analyzerChange(src, changed, deleted)Deleted files must also have their generated .class files removed to avoid false‑positive compilation successes.
5. Future Plans
Implement CLI integration for cross‑platform use.
Improve scenario compatibility and acceleration stability.
Add offline mode support.
Enhance automated testing for higher quality.
Prepare for open‑source release.
Conclusion
Savitar has evolved from an idea to a stable 2.0 product, now used in retail and micro‑mall teams. Ongoing work focuses on broader adoption, stability, and open‑source preparation, with a continued commitment to improving development efficiency.
Youzan Coder
Official Youzan tech channel, delivering technical insights and occasional daily updates from the Youzan tech team.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.