9_四大组件的工作过程

四大组件分别是Activity、Service、BroadcastReceiver和ContentProvider。首先对四大组件的运行状态和工作方式做一个概括化的描述,接着对四大组件的工作过程进行分析。通过分析它们的工作过程我们可以更好地理解系统内部的运行机制。

9.1 四大组件的运行状态

android的四大组件中除了BroadcastReceiver以外,其他组件必须在android-Manifest中注册,对于BroadcastReceiver来说,它既可以Android-Manifest中注册也可以通过代码注册。在调用方式上,activity、Service和BroacastReceiver需要借助Intent,而ContentProvider则无须借助Intent。

activity是一种展示型组件,用于向用户直接地展示一个界面,并且可以接收用户的输入信息从而进行交互。activity是最重要的一种组件,对用户来说,activity就是一个android应用的全部,这是因为其他三大组件对用户来说都是不可感知的。activity的启动由Intent触发,其中Intent可以分为显示Intent和隐式Intent,显示Intent可以明确地指向一个Activity组件,隐式Intent则指向一个或多个目标activity组件,当然也可能没有任何一个activity组件可以处理这个隐式Intent。一个activity组件可以具有特定的启动模式。activity组件是可以停止的,在实际开发中可以通过activity的finish方法来结束一个activity组件的运行。由此可见,activity组件的主要作用是展示一个界面并和用户交互,它扮演的是一个前台界面的角色。

Service是一种计算型组件,用于在后天执行一系列计算任务。由于Service组件工作在后台,因此用户无法直接感知到它的存在。Service组件和activity组件略有不同,activity组件只是一种运行模式,即activity处于启动状态,但是Service组件却有两种状态:启动状态和绑定状态。当Service组件处于启动状态时,这个时候Service是用于执行后台计算的,但是它本身是运行在主线程中的,因此耗时的后台计算仍然需要在单独的线程中去完成。当Service处于绑定状态时,这个时候Service内部同样可以进行后台计算,但是处于这种状态时外界可以很方便地和Service组件进行通信。Service组件也是可以停止的,停止一个Service组件稍显复杂,需要灵活采用stopService和unBindService这两个方法才能完全停止一个Service组件。

BroadcaseReceiver是一种消息型组件,用于在不同组件乃至不同的应用之间传递消息。BroadcaseReceiver同样无法被用户直接感知,因为它工作在系统内部。BroadcaseReceiver也叫广播,广播的注册有两种方式:静态注册和动态注册。静态注册是指在android-Manifest中注册广播,这个广播在应用安装时会被系统解析,此种形式的广播不需要应用启动就可以收到相应的广播。动态注册广播需要通过Context.registerReceiver()来实现,并且在不需要的时候要通过Context.unRegisterReceiver()来解除注册广播,此种形态的广播必须要应用启动才能注册并接收广播,因为应用不启动就无法注册广播,就无法收到相应的广播。在实际开放中通过Context的一系列send方法来发送广播,被发送的广播会被系统发送给感兴趣的广播接收者,发送和接收过程的匹配是通过广播接受者的<intent-filter>来描述的。可以发现,BroadcastReceiver组件可以用来实现低耦合的观测者模式,观测者和被观测者之间可以没有任何耦合。由于BroadcastReceiver的特性,它不适合用来执行耗时操作。

ContentProvider是一种数据共享组件用于向其他组件乃至其他应用共享数据。和BroadcastReceiver一样,同样无法被用户直接感知。对于一个ContentProvider组件来说,内部实现了增删改查四种操作,在内部维护着一份数据集合,这个数据集合即可以通过数据库实现,也可以采用其他任何类型来实现,比如List和Map,ContentProvider对数据集合的具体实现并没有任何要求。需要注意的是,ContentProvider内部的insert,delete,update,query方法需要处理好线程同步,因为这几个方法是在Binder线程池中被调用的,另外ContentProvider组件也不需要手动停止。

9.2 Activity的工作过程。为了方便日常开发工作,系统对四大组件的工作过程进行了很大程度的封装,这使得开发者无须关注实现细节即可快速地使用四大组件。activity作为很重要的一个组件,其内部工作过程系统当然也是做了很多封装,这种封装使得启动一个activity变得异常简单。

系统内部到底是如何启动一个Activity?比如新的activity的对象是何时创建的?activity的onCreate方法又是在何时被系统回调的呢?android作为一个优秀的基于Linux的移动操作系统,其内部一定有很多值得我们学习和借鉴的地方。

从Activity的startActivity方法开始分析,startActivity方法有好几种重载方式,但是它们最终都会调用startActivityForResult方法:

public void More ...startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
3744        if (mParent == null) {
3745            Instrumentation.ActivityResult ar =
3746                mInstrumentation.execStartActivity(
3747                    this, mMainThread.getApplicationThread(), mToken, this,
3748                    intent, requestCode, options);
3749            if (ar != null) {
3750                mMainThread.sendActivityResult(
3751                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
3752                    ar.getResultData());
3753            }
3754            if (requestCode >= 0) {
3755                // If this start is requesting a result, we can avoid making
3756                // the activity visible until the result is received.  Setting
3757                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
3758                // activity hidden during this time, to avoid flickering.
3759                // This can only be done when a result is requested because
3760                // that guarantees we will get information back when the
3761                // activity is finished, no matter what happens to it.
3762                mStartedActivity = true;
3763            }
3764
3765            final View decor = mWindow != null ? mWindow.peekDecorView() : null;
3766            if (decor != null) {
3767                decor.cancelPendingInputEvents();
3768            }
3769            // TODO Consider clearing/flushing other event sources and events for child windows.
3770        } else {
3771            if (options != null) {
3772                mParent.startActivityFromChild(this, intent, requestCode, options);
3773            } else {
3774                // Note we want to go through this method for compatibility with
3775                // existing applications that may have overridden it.
3776                mParent.startActivityFromChild(this, intent, requestCode);
3777            }
3778        }
3779        if (options != null && !isTopOfTask()) {
3780            mActivityTransitionState.startExitOutTransition(this, options);
3781        }
3782    }

上面的代码只需要关注mParent == null 这部分逻辑即可。mParent代表的是Activityroup,ActivityGroup最开始被用来在一个界面中嵌入多个子Activity,但是其在API13中已经被放弃了,系统推荐采用frament来代替activitygroup。在上面的代码中需要注意mMainThread.getApplicationThread()这个参数,它的类型是ApplicationThread,ApplicationThread是activityThread的一个内部类,通过后面的可以发现,ApplicationThread和ActivityThread在activity的启动过程中发挥着很重要的作用。

启动activity真正的实现由activityManagerNative.getDefault()的startActivity方法来完成。activityManagerService继承自activityManagerNative,而ActivityManagerNative继承自Binder并实现了IActivityManager这个Binder接口,因此AMS也是一个Binder,它是IActivityManager的具体实现。由于ActivityManagerNative.getDefault()其实是一个IActivityManager类型的Binder对象,因此它的具体实现是AMS。可以发现,在ActivityManagerNative中,AMS这个Binder对象采用单例模式对外提供,Singleton是一个单例的封装类,第一次调用它的get方法时它会通过create方法来初始化AMS这个Binder对象,在后续的调用中则直接返回之前创建的对象。

Activity由ActivityManagerNative。getDefault()来启动,而ActivityManagerNative.getDefault()实际上是AMS,因此Activity的启动过程又转移到AMS中,为了继续分析这个过,只需要查看AMS的startActivity方法即可。在分析AMS的startActivity方法之前,看一下Instrumentation的execStartActivity方法,其中有一行代码:

checkStartActivityResult(result,intent);

直观上看起来这个方法的作用像是在检查启动Activity的结果。当无法正确地启动一个Activity时,这个方法会抛出异常信息,其中最熟悉不过的就是“Unable to find explicit activity class ” have you declared this activity in your AndroidManifest.xml" 这个异常了,当待启动的Activity没有在AndroidManifest中注册时,就回抛出这个异常。

继续分析AMS的startActivity方法,Activity的启动过程又转移到了ActivityStackSuperVisor的startActivityMayWait方法中了,在startActivityMayWait中又调用了startActivityLocked方法,接着startActivityUncheckedLocked又调用了ActivityStack的resumeTopactivitiesLocked方法,这个时候启动过程已经从ActivityStackSupervisor转移到了ActivityStack。 resumeTopActivitiesLocked方法又调用了ActivityStackSupervisor的startSpecificActivityLocked方法。startSpecificActivityLocked方法调用了realStartActivityLocked方法。

image

其中app.thread的类型为IApplicationThread,IApplicationThread继承了IInterface接口,所以它是一个Binder类型的接口。从IApplicationThread声明的接口方法可以看出,其内部包含了大量启动、停止Activity的接口,此外还包含了启动和停止服务的接口。从接口方法的命名可以猜测,IApplicationThrad这个Binder接口的实现者完成了大量和Activity以及Service启动/停止相关的功能,事实证明的确是这样的。

那么IApplicationThread的实现者IApplicationThread的实现者到底是什么呢?答案就是ActivityThread中的内部类ApplicationThread,下面来看一下ApplicationThread的定义:

private class ApplicationThread extends AplicationThreadNative
public abstract class ApplicationThreadNative extends Binder implements IApplicationThread

可以看出,ApplicationThread继承了ApplicationThreadNative,而ApplicationThreadNative则继承了Binder并实现了IApplicationThread接口。系统为AIDL文件自动生成的代码,就会发现ApplicationThreadNative的作用其实和系统为AIDL文件生成的类是一样的。

在ApplicationThreadNative的内部,还有一个ApplicationThreadProxy类,这个内部类也是系统为AIDL文件自动生成的代理类。ApplicationThreadNative就是IApplicationThread的实现者,由于ApplicationThreadNative被系统定义为抽象类,所以ApplicationThread就成了IApplicationThread最终实现者。

绕了一大圈,Activity的启动过程最终回到了ApplicationThread中,ApplicationThread通过scheduleLaunchActivity方法来启动Activity。

在ApplicationThread中,scheduleLaunchActivity的实现很简单,就是发送一个启动Activity的消息交由Handler处理,这个Handler有着一个很简洁的名字:H。sendMessage的作用是发送一个消息给H处理。

从Handler H 对“LAUNCH_ACTIVITY”这个消息的处理可以知道,Activity的启动过程由ActivityThread的handleLaunchActivity方法来实现。

private void handleLaunchActivity(ActivityClientRecord r,Intent customIntent){
   。。。。
    Activity a = performLaunchActivity(r,coustomIntent);
    if(a != null){
        r.createdConfig = new Configuration(mconfiguration);
        Bundle oldState = r.state;
        handleResumeActivity(r.token,false,r.isForward,!r.activity.mFinished && r.startNotResumed);
        。。。
    }
。。。
}

从上面的源码可以看出,performLaunchActivity方法最终完成了Activity对象的创建和启动过程,并且ActivityThrad通过handleResumeActivity方法来调用被启动Activity的onResume这一生命周期方法。

perforLaunchActivity这个方法主要完成了如下几件事。

1 从ActivityClientRecord中获取待启动的Activity的组件信息

2 通过Instrmentation的newActivity方法使用类加载器创建Activity对象

public Activity newActivity(ClassLoader cl,String className,Intent intent) throws InstantiationException{
    ClassNotFoundException{
        return(Activity)cl.loadClass(className).newInstance();
    }
}

3 通过LoadedApk的makeApplication方法来尝试创建Application对象

从makeApplication的实现可以看出,如果Application已经被创建了,那么就不会再重复创建了,这也意味着一个应用只有一个Application对象。Application对象的创建也是通过Intrmentation来完成的,这个过程和activity对象创建一样都是通过类加载器来完成的。Application创建完毕后,系统会通过Instrumentation的callApplicationOnCreate来调用Application的onCreate方法。

4 创建ContextImpl对象并通过Activity的attach方法来完成一些重要数据的初始化

ContextImpl是一个很重要的数据结构,它是Context的具体实现,Context中的大部分逻辑都是由ContextImpl来完成的。ContextImpl是通过Activity的attach方法来和Activity建立关联的,除此之外,在attach方法中Activity还会完成Window的创建并建立自己和Window的关联,这样当Window接收到外部输入事件后就可以将事件传递给Activity。

5 调用Activity的onCreate方法

mInstrumentation.callActivityOnCreate(activity,r.state),由于Activity的onCreate已经被调用,也意味着Activity已经完成了整个启动过程。

9.3 Service的工作过程

Service的启动过程和绑定过程,在分析Service的工作过程之前,先看一下如何使用一个Service。Service分为两种工作状态,一种是启动状态,主要用于执行后天计算;另一种是绑定状态,主要用于其他组件和Service的交互。需要注意的是,Service的这两种状态是可以共存的,即Service即可以处于启动状态也可以同时处于绑定状态。通过Context的startService方法即可启动一个Service:

Intent intentService = new Intent(this,MyService.class);
startService(intentService);

通过Context的bindService方法即可 以绑定的方式启动一个Service:

Intent intent = new Intent(this,MyService.class);
bindService(intentService,mServiceConnection,BIND_AUTO_CREATE);
9.3.1 Service的启动过程

Service的启动过程从ContextWrapper的startActivity开始:

public ComponentName startService(Intent service){
    return mBase.startService(service);
}

上面的代码的mBase的类型是ContextImpl,Activity被创建时会通过attach方法将一个ContextImpl对象关联起来,这个ContextImpl对象就是上述代码中的mBase。从ContextWrapper的实现可以看出,其大部分操作都是通过mBase来实现的,在设计模式中这是一种典型的桥接模式。

在ContextImpl中,startService方法会调用startServiceCommon方法,而startServiceCommon方法又会通过ActivityManagerNative.getDefault()这个对象来启动一个服务。ActivityManagerNative.getDefault()实际上就是ActivityManagerService,通过AMS来启动服务的行为是一个远程过程调用,AMS会通过mService这个对象来完成Service后续的启动过程,mService对象类型是ActiveServices,ActiveSerivices是一个辅助AMS进行Service管理的类,包括Service的启动、绑定、停止等。在ActiveServices的startLocked方法的尾部会调用startServiceInnerLocked方法。

startServiceInnerLocked方法中ServiceRecord描述的是一个Service记录,ServiceRecord一直贯穿着整个Service的启动过程。startServiceInnerLocked方法并没有完成具体的启动工作,而是把后续的工作交给了bringUpServiceLocked方法来处理,在bringUpServiceLocked方法中又调用realStartServiceLocked方法。从名字上来看,这个方法应该真正地启动一个Service。

在realStartServiceLocked方法中,首先通过app.thread的scheduleCreateService方法来创建Service对象并调用其onCreate,接着再通过sendServiceArgsLocekd方法来调用Service对象的其他方法,比如onStartCommand,这两个过程是进程均是进程间通信。app.thread对象是IApplicationThread类型,它实际上是一个Binder,它的具体实现是ApplicationThread和ApplicationThreadNative,由于ApplicationThread继承了ApplicationThreadNative,因此只需要看ApplicationThread对Service启动过程的处理即可。

pulblic final void scheduleCreateService(IBinder token, ServiceInfo,CompatibilityInfo compatInfo,int processState){
    updateProcessState(processState,false){
        CreateServiecDate s = new CreateServiceData();
        s.token = token;
        s.info = info;
        sendMessage(H.CREATE_SERVICE,s);
    }
    
}

很显然,这个过程和Activity的启动过程是类似的,都是通过发送消息给Handler H来完成的。H会接收这个CREATE_SERVICE消息并通过ActivityThread的handleCreateService方法来完成Service的最终启动.

handleCreateService主要完成了如下几件事:

首先通过类加载器创建Service的实例。然后创建Application对象并调用其onCreate,当然Application的创建过程只会有一次。接着创建ContextImpl对象并通过Service的attach方法建立二者之间的关系,这个过程和Activity实际上是类似的,毕竟Service和Activity都是一个Context。

最后调用Service的onCreate方法并将Service对象存储到ActivityThread中的一个列表中,由于Service的onCreate方法被执行了,这也意味着Service已经启动了,除此之外,ActivityThread中还会通过handleServiceArgs方法调用Service的onStartCommand方法。

9.3.2 Service的绑定过程

和Service的启动过程一样,Service的绑定过程也是从ContextWrapper开始的:

public boolean bindService(Intent service ,ServiceConnection conn,int flags){
    return mBase.bindService(service,conn,flags);
}

这个过程和Service的启动过程是类似的,mBase同样是ContextImpl类型的对象。ContextImpl的bindService方法最终会调用自己的bindServiceCommon方法。

bindServiceCommon方法主要完成两件事:

首先将客户端的ServiceConnection对象转化为ServiceDispatcher.InnerConnection对象。之所以不能直接使用ServiceConnection对象,这是因为服务的绑定有可能跨进程,因此ServiceConnection对象必须借助于Binder才能让远程服务回调自己的方法,而ServiceDispatcher的内部类InnerConnection刚好充当了Binder这个角色。那么ServiceDispathcer的作用是什么呢?其实ServiceDispatch起着连接ServiceConnection和InnerConnection的作用。这个过程由LoadedApk的getServiceDispatcher方法完成。

public final IServiceConnection getServiceDispatcher(ServiceConnection c,Context context,Handler handler, int flags){
    synchronized(mServices){
        LoadedApk.ServiceDispatcher sd = null;
        ArrayMap<ServiceConnection,LoadedApk.ServiceDispatcher> map = mServiecs.get(context);
        if(map != null){
            sd = map.get(c);
        }
        if(sd == null){
            sd = new ServiceDispatcher(c,context,handler,flags);
            if(map == null){
                mServices.put(context,map);
            }
            map.put(c,sd);
        } else{
            sd.validate(context,handler);
        }
        return sd.getIServiceConnection();
    }
}

mServices是一个ArrayMa,它存储了一个应用当前活动的ServiceConnection和ServiceDispatcher的映射关系;

系统首先会查找是否存在相同的ServiceConnection,如果不存在就重新创建一个ServieDispatcher对象并将其存储在mServices中,其中映射关系的key是ServiceConnection,value是ServiceDispatcher,在ServiceDispathcer的内部又保存了ServiceConnection和InnerConnection对象。当Service和客户端建立连接后,系统会通过InnerConnection来调用ServiceDispatcher中的onServiceConnection方法,这个过程可能是跨进程的。当ServiceDispatcher创建好了以后,getServiceDispatcher会返回其保存的InnerConnection对象。

接着bindServiceCommon方法会通过AMS来完成Service的具体的绑定过程,这对应于AMS的bindService方法:

public int bindService(IApplicationThread caller,IBinder token,Intent service,String resolvedType,IServiceConnection connection , int flags,int userId){
    enforceNotIsolatedCaller("bindService");
    if(service != null && service.hasFileDescriptors() == true){
        throw new IllegalArgumentExceptio("File descriptors passed in Intent");
    }
    synchronized(this){
        return mServices.bindServiceLocked(caller,token,service,resolvedType,connection,flags,userId);
    }
}

接下来,AMS会调用ActiveService的bindServiceLocked方法,bindServiceLocked再调用brindUpServiceLocked,bindUpServiceLocked又会调用realStartServiceLocked方法,realStatServiceLocked方法最终都是通过ApplicationThread来完成Service实例的创建并执行其onCreate方法,和启动Service不同的是,Service的绑定过程会调用app.thread的scheduleBindservice方法,这个过程的实现在ActiveServices的requestServiceBindingLocked方法中。

app.thread这个对象多次出现过,对于它我们应该再熟悉不过了,它实际上就是ApplicationThread。ApplicationThread的一系列以schedule开头的方法,其内部都是通过Handler H来中转的;

在H内部,接收到BIND_SERVIC这类消息时,会交给ActivityThread的handleBindService方法来处理。在handleBindService中,首先根据Service的token取出Service对象,然后调用Service的onBind方法,Service的onBind方法会返回一个Binder对象给客户端使用,原则上,Service的onBind方法被调用以后,Service就处于绑定状态了,但是onBind方法是Service的方法,这个时候客户端并不知道已经成功连接Service了,所以还必须调用客户端的ServiceConnection中的onServiceConnected,这个过程是由ActivityManagerNative。getDefault()的publishService方法来完成的,ActivityManagerNative.getDefault()的publishService方法来完成的,而前面多次提到,ActivityManagerNative.getDefault()就是AMS。

Service有一个特性,当多次绑定同一个Service时,Service的onBind方法只会执行一次,除非Service被终止了。当Service的onBind执行以后,系统还需要告知客户端已经成功连接Service了。这个过程由AMS的publishService方法来实现:

public void publishService(IBinder token,Intent intent,Ibinder service){
    if(intent != null && intent.hasFileDescriptors() == true){
        throw new IllegalargumentExcePtion("File descriptors passed in Intent");
    }
    synchronized(this){
        if(!(token instanceof ServiceRecord)){
            throw new IllegaargumentException("Invalid service token");
        }
        mServices.publishServiceLocked((ServiceRecord)token,intent,service);
    }
}

AMS的publishService方法将具体的工作交给了ActivityServices类型的mServices对象来处理。ActiveService的publishServiceLocked方法看起来很复杂,核心代码就只有一句话:c.conn.connected(r.name,service),其中c的类型是ConnectionRecord,c.conn的类型是ServiceDispatch.InnerConnection,service就是Service的onBind方法返回的Binder对象。

对于Service的绑定过程来说,ServiceDispatcher的mActivityThread是一个Handler,其实就是ActivityThread中的H,从前面ServiceDispatcher的创建过程来说,mActivityThread不会为null。这样一来,RunConnection就可以由H的post方法从而运行在主线程中,因此客户端ServiceConnection中的方法是在主线程被回调的。 由于ServiceDispatcher内部保存了客户端的ServiceConnection对象,因此可以很方便地调用ServiceConnection对象的onServiceConnected方法。

9.4 BroadcastReceiver的工作过程

主要包含两方面的内容,一个是广播的注册过程,另一个是广播的发送和接收过程,首先定义广播接收者,只需要继承BrocastReceiver并重写onReceive方法即可,下面是一个典型的广播接收者的实现:

public class MyReceiver extends BroadcaseReceiver{
    @Override
    public void onReceiver(Context context,Intent intent){
        //onReceiver函数不能做耗时的事情,参考值:10s以内
        String action = intent.getAction();
        //do some works
    }
}

定义好了广播接收者,接着还需要注册广播接收者,注册分为两种方式,既可以在AndroidMenifest文件中静态注册,也可以通过代码动态注册。

静态注册:

<receiver android:name=".MyReceiver">
    <intent-filter>
        <action android:name="com.ryg.receivr.LAUNCH"/>
    </intent-filter>
</receiver>

通过代码来动态注册广播也是很简单的,如下所示。需要注意的是,动态注册的广播需要在合适的时机进行解注册,解注册采用unregisterReceiver方法。

IntentFilter filter = new IntentFilter();
filter.addAction("com.ryg.receiver.LAUNCH");
registerReceiver(new MyReceiver(),filter);

注册完成以后就可以通过send方法发送广播了

Intent intent = new Intent();
intent.setAction("com.ryg.receiver.LAUNCH");
sendBroadcase(intent);
9.4.1广播的注册过程

广播的注册分为静态注册和动态注册,其中静态注册的,其中静态注册的广播在应用安装时由系统自动完成注册,具体来说是由PackagerManagerService来完成整个注册进程的,除了广播以外,其他三大组件也是在应用安装时由PackagerManagerService解析并注册的。这里只分析广播的动态注册的过程,动态注册的过程是从ContextWrapper的register方法,和Activity以及Service一样。ContextWrapper并没有做实际工作,而是将注册过程直接交给了ContextImpl来完成:

public Intent registerReceiver(BroacastReceiver receiver, IntentFilter filter){
    return mBase.registerReceiver(receiver,filter);
}

ContextImpl 的registerReceiver方法调用了自己的registerReceiverInternal方法。

系统首先在mPackageInfo获取IIntentReceiver对象,然后再采用跨进程的方式向AMS发送广播注册的请求。之所以采用IIntentReceiver而不是直接采用BroadcastReceiver,这是因为上述注册过程是一个进程间通信过程,而BroadcastReceivr作为Android的一个组件是不能直接跨进程传递的,所以需要通过IIntentReceiver来中转一下。毫无疑问,IIntentReceiver必须是一个Binder接口,它的具体实现是LoadedApk.ReceiverDispatcher.InnerReceiver,ReceiverDispatcher的内部同时保存了BroadcastReceiver和InnerReceiver,这样当广播接收到广播时,ReceiverDispatcher可以很方便地调用BroadcastReceiver的onReceiver方法。可以发现BroadcastReceiver的这个过程和Service的实现原理类似,Service也有一个叫ServiceDispatcher的类,并且其内部类InnerConnection也是一个Binder接口,作用同样也是为了跨进程通信。

ReceiverDispatcher的getIIntentReceiver的实现,很显然,getReceiverDispatcher方法重写创建了一个ReceiverDispatcher对象并将其保存的InnerReceiver对象作为返回值返回,其中InnerRecevier对象和BroadcastReceiver都是在ReceiverDispatcher的构造方法中被保存起来的。

public IItentReceiver getReceiverDispatcher(BroadcastReceiver r,Context context,Handler handler,Instrumenttation instrumentation,boolean registered){
    synchronized(mReceivers){
        LoadedApk.ReceiverDispatcher rd = null;
        ArrayMap<BroadcastReceiver,LoadedApk.ReceiverDispatcher> map = null;
        if(registered){
            map = mReceivers.get(context);
            if(map != null){
                rd = map.get(r);
            }
        }
        if(rd == null){
            rd = new ReceiverDispatcher(r,context,handler,instrumentation,registered);
            if(registered){
                if(map == null){
                    map = new ArrayMap<BroadcastReceiver,LoadedApk.ReceiverDispatcher>();
                }
                map.put(r,rd);
            }
        }else{
            rd.validate(context,handler);
        }
        rd.mForgotten = false;
        returen rd.getIIntentReceiver;
    }
}

由于注册广播的真正实现过程是在AMS中,因此我们需要看一下AMS的具体实现。AMS的registerReceiver方法看起来很长,其实关键点就只有下面一部分,最终会把远程的InnerReceiver对象以及IntentFilter对象存储起来,这样整个广播的注册过程就完成了:

public Intent registerReceiver(IApplicationThread caller,String callerPackage,IIntentReceiver receiver,IntentFilter filter,String permission,int userId){
   mRegisterReceivers.put(receiver,asBinder(),rl);
   BroadcastFilter bf = new BroadcastFilter(filter,fl,callerPackage,permission,callingUid,userId);
   rl.add(bf)
   
   mReceiverResolver.addFilter(bf);
}
9.4.2 广播的发送和接收过程

分析广播的发送和接收过程,当通过send方法来发送广播时,AMS会查找出匹配的广播接收者并将广播发送给它们处理。广播的发送有几种类型:普通广播、有序广播、粘性广播,它们具有不同的特性但它们的发送和接收过程的流程是类似的。

广播的发送和接收过程,其本质是一个过程的两个阶段。这里从广播的发送可以说起,广播的发送仍然开始于ContextWrapper的sendBroadcast方法,之所以不是Context,那是因为Context的sendBroadcast是一个抽象方法,和广播的注册过程一样,ContextWrapper的sendBroadcast方法仍然什么都不做,只是把事情交给ContextImpl去处理,ContextImpl的sendBroadcast方法:

public void sendBroadcast(Intent intent){
    warnIfCallingFromSystemProcess();
    String resolveType = intent.resolveTypeIfNeeded(getContentResolever());
    try{
    intent.prepareToleaveProcess();
    ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread,intent,resolveType,null,Activity.RSULT_OK,null,null,null,AppOpsManager.OP_NONE,false,false,getUserId());
    }catch(RemoteException e){
        
    }
}

从上面的代码来看,ContextImpl也是几乎什么事都没干,它直接向AMS发起了一个异步请求用于发送广播。broadcastIntent调用了broadcastIntentLocked方法,AMS的broacastIntentLocked方法其中一行代码:

intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
这表示在android5.0中,默认情况下广播不会发送给已经停止的应用

FLAG_INCLUDE_STOPPED_PACKAGES

表示包含已经停止的应用,这个时候广播会发送给已经停止的应用。

FLAG_EXCLUDE_STOPPED_PACKAGES

表示不包含已经停止的应用,这个时候广播不会发送给已经停止的应用。

从android3.1开始,系统为所有广播默认添加了FLAG_EXCLUDE_STOPPED_PACKAGES标记,这样做是为了防止广播无意间或者不必要的时候调起已经停止运行的应用。如果的确需要调起未启动的应用,那么只需要为广播的Intent添加FLAG_INCLUDE_STOPPED_PACKAGES标记即可。当FLAG_EXCLUDE_STOPPED_PACKAGES和FLAG_INCLUDE_STOPPED_PACKAGES两种标记位共存时,以FLAG_INCLUDE_STOPPED_PACKAGES为准。这里需要补充一下,一个应用处于停止状态分为两种情形:第一种是应用安装后未运行,第二种是应用被手动或者其他应用强停了。

在broadcastIntentLocked的内部,会根据intent-filter查找出匹配的广播接收者并经过一系列的条件过滤,最终会满足条件的广播接收者添加到BroadcastQueue中,接着BroadcastQueue就会将广播发送给相应的广播接收者。

Broadcastqueue的scheduleBroadcastsLocked方法并没有立即发送广播,而是发送一个BROADCAST_INTENT_MSG类型的消息,BroadcastQueue收到消息后会调用peocessNextBroadcast方法。

无序广播存储在mParalleBroadcasts中,系统会遍历mParallelBroadcasts并将其中的广播发送过给它们所有的接收者,具体的发送过程是通过deliverToTRegisteredReceiverLocked方法来实现的。deliverToRegisteredReceiverLocked方法负责将一个广播发送给一个特定的接收者,它内部调用了performReceiveLocked方法来完成具体的发送过程:

performReceiveLocked(fillter.receiverList.app,filter.receiverList.receiver,new Intent(r.intent),r.resultCode,r.resultData,r.resultExtras,r.ordered,r.initialSicky,r.userId);

由于接收广播会调起应用程序,因此app.thread不为null,根据前面的分析我们知道这里的app.thread仍然指ApplicationThread。

ApplicationThread的scheduleRegisteredReceiver的实现比较简单,它通过InnerReceiver来实现广播的接收。

InnerReceiver的performReceive方法会调用LoadedApkReceiverDispatcher的performReceiver方法。在该方法中,会创建一个Args对象并通过mActivityThread的post方法来执行Args中的逻辑,而Args实现了Runnable接口。mActivityThread是一个Handler,它其实就是ActivityThread中的mH,mH的类型是ActivityThread的内部类H:

final BroadcastReceiver receiver = mReceiver;
receiver.setPendingResult(this);
receiver.onReceiver(mContext,intent);
很显然,这个时候BroadReceiver的onReceiver方法被执行了,也就是说应用已经接收到广播了,同时onRecevie方法是在广播接收者主线程中被调用的。

9.5 ContentProvider的工作过程

ContentProvider是一种内容共享型组件,它通过Binder向其他组件乃至其他应用提供数据。 当ContentProvider所在的进程启动时,ContentProvider会同时启动并被发布到AMS中。需要注意的是,这个时候ContentProvider的onCreate要先于Application的onCreate而执行,这在四大组件中是一个少有的现象。

当一个应用启动时,入口方法为ActivityThread的main方法,main方法是一个静态方法,在main方法中会创建ActivityThread的实例并创建主线程的消息队列,然后在ActivityThread的attach方法中会远程调用AMS的attachApplication方法并将ApplicationThread对象提供给AMS。ApplicationThread是一个Binder对象,它的Binder接口是IApplicationThread,它主要用于ActivityThread和AMS之间的通信,在AMS的attachApplication方法中,会调用ApplicationThread的bindApplication方法,注意这个过程同样是跨进程完成的,bindApplication的逻辑会经过ActivityThread中Mh Handler切换到ActivityThread中执行,具体的方法handleBindApplication。在handleBindApplication方法中,ActivityThread会创建Application对象并加载ContentProvider。需要注意的是,ActivityThread会先加载ContentProvider,然后再调用Application的onCreate方法。 image

这就是ContentProvider的启动过程,ContentProvider启动后,外界就可以通过它所提供的增删改查这四个接口来操作ContentProvider中的数据源,即insert、delete、update和query四个方法。这四个方法都是通过Binder来调用的,外界无法直接访问Contentprovider,它只能通过AMS根据Uri来获取对应的ContentProvider的Binder接口IContentPeovider, 然后再通过IContentProvider来访问ContentProvider中数据源。

ContentProvider都应该是单实例的。ContentProvider到底是不是单实例,这是由它的android:multiprocess属性来决定的,当android:multiprocess为flase时,ContentProvider是单实例,这也是默认值:当android:multiprocess为true时,ContentProvider为多实例,这个时候在每个调用者的进程中都存在一个ContentProvider对象。由于在实际的开放中,并未发现多实例的ContentProvider的具体使用场景,官方文档中的解释是这样可以避免进程间通信的开销,但是这在实际开发中仍然缺少使用价值,我们可以简单认为ContentProvider都是单实例的。

访问ContentProvider需要通过ContentResolver,ContentResolver是一个抽象类,通过Context的getContentResolver方法获取的实际上是ApplicationContentResolver对象,ApplicationContentResolver类继承了ContentResolver并实现了ContentResolver中的抽象方法。当ContentProvider所在的进程未启动时,第一次访问它时就会触发ContentProvider的创建,当然也伴随着ContentProvider所在进程的启动。通过ContentProvider的四个方法的任何一个i额都可以触发ContentProvider的启动过程,这里选择query方法。

ContentProvider的query方法中,首先会获取IContentProvider对象,不管是通过qcquireUnstableProvider方法还是直接通过acquireProvider方法,它们的本质最终都是通过acquireProvider方法来获取ContentProvider。下面是ApplicationContentResolver的acquireProvider方法的具体实现:

protected IContentProvider acquirreProvider(Content context,String auth){
    return mMainThread.acquireProvider(context,ContentProvider.getAuthorityWithoutUserId(auth),resolveUserIdFromAuthority(auth,ture));
}

ApplicationContentsolver的acquireProvider方法并没有处理任何逻辑,它直接调用了ActivityThread的acquireProvider方法。ActivityThread中通过mProviderMap来存储已经启动的ContentProvider对象,mProviderMap:

final ArrayMap<ProviderKey,providerclientRecord>mProviderMap = new ArrayMap<>();

如果目前ContentProvider没有启动,那么就发送一个进程间请求给AMS让其启动目标ContentProvider,最后再通过installProvider方法来修改引用计数。那么AMS是如何启动ContentProvider的呢?ContentProvider被启动时会伴随着进程的启动,在AMS中,首先会启动ContentProvider所在的进程,然后再启动ContentProvider。启动过程是由AMS的StartProcessLocked方法来完成的,其内部主要是通过Process的start方法来完成一个新的进程的启动。

ActivityThread的main方法是一个静态方法,在它内部首先会创建ActivityThread的实例并调用attach方法来进程一系列初始化,接着就开始进行消息循环了。ActivityThread的attach方法将ApplicationThread对象通过AMS的attachApplication方法跨进程传递给AMS,最终AMS会完成ContentProvider的创建过程。AMS的attachApplication方法调用了attachApplicationLocked方法,attachApplicationLocked又调用了ApplicationThread的bindApplication,注意这个过程也是进程间调用。

thread.bindApplication(processName,appInfo,providers,app.instrumentationClass,xxxxxxxxxxxxxxxxx)

ActivityThread的bindApplication会发送一个BIND_APPLICATION类型的消息给mH,mH是一个Handler,它收到消息后调用ActivityThread的handleBindApplication方法。ActivityThread的handleBindApplication则我完成了Application的创建以及ContentProvider的创建。

1 创建ContextImpl和Instrumentation

ContextImpl instrContext = ContextImpl.createAppContext(this,pi);
try{
    java.lang.ClassLoader cl = instrContext.getClassLoader();
    mInstrumentation = (Instrumentation)cl.loadClass(data.instrumentationName.getClassName()).newInstance();
} catch(Exception e){
    throw new RuntimeException(xxxx);
}
mInstrumentation.init(this,instrContext,appContext,xxxxx);

2 创建Application对象

Application app = data.info.makeApplication(data.restrictedBackupMode,null);
mInitialApplication = app;

3 启动当前进程的ContentProvider并调用其onCreate方法

List<ProviderInfo> providers = data.providers;
if(providers != null){
    installContentProviders(app,providers);
    mH.sendEmptyMessageDelayed(H.ENABLE_JIT,10*1000);
}

installContentProviders完成了ContentProvider的启动工作,首先会遍历当前进程的ProviderInfo的列表并一一调用installProvider方法来启动它们,接着将已经启动的ContentProvider发布到AMS中,AMS会把它们存储在ProviderMap中,在installProvider方法中通过类加载器完成了ContentProvider对象的创建。除了完成了ContentProvider对象的创建,还会通过ContentProvider的attachInfo方法来调用它的onCreate方法。到此为止,ContentProvider已经被创建并其onCreate方法也已经被调用。

4 调用Application的onCreate方法

try{
    mInstrumentation.callApplicationOnCreate(app);
} catch(){
    if(!mInstrumentation.onException(app,e)){
        xxxxx
    }
}

经过四个步骤,ContentProvider已经成功启动,并且其所在进程的Application也已经启动,这意味着ContentProvider所在的进程已经完成了整个的启动过程,然后其他应用就可以通过AMS来访问这个ContentProvider了。拿到了ContentProvider以后,就可以通过它所提供的接口方法来访问了。这里的ContentProvider并不是原始的ContentProvider,而是ContentProvider的Binder类型的IContentProvider,IContentProvider.Transport继承了ContentProviderNative,其中ContentProvider.Transport继承了ContentProviderNative。选择query方法,首先其他应用会通过AMS获取到ContentProvider的Binder对象即IContentProvider,而IContentProver的实现者实际上是ContentProvider.Transport。因此其他应用调用IConten天Provider的query方法。

ContentProvider.Transport的query方法调用了ContentProvider的query方法,query方法的执行结果再通过Binder返回给调用者,这样一来整个调用过程就完成了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值