android app 代码重构,从App启动过程看Android 10.0 Framework重构

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.aidl

interface 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.aidl

79/**

80 * System private API for talking with the activity task manager that handles how activities are

81 * 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.java

1678 @UnsupportedAppUsage

1679 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.java

3567 @Override

3568 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.java

966 final ActivityStack stack = mRootActivityContainer.getTopDisplayFocusedStack();

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

// frameworks/base/services/core/java/com/android/server/wm/RootActivityContainer.java

130/**

131 * Root node for activity containers.

132 * TODO: This class is mostly temporary to separate things out of ActivityStackSupervisor.java. The

133 * intention is to have this merged with RootWindowContainer.java as part of unifying the hierarchy.

134 */

135public class RootActivityContainer extends ConfigurationContainer

136 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.java

379 /**

380 * The currently running application zygotes.

381 */

382 final ProcessMap mAppZygotes = new ProcessMap();

383

384 /**

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.java

1813 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);

1830

1831 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里的应用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值