目录

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 文件中已经是混淆后的相关名称