Adapting the QQ Music/Karaoke Android App to Arm64 Architecture
The QQ Music/Karaoke team migrated their Android app from 32‑bit to Arm64‑v8a by reconfiguring Gradle builds, recompiling or replacing over 120 native libraries, extending the dynamic‑resource loader for ABI selection, implementing ABI‑aware update channels, and fixing issues such as library path limits, I/O reliability, camera latency, and WebView cache corruption, completing the transition in early 2021.
In recent years, the performance bottleneck of 32‑bit applications has become increasingly evident as computer hardware evolves. Adapting to 64‑bit is now an industry‑wide trend, affecting both large commercial software and mobile apps. On Android, most devices use ARM architecture, and the latest 64‑bit variant is Arm64‑v8a. The QQ Music/Karaoke (全民K歌) team therefore embarked on a comprehensive migration to Arm64.
Background
ARM (Advanced RISC Machine) is a RISC processor family widely used in embedded systems due to its low power consumption and high performance. Since the introduction of ARMv8 in 2011, the architecture supports 64‑bit instruction sets, larger address space (up to 48‑bit virtual addresses), and modern memory models aligned with C++11/C1x standards. A 32‑bit process can address at most 4 GB, whereas a 64‑bit process can address up to 1 TB, offering substantial performance gains.
Why QQ Music/Karaoke needs Arm64
Improved memory usage efficiency – many native crashes were caused by memory limits of 32‑bit builds.
Better experience on high‑end devices that already run 64‑bit hardware.
Early accumulation of 64‑bit technical expertise, especially as Android 12+ will drop 32‑bit support.
Increased promotion advantage – Google Play requires Arm64 compliance for new releases.
Data shows that over 90 % of active user devices already support Arm64‑v8a.
Adaptation Plan
The migration consists of five major tasks:
Engineering build configuration transformation.
SO library updates.
Extension of the dynamic‑resource loading framework.
Application update strategy.
Issue tracking and mitigation.
1. Build Configuration Transformation
Using Android Studio, the splits block in build.gradle is configured to include the desired ABIs. Example:
splits {
abi {
enable true
reset()
include 'armeabi-v7a', 'x86', 'arm64-v8a'
}
}To produce separate 32‑bit and 64‑bit APKs, an environment variable COMPILE32 is read and the appropriate ABI is selected:
splits {
def arc = "arm64-v8a"
// Determine whether to compile a 32‑bit package
boolean compile32 = Boolean.valueOf(System.getenv("COMPILE32"))
if (compile32) { arc = "armeabi-v7a" }
abi {
enable true
reset()
include arc
universalApk false
}
}A custom BuildConfig field COMPILE32 is added so the runtime can distinguish the package type:
boolean compile32 = Boolean.valueOf(System.getenv("COMPILE32"))
buildConfigField("boolean", "COMPILE32", "$compile32")Business code can then branch on BuildConfig.COMPILE32 to load the correct resources.
2. SO Library Update
More than 120 native .so files (both self‑developed and third‑party SDKs) were audited. Self‑developed modules were re‑compiled with abiFilters 'armeabi-v7a', 'arm64-v8a' in the defaultConfig block:
defaultConfig {
applicationId "com.test.mymodule"
minSdkVersion 19
targetSdkVersion 30
versionCode 1
versionName "1.0"
externalNativeBuild {
cmake {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
}Third‑party SDKs were either replaced with 64‑bit versions or, when unavailable, kept as 32‑bit only with appropriate testing.
3. Dynamic‑Resource Loading Framework Extension
The original DynamicResLoader loaded SOs lazily to reduce APK size. To support multiple ABIs, the framework was modified to register resources per architecture and to inject a unified directory into the system’s native library search path:
// Add resource directory to system path if it contains SO or Dex
if (isResourcesContainSoOrDex(type)) {
if (!extSoDirs.contains(wokingDir.getAbsolutePath())) {
DexUtils.installDexAndSo(mContext, this.getClass().getClassLoader(), null, wokingDir);
extSoDirs.add(wokingDir.getAbsolutePath());
}
}The resource configuration file now supports entries like:
resource_list = [
MODULE_A: ["aaa","aaa.zip", "http://xxxx", 1,"armeabi-v7a"],
MODULE_A_64: ["aaa","aaa.zip", "http://xxxxxxx", 1,"arm64-v8a"],
]During loading, the framework selects the best‑matching ABI based on the device’s supported list.
4. Application Update Strategy
Two update channels are used:
In‑app update – the client sends the device’s ABI list to the server, which returns the appropriate APK URL.
Store update – major Chinese app stores (e.g., Xiaomi, Huawei) already support ABI‑aware delivery.
The device’s ABI list is obtained via:
/**
* Get current supported ABI list
*/
public static String getSupportAbiList() {
String[] abiList = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
abiList = Build.SUPPORTED_ABIS;
} else {
abiList = new String[]{Build.CPU_ABI, Build.CPU_ABI2};
}
StringBuilder s = new StringBuilder();
int size = abiList.length;
if (size > 0) {
for (int i = 0; i < size; i++) {
s.append(abiList[i]);
if (i != size - 1) { s.append(","); }
}
}
LogUtil.i(TAG,"ca:" + s.toString());
return s.toString();
}For stores that do not yet support ABI‑aware delivery, the team coordinates separate 32‑bit and 64‑bit releases.
5. Pitfalls and Resolutions
Native library search path overflow on Android 5.x – the original framework added a directory per module, exceeding the fixed‑size native library array. The fix consolidates all 64‑bit libraries into a single directory before injection.
IO reliability issues – download‑to‑disk failures caused stale resources. The solution stores each resource in a unique directory prefixed with its MD5 hash, preventing overwrite conflicts.
Increased camera capture latency on 64‑bit – texture‑to‑buffer conversion became slower on some GPUs. Switching to PBO (Pixel Buffer Object) reads for OpenGL 3+ devices reduced latency, with a fallback to the original method on older hardware.
WebView cache corruption after ABI switch – mismatched GPU cache caused crashes. The app now clears WebView shared preferences and cache directories when a change in ABI is detected.
Summary
The migration required roughly 30 % of the total effort for engineering configuration and SO updates; the remaining 70 % involved device‑specific compatibility testing, gray‑scale rollout, and issue resolution. The work started in Q3 2020 and was completed by Q1 2021, officially bringing QQ Music/Karaoke into the 64‑bit era.
Note: The document concludes with a recruitment notice for Android/iOS developers, which is not part of the technical content.
Tencent Music Tech Team
Public account of Tencent Music's development team, focusing on technology sharing and communication.
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.