美文网首页
RPC & AIDL

RPC & AIDL

作者: gbmaotai | 来源:发表于2018-10-11 16:21 被阅读0次

    RPC & AIDL

    一般创建的服务并不能被其他的应用程序访问。为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。
    Android使用AIDL来实现。

    每一个进程都有自己的Dalvik VM实例,都有自己的一块独立的内存,都在自己的内存上存储自己的数据,执行着自己的操作,都在自己的那片狭小的空间里过完自己的一生。每个进程之间都你不知我,我不知你,就像是隔江相望的两座小岛一样,都在同一个世界里,但又各自有着自己的世界。而AIDL,就是两座小岛之间沟通的桥梁。相对于它们而言,我们就好像造物主一样,我们可以通过AIDL来制定一些规则,规定它们能进行哪些交流。

    何时使用AIDL是必要的:只有你允许客户端从不同的应用程序为了进程间的通信而去访问你的service。

    Binder RPC 机制

    clipboard.png
    1.client通过获得一个server的代理接口,对server进行直接调用;
    2.代理接口中定义的方法与server中定义的方法是一一对应的;
    3.client调用某个代理接口中的方法时,代理接口的方法会将client传递的参数打包成为Parcel对象;
    4.代理接口将该Parcel发送给内核中的binder driver.
    5.server会读取binder driver中的请求数据,如果是发送给自己的,解包Parcel对象,处理并将结果返回;
    6.整个的调用过程是一个同步过程,在server处理的时候,client会block住。

    应用层AIDL的使用方法

    服务端步骤步骤
    1.建立AIDL,自动生成java接口

    Java包目录中建立一个扩展名为A.aidl的文件,并写下需要的接口。如果aidl文件的内容是正确的,ADT会在gen目录下自动生成一个A.Java接口文件。

    2. 实现service

    建立一个服务类(Service的子类)

    public class MyService extends Service 
    

    创建的服务类中创建一个内部类,实现由aidl文件生成的Java接口

    MyServiceImpl 
    

    服务类的onBind方法返回时,将实现aidl接口的内部类对象返回出去

    return new MyServiceImpl();
    
    public class MyService extends Service {        
    @Override      
    public IBinder onBind(Intent arg0) { 
        return new MyServiceImpl();  
    }        
    public class MyServiceImpl extends IMyService.Stub 
    {      
        public String funcXXX
        {
        }
    
    }  
        
    }
    
    
    3.AndroidManifest.xml文件中配置AIDL服务

    <action>标签中android:name的属性值就是客户端要引用该服务的ID,也就是Intent类的参数值

    客户端端步骤步骤
    1.绑定服务
    // 绑定远程服务端服务         
    Intent serviceIntent = new Intent("name_XXX_refer_service_AndroidManifest");     
    
    bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
    
    
    2.获得服务对象
    IMyService mIMyService;
    
    private ServiceConnection mConnection = new ServiceConnection() 
    {            
    public void onServiceConnected(ComponentName name, IBinder service) 
    {              
    mIMyService = IMyService.Stub.asInterface(service);
    }
    public void onServiceDisconnected(ComponentName name) 
    {             
    // 解除绑定    
    mIMyService = null;     
    } 
    };
    
    

    framework层 AIDL的使用方法

    1. android/os目录下添加aidl
    interface IDoorService
    {
        void setCameraLight(boolean on);
        void door_open_close(int open_close);
    }
    

    编译会在out目录下生成Java文件

    继承android.os.IInterface
    里面有Stub类和自定义的方法,Stub类继承Binder

    asInterface / Proxy 就是客户端使用

    asBinder 就是service自己

    /*
     * This file is auto-generated.  DO NOT MODIFY.
     * Original file: frameworks/base/core/java/android/os/IDoorService.aidl
     */
    package android.os;
    public interface IDoorService extends android.os.IInterface
    {
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements android.os.IDoorService
    {
    private static final java.lang.String DESCRIPTOR = "android.os.IDoorService";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
    this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an android.os.IDoorService interface,
     * generating a proxy if needed.
     */
    public static android.os.IDoorService asInterface(android.os.IBinder obj)
    {
    if ((obj==null)) {
    return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin!=null)&&(iin instanceof android.os.IDoorService))) {
    return ((android.os.IDoorService)iin);
    }
    return new android.os.IDoorService.Stub.Proxy(obj);
    }
    @Override public android.os.IBinder asBinder()
    {
    return this;
    }
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
    switch (code)
    {
    case INTERFACE_TRANSACTION:
    {
    reply.writeString(DESCRIPTOR);
    return true;
    }
    case TRANSACTION_setCameraLight:
    {
    data.enforceInterface(DESCRIPTOR);
    boolean _arg0;
    _arg0 = (0!=data.readInt());
    this.setCameraLight(_arg0);
    reply.writeNoException();
    return true;
    }
    case TRANSACTION_door_open_close:
    {
    data.enforceInterface(DESCRIPTOR);
    int _arg0;
    _arg0 = data.readInt();
    this.door_open_close(_arg0);
    reply.writeNoException();
    return true;
    }
    }
    return super.onTransact(code, data, reply, flags);
    }
    private static class Proxy implements android.os.IDoorService
    {
    private android.os.IBinder mRemote;
    Proxy(android.os.IBinder remote)
    {
    mRemote = remote;
    }
    @Override public android.os.IBinder asBinder()
    {
    return mRemote;
    }
    public java.lang.String getInterfaceDescriptor()
    {
    return DESCRIPTOR;
    }
    @Override public void setCameraLight(boolean on) throws android.os.RemoteException
    {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
    _data.writeInterfaceToken(DESCRIPTOR);
    _data.writeInt(((on)?(1):(0)));
    mRemote.transact(Stub.TRANSACTION_setCameraLight, _data, _reply, 0);
    _reply.readException();
    }
    finally {
    _reply.recycle();
    _data.recycle();
    }
    }
    @Override public void door_open_close(int open_close) throws android.os.RemoteException
    {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
    _data.writeInterfaceToken(DESCRIPTOR);
    _data.writeInt(open_close);
    mRemote.transact(Stub.TRANSACTION_door_open_close, _data, _reply, 0);
    _reply.readException();
    }
    finally {
    _reply.recycle();
    _data.recycle();
    }
    }
    }
    static final int TRANSACTION_setCameraLight = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_door_open_close = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }
    public void setCameraLight(boolean on) throws android.os.RemoteException;
    public void door_open_close(int open_close) throws android.os.RemoteException;
    }
    
    
    
    2.在android/server目录下实现 这个服务
    package com.android.server;
    
    import android.content.Context;
    import com.android.server.LightsService;
    import android.os.IDoorService;
    import android.util.Slog;
    
    public class DoorService extends IDoorService.Stub
    {
        private static final String TAG = "DoorService";
    
        private int mPtr = 0;
        private LightsService mLightsService;
        private LightsService.Light mCameraLight;
         
        DoorService(Context context,LightsService ls)
        {
            mLightsService = ls;
            mCameraLight = mLightsService.getLight(LightsService.LIGHT_ID_CAMERA);
            mPtr = init_native();
    
            if(mPtr == 0)
                Slog.e(TAG, "Fail to initialize DoorService111");
        }
    
        public void door_open_close(int open_close)
        {
            if(mPtr == 0)
            {
                Slog.e(TAG, "DoorService is not initialize");
                return;
            }
    
            door_open_close_native(mPtr, open_close);
                
        }
    
            public void setCameraLight(boolean on) {
             LightsService.Light light;
    
                light = mCameraLight;
    
                light.setBrightness(on?255:0);
            }
        private static native int init_native();
            private static native void door_open_close_native(int ptr, int open_close);
    }
    

    DoorService没有继承Service
    所以这时他不是一个Service.

    它是在SystemServer中注册成为服务的。

           Slog.i(TAG, "Door Service");
           door = new DoorService(context,lights);
           ServiceManager.addService("door", door);
    

    把DoorService对象(也就是Stub)作为一个Service注册给了ServiceManager。并且注册的名字是“door”

    virtual status_t addService(const String16& name, const sp<IBinder>& service,
            bool allowIsolated)
    {
        Parcel data, reply; //Parcel是数据通信包
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());   //写入RPC头信息
        data.writeString16(name);        // name为 "media.player"
        data.writeStrongBinder(service); // MediaPlayerService对象
        data.writeInt32(allowIsolated ? 1 : 0); // allowIsolated= false
        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); //【见流程4】
        return err == NO_ERROR ? reply.readExceptionCode() : err;
    }
    

    addService服务端在service_manager.c实现。

    int do_add_service(struct binder_state *bs,uint16_t *s,unsigned len,void *ptr,unsigned uid,int allow_isolated)
    

    ServiceManager是一个linux级的进程,Native层Service的管理员。

    需要特别注意的是ServiceManager本身也是一个Service,他需要先向Binder注册自己,而且要把自己注册为“管理员”

    serviceManager自己有binder.c直接和Binder驱动来通信,并且只有一个循环binder_loop来进行读取和处理事务,这样的好处是简单而高效。

    serviceManager工作主要就两个:查询和注册服务。

    int binder_become_context_manager(struct binder_state *bs)    
    {              
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);    
    }
    
    3.获得这个服务
    IDoorService.Stub.asInterface
    
        registerService("door", new ServiceFetcher() {  
                public Object createService(ContextImpl ctx) {  
                    IBinder b = ServiceManager.getService("door");  
                    return new DoorManager(ctx, IDoorService.Stub.asInterface(b));  
        }}); 
    
    4.应用如何通过context来获取服务的
    Context.getSystemService(name)
    

    Context的实现类其实是:ContextImpl

    在ContextImpl中定义如下一个HashMap,

    private static final HashMap SYSTEM_SERVICE_MAP = new HashMap();
    
    SYSTEM_SERVICE_MAP的初始化.
    在ContextImp中,有一段static的代码块,用于初始化所有服务的ServiceFetcher,并且加入SYSTEM_SERVICE_MAP里面. 里面定义了createservice
    
    
    registerService("door", new ServiceFetcher() {  
            public Object createService(ContextImpl ctx) {  
                IBinder b = ServiceManager.getService("door");  
                return new DoorManager(ctx, IDoorService.Stub.asInterface(b));  
    }}); 
    
    
    

    这是一个静态的/final的HashMap,其中保存的是每一个服务的ServiceFetcher.

    public Object getSystemService(String name) {
        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
        return fetcher == null ? null : fetcher.getService(this);
    }
    

    当通过getService()来获取服务对象的时候,首先判断这个服务对象是否已经存在:如果已经存在,则立即返回,否则调用他的一个虚的方法createService()来创建,并保存创建的这个服务对象

    相关文章

      网友评论

          本文标题:RPC & AIDL

          本文链接:https://www.haomeiwen.com/subject/pewbaftx.html