基于Android10.0,分析四大组件与进程启动间的关系
一、概述
Android进程对于系统来说非常重要,而Android四大组件是Android应用的基础。在前面分析过Android进程创建的过程,那么对于四大组件来说和进程之间又有什么关联,这里主要看AMS.startProcessLocked方法。
二、四大组件与进程
2.1 四大组件
Activity、Service、ContentProvider、BroadcastReceiver这四大组件,在启动的过程中,当其承载的进程不存在时需要调用startProcessLocked先创建进程。
2.1.1 Activity
启动Activity,调用的是startActivity方法,经过层层调用ActivityStackSupervisor.java中的startSpecificActivityLocked。当activity所属的进程还没有启动时,则需要创建相应的进程。详细见startActivity启动过程
1 | void startSpecificActivityLocked(ActivityRecord r, |
2.1.2 Service
启动Service,调用的是startService方法,经过层层调用ActiveServices.java中的bringUpServiceLocked。当Service所属的进程还没有启动时,则需要创建相应的进程。详细见startService启动过程
1 | private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, |
2.1.3 ContentProvider
ContentProvider.query经过层层调用,最终调用到ActivityManagerService.java中getContentProviderImpl,当ContentProvider所对应进程不存在,则需要创建新进程。详细见ContentProvider原理分析
1 | private ContentProviderHolder getContentProviderImpl(IApplicationThread caller, |
2.1.4 BroadcastReceiver
调用SendBroadcast方法,经过层层调用,最终调用BroadcastQueue.jav的processNextBroadcast方法。当BroadcastReceiver所在的进程没有启动,则创建相应进程。详细见BroadcastCast广播机制原理
1 | final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) { |
2.2 进程启动
ActivityManagerService.java有四个不同startProcessLocked的启动进程方法,详细见第三大节。对于进程启动的触发实际主要是四个组件所在的进程没有启动才会创建。大多数情况下app都是单进程架构,对于多进程的app一般都是通过AndroidManifest.xml中的android:process属性来实现的。
当android:process属于值以”:”开头,则代表进程是私有进程,只有该app可以使用
当android:process属于值不以”:”开头,则代表进程是全局进程,这种情况需要注意进程名至少包含“.”字符。
三、进程创建过程
3.1 AMS.startProcessLocked
[->ActivityManagerService.java]
1 | final ProcessRecord startProcessLocked(String processName, |
3.2 AMS.startProcessLocked
[->ActivityManagerService.java]
1 | @GuardedBy("this") |
主要功能:
1.对于非isolated进程,则根据进程名和uid检查相应的ProcessRecord,如果当前进程处于后台且当前进程处于bad列表则直接返回,否则清空crash次数,以保证其不处于bad进程知道下次再次弹出crash对话框
2.当存在ProcessRecord,且已分配pid(正在启动或者已经启动)的情况
当caller不认为该进程已死亡或者thread对象attached到该进程,则不应该清理该进程,则直接返回;
否则杀死并清理该进程
3.当ProcessRecord为空则新建一个,当创建失败则直接返回
4.当以下3个值为false,则将当前进程加入到mProcessesOnHold,并直接返回,当进程真正创建则从mProcessesOnHold中移除。
当AMS.systemReady执行完成,则mProcessesReady = true;
当进程为persistent,则isAllowedWhileBooting=true;
一般地创建进程时参数allowWhileBooting = flase,只有AMS.startIsolatedProcess该值才为true;
5.最后启动新进程,其参数含义:
hostingType取值为“activity”,”service”,”broadcast”,”contentprovider”
hostingNameStr取值为具体相对应的组件名,类型为ComponentName
3.3 AMS.startProcessLocked
[->ActivityManagerService.java]
1 | private final boolean startProcessLocked(ProcessRecord app, |
1 | /** |
根据不同参数设置相应的runtimeFlags
3.4 AMS.startProcessLocked
[->ActivityManagerService.java]
1 | @GuardedBy("this") |
3.4.1 AMS.startProcess
[->ActivityManagerService.java]
1 | private ProcessStartResult startProcess(String hostingType, String entryPoint, |
3.4.2 AMS.handleProcessStartedLocked
[->ActivityManagerService.java]
1 | private boolean handleProcessStartedLocked(ProcessRecord app, int pid, boolean usingWrapper, |
Process.start是通过socket通信通知Zygote创建fork子进程,创建新进程后将ActivityThread类加入到新进程中,并调用ActivityThread.main方法,详细可以参考Android进程创建流程,接下来进入AT.main方法
3.5 AT.main
[->ActivityThread.java]
1 | public static void main(String[] args) { |
1.创建主线程的Looper对象,该主线程的Looper是在进程创建完成后自动创建完成的,如果子线程中要通过handler通信,那么需要手动创建Looper对象,并且每个线程只能创建一次。
2.创建ActivityThread thread = new ActivityThread();这个过程中汇初始化几个重要的变量:
1 | ApplicationThread mAppThread = new ApplicationThread(); |
3.attach过程是当前主线程向systemserver进程通信的过程,将thread信息通知AMS
4.sMainThreadHandler通过getHandler获取的对象正是mH,这是主线程的handler对象。
5.之后主线程调用 Looper.loop()进入消息循环状态,当没有消息时主线程进入休眠状态,一旦有消息来则唤醒主线程并执行相关的操作。
3.6 AT.attach
[->ActivityThread.java]
1 | private void attach(boolean system, long startSeq) { |
对于非系统处理过程如下:
1.创建线程来开启虚拟机的jit即时编译功能
2.通过Binder机制,调用AMS.attachApplication方法
3.观察虚拟机内存是否快接近heap的上限,当已用内存超过最大内存3/4,则释放内存空间
4.添加config回调接口
3.7 AMS.attachApplication
[->ActivityManagerService.java]
1 | @Override |
3.8 AMS.attachApplicationLocked
[->ActivityManagerService.java]
1 | private final boolean attachApplicationLocked(IApplicationThread thread, |
1.根据pid查询相应的ProcessRecord对象中的app
2.当app==null,如果进程存在则杀掉进程或者停止looper后返回
3.还刚进入attach过程,app.thread不为null,若不为null,则表示该app在上一个进程,则调用handleAppDiedLocked清理
4.绑定死亡通知,如果进程pid死亡,则会通过binder死亡回调来通知systemserver进程死亡的消息
5.重置ProcessRecord的进程信息,此时app.thread赋值,不为空
6.app进程存在正在启动中的provider,则超时10s发送消息
7.调用thread.bindApplication绑定应用进程
8.处理Activity,Service,Broadcast相应流程
3.9 AT.bindApplication
[->ActivityThread.java]
1 | public final void bindApplication(String processName, ApplicationInfo appInfo, |
发送H.SET_CORE_SETTINGS、H.BIND_APPLICATION消息到主线程
3.10 H.handleMessage
[->ActivityThread.java]
1 | class H extends Handler { |
3.11 AT.handleSetCoreSettings
1 | private void handleSetCoreSettings(Bundle coreSettings) { |
3.12 AT.handleBindApplication
[->ActivityThread.java]
1 | private void handleBindApplication(AppBindData data) { |
3.13 LA.makeApplication
[->LoadedApk.java]
1 | public Application makeApplication(boolean forceDefaultAppClass, |
3.13.1 CI.createAppContext
[->ContextImpl.java]
1 | static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) { |
3.13.2 newApplication
[->Instrumentation.java]
1 | public Application newApplication(ClassLoader cl, String className, Context context) |
3.13.3 LA.rewriteRValues
[->LoadedApk.java]
1 | private void rewriteRValues(ClassLoader cl, String packageName, int id) { |
四、总结
介绍了四大组件和进程启动,并分析四大组件共用的启动进程方法startProcessLocked。在这个整个过程中有新创建的进程和systemserver进程之间的交互过程,通过binder进行通信。app的任何组件都需要一个承载其运行的容器即进程,进程的创建过程是由systemserver通过socket向zygote进程请求fork新进程。
附录
源码路径
1 | frameworks/base/core\java\android\os\Process.java |