该文章参考了
jeanboydev(https://blog.csdn.net/freekiteyu/article/details/79318031)
凶残的程序员(https://blog.csdn.net/qian520ao/article/details/78156214)
博主的文章,如有侵权请通知删除
看Activity启动过程前先看看Android开机到Launcher启动过程,如下图。
Android 系统启动后已经启动了 Zygote,ServiceManager,SystemServer 等系统进程;ServiceManager 进程中完成了 Binder 初始化;SystemServer 进程中 ActivityManagerService,WindowManagerService,PackageManagerService 等系统服务在 ServiceManager 中已经注册;最后启动了 Launcher 桌面应用。
其实 Launcher 本身就是一个应用程序,运行在自己的进程中,我们看到的桌面就是 Launcher 中的一个 Activity。
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
应用安装的时候,通过 PackageManagerService 解析 apk 的 AndroidManifest.xml 文件,提取出这个 apk 的信息写入到 packages.xml 文件中,这些信息包括:权限、应用包名、icon、apk 的安装位置、版本、userID 等等。packages.xml 文件位于系统目录下/data/system/packages.xml。
同时桌面 Launcher 会为安装过的应用生成不同的应用入口,对应桌面上的应用图标,下面分析点击应用图标的到应用启动的过程。
其次我们看一张点击Launcher桌面图标后进入应用的流程图
整个启动的大致流程是:
- Launcher通知AMS启动APP的MainActivity,也就是清单文件设置启动的Activity。
- AMS记录要启动的Activity信息,并且通知Launcher进入pause状态。
- Launcher进入pause状态后,通知AMS已经paused了,可以启动app了。
- app未开启过,所以AMS启动新的进程,并且在新进程中创建ActivityThread对象,执行其中的main函数方法。
- app主线程启动完毕后通知AMS,并传入applicationThread以便通讯。
- AMS通知app绑定Application并启动MainActivity。
- app启动MainActivitiy,并且创建和关联Context,最后调用onCreate方法。
Launcher桌面Activity中执行的源码是:
//以上两个方法主要是检查将要打开的 Activity 是否存在
Launcher.startActivitySafely()
Launcher.startActivity()
//这段代码大家已经很熟悉,经常打开 Activity 用的就是这个方法
Activity.startActivity()
//默认 requestCode = -1,也可通过调用 startActivityForResult() 传入 requestCode。
//然后通过 MainThread 获取到 ApplicationThread 传入下面方法。
Activity.startActivityForResult()
//通过 ActivityManagerNative.getDefault() 获取到 ActivityManagerService 的代理为进程通讯作准备。
Instrumentation.execStartActivity()
//调用代理对象的 startActivity() 方法,发送 START_ACTIVITY_TRANSACTION 命令。
ActivityManagerNative.getDefault().startActivity()
ActivityManagerProxy.startActivity()
白话简单来说就是当点击Launcher的应用图标的时候,Launcher会通过Binder在system_server服务进程查询到ActivityManagerService服务类,其次在AMS中找到要启动的Activity信息(信息位置在/data/system/packages.xml ),并且告知Launcher进程我已经准备就绪,当Launcher进程接收到Activity消息后会回调onPause()
方法,并且返回消息告诉AMS:“我已经进入onPause状态,你可以启动APP了”。
至此就完成了Launcher到AMS的Binder交互。
查看源码可知方法执行流程,AMS会调用startActivity
方法传入参数到startActivityAsUser
方法再调用ActivityStarter类的startActivityMayWait
方法解析出与Intent 相匹配的ActivityInfo并得到启动该Activity的Task,紧接着调用 它的startActivityLocked
方法来暂时禁止App的切换和恢复切换然后校检参数,没有问题的话创建ActivityRecord,记录启动的Activity,接着调用它的startActivityUnchecked
方法复用或者新建 待启动的Activity的Task并与之关联,这里是Activity启动模式的关键,紧接着会调用ActivityStackSupervisor的resumeFocusdStackTopActivityLocked
方法来判断启动的Task和当前Task的一致性来进行设置,接着调用ActivityStack类的resumeTopActivityUnCheckedLocked
方法把参数过度发给它的resumeTopActivityInnerLocked
方法,在这个方法中 就会通知Launcher的Activity页面进入onPause状态。
然后判断要启动的App是否已经启动,如果启动过了则会调用ActivityStackSupervisor的startSpecificActivityLocked
方法来realStartActivityLocked
方法(不管是否存在进程,都会调用该方法)来启动Activity,如果没有进程则会通过Socket方式Zygote孵化一个应用进程,然后在该进程中创建一个ActivityThread对象其次通过反射机制来执行其中的main方法,UiThread中的Handler和Looper以及消息队列就是在此处进行初始化的,然后调用attach方法把ApplicationThread发送给AMS来进行绑定AMS,再进行loop循环来完成取出消息分发消息,但实际上并不是ActivityThread和AMS直接进行通讯的,它是通过ApplicationThread代理对象进行与AMS通讯的(它们的通讯方式就是Binder,ApplicationThread属于native客户端持有binder的实体,AMS属于proxy服务端持有binder引用)。而ActivityThread和ApplicationThred也不是直接通讯的,是通过Handler进行通讯的。
至此所有的通讯条件已经达成。接下来就是关联对象了。当ActivityThread和ApplicationThreda和AMS完成绑定后,AMS会在attachApplication
方法中获取到ApplicationThread传来的Binder中date里的数据的(进程的id),再将它传入attachApplicationLocked
方法中,在这个方法中就会给Application绑定Service和Boradcast,然后会调用thread.bindApplication(…)
将Application传给ActivityThread进行绑定,然后通知ActivityStackSupervisor启动Activity,当ActivityThread的Handler收到通过ApplicationThread传来的msg消息的时候,就会调用handleBindApplication
方法来处理绑定事务,也就是在这里面会加载进程中携带的ContentProvider,并初始化Instrumentation实例。这个方法有三个作用:
- 按照Android的要求,完成对进程基本参数的设置置,包括设置进程名、时区、资源及兼容性配置; 同时也添加了一些限制,例如主线程不能访问网络等。
- 创建进程对应的ContextImpl、LoadedApk、Application等对象,同时加载Application中的ContentProvider,并初始化Application。
- 使用Instrumentation监控Activity的生命周期。(一个进程对应一个Instrumentation实例)
上面说到AMS通知ActivityStackSupervisor启动Activity,这里ActivityStackSupervisor会调用attachApplicationLocked
方法来调用上图最终的方法realStartActivityLocked
。这里比较复杂,但是看完这段代码大概就懂了
//ActivityStackSupervisor
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
他最后有回到了ActivityThread类里面。也就是说它调用了ApplicationThread中的scheduleLaunchActivity
方法,想ActivityThread的Handler发送一个LAUNCH_ACTIVITY消息,然后Handler接收到消息,case判断完成会调用handleLaunchActivity
方法,该方法中有两个重要函数。
- performLaunchActivity : 会调用Activity的onCreate,onStart,onResotreInstanceState方法。
- handleResumeActivity : 会调用Activity的onResume方法.
在performLauncherActivity方法中就会从ActivityClientRecord获取到待启动的Activity的组件信息。通过Instrumentation的newActivity方法使用类加载器创建Activity对象。通过LoadedApk的makeApplication方法来创建Application对象。创建ContextImpl对象,并通过Activity的attach方法来完成一些重要数据的初始化。调用Activity的onCreate方法。调用Activity的onStart,onResotreInstanceState方法。
最后Activity调用setContentView方法进行layout布局文件绑定。 再调用handleResumeActivity
方法通过WindowManagerServicer进行Activity与Window关联,就会打开我们点击的应用主页面了。