当前位置: 代码迷 >> Android >> Service与Android系统设计(七)
  详细解决方案

Service与Android系统设计(七)

热度:97   发布时间:2016-05-01 13:05:39.0
Service与Android系统设计(7)

特别声明:本系列文章LiAnLab.org著作权所有,转载请注明出处。作者系LiAnLab.org资深Android技术顾问吴赫老师。本系列文章交流与讨论:@宋宝华Barry

3.     通过Remote Service实现Android系统

对于应用程序编程来说,aidl只是一种可选项,绝大部分的应用程序,其实只是关注于图形界面与交互,所以大部分情况下只是在写Activity,用到Service的可能性并不大。即使是使用到了Service,我们也并非必须要使用aidl。我们从前面也看到了,最方便的Service,是使用简单的UnboundedService,通过Intent来驱动。如果只是针对于本地化进程,特别是一些希望通过Binder来引入灵活性但又不想将内容功能共享出来的情况,我们也可以只使用Local Binder来完成。如果我们希望使用跨进程通讯,但又不需要自动化的线程池运行环境,我们也可以使用在主线程里执行Messenger。所以现在绝大部分应用程序,甚至一些功能比较复杂的Android应用程序,也不一定会用到AIDL。

但这些,对于Android系统层实现来说,却正好相反。由于Android系统是基于跨进程交互的“沙盒”模型建立的,任意两个进程间进行交互,都有需要使用Binder。如果是Java编写的代码,则出于减小代码重复的角度考虑,就会使用AIDL。所以我们在Android源代码里可以看到大量的AIDL,而应用程序使用的像Intent、Messenger这些基础对象,都是通过AIDL来实现的一种更高层次的抽象而已。

3.1   通过Parcelable实现的Intent

首先我们可以来看看Intent与Activity的内部实现机制。作为Android应用层最强大最灵活的跨进程通信方式,Intent本质上就是一个Parcelable类,是通过Parcelable接口创建的,可在多个进程之间进行传输的消息:


Intent实现了Parcelable接口,在传输一个Intent对象时,我们便可以使用Parcelable协议,但Intent里包含的信息写入到一个Parcel对象的buffer里,然后再传递给另一个进程处理。在Intent处理里,大部分信息都是使用的基本数据类型,比如mAction、mType、mPackage、mComponent都是String。对于比较特殊的Uri类型的mData,因为Uri这种类型的类也是复杂构造的类,于是Uri也被会实现Parcelable接口。而另一个复杂类型mExtras,因为我们在现实中可能通过mExtras传递任意复杂的数据对象,于是mExtras是一个继承自Bundle类的字典型数据结构。于是,我们得到的Intent的构成便是一个简单的Parcelable实现:


Intent的源代码位于frameworks/base/core/java/android/content/Intent.java。我们会看到这一代码实现的Parcelable比我们范例里的要复杂。这跟实际情况相符,我们现实中使用的aidl接口实现与Parcelable接口实现,都会比我们例子里的要复杂,因为Parcelable接口与aidl接口只是解决跨进程传输问题,相当于是提供给跨进程访问的Public属性或方法,但我们每个对象除了有Public属性,还会有Private属性,只在当前进程内有效的,为当前对象提供一些辅助属性与操作方法,所以除了aidl与Parcelable,这些基于IBinder的对象还会有其他部分的实现。

3.2   Intent的发送 --- IActiivtyManager接口类

在创建了Intent之后,大体上会有三种Intent的发送方式,startActivity()|startActivityForResult()来启动一个Activity,startService()|bindService()来启动一个Service,以及sendBroadcast()来发送广播消息。而在Android内部实现上,Intent的发送,大致都如下图所示:


Intent的发送,分别有可能通过Context的startActivity()、startService()、sendBroadcast()三个出口进行发送。Context由Framework实现的ContextImpl来提供具体的发送功能,在ContextImpl类里会经过不同的特殊处理,比如在startActivity()之上会再套接一层execStartActivity()方法来驱动Instrumentation测试框架,但最终都会通过ActivityManagerNative类来访问到一个处理Intent请求的gDefault对象。正如我们看到的gDefault,实际上是Singleton<IActivityManager>生成的进程唯一的IActivityManager对象。于是,最终,所有的Intent,都会通过IActivityManager来走入Activity、Service与Broadcast三个不同的处理方法。

如果是按照aidl的标准写法,此时我们理论上应该会在IAcitvityManager.java的同一级目录里找到一个IActivityManager.aidl文件。但很不幸,我们找不到这么一个文件,跟我们前面见到的aidl实现似乎很不一样。所有需要使用到AIDL实现的地方,总需要某种机制可以得到IBinder引用,而像ActivityManager,还有稍后会介绍的一个ServiceManager,都会是尝试去获取一个IBinder引用的,这时便有了个“鸡与蛋”的问题,为了简化逻辑,于是这一层便是绕开AIDL,直接实现IActivityManager接口类。

仔细看一下的话,其实IActivityManager.java与通过aidl自动生成的文件很类似,基本构成都是一样:

public interface IActivityManagerextends IInterface {       1

 

    public intstartActivity(IApplicationThread caller,

           Intent intent, String resolvedType, Uri[] grantedUriPermissions,

           int grantedMode, IBinder resultTo, String resultWho,int requestCode,

           boolean onlyIfNeeded, boolean debug) throws RemoteException; 2

    public booleanfinishActivity(IBinder token,int code, Intent data)

           throws RemoteException;          

    public intbroadcastIntent(IApplicationThread caller, Intent intent,

           String resolvedType, IIntentReceiver resultTo, int resultCode,

           String resultData, Bundle map, String requiredPermission,

           boolean serialized, boolean sticky) throws RemoteException;

    public ComponentNamestartService(IApplicationThread caller, Intent service,

           String resolvedType) throws RemoteException;

    public intbindService(IApplicationThread caller, IBinder token,

           Intent service, String resolvedType,

           IServiceConnection connection, int flags)throws RemoteException;

...

   String descriptor = "android.app.IActivityManager";     3

 

    intSTART_RUNNING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;

    intHANDLE_APPLICATION_ERROR_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;

    intSTART_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;

    intUNHANDLED_BACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;

    intOPEN_CONTENT_URI_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4;              4

...

}

1 与根据aidl定义生成的接口类一样,IActivityManager也是基于IInterface生成的接口类,于是在这里我们只会定义接口方法,而不提供具体实现。

2 对于每一个需要实现接口方法而言,因为每个方法都将是跨进程的调用,所以每个方法都必须抛出Remote Exception。

3 作为使用Binder传输对象,都需要一个DESCRIPTOR作为传输时的标识,于是在Binder接收时会以这个Token作为验证传输是否有效的凭据。

4 虽然不是自动生成,但在这一接口类也会定义一系列Binder命令,Binder命令都是从IBinder.FIRST_CALL_TRANSACTION开始,其他命令都会通过+1进行Binder命令的统一化。

1.3   IActiivtyManager的Proxy端实现

但是,由于IActivityManager.java不是由aidl工具自动生成的,于是不会自生成的Stub和Proxy对象,这些对象都须由实现这一接口类的部分实现,提供发送与接收两端的Binder处理的接口方法。我们可以在源代码里行搜索,发现实现IActivityManager接口类的居然又回到ActivityManagerNative.java,是由这一文件里的ActivityManagerProxy类来实现Proxy端功能。这是Android的一个缺陷,有时代码会不必要地“回溯”。所以从代码角度分析,最后我们得到的会是Remote Service的Proxy端代码:

package android.app;       1

import android.content.ComponentName;

...

public abstractclass ActivityManagerNativeextends Binderimplements IActivityManager        2

{

 

    static publicIActivityManager asInterface(IBinder obj)       3

    {

       if(obj == null) {

           return null;

       }

       IActivityManager in =

           (IActivityManager)obj.queryLocalInterface(descriptor);

       if(in != null) {

           return in;

       }

       

       return new ActivityManagerProxy(obj);      4

    }

   

 

    static publicIActivityManager getDefault()     5   

    {

       if(gDefault != null) {

           return gDefault;

       }

       IBinder b = ServiceManager.getService("activity");    

       gDefault = asInterface(b);               6

       return gDefault;

    }

 

    static publicbooleanisSystemReady() {                7

       if(!sSystemReady) {

           sSystemReady = getDefault().testIsSystemReady();

       }

       return sSystemReady;

    }

    static boolean sSystemReady =false;

   

    publicActivityManagerNative()

    {

       attachInterface(this, descriptor);               8

    }

   

    public boolean onTransact(int code, Parcel data,Parcel reply,int flags)

           throws RemoteException {               9

       switch (code) {

       case START_ACTIVITY_TRANSACTION:           10

                ...

       case START_ACTIVITY_AND_WAIT_TRANSACTION:

                ...

       case START_ACTIVITY_WITH_CONFIG_TRANSACTION:

                ...

       case START_ACTIVITY_INTENT_SENDER_TRANSACTION:

                ...  

       case START_NEXT_MATCHING_ACTIVITY_TRANSACTION:

                ...

       case FINISH_ACTIVITY_TRANSACTION:

                ...

       return super.onTransact(code, data, reply, flags);      11

    }

 

    public IBinderasBinder()                 12

    {

       return this;

    }

 

    private staticIActivityManager gDefault;

}

 

class ActivityManagerProxy implements IActivityManager           13

{

    publicActivityManagerProxy(IBinder remote)

    {

       mRemote = remote;

    }

   

    public IBinderasBinder()                         14

    {

       return mRemote;    

    }

   

    public intstartActivity(IApplicationThread caller, Intent intent,

           String resolvedType, Uri[] grantedUriPermissions, int grantedMode,

           IBinder resultTo, String resultWho,

           int requestCode, boolean onlyIfNeeded,

           boolean debug) throws RemoteException {          15

       Parcel data = Parcel.obtain();

       Parcel reply = Parcel.obtain();

       data.writeInterfaceToken(IActivityManager.descriptor);

       data.writeStrongBinder(caller != null ? caller.asBinder() :null);

       intent.writeToParcel(data, 0);

       data.writeString(resolvedType);

       data.writeTypedArray(grantedUriPermissions, 0);

       data.writeInt(grantedMode);

       data.writeStrongBinder(resultTo);

       data.writeString(resultWho);

       data.writeInt(requestCode);

       data.writeInt(onlyIfNeeded ? 1 : 0);

       data.writeInt(debug ? 1 : 0);

       mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);

       reply.readException();

       int result = reply.readInt();

       reply.recycle();

        data.recycle();

       return result;

    }

    public intbroadcastIntent(IApplicationThread caller,

           Intent intent, String resolvedType, IIntentReceiver resultTo,

           int resultCode, String resultData, Bundle map,

           String requiredPermission, boolean serialized,

           boolean sticky) throws RemoteException          

    {

       Parcel data = Parcel.obtain();

       Parcel reply = Parcel.obtain();

       data.writeInterfaceToken(IActivityManager.descriptor);

       data.writeStrongBinder(caller != null ? caller.asBinder() :null);

       intent.writeToParcel(data, 0);

       data.writeString(resolvedType);

       data.writeStrongBinder(resultTo != null ? resultTo.asBinder() :null);

       data.writeInt(resultCode);

       data.writeString(resultData);

       data.writeBundle(map);

       data.writeString(requiredPermission);

       data.writeInt(serialized ? 1 : 0);

       data.writeInt(sticky ? 1 : 0);

       mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);

       reply.readException();

       int res = reply.readInt();

       reply.recycle();

       data.recycle();

       return res;

    }

                ...   

    private IBinder mRemote;

}

1 从包名也可以看出,这部分代码是属于我们Android应用程序的进程空间内,可直接使用的对象,Intent会由应用程序通过ActivityManagerNative,将方法对应的Binder命令发送出去。

2 这里通过一个ActivityManagerNative类来实现了IActivityManager接口,同时也会继承自Binder,于是这个类具备了Binder通信能力。但我们注意到这个类是一个抽象类,于是它对于接口方法会不会提供实现是没有保证的。而我们可以注意到是,ActivityManagerNative这个对象被创建之后,是会提供给应用程序来使用的,于是最终这个类可能也只会需要Proxy端的功能。

3 正如我们在aidl编程里看到过,asInterface()是提供给Proxy端来创建一个Proxy 对象的接口方法。于是在这一方法的实现里,会先通过queryLocalInterface()查询一下Binder通信里是否存在以descriptor为标识的监听端,存在则说明已经有IActivityManager的Service端,然后就创建一个ActivityManagerProxy对象,准备后续的命令发送。但与aidl不同之处在于,aidl可以通过bindService()来启动一个Service并与之建立binder通信,然后就可以在onServiceConnected()里取回这个Service的IBinder引用。但这种操作对于ActivityManager来说是不现实的,因为基于Intent通信的bindService(),本身也就是通过ActivityManager来发送的(鸡和蛋的问题)。于是,我们并不能直接通过aidl来完成IActivityManager实现,因为没法使用bindService(),这是IActivityManager接口与标准AIDL的唯一区别,IActivityManager是aidl机制的基础。

5 getDefault(),则是解决IActivityManager与aidl的鸡与蛋问题的办法。因为没法使用标准的bindService(),然后再通过IBinder.Stub.asInterface()取回Remote Service引用,所以Intent的发送便使用了比较特殊的方式,会先直接调用ActivityManagerNative对象的getDefault(),正如我们前面的执行流程里分析的那样。而在这个getDefault()方法里,会通过SystemManager.getService()取回来一个叫activity的service。这部分代码在Android 3.0之后,出于兼容Fragment的考虑,开始使用Singleton模式运行ActivityManagerProxy,于是会有我们图中的Singleton<ActivityManagerProxy>。

6 通过asInterface()来检测ActivityManager对应的Service端是否已经就绪,并在就绪的情况下创建ActivityManagerProxy对象。从getDefault()成功之后,Intent则可以通过这个Proxy对象来与系统进程里执行ActivityManagerService来进行通信了。

7 isSystemReady(),通过ActivityManager的testIsSystemReady远程调用来检测系统是否已经就绪。

8 ActivityManagerNative的初始化方法,在这一方法里会将descriptor通过attachInterface()写入Binder通信里。虽然ActivityManagerNative类只是一个抽象类,但提供了这些通用方法,就可以让真正实现IActivityManager接口的ActivityManagerService代码尽可能只专注于Service端代码实现,也通过定义Proxy端与Service端的共用属性,像descriptor、IBinder命令等,来达到代码尽可能被重用的目的。

9 从我们前面aidl实现部分可以看到,实际上onTransact()是完成IBinder命令的解析与转发功能的代码。在抽象类里提供onTransact(),则可以重用IBinder命令的定义。因为这里执行的都会是远程调用,所以也必须抛出Remote Service。

10 通过onTransact()方法解析完成后具体执行的方法,在这里则不会提供实现。对于每一个不同的Binder命令,它都会从Binder里取出参数,然后再调用相应的方法实现(虽然现在还不存在),然后再把执行结果和异常信息写回Binder。于是ActivityManagerService所需要实现的就只剩下这里缺失的具体实现了。

11 出于处理Binder通用性命令的需求,在解析完所有在IActivityManager接口里定义的Binder命令之后,会通过IoC模式,反向调用到Binder的onTransact()处理通用Binder命令。

12 Service端的asBinder实现,返回一个IBinder引用。我们的IInterface接口实际只需要这一接口方法,这一接口方法的神奇之处在于,在客户端调用里,asBinder()会返回针对Proxy端的IBinder引用,在Service实现部分,则会返回Stub对象的IBinder引用。到此为止,实际上ActivityManagerNative就已经把Binder接收部分的代码实现了,对于具体的IActivityManager接口的Service端实现,所剩的工作,也就只有具体的远程方法的实现。

13 因为我们在客户端部分使用IActivityManager接口,已经可以通过ActivityManagerNative类的getDefault()方法来创建Proxy对象来完成,于是IActivityManager接口的Proxy实现,便与普通的aidl实现没有任何区别了。我们的ActivtityManagerProxy,也就会是一个实现IActivityManager接口的类,可以基于这个类来创建Proxy对象。

14 对于同一IInterface,Proxy端提供的asBinder(),会返回Proxy的IBinder引用。

15 作为Proxy对象,ActivityManagerProxy类里也必须提供IActivityManager接口里所有方法的实现。不过,这里并不会有真正的调用实现,而只是将参数通过Parcel进行序列化操作,再把需要执行的Binder命令与写入Parcel的参数,通过Binder发送出去。然后执行将会被Binder阻塞,直接远程调用返回。在继续执行时,这时就取出执行结果与异常信息,返回给调用这一方法的地方。所有的命令在发送时都会使用IActivityManager.descriptor作为传输时的凭据,所以也会保证这些命令会被正确地发送到IActivityManager的Service实现。因为是访问远程方法调用,于是会同样将在Binder里读到的Remote Exception上抛,以被合适的代码捕捉处理。

       所以,从代码层面来看,除了因为bindService()传输上的“鸡与蛋”问题,我们的ActivityManager本身与普通的aidl编程没有本质区别,只是通过一层getDefault()方法来绕开bindService()的使用。但是因为IActivityManager接口本身需要支持bindService()机制,所以对实现IActivityManager的Service端的代码来说,就没有Service的生存周期这回事了。

       基于这样分析,最后,我们上面Proxy端的执行逻辑,实际上在内部实现是这样进行交互的:


通过ActivityManagerNative的getDefault()方法,我们最终得到的gDefault会是一个ActivityManagerProxy对象,然后我们所有的调用,会通过ActivityManagerProxy里对于各个方法的封装,再将具体的命令通过Binder发送到IActivityManager的Service实现部分。

于是对于IActivityManager这一接口类,剩下的工作便是看看它是如何被响应处理的。

  相关解决方案