文章已在『技术最TOP』公众号发布
前言
Activity作为Android四大组件之一,他的启动绝对没有那么简单。这里涉及到了系统服务进程,启动过程细节很多,这里我只展示主体流程。activity的启动流程随着版本的更替,代码细节一直在进行更改,每次都会有很大的修改,如android5.0 android8.0。我这里的版本是基于android api28,也是目前我可以查得到的最新源码了。事实上大题的流程是相同的,掌握了一个版本,其他的版本通过源码也可以很快地掌握。
因为涉及到不同的进程之间的通信:系统服务进程和本地进程,在最新版本的android使用的是AIDL来跨进程通信。所以需要对AIDL有一定的了解,会帮助理解整个启动流程。
源码部分的讲解涉及到很多的代码讲解,可能会有一点不适,但还是建议看完源码。源码的关键代码处我都会加上注释,方便理解。
代码不会过分关注细节,只注重整体流程。想知道具体细节可以去查看源码。每份代码所在的路径我都会在代码前面标注出来,各位可以去查看相对应的源码。
每部分源码前我都会放流程图,一定要配合流程图食用,不然可能会乱。
整体流程概述
这一部分侧重于对整个启动流程的概述,在心中有大体的概念,这样可以帮助对下面具体细节流程的理解。
普通Activity的创建
普通Activity创建也就是平常我们在代码中采用startActivity(Intent intent)
方法来创建Activity的方式。总体流程如下图:
启动过程设计到两个进程:本地进程和系统服务进程。本地进程也就是我们的应用所在进程,系统服务进程为所有应用共用的服务进程。整体思路是:
-
activity向Instrumentation请求创建
-
Instrumentation通过AMS在本地进程的IBinder接口,访问AMS,这里采用的跨进程技术是AIDL。
-
然后AMS进程一系列的工作,如判断该activity是否存在,启动模式是什么,有没有进行注册等等。
-
通过ClientLifeCycleManager,利用本地进程在系统服务进程的IBinder接口直接访问本地ActivityThread。
ApplicationThread是ActivityThread的内部类,IApplicationThread是在远程服务端的Binder接口
-
ApplicationThread接收到服务端的事务后,把事务直接转交给ActivityThread处理。
-
ActivityThread通过Instrumentation利用类加载器进行创建实例,同时利用Instrumentation回调activity的生命中周期
这里涉及到了两个进程,本地进程主要负责创建activity以及回调生命周期,服务进程主要判断该activity是否合法,是否需要创建activity栈等等。进程之间就涉及到了进程通信:AIDL。(如果不熟悉可以先去了解一下,但可以简单理解为接口回调即可)
下面介绍几个关键类:
-
Instrumentation是activity与外界联系的类(不是activity本身的统称外界,相对activity而言),activity通过Instrumentation来请求创建,ActivityThread通过Instrumentation来创建activity和调用activity的生命周期。
-
ActivityThread,每个应用程序唯一一个实例,负责对Activity创建的管理,而ApplicationThread只是应用程序和服务端进程通信的类而已,只负责通信,把AMS的任务交给ActivityThread。
-
AMS,全称ActivityManagerService,负责统筹服务端对activity创建的流程。
其他的类,后面的源码解析会详解。
根Activity的创建
根Activity也就是我们点击桌面图标的时候,应用程序第一个activity启动的流程。这里我侧重讲解多个进程之间的关系,下面的源码也不会讲细节,只讲解普通activity的创建流程。这里也相当于一个补充。先看整体流程图:
主要涉及四个进程:
- Launcher进程,也就是桌面进程
- 系统服务进程,AMS所在进程
- Zygote进程,负责创建进程
- 应用程序进程,也就是即将要启动的进程
主要流程:
- Launcher进程请求AMS创建activity
- AMS请求Zygote创建进程。
- Zygote通过fork自己来创建进程。并通知AMS创建完成。
- AMS通知应用进程创建根Activity。
和普通Activity的创建很像,主要多了创建进程这一步。
源码讲解
Activity请求AMS的过程
流程图
源码
-
系统通过调用Launcher的startActivitySafely方法来启动应用程序。Launcher是一个类,负责启动根Activity。
这一步是根Activity启动才有的流程,普通启动是没有的,放在这里是作为一点补充而已
packages/apps/Launcher3/src/com/android/launcher3/Launcher.java/; public boolean startActivitySafely(View v, Intent intent, ItemInfo item) { //这里调用了父类的方法,继续查看父类的方法实现 boolean success = super.startActivitySafely(v, intent, item); ... return success; }
packages/apps/Launcher3/src/com/android/launcher3/BaseDraggingActivity.java/; public boolean startActivitySafely(View v, Intent intent, ItemInfo item) { ... // Prepare intent //设置标志singleTask,意味着在新的栈打开 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (v != null) { intent.setSourceBounds(getViewBounds(v)); } try { boolean isShortcut = Utilities.ATLEAST_MARSHMALLOW && (item instanceof ShortcutInfo) && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) && !((ShortcutInfo) item).isPromise(); //下面注释1和注释2都是直接采用startActivity进行启动。注释1会做一些设置 //BaseDraggingActivity是继承自BaseActivity,而BaseActivity是继承自Activity //所以直接就跳转到了Activity的startActivity逻辑。 if (isShortcut) { // Shortcuts need some special checks due to legacy reasons. startShortcutIntentSafely(intent, optsBundle, item);//1 } else if (user == null || user.equals(Process.myUserHandle())) { // Could be launching some bookkeeping activity startActivity(intent, optsBundle);//2 } else { LauncherAppsCompat.getInstance(this).startActivityForProfile( intent.getComponent(), user, intent.getSourceBounds(), optsBundle); } ... } ... return false; }
-
Activity通过Instrumentation来启动Activity
/frameworks/base/core/java/android/app/Activity.java/; public void startActivity(Intent intent, @Nullable Bundle options) { //最终都会跳转到startActivityForResult这个方法 if (options != null) { startActivityForResult(intent, -1, options); } else { // Note we want to go through this call for compatibility with // applications that may have overridden the method. startActivityForResult(intent, -1); } } public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) { //mParent是指activityGroup,现在已经采用Fragment代替,这里会一直是null //下一步会通过mInstrumentation.execStartActivity进行启动 if (mParent == null) { options = transferSpringboardActivityOptions(options); Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options);//1 if (ar != null) { mMainThread.sendActivityResult( mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); } ... } ... }
-
Instrumentation请求AMS进行启动。该类的作用是监控应用程序和系统的交互。到此为止,任务就交给了AMS了,AMS进行一系列处理后,会通过本地的接口IActivityManager来进行回调启动activity。
/frameworks/base/core/java/android/app/Instrumentation.java/; public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { ... //这个地方比较复杂,先说结论。下面再进行解释 //ActivityManager.getService()获取到的对象是ActivityManagerService,简称AMS //通过AMS来启动activity。AMS是全局唯一的,所有的活动启动都要经过他的验证,运行在独立的进程中 //所以这里是采用AIDL的方式进行跨进程通信,获取到的对象其实是一个IBinder接口 //注释2是进行检查启动结果,如果异常则抛出,如没有注册。 try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(who); int result = ActivityManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);//1 checkStartActivityResult(result, intent);//2 } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } return null; }
这一步是通过AIDL技术进行跨进行通信。拿到AMS的代理对象,把启动任务交给了AMS。
/frameworks/base/core/java/android/app/ActivityManager.java/; //单例类 public static IActivityManager getService() { return IActivityManagerSingleton.get(); } private static final Singleton<IActivityManager> IActivityManagerSingleton = new Singleton<IActivityManager>() { @Override protected IActivityManager create() { //得到AMS的IBinder接口 final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE); //转化成IActivityManager对象。远程服务实现了这个接口,所以可以直接调用这个 //AMS代理对象的接口方法来请求AMS。这里采用的技术是AIDL final IActivityManager am = IActivityManager.Stub.