Baseline Profile
目录
Baseline Profile
Baseline Profile 可以用于 Andorid 8.0 以上系统的性能优化
原理简单来说还是 dex2oat 那一套东西,但是我们可以自己收集热点代码,生成对应的二进制文件,加速执行
想要使用,查阅 https://developer.android.com/topic/performance/baselineprofiles/overview 即可
疑问
按照上述官方问题的操作以后,我们会得到一个 txt 文件,里面记录了某个我们自己定义的场景的方法,且编译后在 asserts 目录下会多一个 dexopt 目录,内部有两份文件(profile installer 就是将这两份文件拷贝到系统目录下)
但是,这明显是有一个问题的,那就是混淆问题!
官方文档特地强调,在生成 txt 文件时,一定要关闭混淆
那么问题来了,既然关闭了混淆,热点方法全是原始方法名,而 release 包在运行时,肯定是混淆后的名字,那又是如何对应到一起的呢?
源码
靠猜也知道,肯定是编译过程中,生成 profile 文件时做了一些特殊处理,但是没有实锤肯定是不安心的
终于,在 AGP 源码中,找到了 CompileArtProfileTask
override fun run() {
val diagnostics = Diagnostics {
error -> throw RuntimeException("Error parsing baseline-prof.txt : $error")
}
val humanReadableProfile = HumanReadableProfile(
parameters.mergedArtProfile.get().asFile,
diagnostics
) ?: throw RuntimeException(
"Merged ${SdkConstants.FN_ART_PROFILE} cannot be parsed successfully."
)
val supplier = DexFileNameSupplier()
val artProfile = ArtProfile(
humanReadableProfile,
if (parameters.obfuscationMappingFile.isPresent) {
ObfuscationMap(parameters.obfuscationMappingFile.get().asFile)
} else {
ObfuscationMap.Empty
},
//need to rename dex files with sequential numbers the same way [DexIncrementalRenameManager] does
parameters.dexFolders.asFileTree.files.sortedWith(DexFileComparator()).map {
DexFile(it.inputStream(), supplier.get())
}
)
// the P compiler is always used, the server side will transcode if necessary.
parameters.binaryArtProfileOutputFile.get().asFile.outputStream().use {
artProfile.save(it, ArtProfileSerializer.V0_1_0_P)
}
// create the metadata for N and above.
parameters.binaryArtProfileMetadataOutputFile.get().asFile.outputStream().use {
artProfile.save(it, ArtProfileSerializer.METADATA_FOR_N)
}
}
可以看到其中使用了 obfuscationMap,进一步查看 ArtProfile 的生成,会发现使用了 deobfuscate 方法,源码如下
fun ArtProfile(
hrp: HumanReadableProfile,
obf: ObfuscationMap,
dexes: List<DexFile>,
apkName: String = ""
): ArtProfile {
val profileData = HashMap<DexFile, DexFileData>()
for (iDex in dexes.indices) {
val dex = dexes[iDex]
val methods = dex.methodPool
val types = dex.typePool
val classDefs = dex.classDefPool
val profileTypeIndexes = mutableSetOf<Int>()
val profileClassIndexes = mutableSetOf<Int>()
val profileMethods = mutableMapOf<Int, MethodData>()
for (iMethod in methods.indices) {
val method = methods[iMethod]
val deobfuscated = obf.deobfuscate(method)
val flags = hrp.match(deobfuscated)
if (flags != 0) {
profileMethods[iMethod] = MethodData(flags)
}
}
for (classIndex in classDefs.indices) {
val typeIndex = classDefs[classIndex]
val type = types[typeIndex]
if (obf.deobfuscate(type).any { hrp.match(it) != 0 }) {
profileTypeIndexes.add(typeIndex)
profileClassIndexes.add(classIndex)
}
}
if (profileTypeIndexes.isNotEmpty() || profileMethods.isNotEmpty()) {
profileData[dex] = DexFileData(
profileTypeIndexes,
profileClassIndexes,
profileMethods
)
}
}
return ArtProfile(profileData, apkName)
}
破案,在打包过程中,执行了 CompileArtProfileTask,所以最终生成的 profile 文件中已经是混淆后的相关名称