字节跳动技术团队

Baseline Profile 安装时优化在西瓜视频的实践

â€چ هٹ¨و‰‹ç‚¹ه…³و³¨
ه¹²è´§ن¸چè؟·è·¯

背و™¯

هœ¨Androidن¸ٹ,Java/Kotlinن»£ç پن¼ڑ编译ن¸؛DEXه­—èٹ‚ç پ,هœ¨è؟گè،Œوœںç”±è™ڑو‹ںوœ؛è§£é‡ٹو‰§è،Œم€‚ن½†وک¯ï¼Œه­—èٹ‚ç پè§£é‡ٹو‰§è،Œçڑ„é€ںه؛¦و¯”较و…¢م€‚و‰€ن»¥ï¼Œé€ڑه¸¸è™ڑو‹ںوœ؛ن¼ڑهœ¨è§£é‡ٹو¨،ه¼ڈهں؛ç،€ن¸ٹهپڑن¸€ن؛›ه؟…è¦پçڑ„ن¼کهŒ–م€‚

هœ¨Android 5,Google采用çڑ„ç­–ç•¥وک¯هœ¨ه؛”用ه®‰è£…وœںé—´ه¯¹APPçڑ„ه…¨é‡ڈDEXè؟›è،ŒAOTن¼کهŒ–م€‚AOTن¼کهŒ–(Ahead of time),ه°±وک¯هœ¨APPè؟گè،Œه‰چه°±وٹٹDEXه­—èٹ‚ç پ编译وˆگوœ¬هœ°وœ؛ه™¨ç پم€‚虽然è؟گè،Œو•ˆçژ‡ç›¸و¯”DEXè§£é‡ٹو‰§è،Œوœ‰ن؛†ه¤§ه¹…وڈگé«ک,ن½†ç”±ن؛ژوک¯ه…¨é‡ڈAOT,ه°±ن¼ڑه¯¼è‡´ç”¨وˆ·éœ€è¦پç­‰ه¾…较é•؟çڑ„و—¶é—´و‰چ能و‰“ه¼€ه؛”用,ه¯¹ن؛ژç£پç›کç©؛é—´çڑ„هچ ç”¨ن¹ںو€¥ه‰§ه¢‍ه¤§م€‚

ن؛ژوک¯ï¼Œن¸؛ن؛†éپ؟ه…چè؟‡و—©çڑ„资و؛گهچ ç”¨ï¼Œن»ژAndroid 7ه¼€ه§‹ن¾؟ن¸چه†چè؟›è،Œه…¨é‡ڈAOT,而وک¯JIT+AOTçڑ„و··هگˆç¼–译و¨،ه¼ڈم€‚JIT(Just in time),ه°±وک¯هچ³و—¶ن¼کهŒ–,ن¹ںه°±وک¯هœ¨APPè؟گè،Œè؟‡ç¨‹ن¸­ï¼Œه®‍و—¶هœ°وٹٹDEXه­—èٹ‚ç پ编译وˆگوœ¬هœ°وœ؛ه™¨ç پم€‚ه…·ن½“و–¹ه¼ڈوک¯ï¼Œهœ¨APPè؟گè،Œو—¶هˆ†و‍گè؟گè،Œè؟‡çڑ„热ن»£ç پ,然هگژهœ¨è®¾ه¤‡ç©؛é—²و—¶è§¦هڈ‘AOT,هœ¨ن¸‹و¬،è؟گè،Œه‰چ预编译热ن»£ç پ,وڈگهچ‡هگژç»­APPè؟گè،Œو•ˆçژ‡م€‚

ن½†وک¯çƒ­ن»£ç پن»£ç پو”¶é›†éœ€è¦پو¯”较é•؟ه‘¨وœں,هœ¨APPهچ‡ç؛§è¦†ç›–ه®‰è£…ن¹‹هگژ,هژںوœ‰çڑ„预编译çڑ„热ن»£ç په¤±و•ˆï¼Œéœ€è¦په†چèµ°ن¸€éپچè؟گè،Œو—¶هˆ†و‍گم€پç©؛é—²و—¶AOTçڑ„وµپ程م€‚هœ¨هچ•ه‘¨è؟­ن»£çڑ„ç ”هڈ‘و¨،ه¼ڈن¸‹é—®é¢که°¤ن¸؛وکژوک¾م€‚

ه› و­¤ï¼Œن»ژAndroid 9 ه¼€ه§‹ï¼ŒGoogleوژ¨ه‡؛ن؛†Cloud Profilesوٹ€وœ¯م€‚ه®ƒçڑ„هژںçگ†وک¯ï¼Œهœ¨éƒ¨هˆ†ه…ˆه®‰è£…APKçڑ„用وˆ·و‰‹وœ؛ن¸ٹ,Google Play Storeو”¶é›†هˆ°çƒ­ç‚¹ن»£ç پ,然هگژن¸ٹن¼ هˆ°ن؛‘端ه¹¶èپڑهگˆم€‚è؟™و ·ï¼Œه¯¹ن؛ژهگژé‌¢ه®‰è£…çڑ„用وˆ·ï¼ŒPlay Storeن¼ڑن¸‹هڈ‘热点ن»£ç پé…چç½®è؟›è،Œé¢„编译,è؟™ن؛›ç”¨وˆ·ه°±ن¸چ需è¦پè؟›è،Œè؟گè،Œو—¶هˆ†و‍گ,ه¤§ه¤§وڈگه‰چن؛†ن¼کهŒ–و—¶وœ؛م€‚ن¸چè؟‡ï¼Œè؟™ن¸ھو”¶é›†èپڑهگˆن¸‹هڈ‘è؟‡ç¨‹éœ€è¦په‡ ه¤©و—¶é—´ï¼Œه¤§éƒ¨هˆ†ç”¨وˆ·è؟کوک¯و²،و³•ن؛«هڈ—هˆ°è؟™ن¸ھن¼کهŒ–م€‚

وœ€ç»ˆï¼Œهœ¨2022ه¹´Googleوژ¨ه‡؛ن؛† Baseline Profiles (https://developer.android.com/topic/performance/baselineprofiles/overview?hl=zh-cn) وٹ€وœ¯م€‚ه®ƒه…پ许ه¼€هڈ‘者ه†…ç½®è‡ھه·±ه®ڑن¹‰çڑ„热点ن»£ç پé…چç½®و–‡ن»¶م€‚هœ¨APPه®‰è£…وœں间,系ç»ںوڈگه‰چ预编译热点ن»£ç پ,ه¤§ه¹…وڈگهچ‡APPè؟گè،Œو•ˆçژ‡م€‚

ن¸چè؟‡ï¼ŒGoogleه®کو–¹çڑ„Baseline Profilesه­کهœ¨ن»¥ن¸‹ه±€é™گو€§ï¼ڑ

  • Baseline Profile 需è¦پن½؟用 AGP 7 هڈٹن»¥ن¸ٹçڑ„版وœ¬ï¼Œه…¬هڈ¸ه†…هگ„ه¤§APPçڑ„版وœ¬éƒ½è؟کو¯”较ن½ژ,çں­وœںه†…ه¹¶ن¸چهڈ¯ç”¨
  • ه®‰è£…و—¶ن¼کهŒ–ن¾‌èµ–Google Play,ه›½ه†…و— و³•ن½؟用

ن¸؛و­¤ï¼Œوˆ‘ن»¬ه¼€هڈ‘ن؛†ن¸€ه¥—ه®ڑهˆ¶هŒ–çڑ„Baseline Profilesن¼کهŒ–و–¹و،ˆï¼Œهڈ¯ن»¥é€‚用ن؛ژه…¨ç‰ˆوœ¬AGPم€‚هگŒو—¶é€ڑè؟‡ن¸ژه›½ه†…ن¸»وµپهژ‚ه•†هگˆن½œï¼Œوژ¨è؟›و”¯وŒپن؛†ه®‰è£…و—¶ن¼کهŒ–ç”ںو•ˆم€‚

و–¹و،ˆوژ¢ç´¢ن¸ژه®‍çژ°

وˆ‘ن»¬ه…ˆو‌¥çœ‹ن¸€ن¸‹ه®کو–¹Baseline Profileه®‰è£…و—¶ن¼کهŒ–çڑ„وµپ程ï¼ڑ

è؟™é‡Œé‌¢ن¸»è¦پهŒ…هگ«3ن¸ھو­¥éھ¤ï¼ڑ
  1. 热点و–¹و³•و”¶é›†ï¼Œé€ڑè؟‡وœ¬هœ°è؟گè،Œè®¾ه¤‡وˆ–者ن؛؛ه·¥é…چ置,ه¾—هˆ°هڈ¯è¯»و ¼ه¼ڈçڑ„هں؛ه‡†é…چç½®و–‡وœ¬و–‡ن»¶ï¼ˆbaseline-prof.txt)
  2. 编译وœںه¤„çگ†ï¼Œه°†هں؛ه‡†é…چç½®و–‡وœ¬و–‡ن»¶è½¬وچ¢وˆگن؛Œè؟›هˆ¶و–‡ن»¶ï¼Œو‰“هŒ…至apkه†…(baseline.profه’Œbaseline.profm),هڈ¦ه¤–Google Playوœچهٹ،端è؟کن¼ڑه°†ن؛‘端profileن¸ژbaseline.profèپڑهگˆه¤„çگ†م€‚
  3. ه®‰è£…و—¶ï¼Œç³»ç»ںن¼ڑè§£و‍گapkه†…çڑ„baseline.profن؛Œè؟›هˆ¶و–‡ن»¶ï¼Œو ¹وچ®ç‰ˆوœ¬هڈ·ï¼Œهپڑن¸€ن؛›è½¬وچ¢هگژ,وڈگه‰چ预编译وŒ‡ه®ڑçڑ„热点ن»£ç پن¸؛وœ؛ه™¨ç پم€‚

热点و–¹و³•و”¶é›†

ه®کو–¹و–‡و،£ (https://developer.android.com/topic/performance/baselineprofiles/create-baselineprofile) وڈگهˆ°ن½؟用Jetpack Macrobenchmarkه؛“ (https://developer.android.com/macrobenchmark) ه’Œ BaselineProfileRule è‡ھهٹ¨و”¶é›†çƒ­ç‚¹و–¹و³•م€‚é€ڑè؟‡هœ¨Android Studioن¸­ه¼•ه…¥Benchmark module,需è¦پç¼–ه†™ç›¸ه؛”çڑ„Rule触هڈ‘و‰“هŒ…م€پوµ‹è¯•ç­‰وµپ程م€‚

ن»ژن¸‹é‌¢و؛گç پهڈ¯ن»¥çœ‹هˆ°ï¼Œوœ€ç»ˆوک¯é€ڑè؟‡profmanه‘½ن»¤هڈ¯ن»¥و”¶é›†هˆ°appè؟گè،Œè؟‡ç¨‹ن¸­çڑ„热点و–¹و³•م€‚

privateآ funآ profmanGetProfileRules(apkPath:آ String,آ pathOptions:آ List<String>):آ Stringآ {
آ آ آ آ //آ Whenآ compilingآ withآ CompilationMode.SpeedProfile,آ ARTآ storesآ theآ profileآ inآ oneآ of
آ آ آ آ //آ 2آ locations.آ Theآ `ref`آ profileآ path,آ orآ theآ `current`آ path.
آ آ آ آ //آ Theآ `current`آ pathآ isآ eventuallyآ mergedآ آ intoآ theآ `ref`آ pathآ afterآ backgroundآ dexopt.
آ آ آ آ valآ profilesآ =آ pathOptions.mapNotNullآ {آ currentPathآ ->
آ آ آ آ آ آ آ آ Log.d(TAG,آ "Usingآ profileآ location:آ $currentPath")
آ آ آ آ آ آ آ آ valآ profileآ =آ Shell.executeScriptCaptureStdout(
آ آ آ آ آ آ آ آ آ آ آ آ "profmanآ --dump-classes-and-methodsآ --profile-file=$currentPathآ --apk=$apkPath"
آ آ آ آ آ آ آ آ )
آ آ آ آ آ آ آ آ profile.ifBlankآ {آ nullآ }
آ آ آ آ }
آ آ آ آ ...
آ آ آ آ returnآ builder.toString()
}

و‰€ن»¥ï¼Œوˆ‘ن»¬هڈ¯ن»¥ç»•è؟‡Macrobenchmarkه؛“,直وژ¥ن½؟用profmanه‘½ن»¤ï¼Œه‡ڈه°‘è‡ھهٹ¨هŒ–وژ¥ه…¥وˆگوœ¬م€‚ه…·ن½“ه‘½ن»¤ه¦‚ن¸‹ï¼ڑ

adbآ shellآ profmanآ --dump-classes-and-methodsآ \
--profile-file=/data/misc/profiles/cur/0/com.ss.android.article.video/primary.profآ \
--apk=/data/app/com.ss.android.article.video-Ctzj32dufeuXB8KOhAqdGg==/base.apkآ \
>آ baseline-prof.txt

ç”ںوˆگçڑ„baseline-prof.txtو–‡ن»¶ه†…ه®¹ه¦‚ن¸‹ï¼ڑ

PLcom/bytedance/apm/perf/b/f;->a(Lcom/bytedance/apm/perf/b/f;)Ljava/lang/String;
PLcom/bytedance/bdp/bdpbase/ipc/n$a;->a()Lcom/bytedance/bdp/bdpbase/ipc/n;
HSPLorg/android/spdy/SoInstallMgrSdk;->initSo(Ljava/lang/String;I)Z
HSPLorg/android/spdy/SpdyAgent;->InvlidCharJudge([B[B)V
Lanet/channel/e/a$b;
Lcom/bytedance/alliance/services/impl/c;
...

è؟™ن؛›è§„هˆ™é‡‡ç”¨ن¸¤ç§چه½¢ه¼ڈ,هˆ†هˆ«وŒ‡وکژو–¹و³•ه’Œç±»م€‚و–¹و³•çڑ„è§„هˆ™ه¦‚ن¸‹و‰€ç¤؛:

[FLAGS][CLASS_DESCRIPTOR]->[METHOD_SIGNATURE]
FLAGSè،¨ç¤؛ H م€پ S ه’Œ P ن¸­çڑ„ن¸€ن¸ھوˆ–ه¤ڑن¸ھه­—符,用ن؛ژوŒ‡ç¤؛相ه؛”و–¹و³•هœ¨هگ¯هٹ¨ç±»ه‍‹و–¹é‌¢ه؛”و ‡è®°ن¸؛ Hot م€پ Startup è؟کوک¯ Post Startup ï¼ڑ
  • ه¸¦وœ‰ H و ‡è®°è،¨ç¤؛相ه؛”و–¹و³•وک¯ن¸€ç§چ“热â€‌و–¹و³•,è؟™و„ڈه‘³ç‌€ç›¸ه؛”و–¹و³•هœ¨ه؛”用çڑ„و•´ن¸ھç”ںه‘½ه‘¨وœںه†…ن¼ڑ被调用ه¤ڑو¬،م€‚
  • ه¸¦وœ‰ S و ‡è®°è،¨ç¤؛相ه؛”و–¹و³•هœ¨هگ¯هٹ¨و—¶è¢«è°ƒç”¨م€‚
  • ه¸¦وœ‰ P و ‡è®°è،¨ç¤؛相ه؛”و–¹و³•وک¯ن¸ژهگ¯هٹ¨و— ه…³çڑ„热و–¹و³•م€‚

ç±»çڑ„è§„هˆ™ï¼Œهˆ™وک¯ç›´وژ¥وŒ‡وکژ类签هگچهچ³هڈ¯ï¼ڑ

[CLASS_DESCRIPTOR]

ن¸چè؟‡è؟™é‡Œوک¯هڈ¯è¯»çڑ„و–‡وœ¬و ¼ه¼ڈ,هگژç»­è؟ک需è¦پè؟›ن¸€و­¥è½¬ن¸؛ن؛Œè؟›هˆ¶و‰چهڈ¯ن»¥è¢«ç³»ç»ں识هˆ«م€‚

هڈ¦ه¤–,releaseهŒ…ه¯¼ه‡؛çڑ„وک¯و··و·†هگژçڑ„符هڈ·ï¼Œéœ€è¦پو ¹وچ®mappingو–‡ن»¶ه†چهپڑن¸€و¬،هڈچو··و·†و‰چ能ن½؟用م€‚

编译وœںه¤„çگ†

هœ¨ه¾—هˆ°base.apkçڑ„هں؛ه‡†é…چç½®و–‡وœ¬و–‡ن»¶ï¼ˆbaseline-prof.txt)ن¹‹هگژè؟کن¸چه¤ں,ن¸€ن؛›ه؛“里é‌¢

(و¯”ه¦‚androidxçڑ„ه؛“里 https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:recyclerview/recyclerview/src/main/baseline-prof.txt )

ن¹ںن¼ڑè‡ھه¸¦baseline-prof.txtو–‡ن»¶م€‚و‰€ن»¥ï¼Œوˆ‘ن»¬è؟ک需è¦پوٹٹè؟™ن؛›ه­گlibraryه†…附ه¸¦çڑ„baseline-prof.txtهڈ–ه‡؛و‌¥ï¼Œن¸ژbase.apkçڑ„é…چç½®ن¸€èµ·هگˆه¹¶وˆگه®Œو•´çڑ„هں؛ه‡†é…چç½®و–‡وœ¬و–‡ن»¶م€‚

وژ¥ن¸‹و‌¥ï¼Œوˆ‘ن»¬éœ€è¦پوٹٹه®Œو•´çڑ„é…چç½®و–‡ن»¶è½¬وچ¢وˆگbaseline.profن؛Œè؟›هˆ¶و–‡ن»¶م€‚ه…·ن½“وک¯ç”±AGP 7.xه†…çڑ„ CompileArtProfileTask.kt ه®‍çژ°çڑ„ ï¼ڑ
/**
آ *آ Taskآ thatآ transformsآ aآ humanآ readableآ artآ profileآ intoآ aآ binaryآ formآ versionآ thatآ canآ beآ shipped
آ *آ insideآ anآ APKآ orآ aآ Bundle.
آ */
abstractآ classآ CompileArtProfileTask:آ NonIncrementalTask()آ {
...
آ آ آ آ abstractآ classآ CompileArtProfileWorkAction:
آ آ آ آ آ آ آ آ آ آ آ آ ProfileAwareWorkAction<CompileArtProfileWorkAction.Parameters>()آ {

آ آ آ آ آ آ آ آ 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.
آ آ آ آ آ آ آ آ آ آ آ آ parameters.binaryArtProfileMetadataOutputFile.get().asFile.outputStream().useآ {
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ artProfile.save(it,آ ArtProfileSerializer.METADATA_0_0_2)
آ آ آ آ آ آ آ آ آ آ آ آ }
آ آ آ آ آ آ آ آ }
آ آ آ آ }

è؟™é‡Œçڑ„و ¸ه؟ƒé€»è¾‘ه°±وک¯هپڑن؛†ن»¥ن¸‹3ن»¶ن؛‹ï¼ڑ

  1. 读هڈ–baseline-prof.txtهں؛ه‡†é…چç½®و–‡وœ¬و–‡ن»¶ï¼Œن¸‹و–‡ç”¨HumanReadableProfileè،¨ç¤؛
  2. ه°†HumanReadableProfileم€پproguard mappingو–‡ن»¶م€پdexو–‡ن»¶ن½œن¸؛输ه…¥ن¼ ç»™ArtProfile
  3. ç”±ArtProfileç”ںوˆگ特ه®ڑ版وœ¬و ¼ه¼ڈçڑ„baseline.profن؛Œè؟›هˆ¶و–‡ن»¶
ArtProfileç±»وک¯هœ¨profgen ه­گه·¥ç¨‹ه†…ه®‍çژ°çڑ„,ه…¶ن¸­وœ‰ن¸¤ن¸ھه…³é”®çڑ„و–¹و³•ï¼ڑ
  • و‍„造و–¹و³•ï¼ڑ读هڈ–HumanReadableProfileم€پproguard mappingو–‡ن»¶م€پdexو–‡ن»¶ن½œن¸؛هڈ‚و•°ï¼Œو‍„造ArtProfileه®‍ن¾‹
  • save()و–¹و³•ï¼ڑ输ه‡؛وŒ‡ه®ڑ版وœ¬و ¼ه¼ڈçڑ„baseline.profن؛Œè؟›هˆ¶و–‡ن»¶

هڈ‚考链وژ¥ï¼ڑ

https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:profgen/profgen/src/main/kotlin/com/android/tools/profgen/

至و­¤ï¼Œوˆ‘ن»¬هڈ¯ن»¥هں؛ن؛ژprofgenه¼€هڈ‘ن¸€ن¸ھgradle plugin,هœ¨ç¼–译و‍„ه»؛وµپ程ن¸­وڈ’ه…¥ن¸€ن¸ھè‡ھه®ڑن¹‰task,ه°†baseline-prof.txt转وچ¢وˆگbaseline.prof,ه¹¶ه†…ç½®هˆ°apkçڑ„assetç›®ه½•م€‚

و ¸ه؟ƒن»£ç په¦‚ن¸‹ï¼ڑ

valآ packageAndroidTaskآ =
آ آ آ آ variant.variantScope.taskContainer.packageAndroidTask?.get()
packageAndroidTask?.doFirstآ {
آ آ آ آ varآ dexFilesآ =آ collectDexFiles(variant.packageApplication.dexFolders)
آ آ آ آ dexFilesآ =آ dexFiles.sortedWith(DexFileComparator())آ 
آ آ آ آ //هں؛ه‡†é…چç½®و–‡ن»¶çڑ„ه†…ه­کè،¨ç¤؛
آ آ آ آ varآ hrpآ =آ HumanReadableProfile("baseline-prof.txt")
آ آ آ آ varآ obfFile:آ File?آ =آ getObfFile(variant,آ proguardTask)
آ آ آ آ valآ apkآ =آ Apk(dexFiles,آ "")
آ آ آ آ valآ obfآ =
آ آ آ آ آ آ آ آ ifآ (obfFileآ !=آ null)آ ObfuscationMap(obfFile)آ elseآ ObfuscationMap.Empty
آ آ آ آ valآ profileآ =آ ArtProfile(hrp!!,آ obf,آ apk)

آ آ آ آ valآ dexoptDirآ =آ File(variant.mergedAssets.first(),آ profDir)

آ آ آ آ ifآ (!dexoptDir.exists())آ {
آ آ آ آ آ آ آ آ dexoptDir.mkdirs()
آ آ آ آ }
آ آ آ آ valآ outFileآ =آ File(dexoptDir,آ "baseline.prof")
آ آ آ آ valآ metaFileآ =آ File(dexoptDir,آ "baseline.profm")
آ آ آ آ profile.save(outFile.outputStream(),آ ArtProfileSerializer.V0_1_0_P)
آ آ آ آ profile.save(metaFile.outputStream(),آ ArtProfileSerializer.METADATA_0_0_2)
آ آ }آ آ 

è‡ھه®ڑن¹‰taskن¸»è¦پهŒ…هگ«ن»¥ن¸‹ه‡ ن¸ھو­¥éھ¤ï¼ڑ

  1. è§£هژ‹apkèژ·هڈ–dexهˆ—è،¨ï¼ŒوŒ‰ç…§ن¸€ه®ڑè§„هˆ™وژ’ه؛ڈ(è·ںAndroidçڑ„و‰“هŒ…è§„هˆ™وœ‰ه…³ï¼Œdexو–‡ن»¶هگچه’Œcrcç­‰ن؟،وپ¯éœ€è¦په’Œprofن؛Œè؟›هˆ¶و–‡ن»¶ه†…çڑ„ه¯¹ه؛”ن¸ٹ)
  2. é€ڑè؟‡ObfuscationMapه°†baseline-prof.txtو–‡ن»¶ن¸­çڑ„符هڈ·è½¬وچ¢وˆگو··و·†هگژçڑ„符هڈ·
  3. é€ڑè؟‡ArtProfileوŒ‰ç…§ن¸€ه®ڑو ¼ه¼ڈ转وچ¢وˆگbaseline.profن¸ژbaseline.profmن؛Œè؟›هˆ¶و–‡ن»¶

ه…¶ن¸­وœ‰ن¸¤ن¸ھو–‡ن»¶ï¼ڑ

  • baseline.profï¼ڑهŒ…هگ«çƒ­ç‚¹و–¹و³•idم€پç±»idن؟،وپ¯çڑ„ن؛Œè؟›هˆ¶ç¼–ç پو–‡ن»¶
  • baseline.profmï¼ڑ用ن؛ژé«ک版وœ¬è½¬ç پçڑ„ن؛Œè؟›هˆ¶و‰©ه±•و–‡ن»¶
ه…³ن؛ژbaseline.profçڑ„و ¼ه¼ڈ,وˆ‘ن»¬ن»ژ ArtProfileSerializer.kt çڑ„و³¨é‡ٹهڈ¯ن»¥çœ‹هˆ°ن¸چهگŒAndroid版وœ¬وœ‰ن¸چهگŒçڑ„و ¼ه¼ڈم€‚Android 12 ه¼€ه§‹éœ€è¦پهڈ¦ه¤–转ç پو‰چ能ه…¼ه®¹ï¼Œè¯¦è§پهڈ¯ن»¥çœ‹è؟™ن¸ھissueï¼ڑ

هڈ‚考链وژ¥ï¼ڑhttps://issuetracker.google.com/issues/234353689

ه®‰è£…وœںه¤„çگ†

هœ¨ç”ںوˆگه¸¦وœ‰baseline.profن؛Œè؟›هˆ¶و–‡ن»¶çڑ„APKن¹‹هگژ,ه†چو‌¥çœ‹ن¸€ن¸‹ç³»ç»ںهœ¨ه®‰è£…apkو—¶ه¦‚ن½•ه¤„çگ†è؟™ن¸ھbaseline.profو–‡ن»¶ï¼ˆهں؛ن؛ژAndroid 13و؛گç پهˆ†و‍گ)م€‚وœ¬هœ°وµ‹è¯•é€ڑè؟‡ adb install-multiple release.apk release.dm ه‘½ن»¤و‰§è،Œه®‰è£…,然هگژé€ڑè؟‡Androidç³»ç»ںهŒ…ç®،çگ†ه­گç³»ç»ںè؟›è،Œه®‰è£…و—¶ن¼کهŒ–م€‚

Androidç³»ç»ںهŒ…ç®،çگ†و،†و‍¶هˆ†ن¸؛3ه±‚ï¼ڑ

  1. ه؛”用ه±‚ï¼ڑه؛”用é€ڑè؟‡getPackageManagerèژ·هڈ–PMSçڑ„ه®‍ن¾‹ï¼Œç”¨ن؛ژه؛”用çڑ„ه®‰è£…,هچ¸è½½ï¼Œو›´و–°ç­‰و“چن½œ
  2. PMSوœچهٹ،ه±‚ï¼ڑو‹¥وœ‰ç³»ç»ںو‌ƒé™گ,解و‍گه¹¶è®°ه½•ه؛”用çڑ„هں؛وœ¬ن؟،وپ¯ï¼ˆه؛”用هگچ称,و•°وچ®ه­کو”¾è·¯ه¾„م€په…³ç³»ç®،çگ†ç­‰ï¼‰ï¼Œوœ€ç»ˆé€ڑè؟‡binderç³»ç»ںه±‚çڑ„installdç³»ç»ںوœچهٹ،è؟›è،Œé€ڑ讯
  3. Installdç³»ç»ںوœچهٹ،ه±‚ï¼ڑو‹¥وœ‰rootو‌ƒé™گ,ه®Œوˆگوœ€ç»ˆçڑ„apkه®‰è£…م€پdexن¼کهŒ–

ه…¶ن¸­ه¤„çگ†baseline.profن؛Œè؟›هˆ¶و–‡ن»¶ه¹¶وœ€ç»ˆوŒ‡ه¯¼ç¼–译ç”ںوˆگodexçڑ„ن¸»è¦پè·¯ه¾„ه¦‚ن¸‹:

InstallPackageHelper.java#installPackagesLI
آ آ آ آ InstallPackageHelper.java#executePostCommitSteps
آ آ آ آ آ آ آ آ ArtManagerService.java#prepareAppProfiles
آ آ آ آ آ آ آ آ آ آ آ آ Installer.java#prepareAppProfile
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ InstalldNativeService.cpp#prepareAppProfile
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ dexopt.cpp#prepare_app_profile
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ ProfileAssistant.cpp#ProcessProfilesInternal
آ آ آ آ آ آ آ آ PackageDexOptimizer.java#performDexOpt
آ آ آ آ آ آ آ آ آ آ آ آ PackageDexOptimizer.java#performDexOptLI
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ PackageDexOptimizer.java#dexOptPath
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ InstalldNativeService.cpp#dexopt
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ dexopt.cpp#dexopt
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ dex2oat.ccآ 

هœ¨ه…¥هڈ£installPackagesLIه‡½و•°ن¸­ï¼Œç»ڈè؟‡prepareم€پscanم€پReconcileم€پCommit ه››ن¸ھéک¶و®µهگژوœ€ç»ˆè°ƒç”¨executePostCommitStepsه®Œوˆگapkه®‰è£…م€پprofو–‡ن»¶ه†™ه…¥م€پdexoptن¼کهŒ–ï¼ڑ

آ آ آ آ privateآ voidآ installPackagesLI(List<InstallRequest>آ requests)آ {
آ آ آ آ آ آ آ آ آ //éک¶و®µ1ï¼ڑprepare
آ آ آ آ آ آ آ آ آ prepareResultآ =آ preparePackageLI(request.mArgs,آ request.mInstallResult);
آ آ آ آ آ آ آ آ آ //éک¶و®µ2ï¼ڑscan
آ آ آ آ آ آ آ آ آ finalآ ScanResultآ resultآ =آ scanPackageTracedLI(
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ prepareResult.mPackageToScan,آ prepareResult.mParseFlags,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ prepareResult.mScanFlags,آ System.currentTimeMillis(),
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ request.mArgs.mUser,آ request.mArgs.mAbiOverride);
آ آ آ آ آ آ آ آ آ //éک¶و®µ3ï¼ڑReconcile
آ آ آ آ آ آ آ آ آ reconciledPackagesآ =آ ReconcilePackageUtils.reconcilePackages(
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ reconcileRequest,آ mSharedLibraries,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ mPm.mSettings.getKeySetManagerService(),آ mPm.mSettings);
آ آ آ آ آ آ آ آ آ //éک¶و®µ4ï¼ڑCommitه¹¶ه®‰è£…
آ آ آ آ آ آ آ آ آ commitRequestآ =آ newآ CommitRequest(reconciledPackages,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ mPm.mUserManager.getUserIds());آ 
آ آ آ آ آ آ آ آ آ executePostCommitSteps(commitRequest);آ آ آ آ آ آ آ آ آ آ آ آ 
آ آ آ آ }

executePostCommitStepsن¸­ï¼Œن¸»è¦په®Œوˆگprofو–‡ن»¶ه†™ه…¥ن¸ژdexن¼کهŒ–ï¼ڑ

privateآ voidآ executePostCommitSteps(CommitRequestآ commitRequest)آ {
آ آ آ آ آ آ آ آ forآ (ReconciledPackageآ reconciledPkgآ :آ commitRequest.mReconciledPackages.values())آ {
آ آ آ آ آ آ آ آ آ آ آ آ finalآ AndroidPackageآ pkgآ =آ reconciledPkg.mPkgSetting.getPkg();
آ آ آ آ آ آ آ آ آ آ آ آ finalآ Stringآ packageNameآ =آ pkg.getPackageName();
آ آ آ آ آ آ آ آ آ آ آ آ finalآ Stringآ codePathآ =آ pkg.getPath();
آ 
آ آ آ آ آ آ آ آ آ آ آ آ آ //و­¥éھ¤1ï¼ڑprofو–‡ن»¶ه†™ه…¥
آ آ آ آ آ آ آ آ آ آ آ آ //آ Prepareآ theآ applicationآ profilesآ forآ theآ newآ codeآ paths.
آ آ آ آ آ آ آ آ آ آ آ آ //آ Thisآ needsآ toآ beآ doneآ beforeآ invokingآ dexoptآ soآ thatآ anyآ install-timeآ profile
آ آ آ آ آ آ آ آ آ آ آ آ //آ canآ beآ usedآ forآ optimizations.
آ آ آ آ آ آ آ آ آ آ آ آ mArtManagerService.prepareAppProfiles(pkg,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ mPm.resolveUserIds(reconciledPkg.mInstallArgs.mUser.getIdentifier()),
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ /*آ updateReferenceProfileContent=آ */آ true);

آ آ آ آ آ آ آ آ آ آ آ آ آ //و­¥éھ¤2ï¼ڑdexن¼کهŒ–,هœ¨ه¼€هگ¯baseline profileن¼کهŒ–ن¹‹هگژcompilation-reason=install-dm
آ آ آ آ آ آ آ آ آ آ آ آ finalآ intآ compilationReasonآ =
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ mDexManager.getCompilationReasonForInstallScenario(
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ reconciledPkg.mInstallArgs.mInstallScenario);
آ آ آ آ آ آ آ آ آ آ آ آ DexoptOptionsآ dexoptOptionsآ =
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ newآ DexoptOptions(packageName,آ compilationReason,آ dexoptFlags);

آ آ آ آ آ آ آ آ آ آ آ آ ifآ (performDexopt)آ {
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ //آ Compileآ theآ layoutآ resources.
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ ifآ (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS,آ false))آ {
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ mViewCompiler.compileLayouts(pkg);
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ }

آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ ScanResultآ resultآ =آ reconciledPkg.mScanResult;

آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ mPackageDexOptimizer.performDexOpt(pkg,آ realPkgSetting,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ nullآ /*آ instructionSetsآ */,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ mPm.getOrCreateCompilerPackageStats(pkg),
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ mDexManager.getPackageUseInfoOrDefault(packageName),
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ dexoptOptions);
آ آ آ آ آ آ آ آ آ آ آ آ }

آ آ آ آ آ آ آ آ آ آ آ آ //آ Notifyآ BackgroundDexOptServiceآ thatآ theآ packageآ hasآ beenآ changed.
آ آ آ آ آ آ آ آ آ آ آ آ //آ Ifآ thisآ isآ anآ updateآ ofآ aآ packageآ whichآ usedآ toآ failآ toآ compile,
آ آ آ آ آ آ آ آ آ آ آ آ //آ BackgroundDexOptServiceآ willآ removeآ itآ fromآ itsآ denylist.
آ آ آ آ آ آ آ آ آ آ آ آ BackgroundDexOptService.getService().notifyPackageChanged(packageName);
آ آ آ آ آ آ آ آ آ آ آ آ notifyPackageChangeObserversOnUpdate(reconciledPkg);
آ آ آ آ آ آ آ آ }
آ آ آ آ آ آ آ آ PackageManagerServiceUtils.waitForNativeBinariesExtractionForIncremental(
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ incrementalStorages);
آ آ آ آ }

profو–‡ن»¶ه†™ه…¥

ه…ˆو‌¥çœ‹ن¸‹profو–‡ن»¶ه†™ه…¥وµپ程,ن¸»è¦پوµپ程ه¦‚ن¸‹ه›¾و‰€ç¤؛ï¼ڑ

ه…¶ه…¥هڈ£هœ¨ ArtManagerService.java``#``prepareAppProfiles ï¼ڑ
آ آ آ آ /**
آ آ آ آ آ *آ Prepareآ theآ applicationآ profiles.
آ آ آ آ آ *آ آ آ -آ createآ theآ currentآ primaryآ profileآ toآ saveآ timeآ atآ appآ startupآ time.
آ آ آ آ آ *آ آ آ -آ copyآ theآ profilesآ fromآ theآ associatedآ dexآ metadataآ fileآ toآ theآ referenceآ profile.
آ آ آ آ آ */
آ آ آ آ publicآ voidآ prepareAppProfiles(
آ آ آ آ آ آ آ آ آ آ آ آ AndroidPackageآ pkg,آ @UserIdIntآ intآ user,
آ آ آ آ آ آ آ آ آ آ آ آ booleanآ updateReferenceProfileContent)آ {
آ آ آ آ آ آ آ آ tryآ {
آ آ آ آ آ آ آ آ آ آ آ آ ArrayMap<String,آ String>آ codePathsProfileNamesآ =آ getPackageProfileNames(pkg);
آ آ آ آ آ آ آ آ آ آ آ آ forآ (intآ iآ =آ codePathsProfileNames.size()آ -آ 1;آ iآ >=آ 0;آ i--)آ {
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ Stringآ codePathآ =آ codePathsProfileNames.keyAt(i);
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ Stringآ profileNameآ =آ codePathsProfileNames.valueAt(i);
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ Stringآ dexMetadataPathآ =آ null;
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ //آ Passingآ theآ dexآ metadataآ fileآ toآ theآ prepareآ methodآ willآ updateآ theآ reference
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ //آ profileآ content.آ Asآ such,آ weآ lookآ forآ theآ dexآ metadataآ fileآ onlyآ ifآ weآ needآ to
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ //آ performآ anآ update.
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ ifآ (updateReferenceProfileContent)آ {
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ Fileآ dexMetadataآ =آ DexMetadataHelper.findDexMetadataForFile(newآ File(codePath));
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ dexMetadataPathآ =آ dexMetadataآ ==آ nullآ ?آ nullآ :آ dexMetadata.getAbsolutePath();
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ }
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ synchronizedآ (mInstaller)آ {
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ booleanآ resultآ =آ mInstaller.prepareAppProfile(pkg.getPackageName(),آ user,آ appId,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ profileName,آ codePath,آ dexMetadataPath);
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ }
آ آ آ آ آ آ آ آ آ آ آ آ }
آ آ آ آ آ آ آ آ }آ catchآ (InstallerExceptionآ e)آ {
آ آ آ آ آ آ آ آ }
آ آ آ آ }آ 

ه…¶ن¸­dexMetadataوک¯هگژç¼€ن¸؛.dmçڑ„هژ‹ç¼©و–‡ن»¶ï¼Œه†…部هŒ…هگ«primary.profم€پprimary.profmو–‡ن»¶ï¼Œapkçڑ„baseline.profم€پbaseline.profmن¼ڑهœ¨ه®‰è£…éک¶و®µè½¬ن¸؛وˆگdmو–‡ن»¶م€‚

mInstaller.prepareAppProfile وœ€ç»ˆن¼ڑ调用هˆ° dexopt.cpp#prepare_app_profile ن¸­ï¼Œé€ڑè؟‡forkن¸€ن¸ھه­گè؟›ç¨‹و‰§è،Œprofmanن؛Œè؟›هˆ¶ç¨‹ه؛ڈ,ه°†dmو–‡ن»¶م€پreference_profileو–‡ن»¶ï¼ˆن½چن؛ژ设ه¤‡ن¸ٹه›؛ه®ڑè·¯ه¾„,ه­که‚¨و±‡و€»çڑ„热点و–¹و³•)م€پapkو–‡ن»¶ن½œن¸؛هڈ‚و•°è¾“ه…¥ï¼ڑ
//frameworks/native/cmds/installd/dexopt.cpp
boolآ prepare_app_profile(constآ std::string&آ package_name,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ userid_tآ user_id,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ appid_tآ app_id,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ constآ std::string&آ profile_name,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ constآ std::string&آ code_path,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ constآ std::optional<std::string>&آ dex_metadata)آ {

آ آ آ آ //آ Weآ haveآ aآ dexآ metdata.آ Mergeآ theآ profileآ intoآ theآ referenceآ profile.
آ آ آ آ unique_fdآ ref_profile_fdآ =
آ آ آ آ آ آ آ آ آ آ آ آ open_reference_profile(multiuser_get_uid(user_id,آ app_id),آ package_name,آ profile_name,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ /*read_write*/آ true,آ /*is_secondary_dex*/آ false);
آ آ آ آ unique_fdآ dex_metadata_fd(TEMP_FAILURE_RETRY(
آ آ آ آ آ آ آ آ آ آ آ آ open(dex_metadata->c_str(),آ O_RDONLYآ |آ O_NOFOLLOW)));
آ آ آ آ unique_fdآ apk_fd(TEMP_FAILURE_RETRY(open(code_path.c_str(),آ O_RDONLYآ |آ O_NOFOLLOW)));
آ آ آ آ RunProfmanآ args;
آ آ آ آ args.SetupCopyAndUpdate(dex_metadata_fd,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ ref_profile_fd,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ apk_fd,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ code_path);
آ آ آ آ pid_tآ pidآ =آ fork();
آ آ آ آ ifآ (pidآ ==آ 0)آ {
آ آ آ آ آ آ آ آ args.Exec();
آ آ آ آ }
آ آ آ آ returnآ true;
}
آ آ آ آ voidآ SetupCopyAndUpdate(constآ unique_fd&آ profile_fd,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ constآ unique_fd&آ reference_profile_fd,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ constآ unique_fd&آ apk_fd,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ constآ std::string&آ dex_location)آ {
آ آ آ آ آ آ آ آ SetupArgs(...);
آ آ آ آ }
آ آ آ آ voidآ SetupArgs(constآ std::vector<T>&آ profile_fds,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ constآ unique_fd&آ reference_profile_fd,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ constآ std::vector<U>&آ apk_fds,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ constآ std::vector<std::string>&آ dex_locations,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ boolآ copy_and_update,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ boolآ for_snapshot,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ boolآ for_boot_image)آ {
آ آ آ آ آ آ آ آ constآ char*آ profman_binآ =آ select_execution_binary("/profman");
آ آ آ آ آ آ آ آ ifآ (reference_profile_fdآ !=آ -1)آ {
آ آ آ آ آ آ آ آ آ آ آ آ AddArg("--reference-profile-file-fd="آ +آ std::to_string(reference_profile_fd.get()));
آ آ آ آ آ آ آ آ }
آ آ آ آ آ آ آ آ forآ (constآ T&آ fdآ :آ profile_fds)آ {
آ آ آ آ آ آ آ آ آ آ آ آ AddArg("--profile-file-fd="آ +آ std::to_string(fd.get()));
آ آ آ آ آ آ آ آ }
آ آ آ آ آ آ آ آ forآ (constآ U&آ fdآ :آ apk_fds)آ {
آ آ آ آ آ آ آ آ آ آ آ آ AddArg("--apk-fd="آ +آ std::to_string(fd.get()));
آ آ آ آ آ آ آ آ }
آ آ آ آ آ آ آ آ forآ (constآ std::string&آ dex_locationآ :آ dex_locations)آ {
آ آ آ آ آ آ آ آ آ آ آ آ AddArg("--dex-location="آ +آ dex_location);
آ آ آ آ آ آ آ آ }
آ آ آ آ آ آ آ آ ...
}

ه®‍é™…ن¸ٹ,ه°±وک¯و‰§è،Œن؛†ن¸‹é‌¢çڑ„profmanه‘½ن»¤ï¼ڑ

./profmanآ --reference-profile-file-fd=9آ \
--profile-file-fd=10آ --apk-fd=11آ \
--dex-location=/data/app/com.ss.android.article.video-4-JZaMrtO7n_kFe4kbhBBA==/base.apkآ \
--copy-and-update-profile-key
reference-profile-file-fdوŒ‡هگ‘ /data/misc/profile/ref/$package/primary.prof و–‡ن»¶ï¼Œè®°ه½•ه½“ه‰چapk版وœ¬çڑ„热点و–¹و³•,وœ€ç»ˆbaseline.profن؟‌ه­کçڑ„热点و–¹و³•ن؟،وپ¯éœ€è¦په†™ه…¥هˆ°reference-profileو–‡ن»¶م€‚

profmanن؛Œè؟›هˆ¶ç¨‹ه؛ڈçڑ„ن»£ç په¦‚ن¸‹ï¼ڑ

classآ ProfManآ finalآ {
آ public:
آ آ voidآ ParseArgs(intآ argc,آ charآ **argv)آ {
آ آ آ آ MemMap::Init();

آ آ آ آ forآ (intآ iآ =آ 0;آ iآ <آ argc;آ ++i)آ {
آ آ آ آ آ آ ifآ (StartsWith(option,آ "--profile-file="))آ {
آ آ آ آ آ آ آ آ profile_files_.push_back(std::string(option.substr(strlen("--profile-file="))));
آ آ آ آ آ آ }آ elseآ ifآ (StartsWith(option,آ "--profile-file-fd="))آ {
آ آ آ آ آ آ آ آ ParseFdForCollection(raw_option,آ "--profile-file-fd=",آ &profile_files_fd_);
آ آ آ آ آ آ }آ elseآ ifآ (StartsWith(option,آ "--dex-location="))آ {
آ آ آ آ آ آ آ آ dex_locations_.push_back(std::string(option.substr(strlen("--dex-location="))));
آ آ آ آ آ آ }آ elseآ ifآ (StartsWith(option,آ "--apk-fd="))آ {
آ آ آ آ آ آ آ آ ParseFdForCollection(raw_option,آ "--apk-fd=",آ &apks_fd_);
آ آ آ آ آ آ }آ elseآ ifآ (StartsWith(option,آ "--apk="))آ {
آ آ آ آ آ آ آ آ apk_files_.push_back(std::string(option.substr(strlen("--apk="))));
آ آ آ آ آ آ }آ 
آ آ آ آ آ آ ...
آ آ }
آ 
آ staticآ intآ profman(intآ argc,آ char**آ argv)آ {
آ آ ProfManآ profman;
آ آ //آ Parseآ arguments.آ Argumentآ mistakesآ willآ leadآ toآ exit(EXIT_FAILURE)آ inآ UsageError.
آ آ profman.ParseArgs(argc,آ argv);
آ آ //آ Initializeآ MemMapآ forآ ZipArchive::OpenFromFd.
آ آ MemMap::Init();آ 
آ آ ...
آ آ آ //آ Processآ profileآ informationآ andآ assessآ ifآ weآ needآ toآ doآ aآ profileآ guidedآ compilation.
آ آ //آ Thisآ operationآ involvesآ I/O.
آ آ returnآ profman.ProcessProfiles();
آ آ }
هڈ¯ن»¥çœ‹هˆ°وœ€هگژن¸€è،Œè°ƒç”¨هˆ°profmançڑ„ProcessProfilesو–¹و³•,ه®ƒé‡Œé‌¢è°ƒç”¨ن؛†ProfileAssistant.cpp#ProcessProfilesInternal [https://cs.android.com/android/platform/superproject/+/master:art/profman/profile_assistant.cc;l=30?q=ProcessProfilesInternal] ,و ¸ه؟ƒن»£ç په¦‚ن¸‹ï¼ڑ
ProfmanResult::ProcessingResultآ ProfileAssistant::ProcessProfilesInternal(
آ آ آ آ constآ std::vector<ScopedFlock>&آ profile_files,
آ آ آ آ constآ ScopedFlock&آ reference_profile_file,
آ آ آ آ constآ ProfileCompilationInfo::ProfileLoadFilterFn&آ filter_fn,
آ آ آ آ constآ Options&آ options)آ {
آ آ ProfileCompilationInfoآ info(options.IsBootImageMerge());
آ آ //و­¥éھ¤1ï¼ڑLoad the reference profile.
آ آ ifآ (!info.Load(reference_profile_file->Fd(),آ true,آ filter_fn))آ {
آ آ آ آ returnآ ProfmanResult::kErrorBadProfiles;
آ آ }
آ آ آ //آ Storeآ theآ currentآ stateآ ofآ theآ referenceآ profileآ beforeآ mergingآ withآ theآ currentآ profiles.
آ آ آ uint32_tآ number_of_methodsآ =آ info.GetNumberOfMethods();
آ آ آ uint32_tآ number_of_classesآ =آ info.GetNumberOfResolvedClasses();

آ آ //و­¥éھ¤2ï¼ڑMerge all current profiles.
آ آ forآ (size_tآ iآ =آ 0;آ iآ <آ profile_files.size();آ i++)آ {
آ آ آ آ ProfileCompilationInfoآ cur_info(options.IsBootImageMerge());
آ آ آ آ ifآ (!cur_info.Load(profile_files[i]->Fd(),آ /*merge_classes=*/آ true,آ filter_fn))آ {
آ آ آ آ آ آ returnآ ProfmanResult::kErrorBadProfiles;
آ آ آ آ }
آ آ آ آ ifآ (!info.MergeWith(cur_info))آ {
آ آ آ آ آ آ returnآ ProfmanResult::kErrorBadProfiles;
آ آ آ آ }
آ آ }
آ آ //آ ه¦‚و‍œو–°ه¢‍و–¹و³•/ç±»و²،وœ‰è¾¾هˆ°éکˆه€¼ï¼Œهˆ™è·³è؟‡
آ ifآ (((info.GetNumberOfMethods()آ -آ number_of_methods)آ <آ min_change_in_methods_for_compilation)آ 
آ آ آ آ آ &&آ ((info.GetNumberOfResolvedClasses()آ -آ number_of_classes)آ <آ min_change_in_classes_for_compilation))آ {
آ آ آ آ آ آ returnآ kSkipCompilation;
آ آ آ }
آ آ ...
آ آ آ آ //و­¥éھ¤3ï¼ڑWe were successful in merging all profile information. Update the reference profile.
آ آ ...
آ آ ifآ (!info.Save(reference_profile_file->Fd()))آ {
آ آ آ آ returnآ ProfmanResult::kErrorIO;
آ آ }آ آ 
آ آ returnآ options.IsForceMerge()آ ?آ ProfmanResult::kSuccessآ :آ ProfmanResult::kCompile;
}

è؟™é‡Œé¦–ه…ˆé€ڑè؟‡ProfileCompilationInfoçڑ„loadو–¹و³•,读هڈ–reference_profileن؛Œè؟›هˆ¶و–‡ن»¶ه؛ڈهˆ—هŒ–هٹ è½½هˆ°ه†…ه­کم€‚ه†چ调用MergeWithو–¹و³•ه°†cur_profileن؛Œè؟›هˆ¶و–‡ن»¶ï¼ˆن¹ںه°±وک¯apkه†…çڑ„baseline.prof)هگˆه¹¶هˆ°reference_profileو–‡ن»¶ن¸­ï¼Œوœ€هگژ调用Saveو–¹و³•ن؟‌ه­کم€‚

ه†چو‌¥çœ‹ن¸‹ProfileCompilationInfoçڑ„类结و‍„,هڈ¯ن»¥هڈ‘çژ°ن¸ژه‰چé‌¢ç¼–译وœںه¤„çگ†وڈگهˆ°çڑ„ArtProfileه؛ڈهˆ—هŒ–و ¼ه¼ڈوک¯ن¸€è‡´çڑ„م€‚

هڈ‚考链وژ¥ï¼ڑhttps://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:profgen/profgen/src/main/kotlin/com/android/tools/profgen/ArtProfileSerializer.kt

//art/libprofile/profile/profile_compilation_info.h
/**
آ *آ Profileآ informationآ inآ aآ formatآ suitableآ toآ beآ queriedآ byآ theآ compilerآ and
آ *آ performingآ profileآ guidedآ compilation.
آ *آ Itآ isآ aآ serialize-friendlyآ formatآ basedآ onآ informationآ collectedآ byآ the
آ *آ interpreterآ (ProfileInfo).
آ *آ Currentlyآ itآ storesآ onlyآ theآ hotآ compiledآ methods.
آ */
classآ ProfileCompilationInfoآ {
آ public:
آ آ staticآ constآ uint8_tآ kProfileMagic[];
آ آ staticآ constآ uint8_tآ kProfileVersion[];
آ آ staticآ constآ uint8_tآ kProfileVersionForBootImage[];
آ آ staticآ constآ charآ kDexMetadataProfileEntry[];

آ آ staticآ constexprآ size_tآ kProfileVersionSizeآ =آ 4;
آ آ staticآ constexprآ uint8_tآ kIndividualInlineCacheSizeآ =آ 5;
آ آ ...
آ }آ 

dexن¼کهŒ–

هˆ†و‍گه®Œprofن؛Œè؟›هˆ¶و–‡ن»¶ه¤„çگ†وµپ程ن¹‹هگژ,وژ¥ç‌€ه†چو‌¥çœ‹dexن¼کهŒ–部هˆ†م€‚ن¸»è¦پوµپ程ه¦‚ن¸‹ه›¾و‰€ç¤؛ï¼ڑ

dexن¼کهŒ–çڑ„ه…¥هڈ£ه‡½و•° PackageDexOptimizer.java#performDexOptLI ,è·ںè¸ھن»£ç پهڈ¯ن»¥هڈ‘çژ°وœ€ç»ˆوک¯é€ڑè؟‡è°ƒç”¨dex2oatن؛Œè؟›هˆ¶ç¨‹ه؛ڈï¼ڑ
//dexopt.cpp
intآ dexopt(constآ char*آ dex_path,آ uid_tآ uid,آ constآ char*آ pkgname,آ constآ char*آ instruction_set,
آ آ آ آ آ آ آ آ intآ dexopt_needed,آ constآ char*آ oat_dir,آ intآ dexopt_flags,آ constآ char*آ compiler_filter,
آ آ آ آ آ آ آ آ constآ char*آ volume_uuid,آ constآ char*آ class_loader_context,آ constآ char*آ se_info,
آ آ آ آ آ آ آ آ boolآ downgrade,آ intآ target_sdk_version,آ constآ char*آ profile_name,
آ آ آ آ آ آ آ آ constآ char*آ dex_metadata_path,آ constآ char*آ compilation_reason,آ std::string*آ error_msg,
آ آ آ آ آ آ آ آ /*آ outآ */آ bool*آ completed)آ {
آ آ آ آ ...آ آ آ آ 
آ آ آ آ RunDex2Oatآ runner(dex2oat_bin,آ execv_helper.get());
آ آ آ آ runner.Initialize(...);

آ آ آ آ boolآ cancelledآ =آ false;
آ آ آ آ pid_tآ pidآ =آ dexopt_status_->check_cancellation_and_fork(&cancelled);
آ آ آ آ ifآ (cancelled)آ {
آ آ آ آ آ آ آ آ *completedآ =آ false;
آ آ آ آ آ آ آ آ returnآ 0;
آ آ آ آ }
آ آ آ آ ifآ (pidآ ==آ 0)آ {
آ آ آ آ آ آ آ آ //设置schedpolicy,设置ن¸؛هگژهڈ°ç؛؟程
آ آ آ آ آ آ آ آ SetDex2OatScheduling(boot_complete);
آ آ آ آ آ آ آ آ //و‰§è،Œdex2oatه‘½ن»¤
آ آ آ آ آ آ آ آ runner.Exec(DexoptReturnCodes::kDex2oatExec);
آ آ آ آ }آ elseآ {
آ آ آ آ آ آ آ آ //父è؟›ç¨‹ç­‰ه¾…dex2oatه­گè؟›ç¨‹و‰§è،Œه®Œ,è¶…و—¶و—¶é—´9.5هˆ†é’ں.
آ آ آ آ آ آ آ آ intآ resآ =آ wait_child_with_timeout(pid,آ kLongTimeoutMs);
آ آ آ آ آ آ آ آ ifآ (resآ ==آ 0)آ {
آ آ آ آ آ آ آ آ آ آ آ آ LOG(VERBOSE)آ <<آ "DexInv:آ ---آ ENDآ '"آ <<آ dex_pathآ <<آ "'آ (success)آ ---";
آ آ آ آ آ آ آ آ }آ elseآ {
آ آ آ آ آ آ آ آ آ آ آ آ //dex2oatو‰§è،Œه¤±è´¥
آ آ آ آ آ آ آ آ }
آ آ آ آ }
آ آ آ آ //آ dex2oatآ ranآ successfully,آ soآ profileآ isآ safeآ toآ keep.
آ آ آ آ reference_profile.DisableCleanup();
آ آ آ آ returnآ 0;
}

ه®‍é™…ن¸ٹوک¯و‰§è،Œن؛†ه¦‚ن¸‹ه‘½ن»¤ï¼ڑ

/apex/com.android.runtime/bin/dex2oatآ \
--input-vdex-fd=-1آ --output-vdex-fd=11آ \
--resolve-startup-const-strings=trueآ \
--max-image-block-size=524288آ --compiler-filter=speed-profileآ --profile-file-fd=14آ \
--classpath-dir=/data/app/com.ss.android.article.video-4-JZaMrtO7n_kFe4kbhBBA==آ \
--class-loader-context=PCL[]{PCL[/system/framework/org.apache.http.legacy.jar]}آ \
--generate-mini-debug-infoآ --compact-dex-level=noneآ --dm-fd=15آ \
--compilation-reason=install-dm

ه¸¸è§„ه®‰è£…و—¶ن¸چن¼ڑه¸¦ن¸ٹdm-fdه’Œinstall-dmهڈ‚و•°ï¼Œو‰€ن»¥ن¸چن¼ڑ触هڈ‘baseline profile相ه…³ن¼کهŒ–م€‚

dex2oat用ن؛ژه°†dexه­—èٹ‚ç پ编译وˆگوœ¬هœ°وœ؛ه™¨ç پ,相ه…³çڑ„编译وµپ程ه¦‚ن¸‹ن»£ç پï¼ڑ


staticآ dex2oat::ReturnCodeآ Dex2oat(intآ argc,آ char**آ argv)آ {
آ آ TimingLoggerآ timings("compiler",آ false,آ false);
آ آ //آ è§£و‍گهڈ‚و•°
آ آ dex2oat->ParseArgs(argc,آ argv);
آ آ art::MemMap::Init();آ 
آ آ //آ هٹ è½½profile热点و–¹و³•و–‡ن»¶
آ آ ifآ (dex2oat->HasProfileInput())آ {
آ آ آ آ ifآ (!dex2oat->LoadProfile())آ {
آ آ آ آ آ آ returnآ dex2oat::ReturnCode::kOther;
آ آ آ آ }
آ آ }
آ آ //و‰“ه¼€è¾“ه…¥و–‡ن»¶
آ آ dex2oat->OpenFile();
آ آ //ه‡†ه¤‡de2oatçژ¯ه¢ƒï¼ŒهŒ…و‹¬هگ¯هٹ¨runtimeم€پهٹ è½½bootآ classآ path
آ آ dex2oat::ReturnCodeآ setup_codeآ =آ dex2oat->Setup();

آ آ آ //و£€وں¥profile热点و–¹و³•وک¯هگ¦è¢«هٹ è½½هˆ°ه†…ه­ک,ه¹¶هپڑcrcو ،éھŒ
آ آ ifآ (dex2oat->DoProfileGuidedOptimizations())آ {آ 
آ آ آ آ //و ،éھŒprofile_compilation_info_ن¸­dexçڑ„crcن¸ژapkن¸­dexçڑ„crcوک¯هگ¦ن¸€è‡´
آ آ آ آ dex2oat->VerifyProfileData();
آ آ }
آ آ ...آ آ 
آ آ //و­£ه¼ڈه¼€ه§‹ç¼–译
آ آ dex2oat::ReturnCodeآ resultآ =آ DoCompilation(*dex2oat);
آ آ ...آ آ 
آ آ returnآ result;
}

è؟™ن¸ھوµپ程هŒ…هگ«ï¼ڑ

  • è§£و‍گه‘½ن»¤è،Œن¼ ه…¥çڑ„هڈ‚و•°
  • 调用LoadProfile()هٹ è½½profile热点و–¹و³•و–‡ن»¶ï¼Œن؟‌ه­کهˆ°profile_compilation_info_وˆگه‘کهڈکé‡ڈن¸­
  • ه‡†ه¤‡dex2oatçژ¯ه¢ƒï¼ŒهŒ…و‹¬هگ¯هٹ¨unstarted runtimeم€پهٹ è½½boot class path
  • profile相ه…³و ،éھŒï¼Œن¸»è¦پو£€وں¥profile_compilation_info_ن¸­çڑ„dexçڑ„crcن¸ژapkن¸­dexçڑ„crcوک¯هگ¦ن¸€è‡´ï¼Œو–¹و³•و•°وک¯هگ¦ن¸€è‡´
  • 调用DoCompilationو­£ه¼ڈه¼€ه§‹ç¼–译

LoadProfileو–¹و³•هٹ è½½profile热点و–¹و³•و–‡ن»¶ه¦‚ن¸‹ن»£ç پï¼ڑ

boolآ LoadProfile()آ {
آ آ آ آ //هˆ‌ه§‹هŒ–profile热点و–¹و³•çڑ„ه†…ه­که¯¹è±،ï¼ڑprofile_compilation_info_
آ آ آ آ profile_compilation_info_.reset(newآ ProfileCompilationInfo());

آ آ آ آ //读هڈ–referenceآ profileو–‡ن»¶هˆ—è،¨
آ آ آ آ //آ Dex2oatآ onlyآ usesآ theآ referenceآ profileآ andآ thatآ isآ notآ updatedآ concurrentlyآ byآ theآ appآ or
آ آ آ آ //آ otherآ processes.آ Soآ weآ don'tآ needآ toآ lockآ (asآ weآ haveآ toآ doآ inآ profmanآ orآ whenآ writingآ the
آ آ آ آ //آ profileآ info).
آ آ آ آ std::vector<std::unique_ptr<File>>آ profile_files;
آ آ آ آ ifآ (!profile_file_fds_.empty())آ {
آ آ آ آ آ آ forآ (intآ fdآ :آ profile_file_fds_)آ {
آ آ آ آ آ آ آ آ profile_files.push_back(std::make_unique<File>(DupCloexec(fd)));
آ آ آ آ آ آ }
آ آ آ آ }آ 
آ آ آ آ ...
آ آ آ آ //ن¾‌و¬،هٹ è½½هˆ°profile_compilation_info_ن¸­
آ آ آ آ forآ (constآ std::unique_ptr<File>&آ profile_fileآ :آ profile_files)آ {
آ آ آ آ آ آ ifآ (!profile_compilation_info_->Load(profile_file->Fd()))آ {
آ آ آ آ آ آ آ آ returnآ false;
آ آ آ آ آ آ }
آ آ آ آ }
آ آ آ آ returnآ true;
آ آ }

LoadProfileو–¹و³•,ه°†ن¹‹ه‰چç”ںوˆگçڑ„profileو–‡ن»¶هٹ è½½هˆ°ه†…ه­ک,ن؟‌ه­کهˆ°profile_compilation_info_هڈکé‡ڈن¸­م€‚

وژ¥ç‌€è°ƒç”¨Compileو–¹و³•ه®Œوˆگodexو–‡ن»¶çڑ„编译ç”ںوˆگ,ه¦‚ن¸‹ن»£ç پï¼ڑ

آ //آ Setآ upآ andآ createآ theآ compilerآ driverآ andآ thenآ invokeآ itآ toآ compileآ allآ theآ dexآ files.
آ آ jobjectآ Compile()آ REQUIRES(!Locks::mutator_lock_)آ {
آ آ آ آ ClassLinker*آ constآ class_linkerآ =آ Runtime::Current()->GetClassLinker();
آ آ آ آ 
آ آ آ آ TimingLogger::ScopedTimingآ t("dex2oatآ Compile",آ timings_);
آ آ آ آ ...
آ آ آ آ compiler_options_->profile_compilation_info_آ =آ profile_compilation_info_.get();

آ آ آ آ driver_.reset(newآ CompilerDriver(compiler_options_.get(),
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ verification_results_.get(),
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ compiler_kind_,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ thread_count_,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ swap_fd_));
آ آ آ آ driver_->PrepareDexFilesForOatFile(timings_);
آ آ آ آ returnآ CompileDexFiles(dex_files);
آ آ }

profile_compilation_info_ن½œن¸؛هڈ‚و•°ن¼ ç»™ن؛†CompilerDriver,هœ¨ن¹‹هگژçڑ„编译è؟‡ç¨‹ن¸­ه°†ç”¨و‌¥هˆ¤و–­وک¯هگ¦ç¼–译وںگن¸ھو–¹و³•ه’Œوœ؛ه™¨ç پé‡چوژ’م€‚

CompilerDriver::Compileو–¹و³•ه¼€ه§‹ç¼–译dexه­—èٹ‚ç پ,ن»£ç په¦‚ن¸‹ï¼ڑ

voidآ CompilerDriver::Compile(jobjectآ class_loader,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ constآ std::vector<constآ DexFile*>&آ dex_files,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ TimingLogger*آ timings)آ {
آ آ forآ (constآ DexFile*آ dex_fileآ :آ dex_files)آ {
آ آ آ آ CompileDexFile(this,class_loader,*dex_file,dex_files,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ "Compileآ Dexآ Fileآ Quick",CompileMethodQuick);
آ آ }
}

staticآ voidآ CompileMethodQuick(...)آ {
آ آ autoآ quick_fnآ =آ [profile_index](...)آ {
آ آ آ آ CompiledMethod*آ compiled_methodآ =آ nullptr;
آ آ آ آ ifآ ((access_flagsآ &آ kAccNative)آ !=آ 0)آ {
آ آ آ آ آ آ آ آ //jniو–¹و³•编译...
آ آ آ آ }آ elseآ ifآ ((access_flagsآ &آ kAccAbstract)آ !=آ 0)آ {
آ آ آ آ آ آ //آ Abstractآ methodsآ don'tآ haveآ code.
آ آ آ آ }آ elseآ ifآ (annotations::MethodIsNeverCompile(dex_file,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ dex_file.GetClassDef(class_def_idx),
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ method_idx))آ {
آ آ آ آ آ آ //آ Methodآ isآ annotatedآ withآ @NeverCompileآ andآ shouldآ notآ beآ compiled.
آ آ آ آ }آ elseآ {
آ آ آ آ آ آ constآ CompilerOptions&آ compiler_optionsآ =آ driver->GetCompilerOptions();
آ آ آ آ آ آ constآ VerificationResults*آ resultsآ =آ driver->GetVerificationResults();
آ آ آ آ آ آ MethodReferenceآ method_ref(&dex_file,آ method_idx);
آ آ آ آ آ آ //آ Don'tآ compileآ classآ initializersآ unlessآ kEverything.
آ آ آ آ آ آ boolآ compileآ =آ (compiler_options.GetCompilerFilter()آ ==آ CompilerFilter::kEverything)آ ||
آ آ آ آ آ آ آ آ آ ((access_flagsآ &آ kAccConstructor)آ ==آ 0)آ ||آ ((access_flagsآ &آ kAccStatic)آ ==آ 0);
آ آ آ آ آ آ //آ Checkآ ifآ it'sآ anآ uncompilableآ methodآ foundآ byآ theآ verifier.
آ آ آ آ آ آ compileآ =آ compileآ &&آ !results->IsUncompilableMethod(method_ref);
آ آ آ آ آ آ //آ Checkآ ifآ weآ shouldآ compileآ basedآ onآ theآ profile.
آ آ آ آ آ آ compileآ =آ compileآ &&آ ShouldCompileBasedOnProfile(compiler_options,آ profile_index,آ method_ref);
آ آ آ آ آ آ ifآ (compile)آ {
آ آ آ آ آ آ آ آ compiled_methodآ =آ driver->GetCompiler()->Compile(...);
آ آ آ آ آ آ }
آ آ آ آ }
آ آ آ آ returnآ compiled_method;
آ آ };
آ آ CompileMethodHarness(self,driver,code_item,access_flags,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ invoke_type,class_def_idx,class_loader,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ dex_file,dex_cache,quick_fn);
}

هœ¨CompileMethodQuickو–¹و³•ن¸­هڈ¯ن»¥çœ‹هˆ°é’ˆه¯¹ن¸چهگŒçڑ„و–¹و³•(jniو–¹و³•م€پè™ڑو–¹و³•م€پو‍„造ه‡½و•°ç­‰ï¼‰وœ‰ن¸چهگŒçڑ„ه¤„çگ†و–¹ه¼ڈ,ه¸¸è§„و–¹و³•ن¼ڑé€ڑè؟‡ShouldCompileBasedOnProfileو‌¥هˆ¤و–­وںگن¸ھmethodوک¯هگ¦éœ€è¦پ被编译م€‚

ه…·ن½“هˆ¤و–­و‌،ن»¶ه¦‚ن¸‹ï¼ڑ

//آ Checksآ whetherآ profileآ guidedآ compilationآ isآ enabledآ andآ ifآ theآ methodآ shouldآ beآ compiled
//آ accordingآ toآ theآ profileآ file.
staticآ boolآ ShouldCompileBasedOnProfile(constآ CompilerOptions&آ compiler_options,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ ProfileCompilationInfo::ProfileIndexTypeآ profile_index,
آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ آ MethodReferenceآ method_ref)آ {
آ آ ifآ (profile_indexآ ==آ ProfileCompilationInfo::MaxProfileIndex())آ {
آ آ آ آ //آ Noآ profileآ forآ thisآ dexآ file.آ Checkآ ifآ we'reآ actuallyآ compilingآ basedآ onآ aآ profile.
آ آ آ آ ifآ (!CompilerFilter::DependsOnProfile(compiler_options.GetCompilerFilter()))آ {
آ آ آ آ آ آ returnآ true;
آ آ آ آ }
آ آ آ آ //آ Profile-basedآ compilationآ withoutآ profileآ forآ thisآ dexآ file.آ Doآ notآ compileآ theآ method.
آ آ آ آ returnآ false;
آ آ }آ elseآ {
آ آ آ آ constآ ProfileCompilationInfo*آ profile_compilation_infoآ =
آ آ آ آ آ آ آ آ compiler_options.GetProfileCompilationInfo();

آ آ آ آ //آ Compileآ onlyآ hotآ methods,آ itآ isآ theآ profileآ saver'sآ jobآ toآ decide
آ آ آ آ //آ whatآ startupآ methodsآ toآ markآ asآ hot.
آ آ آ آ boolآ resultآ =آ profile_compilation_info->IsHotMethod(profile_index,آ method_ref.index);
آ آ آ ifآ (kDebugProfileGuidedCompilation)آ {
آ آ آ آ آ آ LOG(INFO)آ <<آ "[ProfileGuidedCompilation]آ "
آ آ آ آ آ آ آ آ آ آ <<آ (resultآ ?آ "Compiled"آ :آ "Skipped")آ <<آ "آ method:"آ <<آ method_ref.PrettyMethod(true);
آ آ آ آ }
آ آ آ آ returnآ result;
آ آ }
}

هڈ¯ن»¥çœ‹هˆ°وک¯ن¾‌وچ®profile_compilation_info_وک¯هگ¦ه‘½ن¸­hotmethodو‌¥هˆ¤و–­م€‚وˆ‘ن»¬وٹٹ编译و—¥ه؟—و‰“ه¼€ï¼Œهڈ¯ن»¥çœ‹هˆ°ه…·ن½“ه“ھن؛›و–¹و³•被编译,ه“ھن؛›و–¹و³•被跳è؟‡ï¼Œه¦‚ن¸‹ه›¾و‰€ç¤؛,è؟™ن¸ژوˆ‘ن»¬é…چç½®çڑ„profileوک¯ن¸€è‡´çڑ„م€‚

وœ؛ه™¨ç پç”ںوˆگçڑ„ه®‍çژ°هœ¨CodeGeneratorç±»ن¸­ï¼Œن»£ç په¦‚ن¸‹ï¼Œه…·ن½“细èٹ‚ه°†ن¸چه†چه±•ه¼€م€‚

//art/compiler/optimizing/code_generator.cc
voidآ CodeGenerator::Compile(CodeAllocator*آ allocator)آ {
آ آ InitializeCodeGenerationData();
آ آ HGraphVisitor*آ instruction_visitorآ =آ GetInstructionVisitor();
آ آ GetStackMapStream()->BeginMethod(...);

آ آ size_tآ frame_startآ =آ GetAssembler()->CodeSize();
آ آ GenerateFrameEntry();
آ آ ifآ (disasm_info_آ !=آ nullptr)آ {
آ آ آ آ disasm_info_->SetFrameEntryInterval(frame_start,آ GetAssembler()->CodeSize());
آ آ }

آ آ forآ (size_tآ eآ =آ block_order_->size();آ current_block_index_آ <آ e;آ ++current_block_index_)آ {
آ آ آ آ HBasicBlock*آ blockآ =آ (*block_order_)[current_block_index_];
آ آ آ آ Bind(block);
آ آ آ آ MaybeRecordNativeDebugInfo(/*آ instruction=آ */آ nullptr,آ block->GetDexPc());
آ آ آ آ forآ (HInstructionIteratorآ it(block->GetInstructions());آ !it.Done();آ it.Advance())آ {
آ آ آ آ آ آ HInstruction*آ currentآ =آ it.Current();
آ آ آ آ آ آ DisassemblyScopeآ disassembly_scope(current,آ *this);
آ آ آ آ آ آ current->Accept(instruction_visitor);
آ آ آ آ }
آ آ }
آ آ GenerateSlowPaths();
آ آ ifآ (graph_->HasTryCatch())آ {
آ آ آ آ RecordCatchBlockInfo();
آ آ }
آ آ //آ Finalizeآ instructionsآ inآ assember;
آ آ Finalize(allocator);
آ آ GetStackMapStream()->EndMethod(GetAssembler()->CodeSize());
}

هڈ¦ه¤–,profile_compilation_info_ن¹ںن¼ڑه½±ه“چوœ؛ه™¨ç پé‡چوژ’,وˆ‘ن»¬çں¥éپ“ç³»ç»ںهœ¨é€ڑè؟‡IOهٹ è½½و–‡ن»¶çڑ„و—¶ه€™ï¼Œن¸€èˆ¬éƒ½وک¯وŒ‰é،µç»´ه؛¦و‌¥هٹ è½½çڑ„(ن¸€èˆ¬ç­‰ن؛ژ4KB),热点ن»£ç پé‡چوژ’هœ¨ن¸€èµ·ï¼Œهڈ¯ن»¥ه‡ڈه°‘IO读هڈ–çڑ„و¬،و•°ï¼Œن»ژ而وڈگهچ‡و€§èƒ½م€‚

odexو–‡ن»¶çڑ„وœ؛ه™¨ç په¸ƒه±€éƒ¨هˆ†ç”± OatWriter ç±»ه®‍çژ°ï¼Œه£°وکژن»£ç په¦‚ن¸‹ï¼ڑ
آ classآ OatWriterآ {
آ public:
آ آ OatWriter(constآ CompilerOptions&آ compiler_options,
آ آ آ آ آ آ آ آ آ آ آ آ constآ VerificationResults*آ verification_results,
آ آ آ آ آ آ آ آ آ آ آ آ TimingLogger*آ timings,
آ آ آ آ آ آ آ آ آ آ آ آ ProfileCompilationInfo*آ info,
آ آ آ آ آ آ آ آ آ آ آ آ CompactDexLevelآ compact_dex_level);
آ آ ...آ آ آ آ آ آ آ آ آ آ 
آ آ //آ Profileآ infoآ usedآ toآ generateآ newآ layoutآ ofآ files.
آ آ ProfileCompilationInfo*آ profile_compilation_info_;

آ آ //آ Compactآ dexآ levelآ thatآ isآ generated.
آ آ CompactDexLevelآ compact_dex_level_;
آ آ usingآ OrderedMethodListآ =آ std::vector<OrderedMethodData>;
آ آ ...
ن»ژن¸­هڈ¯ن»¥çœ‹هˆ°profile_compilation_info_ن¼ڑ被 OatWriter 类用هˆ°ï¼Œç”¨ن؛ژç”ںوˆگodexوœ؛ه™¨ç پçڑ„ه¸ƒه±€م€‚

ه…·ن½“ن»£ç په¦‚ن¸‹ï¼ڑ


//آ Visitآ everyآ compiledآ methodآ inآ orderآ toآ determineآ itsآ orderآ withinآ theآ OATآ file.
//آ Methodsآ fromآ theآ sameآ classآ doآ notآ needآ toآ beآ adjacentآ inآ theآ OATآ code.
classآ OatWriter::LayoutCodeMethodVisitorآ finalآ :آ publicآ OatDexMethodVisitorآ {
آ public:
آ آ LayoutCodeMethodVisitor(OatWriter*آ writer,آ size_tآ offset)
آ آ آ آ آ آ :آ OatDexMethodVisitor(writer,آ offset),
آ آ آ آ آ آ آ آ profile_index_(ProfileCompilationInfo::MaxProfileIndex()),
آ آ آ آ آ آ آ آ profile_index_dex_file_(nullptr)آ {
آ آ }

آ آ boolآ StartClass(constآ DexFile*آ dex_file,آ size_tآ class_def_index)آ finalآ {
آ آ آ آ //آ Updateآ theآ cachedآ `profile_index_`آ ifآ needed.آ Thisآ happensآ onlyآ onceآ perآ dexآ file
آ آ آ آ //آ becauseآ weآ visitآ allآ classesآ inآ aآ dexآ fileآ together,آ soآ markآ thatآ asآ `UNLIKELY`.
آ آ آ آ ifآ (UNLIKELY(dex_fileآ !=آ profile_index_dex_file_))آ {
آ آ آ آ آ آ ifآ (writer_->profile_compilation_info_آ !=آ nullptr)آ {
آ آ آ آ آ آ آ آ profile_index_آ =آ writer_->profile_compilation_info_->FindDexFile(*dex_file);
آ آ آ آ آ آ }
آ آ آ آ آ آ profile_index_dex_file_آ =آ dex_file;
آ آ آ آ }
آ آ آ آ returnآ OatDexMethodVisitor::StartClass(dex_file,آ class_def_index);
آ آ }

آ آ boolآ VisitMethod(size_tآ class_def_method_index,آ constآ ClassAccessor::Method&آ method){
آ آ آ آ OatClass*آ oat_classآ =آ &writer_->oat_classes_[oat_class_index_];
آ آ آ آ CompiledMethod*آ compiled_methodآ =آ oat_class->GetCompiledMethod(class_def_method_index);

آ آ آ آ ifآ (HasCompiledCode(compiled_method))آ {
آ آ آ آ آ آ //آ Determineآ theآ `hotness_bits`,آ usedآ toآ determineآ relativeآ order
آ آ آ آ آ آ //آ forآ OATآ codeآ layoutآ whenآ determiningآ binning.
آ آ آ آ آ آ uint32_tآ method_indexآ =آ method.GetIndex();
آ آ آ آ آ آ MethodReferenceآ method_ref(dex_file_,آ method_index);
آ آ آ آ آ آ uint32_tآ hotness_bitsآ =آ 0u;
آ آ آ آ آ آ ifآ (profile_index_آ !=آ ProfileCompilationInfo::MaxProfileIndex())آ {
آ آ آ آ آ آ آ آ ProfileCompilationInfo*آ pciآ =آ writer_->profile_compilation_info_;
آ آ آ آ آ آ آ آ //آ Note:آ Bin-to-binآ orderآ doesآ notآ matter.آ Ifآ theآ kernelآ doesآ orآ doesآ notآ read-ahead
آ آ آ آ آ آ آ آ //آ anyآ memory,آ itآ onlyآ goesآ intoآ theآ bufferآ cacheآ andآ doesآ notآ growآ theآ PSSآ untilآ the
آ آ آ آ آ آ آ آ //آ firstآ timeآ thatآ memoryآ isآ referencedآ inآ theآ process.
آ آ آ آ آ آ آ آ hotness_bitsآ =
آ آ آ آ آ آ آ آ آ آ آ آ (pci->IsHotMethod(profile_index_,آ method_index)آ ?آ kHotBitآ :آ 0u)آ |
آ آ آ آ آ آ آ آ آ آ آ آ (pci->IsStartupMethod(profile_index_,آ method_index)آ ?آ kStartupBitآ :آ 0u)آ 
آ آ آ آ آ آ آ آ }
آ آ آ آ آ آ }

آ آ آ آ آ آ OrderedMethodDataآ method_dataآ =آ {hotness_bits,oat_class,compiled_method,method_ref,...};
آ آ آ آ آ آ ordered_methods_.push_back(method_data);
آ آ آ آ }
آ آ آ آ returnآ true;
آ آ }

هœ¨LayoutCodeMethodVisitorç±»ن¸­ï¼Œو ¹وچ®profile_compilation_info_وŒ‡ه®ڑçڑ„热点و–¹و³•çڑ„FLAG,هˆ¤و–­وک¯هگ¦و‰“ه¼€hotness_bitsو ‡ه؟—ن½چم€‚热点و–¹و³•ن¼ڑن¸€èµ·è¢«é‡چوژ’هœ¨odexو–‡ن»¶é‌ ه‰چçڑ„ن½چç½®م€‚

ه°ڈ结ن¸€ن¸‹ï¼Œهœ¨ç³»ç»ںه®‰è£…appéک¶و®µï¼Œن¼ڑ读هڈ–apkن¸­baselineprofileو–‡ن»¶ï¼Œç»ڈè؟‡porfmanو ¹وچ®ه½“ه‰چç³»ç»ں版وœ¬هپڑن¸€ه®ڑ转وچ¢ه¹¶ه؛ڈهˆ—هŒ–هˆ°وœ¬هœ°çڑ„reference_profileè·¯ه¾„ن¸‹ï¼Œه†چé€ڑè؟‡dexoat编译热点و–¹و³•ن¸؛وœ¬هœ°وœ؛ه™¨ç په¹¶é€ڑè؟‡ن»£ç پé‡چوژ’وڈگهچ‡و€§èƒ½م€‚

هژ‚ه•†هگˆن½œ

Baseline Profileه®‰è£…و—¶ن¼کهŒ–需è¦پGoogle Playو”¯وŒپ,ن½†ه›½ه†…و‰‹وœ؛ç”±ن؛ژو²،وœ‰Google Play,و— و³•هœ¨ه®‰è£…وœںهپڑه®‍çژ°ن¼کهŒ–و•ˆو‍œم€‚ن¸؛و­¤ï¼Œوˆ‘ن»¬هچڈهگŒوٹ–éں³ن¸ژه°ڈç±³م€پهچژن¸؛ç­‰ن¸»وµپهژ‚ه•†ه»؛ç«‹ن؛†هگˆن½œï¼Œه…±هگŒوژ¨è؟›Baseline Profileه®‰è£…و—¶ن¼کهŒ–هœ¨ه›½ه†…çژ¯ه¢ƒçڑ„èگ½هœ°م€‚ه…·ن½“çڑ„هگˆن½œو–¹ه¼ڈوک¯ï¼ڑ

  • وˆ‘ن»¬é€ڑè؟‡ç¼–译وœںو”¹é€ ï¼Œوڈگن¾›ه¸¦Baseline Profileçڑ„APKç»™هˆ°هژ‚ه•†éھŒè¯پèپ”è°ƒم€‚
  • هژ‚ه•†ه…·ن½“çڑ„ن¼کهŒ–ç­–ç•¥ن¼ڑ综هگˆè€ƒé‡ڈه®‰è£…و—¶é•؟م€پdex2oatو¶ˆè€—资و؛گوƒ…ه†µè€Œه®ڑ,و¯”ه¦‚ه…ˆç”¨é»ک认策略ه®‰è£…apk,ه†چهگژهڈ°ه¼‚و­¥و‰§è،ŒBaseline Profile编译م€‚
  • وœ€هگژé€ڑè؟‡Googleوڈگن¾›çڑ„هˆ‌و­¥وک¾ç¤؛و‰€ç”¨و—¶é—´ (TTID) و‌¥éھŒè¯پن¼کهŒ–و•ˆو‍œï¼ˆTTIDوŒ‡و ‡ç”¨ن؛ژوµ‹é‡ڈه؛”用ç”ںوˆگ第ن¸€ه¸§و‰€ç”¨çڑ„و—¶é—´ï¼ŒهŒ…و‹¬è؟›ç¨‹هˆ‌ه§‹هŒ–م€پactivity هˆ›ه»؛ن»¥هڈٹوک¾ç¤؛第ن¸€ه¸§م€‚)

هڈ‚考链وژ¥

https://developer.android.com/topic/performance/vitals/launch-time?hl=zh-cn

هœ¨ن¸ژهژ‚ه•†èپ”è°ƒçڑ„è؟‡ç¨‹ن¸­ï¼Œوˆ‘ن»¬è§£ه†³ن؛†هگ„ç§چé—®é¢ک,ه…¶ن¸­هŒ…و‹¬وœ‰ن¸€ن¸ھ资و؛گهژ‹ç¼©و–¹ه¼ڈ错误م€‚ه…·ن½“错误ن؟،وپ¯ه¦‚ن¸‹ï¼ڑ

java.io.FileNotFoundException:آ 
Thisآ fileآ canآ notآ beآ openedآ asآ aآ fileآ descriptor;آ itآ isآ probablyآ compressed

هژںو‌¥ه®‰هچ“ç³»ç»ںè¦پو±‚apkه†…çڑ„baseline.profن؛Œè؟›هˆ¶وک¯ن¸چهژ‹ç¼©و ¼ه¼ڈçڑ„م€‚وˆ‘ن»¬هڈ¯ن»¥ç”¨unzip -vو‌¥و£€éھŒو–‡ن»¶وک¯هگ¦وœھ被هژ‹ç¼©ï¼ŒDeflو ‡ه؟—è،¨ç¤؛هژ‹ç¼©ï¼ŒStoredو ‡ه؟—è،¨ç¤؛وœھهژ‹ç¼©م€‚

وˆ‘ن»¬هڈ¯ن»¥هœ¨و‰“هŒ…وµپ程ن¸­وŒ‡ه®ڑه…¶ن¸؛STOREDو ¼ه¼ڈ,هچ³ن¸چهژ‹ç¼©م€‚

privateآ voidآ writeNoCompress(@NonNullآ JarEntryآ entry,آ @NonNullآ InputStreamآ from)آ throwsآ IOExceptionآ {
آ آ آ آ byte[]آ bytesآ =آ newآ byte[from.available()];
آ آ آ آ from.read(bytes);
آ آ آ آ entry.setMethod(JarEntry.STORED);
آ آ آ آ entry.setSize(bytes.length);
آ آ آ آ CRC32آ crc32آ =آ newآ CRC32();
آ آ آ آ crc32.update(bytes,0,bytes.length);
آ آ آ آ entry.setCrc(crc32.getValue());

آ آ آ آ setEntryAttributes(entry);
آ آ آ آ jarOutputStream.putNextEntry(entry);
آ آ آ آ jarOutputStream.write(bytes,آ 0,آ bytes.length);
آ آ آ آ jarOutputStream.closeEntry();
}

و”¹ه®Œن¹‹هگژوˆ‘ن»¬ه†چو£€وں¥ن¸€ن¸‹و–‡ن»¶وک¯هگ¦è¢«هژ‹ç¼©م€‚

baseline.profن؛Œè؟›هˆ¶وک¯ن¸چهژ‹ç¼©ه¯¹هŒ…ن½“积ه½±ه“چو¯”较ه°ڈ,ه› ن¸؛è؟™ن¸ھو–‡ن»¶ه¤§éƒ¨هˆ†éƒ½وک¯intç±»ه‍‹çڑ„methodidم€‚ç»ڈوµ‹è¯•,7ن¸‡+热点و–¹و³•و–‡ن»¶ï¼Œç”ںوˆگbaseline.profن؛Œè؟›هˆ¶و–‡ن»¶62KB,هژ‹ç¼©çژ‡هڈھوœ‰0.1%ï¼›ه¦‚و‍œé€ڑè؟‡é€ڑé…چ符é…چ置,هژ‹ç¼©çژ‡هœ¨5%ه·¦هڈ³م€‚

ن¸€èˆ¬ه؛”用ه•†ه؛—ن¸‹è½½ه®‰è£…هŒ…و—¶هœ¨ç½‘络ن¼ è¾“è؟‡ç¨‹ن¸­هپڑن؛†ï¼ˆهژ‹ç¼©ï¼‰ https://zh.wikipedia.org/wiki/HTTP%E5%8E%8B%E7%BC%A9 ه¤„çگ†ï¼Œè؟™ç§چوƒ…ه†µن¸چهژ‹ç¼©ه¤„çگ†هں؛وœ¬ن¸چه½±ه“چهŒ…ه¤§ه°ڈ,هگŒو—¶ن¸چهژ‹ç¼©ه¤„çگ†ن¹ں能éپ؟ه…چè§£هژ‹ç¼©ه¸¦و‌¥çڑ„耗و—¶م€‚

ن¼کهŒ–و•ˆو‍œ

هœ¨è‡ھوµ‹ن¸­ï¼Œوˆ‘ن»¬هڈ¯ن»¥é€ڑè؟‡ن¸‹é‌¢çڑ„و–¹ه¼ڈé€ڑè؟‡ install-multiple ه‘½ن»¤ه®‰è£…APKم€‚
#آ Unzipآ theآ Releaseآ APKآ first
unzipآ release.apk
#آ Createآ aآ ZIPآ archive
cpآ assets/dexopt/baseline.profآ primary.prof
cpآ assets/dexopt/baseline.profmآ primary.profm
#آ Createآ anآ archive
zipآ -rآ release.dmآ primary.profآ primary.profm
#آ Installآ APKآ +آ Profileآ together
adbآ install-multipleآ release.apkآ release.dm

هœ¨هژ‚ه•†وµ‹è¯•ن¸­é€ڑè؟‡ن¸‹é‌¢çڑ„ه‘½ن»¤وµ‹è¯•ه†·هگ¯هٹ¨è€—و—¶

PACKAGE_NAME=com.ss.android.article.video
adbآ shellآ amآ start-activityآ -Wآ -nآ $PACKAGE_NAME/.SplashActivityآ |آ grepآ "TotalTime"
ه†·هگ¯هٹ¨Activity耗و—¶و¯”较 وœھن¼کهŒ– ه·²ن¼کهŒ– ن¼کهŒ–çژ‡
èچ£è€€Android11 950ms 884ms 6.9%
ه°ڈç±³Android13 821ms 720ms 12.3%
هڈ¯ن»¥çœ‹هˆ°ï¼Œهœ¨ه¼€هگ¯Baseline Profileن¼کهŒ–ن¹‹هگژ,首装ه†·هگ¯هٹ¨ï¼ˆ TTID )耗و—¶ه‡ڈه°‘ç؛¦10%ه·¦هڈ³ï¼Œن¸؛و–°ç”¨وˆ·çڑ„هگ¯هٹ¨é€ںه؛¦ن½“éھŒه¸¦و‌¥ن؛†و‍په¤§çڑ„وڈگهچ‡م€‚

هڈ‚考و–‡ç«

ه›¢éکںن»‹ç»چ

وˆ‘ن»¬وک¯ه­—èٹ‚è·³هٹ¨è¥؟瓜视频ه®¢وˆ·ç«¯ه›¢éکں,ن¸“و³¨ن؛ژè¥؟瓜视频 App çڑ„ه¼€هڈ‘ه’Œهں؛ç،€وٹ€وœ¯ه»؛设,هœ¨ه®¢وˆ·ç«¯و‍¶و‍„م€پو€§èƒ½م€پ稳ه®ڑو€§م€پ编译و‍„ه»؛م€پç ”هڈ‘ه·¥ه…·ç­‰و–¹هگ‘都وœ‰وٹ•ه…¥م€‚ه¦‚و‍œن½ ن¹ںوƒ³ن¸€èµ·و”»ه…‹وٹ€وœ¯éڑ¾é¢ک,è؟ژوژ¥و›´ه¤§çڑ„وٹ€وœ¯وŒ‘وˆک,و¬¢è؟ژ点ه‡»éک…读هژںو–‡ï¼Œوˆ–者وٹ•递简هژ†هˆ°[email protected]م€‚

وœ€ Nice çڑ„ه·¥ن½œو°›ه›´ه’Œوˆگé•؟وœ؛ن¼ڑ,ç¦ڈهˆ©ن¸ژوœ؛éپ‡ه¤ڑه¤ڑ,هœ¨هŒ—ن¸ٹو‌­ن¸‰هœ°ه‌‡وœ‰èپŒن½چ,و¬¢è؟ژهٹ ه…¥è¥؟瓜视频ه®¢وˆ·ç«¯ه›¢éکں ï¼پ

点ه‡»م€Œéک…读هژںو–‡م€چن¸€é”®وٹ•递ï¼پ