四大组件的工作过程(上):

目录

 

 

根Activity的启动过程:

 

 

1.Launcher请求AMS过程:

 

 

2.AMS到ApplicationThread的调用过程:

 

 

 

3.ActivityThread启动Activity的过程:

 

 

 

4.根Activity启动过程中涉及的进程:

5.普通Activity的启动过程:

 

 

 

 

Service的启动过程:

 

 

 

1.ContextImpl到ActivityManagerService的调用过程:

 

 

 

2.ActivityThread启动Service:

 

 

 

 

Service的绑定过程:

 

 

 

1.ContextImpl到AMS的调用过程:

 

 

 

2.Service的绑定过程:


 

在系统启动和应用程序进程启动之后,就应该启动应用程序了,也就是启动根Activity。而Activity是四大组件之一,其他还有Service,BroadcastReceiver和ContentProvider。

 

 

 

 

根Activity的启动过程:

Activity的启动过程分为两种:一种是根Activity的启动过程;另一种是普通的Activity的启动过程。根Activity指的是应用程序启动的第一个Activity,因此根Activity的启动过程一般情况下也可以理解为应用程序的启动过程。普通的Activity指的是除根Ativity之外的其他的Activity。

根Activity的启动过程主要分为三部分:分别是Launcher请求AMS过程,AMS到ApplicationThread的调用过程和ActivityThread启动Activity

 

 

 

1.Launcher请求AMS过程:

在系统启动中写过Launcher启动之后会将已经安装的应用程序快捷图标显示到桌面上,而这些应用程序的快捷图标就是启动根Activity的入口。当点击某个应用程序的快捷图标时,就会通过Launcher来请求AMS启动该应用程序。

当我们点击应用程序的快捷图标时,就会调用Launcher的startActivitySafely方法。路径在:packages/apps/Launcher3/src/com/android/launcher3/Launcher.java。该方法主要首先通过intent.addFlags把Flag设置为Intent.FLAG_ACTIVITY_NEW_TASK,表示根Activity会在新的任务栈中启动,后续调用startActivity方法,它在frameworks/base/core/java/android/app/Activity.java中定义。它内部调用了startActivityForResult方法,调用startActivityForResult方法的第二个参数-1表示Launcher不需要知道Activity启动的结果,这个方法有一句mParent==null,这里的mParent是Activity类型的,表示当前Activity的父类,但是因为目前根Activity没有被创建出来,故mParent==null成立。那么就会调用Instrumentation的execStartActivity方法,其中Instrumentation类主要是用来监控应用程序和系统交互的,而execStartActivity方法主要调用了ActivityManager的getService方法来获取AMS的代理对象,接着调用AMS代理对象的startActivity方法。

我们来看getService方法做了什么:getService方法调用了IActivityManagerSingleton的get方法。而IActivityManagerSingleton是一个单例类。它在create方法内通过serviceManager类的getservice方法获取了service的引用,也就是IBinder类型的AMS引用,再通过IActivityManager.stub.asInterface方法将这个AMS引用转换为IActivityManager类型的对象,并且返回。注意:IActivityManager.java类是由AIDL工具在编译时自动生成的,它是AIDL,要实现进程之间通信,也可以采用AIDL的方式,而服务器端也就是AMS只需要继承IActivityManager.Stub类并且实现相应的方法即可。

 

 

 

2.AMS到ApplicationThread的调用过程:

接下来到了AMS中。AMS的startActivity方法(frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java),它返回了startActivityAsUser方法,但是startActivityAsUser方法多了一个参数,即UserHandle.getCallingUserId()方法这个参数,这个方法会获取调用者的UserId,AMS会根据这个UserId来确定调用者的权限。回到startActivityAsUser方法它主要做了:首先调用enforceNotIsolatedCaller方法判断调用者进程是否被隔离,是则抛出SecurityException异常;接着检查调用者是否有权限,没有权限也会抛出该异常;最后调用了ActivityStarter的startActivityLocked方法(frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java)。

 

startActivityLocked方法的参数比startActivityAsUser方法的参数又多了几个,包括TaskRecord,代表启动的Activity所在的栈,以及最后一个参数代表启动的理由。

ActivityStarter是Android7.0新加入的类,它是加载Activity的控制类,它会收集所有的逻辑来决定如何将intent和flags转换为Activity,并且将Task以及Stack相关联。

 

回到ActivityStarter的startActivityLocked方法,它在使用TextUtils.isEmpty判断启动的理由不为空后,调用ActivityStarter的startActivity方法。该方法逻辑较多,关注的地方有:首先判断caller是否为null,这个caller是一路传过来的,指的是Launcher所在的应用程序进程的ApplicationThread对象。不为空的情况下把它传入AMS的getRecordForAppLocked方法,就会返回代表Launcher进程的callerApp对象,它是ProcessRecord类型的,该类型是来描述一个应用程序进程的。接下来创建一个ActivityRecord类型的对象,它是用来描述一个Activity的,记录着一个Activity的所有信息。然后把它赋值给ActivityRecord[]类型的对象outActivity中,最后把这个outActivity作为参数的一部分传递给ActivityStarter的另一个startActivity方法中。该方法内部调用了startActivityUnchecked方法。

 

startActivityUnchecked方法主要处理与栈管理相关的逻辑。在判断条件满足的情况下,就会调用setTaskFromReuseOrCreateNewTask创建一个新的TaskRecord,用来描述一个新的Activity的任务栈,其实这个任务栈是一个假想的模型。后续调用ActivityStackSupervisor的resumeFocusedStackTopActivityLocked方法。

resumeFocusedStackTopActivityLocked方法主要调用ActivityStack的topRunningActivityLocked方法来获取要启动的Activity所在栈的栈顶的不是处于停止状态的ActivityRecord。如果该ActivityRecord不是null或者要启动的activity不是RESUMED状态,就会调用ActivityStack的resumeTopActivityUncheckedLocked方法。该方法主要调用了ActivityStack的resumeTopActivityInnerLocked方法。

resumeTopActivityInnerLocked方法代码很多,主要关注ActivityStackSupervisor的startSpecificActivityLocked方法,它主要通过getProcessRecordLocked获取即将启动的Activity所在的应用程序进程,在判断该进程已经运行的情况下,调用realStartActivityLocked方法,该方法中有一个app.thread.scheduleLaunchActivity方法。其中app指的是传入的activity所在的应用程序进程,app.thread指的是IApplicationThread,它的实现类是ActivityThread的内部类ApplicationThread类。这段代码表示要在目的应用程序进程启动activity。而这个ApplicationThread负责通过Binder来进行AMS所在的进程(systemserver进程)与应用程序进程通信。

 

 

 

3.ActivityThread启动Activity的过程:

补充:ActivityThread是应用程序进程创建之后会运行代表主线程的实例。继续ApplicationThread类scheduleLaunchActivity方法首先将Activity的启动参数包装成ActivityClientRecord类型的对象。再通过sendMessage方法向H类发送类型为LAUNCH_ACTIVITY的消息,并且将ActivityClientRecord类型的对象传递进去(H类是ActivityThread的内部类,用于处理主线程的消息循环)。(frameworks/base/core/java/android/app/ActivityThread.java)

 

sendMessage方法中因为ApplicationThread是一个Binder,它的逻辑运行在Binder线程池中,所以要在H类的handleMessage方法将逻辑切换到主线程中。该方法具体是把msg的成员变量obj转换为ActivityClientRecord,再通过getpackageInfoNoCheck方法获取LoadedApk类型的对象并且赋值给ActivityClientRecord的成员变量packageInfo。应用程序进程要启动Activity就需要它的APK加载进来,而LoadedApk就是用来描述已经加载的APK文件的。然后再调用handleLaunchActivity方法。

handleLaunchActivity方法使用performLaunchActivity方法来启动Activity,并且使用handleResumeActivity方法来将Activity的状态设置为Resume。如果该Activity为null则会通知AMS停止启动Activity。

回到performLaunchActivity方法它会获取ActivityInfo对象,它是用来存储代码以及AndroidManifes设置的Activity和Receiver节点信息。接着使用getPackageInfo方法获取APK的描述类LoadApk。再通过r.intent.getComponent获取ComponentName类,该类保存了该Activity的包名和类名。然后使用createBaseContextForActivity方法创建启动Activity的上下文环境。再然后根据ComponentName类存储的Activity类名,用类加载器创建该Activity的实例(调用的为mInstrumentation.newActivity)。接着通过makeApplication方法内部调用Application的onCreate方法来创建Application。然后调用Activity的attach方法初始化Activity,并且在attach方法中创建Window对象与Activity相关联。最后调用了Instrumentation的callActivityOnCreate方法来启动Activity。

在callActivityOnCreate方法内部调用了activity的performCreate方法,在该方法内部就会调用Activity的onCreate方法,这个时候根Activity就启动了。

 

 

 

4.根Activity启动过程中涉及的进程:

根Activity启动过程中会涉及4个进程,分别是Zygote进程,Launcher进程,AMS所在的进程(SystemServer进程),应用程序进程。

 

7e62a5d4f95944d6959ff22890663dba.png

5.普通Activity的启动过程:

普通的Activity的启动过程只涉及到两个进程,分别是应用程序进程和SystemServer进程。在应用程序进程中的Activity向AMS请求创建普通的Activity,AMS会对这个Activity的生命周期和栈进行管理,校验Activity等等。如果Activity满足AMS的校验,AMS就会请求应用程序进程中的ActivityThread去创建并且启动普通的Activity。

7a42a191d7e54c9b95f0e193e8c43367.png

 

 

补充:

  1. 步骤2采用的是Socket通信,步骤1和4采用的是Binder通信。
  2. 普通的Activity启动过程涉及两个进程:AMS所在的进程和应用程序进程。

 

 

 

 

Service的启动过程:

Service的启动过程可以分为两个部分:ContextImpl到ActivityManagerService的调用过程和ActivtiyThread启动Service。

 

 

 

1.ContextImpl到ActivityManagerService的调用过程:

要启动Service,我们会调用startService方法,它在ContextWrapper中实现。路径:frameworks/base/core/java/android/content/ContextWrapper.java。在startService方法的内部返回了一个Context类型(具体是ContextImpl类型)的mBase对象的startService方法。在该方法中会返回startServiceCommon方法,startServiceCommon方法中会调用AMS代理的IActivityManager的startService方法,最终会调用AMS的startService方法。这个与:1.Launcher请求AMS过程这一节有相似之处。

 

之前在:3.ActivityThread启动Activity的过程这一节写到ActivityThread启动Activity时会调用createBaseContextForActivity方法来创建Activity的上下文环境,并且传入attach方法中,这样Activity就和上下文对象相关联。而这个上下文对象的具体类型为ContextImpl,在activity的attach方法中也是将这个上下文对象赋值给ContextWrapper类的成员变量mBase。注意:Context类是一个抽象类,而ContextImpl类是它的一个实现类。

 

 

 

2.ActivityThread启动Service:

AMS的startService方法主要调用了mServices的startServiceLocked方法,而这个mServices的类型是ActiveServices (frameworks/base/services/core/java/com/android/server/amActiveServices.java)。那么startServiceLocked方法首先使用retrieveServiceLocked方法来查找是否有与参数service相对应的ServiceRecord,如果没有该方法内部就会调用PackageManagerService去获取与参数service相对应的service信息,并且封装到ServiceRecord中,最后ServiceRecord会被封装为ServiceLookupResult,然后返回。其中:ServiceRecord是用来描述一个service的,与ActivityRecord相似。接着从返回的ServiceLookupResult中调用它的record方法,得到一个ServiceRecord对象,并且传入startServiceInnerLocked方法中。

 

在startServiceInnerLocked方法中又调用了bringUpServiceLocked方法,该方法内部首先调用ServiceRecord的processName值赋值给procName。其中processName是用来描述Service想要在哪个进程中运行的,默认是当前进程,也可以在AndroidManifest文件中通过android:process属性来开启一个新进程来运行service。接着把procName和service的uid等参数传入AMS的getProcessRecordLocked方法中,来查询是否存在与service相对应的ProcessRecord类型的对象。ProcessRecord类型是用来描述运行的应用程序进程的信息的。如果不存在,就调用startProcessLocked方法创建进程。如果存在就调用realStartServiceLocked方法来启动Service。

继续realStartServiceLocked方法,类似的该方法也有一个app.thread.scheduleCreateService方法,其中app和thread等等是什么参考:2.AMS到ApplicationThread的调用过程这一节。我们来看scheduleCreateService方法,它将Service的启动参数封装成CreateServiceData类型的对象,然后调用sendMessage方法向H类发送一个类型为CREATE_SERVICE的消息,并且将这个CreateServiceData类型的对象作为参数传递给sendMessage方法。然后在H类的handleMessage方法中,根据消息类型CREATE_SERVICE会调用handleCreateService方法。

frameworks/base/core/java/android/app/ActivityThread.java

接着handleCreateService方法主要先调用getPackageInfoNoCheck方法获取要启动的Service的应用程序的LoadedApk,它是APK文件的描述类。再调用LoadedApk的getClassLoader方法获取类加载器。接着利用类加载器调用loadClass.newIntance方法根据CreateServiceData对象存储的信息创建一个service实例。然后通过ContextImpl的createAppContext方法创建上下文环境。再接着通过Service的attach方法来初始化Service。最后就可以通过service的onCreate方法启动Service了。补充一点:mService的put方法是把即将启动的Service加入到ActivityThread的成员变量mServices中,其中mService是ArrayMap类型的。

 

 

 

 

Service的绑定过程:

除了调用startService方法来启动Service,也可以通过Context的bindService方法来绑定Service。Service的绑定过程分为两部分:ContextImpl到AMS的调用过程和Service的绑定过程。

 

 

 

1.ContextImpl到AMS的调用过程:

我们可以用bindService方法来绑定Service,它在ContextWrapper (frameworks/base/core/java/android/content/ContextWrapper.java)中实现。在bindService方法的内部返回了一个Context类型(具体是ContextImpl类型)的mBase对象的bindService方法。接着来看ContextImpl类型的bindService方法,它内部返回bindServiceCommon方法。

 

ContextImpl类:frameworks/base/core/java/android/app/ContextImpl.java

bindServiceCommon方法主要调用了LoadedApk类型的对象mPackageInfo的getServiceDispatcher方法,它的主要作用是将ServiceConnection封装为IServiceConnection类型的对象。其中IServiceConnection类它实现了Binder机制,这样Service的绑定就支持了跨进程。最后调用AMS的bindService方法(ActivityManager的getService.bindService)。

 

 

 

2.Service的绑定过程:

AMS的bindService方法最后会调用mServices的bindServiceLocked方法,而这个mServices的类型是ActiveServices。

 

ActiveServices类:frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

补充一点:

  • ServiceRecord:用于描述一个service。
  • ProcessRecord:用于描述一个进程的信息。
  • ConnectionRecord:用于描述应用程序进程和service建立的一次通信。
  • AppBindRecord:应用程序进程通过intent绑定service时,会通过它来维护两者关联。
  • IntentBindRecord:用于描述绑定service的Intent。

 

bindServiceLocked方法内部主要先调用了ServiceRecord的retrieveAppBindingLocked方法来获取AppBindRecord对象。后续也会再说retrieveAppBindingLocked方法//①。接着再看bringUpServiceLocked方法,它在内部会调用realStartServiceLocked方法,最后也会到service的onCreate方法。详见service启动过程第二节。这也说明了bindService方法内部会启动Service。再然后看if(s.app!=null&&b.intent.received),表示Service已经运行并且当前应用程序进程已经收到了绑定Service时返回的Binder(s是ServiceRecord,app是ProcessRecord),这样应用程序进程就可以通过Binder来获取要绑定的Service的访问接口了。然后再看c.conn的connected方法,其中c.conn指的是IServiceConnection,它是ServiceConnection在本地的代理,它的具体实现为ServiceDispatcher.InnerConnection,其中ServiceDispatcher是LoadedApk的内部类,InnerConnection的connected方法内部会调用H的post方法向主线程发送消息,并且解决当前应用程序进程和Service跨进程通信的问题,后续也会说到//②。再接着看判断当前应用程序进程是第一个与Service进行绑定,且Service调用过onUnBind方法,则调用requestServiceBindingLocked方法,且它的最后一个参数传入true//③;如果应用程序进程的client端没有发送过绑定Service的请求,也会调用requestServiceBindingLocked方法,但它的最后一个参数传入false。

 

IntentBindRecord类型:因为不同的应用程序进程可能会使用同一个Intent来绑定Service,因此它会在内部使用ArrayMap类型的apps来存储当前Intent绑定的Service的应用程序进程。

//①:retrieveAppBindingLocked方法内部首先通过new创建了一个IntentBindRecord,再根据类型为ProcessRecord的参数2获取AppBindRecord,并且把AppBindRecord作为value,ProcessRecord作为key传入IntentBindRecord的app中。

 

继续来看requestServiceBindingLocked方法,在使用i.requested等判断是否发送过绑定service的请求后,就会调用r.app.thread.scheduleBindService方法,实现类是ApplicationThread。scheduleBindService方法,它将Service的信息封装成BindServiceData类型的对象,其中BindServiceData的成员变量rebind为false//④。然后调用sendMessage方法向H类发送一个类型为BIND_SERVICE的消息,并且将这个BindServiceData类型的对象作为参数传递给sendMessage方法。然后在H类的handleMessage方法中,根据消息类型BIND_SERVICE会调用handleBindService方法。

 

handleBindService方法主要先通过mService.get获取要绑定的Service。再判断//④处的rebind值,如果值为false,则调用Service的onBind方法,到这里Service就处于绑定状态了,后面再调用AMS的publishService方法;如果值为true,则表示绑定过的情况,就会调用onRebind方法(也就是当前应用程序进程是第一个与Service进行绑定,且Service调用过onUnBind方法,其实最后是调用的onRebind方法)//③。

 

AMS的publishService方法中调用了ActiveService类型的mService对象的publishServiceLocked方法。该方法主要先调用c.conn的connected方法//②。在connected方法内部调用了ServiceDispatcher类型对象sd的connected方法。

 

ServiceDispatcher类型对象sd的connected方法通过调用Handler类型对象(实际上是H类)mActivityThread的post方法,将RunConnection对象的内容运行在主线程中。RunConnection类也是LoadedApk的内部类。RunConnection类的run方法调用了doConnected方法,该方法通过调用了ServiceConnection类型的对象mConnection的onServiceConnected方法,那么在客户端实现了ServiceConnection接口类的onServiceConnected方法就会被执行。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mo@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值