code小生 一个专注大前端领域的技术平台公众号回复Android加入安卓技术群

作者:Michaelbest1
链接:https://www.jianshu.com/p/5a7035ee99e6
声明:本文已获Michaelbest1授权发表,转发等请联系原作者授权

Android每个大版本都会对framework进行一定的重构,10.0也不例外。这次,谷歌把重构的对象瞄准了AMS。看过AMS代码的同学都知道,AcitivityManagerService.java是Android Framework里的一个超大文件。在Android 9.0里,AMS已经膨胀到28K+行。谷歌肯定是觉得不能忍了,于是对AMS进行了一定重构,目前10.0里AMS已经缩减到19K行了。相应的,为了配合AMS的重构,WMS也做了一些重构。本文就尝试从App启动过程作为一个切入点,来看看10.0上Framework都做了哪些相关的重构,并简单分析这些重构的原因。

注意:

  1. 本文假设读者对Android Framework有一定基础,特别是对App的启动过程有一定了解。如果对这个过程不太了解,可以先阅读相关文章,再来看10.0上的重构。

  2. 我会尝试分析每一个重构的原因。如果读者有更好的建议,非常欢迎交流!

重构1:引入ATMS(ActivityTaskManagerService),接管Activity生命周期相关接口的实现。

这是Android 10.0上AMS的最大重构。Android 10.0上,IActivityManager.aidl中的接口大部分都被移动到了IActivityTaskManagerService.aidl里,并在原接口处加上了UnsupportedAppUsage注解。这些接口就包含了我们启动Activity的重要接口startActivity:

// frameworks/base/core/java/android/app/IActivityManager.aidlinterface IActivityManager {    ...    @UnsupportedAppUsage    int startActivity(in IApplicationThread caller, in String callingPackage, in Intent intent,            in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode,            int flags, in ProfilerInfo profilerInfo, in Bundle options);            ...}

我们看到新的接口已经移动到了ActivityTaskManager.aidl里:

// frameworks/base/core/java/android/app/IActivityTaskManager.aidl79/**80 * System private API for talking with the activity task manager that handles how activities are81 * managed on screen.82 *83 * {@hide}84 */85interface IActivityTaskManager {86    int startActivity(in IApplicationThread caller, in String callingPackage, in Intent intent,87            in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode,88            int flags, in ProfilerInfo profilerInfo, in Bundle options);89    int startActivities(in IApplicationThread caller, in String callingPackage,90            in Intent[] intents, in String[] resolvedTypes, in IBinder resultTo,91            in Bundle options, int userId);

这个改动对一般开发者影响不大,因为正如注释所述,IActivityTaskManager的startActivity是系统私有API,系统内部调用的。开发者调用到的是Activity里的startActivity,并不会直接调用到ATMS的startActivity。真正调用ATMS的startActivity的地方就是以前调用AMS的地方:

// frameworks/base/core/java/android/app/Instrumentation.java1678    @UnsupportedAppUsage1679    public ActivityResult execStartActivity(1680            Context who, IBinder contextThread, IBinder token, Activity target,1681            Intent intent, int requestCode, Bundle options) {...1715            int result = ActivityTaskManager.getService()1716                .startActivity(whoThread, who.getBasePackageName(), intent,1717                        intent.resolveTypeIfNeeded(who.getContentResolver()),1718                        token, target != null ? target.mEmbeddedID : null,1719                        requestCode, 0, null, options);1720            checkStartActivityResult(result, intent);...}

这里1715行,原来调用的就是AMS的startActivity。

到这里,我们已经了解了App端ATMS相关的重构。可以看到App端的影响并不大,只不过把原来部分调用AMS的binder call调整到ATMS里,而且这个对开发者基本透明。

再来看看服务端有哪些改变。我们先来看看现在AMS里startActivity是怎么实现的:

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java3567    @Override3568    public int startActivity(IApplicationThread caller, String callingPackage,3569            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,3570            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {3571        return mActivityTaskManager.startActivity(caller, callingPackage, intent, resolvedType,3572                resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions);3573    }

这里的mActivityTaskManager正如其名所暗示的那样是ActivityTaskManagerService实例的引用。因此我们可以知道,AMS把Activity生命周期相关的实现都委托到ATMS里了。ATMS并没有持有AMS的引用,仅有一处调用了AMS的一个静态方法。这样的设计可以降低ATMS对AMS的依赖。可以看出谷歌在OO设计方面还是比较讲究的。ATMS里的startActivity实现就和AMS基本是一样的,最终都是调用到startActivityAsUser。这里就不再贴代码了。

重构意义:这个重构的主要目的还是为了把AMS维护Acitvity生命周期相关的职责交给ATMS来承担。我们知道OO设计原则中有一项就是单一职责原则(Single Reponsibility Principle)。AMS的代码既然膨胀到这么大,那么原因很可能就是其承担了过多职责造成的。如果一个类承担的职责过多,就难免会增加其复杂度,降低类的内聚性,进而影响到后续类的可扩展性、可维护性等诸多方面。所以,当一个类承担的职责过多时,我们就有必要把其中一部分职责抽出来,交个其它类来承担。

重构2:ActivityStarter从am移动到wm

我们知道ActivityStarter是启动Activity时的一个重要类,它封装了启动Activity这个行为,包括这个行为需要的一些状态、属性等等。Android 10.0把这个类从am移动到了wm。简单对比了一下两个版本,这个类的改动并不大。从重要成员变量的角度看,10.0只是多了mRootActivityContainer和mRestrictedBgActivity两个。前者将会在重构3中讲解,后者是和10.0上引入的后台启动Activity限制相关的,具体可以参考谷歌官方网文档: 

https://developer.android.com/guide/components/activities/background-starts

重构意义:这个重构没有什么太多可说的。我估计谷歌只是觉得ActivityStarter和ActivityStack, ActivityStackSupervisor等类的耦合更多,而这些类都在wm里,所以就把这个类也移动到wm里了。我们就不要给它强行加戏了。

重构3:引入RootActivityContainer

在启动Activity时,我们需要拿到当前的focusedStack。9.0上,可以直接通过ActivityStarter对象的mFocusedStack成员变量拿到。而10.0上,则是通过RootActivityContainer对象拿到的:

// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java966 final ActivityStack stack = mRootActivityContainer.getTopDisplayFocusedStack();

这里mRootActivityContainer就是RootActivityContainer类的实例。RootActivityContainer是10.0新引入的类,我们可以先通过注释初步认识一下它的职责:

// frameworks/base/services/core/java/com/android/server/wm/RootActivityContainer.java130/**131 * Root node for activity containers.132 * TODO: This class is mostly temporary to separate things out of ActivityStackSupervisor.java. The133 * intention is to have this merged with RootWindowContainer.java as part of unifying the hierarchy.134 */135public class RootActivityContainer extends ConfigurationContainer136        implements DisplayManager.DisplayListener 

通过注释我们看到,这个类是暂时用来分担ActivityStackSupervisor的部分职责的,主要目的是使ActivityContainer的结构和WindowContainer的结构保持一致。

重构意义:目前除了和WindowContainer保持一致外,尚未发现其它意义。留待后续继续学习。

重构4:startProcess核心逻辑移动到ProcessList里

ProcessList类在9.0上就有了。但9.0及之前,startProcess的核心逻辑都直接写在AMS里。10.0上,这些逻辑都被移动到了ProcessList里。这也是合理的。因为根据OO中的SRP原则,进程启动相关逻辑应当放到进程管理相关的类里,于是ProcessList就接管了这一任务。

重构意义:维持SRP的OO设计原则。

重构5:增加AppZygote类用于维护App的Zygote进程

ProcessList里增加了mAppZygotes和mAppZygoteProcesses两个集合分别用于维护App的Zygote进程和App的进程组:

// frameworks/base/services/core/java/com/android/server/am/ProcessList.java379    /**380     * The currently running application zygotes.381     */382    final ProcessMap mAppZygotes = new ProcessMap();383384    /**385     * The processes that are forked off an application zygote.386     */387    final ArrayMap> mAppZygoteProcesses =388            new ArrayMap>();

于是在ProcessList.startProcess里,如果是App的zygote进程,就会走不一样的逻辑:

// frameworks/base/services/core/java/com/android/server/am/ProcessList.java1813    private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,1814            ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,1815            String seInfo, String requiredAbi, String instructionSet, String invokeWith,1816            long startTime) {1817        try {1818            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +1819                    app.processName);1820            checkSlow(startTime, "startProcess: asking zygote to start proc");1821            final Process.ProcessStartResult startResult;1822            if (hostingRecord.usesWebviewZygote()) {1823                startResult = startWebView(entryPoint,1824                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,1825                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,1826                        app.info.dataDir, null, app.info.packageName,1827                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});1828            } else if (hostingRecord.usesAppZygote()) {1829                final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);18301831                startResult = appZygote.getProcess().start(entryPoint,1832                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,1833                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,1834                        app.info.dataDir, null, app.info.packageName,1835                        /*useUsapPool=*/ false,1836                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});1837            } else {1838                startResult = Process.start(entryPoint,1839                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,1840                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,1841                        app.info.dataDir, invokeWith, app.info.packageName,1842                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});1843            }

在9.0之前的版本里,是没有1828行这个分支的。

但是目前没有发现维护AppZygotes的原因。从ProcessList的源码来看,只是在进程创建和销毁的时候分别把appZygote实例从集合中加入和移除,未发现其它使用这个集合的地方。需要后续调查。

重构意义:目前尚未发现这个重构的意义。留待后续学习。

总结:

本文从App启动过程讲解了Android 10.0上Framework的一些重构。从这些重构来看,主要目的还是为了细分职责,简化那些过于臃肿的模块,尽量做到高内聚低耦合。后续希望能继续深入研究Framework,体会OO设计原则、设计模式等在Android里的应用。

相关阅读

1 Android 10文档阅读总结
2 Android 10 开发者常见问题
3 Android 如何从应用深入到 Framework (二)
4 Android Binder—APP->framework(mRemote的前世今生)
5 Android Studio 查看Android内部隐藏源码

如果你想要跟大家分享你的文章

欢迎投稿

更多相关文章

  1. 跨进程调用Service(AIDL服务) (附图 附源码)
  2. 我的Android读书笔记——(1)
  3. Android(安卓)开机动画客制化
  4. Android应用进程分裂分析
  5. 【腾讯Bugly干货分享】Android进程保活招式大全
  6. 理解Android系统的进程间通信原理(二)----RPC机制
  7. 框架层理解Activity生命周期(APP启动过程)
  8. Android性能测试工具APT使用指南
  9. Android中app进程ABI确定过程

随机推荐

  1. 共同期待美好2020
  2. ES6 模块知识入门
  3. Java并发编程学习4-线程封闭和安全发布
  4. ISIS路由泄露,如何避免路由环路?
  5. 如何批量Ping N个IP地址,掌握一个命令让你
  6. H3C交换机命名规则
  7. 网工必知:用于监控企业网络的10款最佳工具
  8. 如何制作毛玻璃效果?
  9. DOS***、DDOS***不懂?看完让你秒懂!
  10. 1分钟手把手教你破解华为交换机密码