-
安卓系统中,组件,应用,与进程的关系:
- 一个组件需要依附于一个应用(其对应Application类必须先初始化,ContentProvider除外,看后面)
- 一个应用可以拥有多个进程(其Application对象在每个进程中被初始化一遍)
- 一个进程可以承载多个应用 (一个进程可以拥有多个Application对象)
-
例子:
- 通常情况,一个应用运行与一个进程,对应一个Application对象
- 一个应用中,某些组件在注册清单中指定了不同进程,则启动时会将这些组件在对应进程中启动,且在这之前,会在每个对应进程中初始化这个应用的Application对象。
- 一个进程承载多个应用,若多个应用指定相同UID,且拥有相同签名,则这些应用可以运作在同一个进程,则每个应用的Application都会在这个进程中初始化
四大组件的启动都涉及到进程和应用的启动,我们这里以最常见的Activity的启动来解析安卓应用的启动流程,以下是Activity的启动分类:
四种判断结果分别各举一例情况:
- Activity已经以SingleTask,SingleTop,SingleInstance 模式启动,当有其它意图再次启动该Activity 时,不再重复创建实例,当前Activity走onNewIntent方法,获取外部传入的数据,并根据当前Activity所处的情况,走其它生命周期。
- Activity以普通启动模式,此情况为一般情况,直接创建Activity实例,并走生命周期。
- UserId和签名相同的应用可以运行于同一个进程中,当需要启动应用时,若判断出这个进程已经启动,则在对应进程中,完成应用的Application的实例化和生命周期,再完成Activity的实例化与生命周期。
- 在进程也不存在的情况下,则先让进程启动,完成初始化工作,再在进程完成Application的实例化与生命周期,再让后完成Activity的实例化与生命周期。
以下具体分析第四种情况,即需要启动的Activity所需依附的进程未启动
概念明确:
- 安卓的四大组件的管理全部由ActivityManagerService(以下简称AMS)及其几个协助类完成,启动Activity时,我们需要向AMS发出我们的启动意图,AMS会解析意图,并作出对应的处理。
- Binder作为安卓的IPC机制,其分为C/S两端。Server端接收Client端发过来的数据并作出处理,并返回处理结果。
- Binder服务端的对象,当被Binder客户端跨进程调用时,其方法的执行是在Binder线程里。
- Binder分为匿名Binder和有名Binder,有名可以直接通过ServiceManager获取,即通过键名查询到对应的Binder。匿名Binder未将自己注册到ServiceManager,所以不能通过键名获取到。
- AMS本身为Binder子类,为一个Binder服务端,工作在system_server进程,其在系统启动时将自己注册入ServiceManager,所以其为有名Binder,与服务端对应的客户端BinderProxy对象存在于各个应用进程里,但通常使用其封装类ActivityManagerProxy(AMP),与AMS完成远程调用。
- Binder可以通过Binder传递,要使用匿名Binder,需要先利用其它Binder获取到这个匿名Binder,如应用进程就在启动时将自己的匿名Binder ApplicationThread通过AMS/AMP传递给了system_server进程,这样system_server进程就存有了应用进程的Binder客户端,可以通过这个客户端调用应用进程的方法,从而实现对应用的管理。
- Instrumentation,用于管理应用程序和系统(主要与应用程序内的Activity)的交互过程,如startActivity时由Instrumentation对象将请求发往AMS,而系统对组件管理通Instrumentation对象实现,如Activity对象创建与生命周期的调用,Instrumentation将在应用初始化时被初始化,每个进程只会存在一个Instrumentation对象,且每个Activity都有此对象的引用,
- AMS 对四大组件的管理具体实现是由几个类的协助完成的,ActivityStarter对应Activity,ActiveService 对应service,BroadcastQueue对应Broadcast。与Activity相关还涉及到ActivityStack和ActivityStackSupervisor,负责Activity,Task与Stack管理,Activity启动过程中,AMS,ActivityStarter,ActivityStack,ActivityStackSupervisor需要协同工作,以下我们称这几个类为AMS模块。
- ActivityThread,与其内部类ApplicationThread协同,与AMS交互,其mian方法可以理解为应用进程的根方法,进程初始化完成后主线程会进入Looper循环,开始接收ApplicationThread转发过来的消息。
- ApplicationThread,Binder子类,匿名Binder,作为Binder服务端,接收AMS发过来的消息,由于服务端的方法在Binder调用时都运行在Binder线程,所以需要再通过Hander转发到主线程中,ApplicationThread接收到的调用都会通过Handler再转到主线程中处理,对应的处理方法都是ActivityThread的方法。
启动流程:
-
从startActivity开始,Activity重写了Context的startActivity方法,但大致流程是不变的,以下为Lancher应用启动一个应用时主线程的调用栈:
可以看出:
- Activity的startActivity走了startActivityForResult方法
- startActivityForResult调用了Instrumentation的execStartActivity方法
- Instrumentation 最终调用AMP的startActivity,AMP会将Intent传递给AMS,所以现在system_server进程里就会有一个Binder线程会去调用AMS的startActivity 方法,这次调用中做了几件重要的事:
- 解析Intent,并根据pkms扫描到的信息,创建对应的ActivityRecord,每一个ActivityRecord对应一个应用进程中的Activity实例,ActivityRecord中还会创建这个Activity对应的唯一的token,其会在Activity创建时被传递给对应的Activity,
- 通知WMS,显示startWindow ,即对应应用Activity的主题里面windowBackground对应资源,这个窗口由system_server进程显示,不必等到应用进程启动后再显示,所以其启动速度很快。
- 远程调用当前前台Activity的schedulePause方法,对应Activity的主线程会走onPause生命周期。 走完后,其会再通知AMS,它已经走完onPause,AMS开始准备启动目标Activity。
-
在ActivityStackSupervisor这个类中,判断出 要启动的Activity所需要的进程还未启动,所以需要先启动其进程:
AMS 通知Zygote 进程启动一个应用进程,这个IPC是socket,Zygote 进程收到消息后fork出一个进程,这个进程就是新的Activity所需依附的应用进程,应用进程被fork出来之后,将AMS传递过来的参数配置给自己,然后就会反射调用ActivityThread的main方法。
-
此时AMS对这个新进程还是无感知的,需要新进程主动‘联系’AMS,所以进程进入ActivityThread的main之后,主要做两件事:
-
实例化自身,进而实例化其成员变量ApplicationThread(匿名Binder服务端),通过AMP远程调用AMS的attachApplication方法,把自己的ApplicationThread传递给AMS模块,现在AMS就知道新进程已经创建完毕,并得到了其ApplicationThread客户端,可以通过这个Binder远程管理应用进程。
final IActivityManager mgr = ActivityManagerNative.getDefault(); try { mgr.attachApplication(mAppThread); } catch (RemoteException ex) { // Ignore }
调用Looper.prepareMainLooper 准备主线程Looper, Looper.loop() 进入循环,等待外界发来消息,此时,应用的进程初始化算完成,从被fork出来到配置参数,到将自己注册入AMS,再Loop主线程进入循环,等待外部消息。
-
-
启动Application:
以上完成了应用进程的初始化,AMS模块在收到应用进程发过来消息后,会连续做两件事,应用的启动和组件的启动,这里就是Activity的启动。
AMS收到应用进程准备完毕的消息后,会通过传递过来的ApplicationThread,调用其bindApplication方法,然后在应用进程中,ApplicationThread将这消息转发给主线程,所以在ActivityThread中会走到handleBindApplication,这个方法里完成:
-
Application的实例化,在LoadedApk里面完成,并添加到ActivityThead中的Application列表。
try { java.lang.ClassLoader cl = getClassLoader(); if (!mPackageName.equals("android")) { initializeJavaContextClassLoader(); } ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); app = mActivityThread.mInstrumentation.newApplication( cl, appClass, appContext); appContext.setOuterContext(app); } catch (Exception e) { if (!mActivityThread.mInstrumentation.onException(app, e)) { throw new RuntimeException( "Unable to instantiate application " + appClass + ": " + e.toString(), e); } } mActivityThread.mAllApplications.add(app); mApplication = app;
mInitialApplication = app;
并复制给mInitialApplication,这个变量保存安卓进程中第一个启动的Application,如果多个应用共享进程,那这个变量就是第一个启动的应用的Application
ContentProvider的实例化和onCreate,并注册到AMS
Application的onCreate
-
-
Activity的启动
bindApplication之后,AMS模块接着就会调用realStartActivityLocked,同样是通过ApplicationThread,调用其scheduleLaunchActivity,同样通过Handler转到主线程,调用ActivityThread的handleLaunchActivity 方法,这里这个方法里完成几件事:
Activity的对象创建,通过Instrumentation完成
调用Activity的attach,这里面会将一个contextImpl对象传递给Activity,Activity本身是ContextWrapper,很多操作是委托给contextImpl完成的,同时还会创PhoneWindow对象作为成员变量
-
走生命周期
if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } //////////////////// if (!r.activity.mFinished) { activity.performStart(); } //////////////////// performResumeActivity(token, clearHide);
分别会调用Activity的onCreate,onStart,onResume,方法
-
将视图添加到WMS
从PhoneWindow拿到DecorView,调用WindowManager的addView,addView里面会走到WindowManagerGlobal里面,创建ViewRootImpl,完成与WMS的通信,之后开始绘制视图
r.window = r.activity.getWindow(); View decor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; if (a.mVisibleFromClient) { a.mWindowAdded = true; wm.addView(decor, l); }