Binder总结分析_应用层

Binder总结分析_native层

Binder是Android系统提供的一种IPC机制(Inter-Process Communication,进程间通信)。

进程是系统进行资源分配和调度的基本单位,进程的用户空间是互相独立的,那么两个进程之间的数据如何交互?一种简单的方式,采用c/s模式,分成客户端和服务端,客户端分送数据,服务端接收处理后,给出响应,这样就实现了数据的交互。

Binder架构

Binder就是一种c/s架构,分为客户端、Binder 驱动、服务端三个模块。

  1. 客户端通过 IBinder.transact() 方法将数据传递给Binder 驱动。
  2. Binder 驱动接收到数据,将这个数据传递给对应的服务端,并将当前线程(客户端线程)阻塞,等待服务端消息返回。
  3. 服务端接收到数据,并调用Binder.onTransact()方法进行相应处理,再将结果返回给Binder 驱动。
  4. Binder 驱动接收的数据,唤醒客户端线程,将结果返回给客户端。

整个Binder框架远比这个复杂,应用层Binder其实都是基于native(C/C++)层的binder架构,Binder 驱动其实是在Linux的kernel层。这里我们只分析Binder在应用层的体现,而native层的binder架构在下一篇文章中介绍。

上面的流程,有两个重要的方法 IBinder.transact、Binder.onTransact。

public interface IBinder {

   public boolean transact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException;

}

注意这个方法是定义在IBinder接口中的,发送Binder请求。

  1. code:请求码,主要用于在Binder.onTransact方法中,标识客户端期望调用服务端的哪个函数。
  2. data:客户端请求数据都储存这个对象里面。
  3. reply:服务端返回的数据都储存在这个对象里。(当然要等服务端正确返回之后,这个对象里才有值)。
  4. flags:这是一个标志位,一种是双向,用常量 0 表示, 其含义是服务端执行完指定服务后会返回一定的数据;另一种是单向,用常量 1 表示,其含义是不返回 任何数据。
public class Binder implements IBinder {
     protected boolean onTransact(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException {
    }
}

这个方法在Binder里,根据客户端发送过来的数据,调用响应的方法处理后,将结果存储在reply里,然后返回给Binder驱动。

注意onTransact方法中的data和reply和transact方法里的,并不是同一个对象,因为它们是在两个进程中的。其实过程是这个样子:

  1. 客户端通过transact方法将data数据赋值给自己进程的Binder驱动。
  2. 然后本进程的Binder驱动,会找到目标进程的Binder驱动,将数据重新复制一份传递给目标Binder驱动,然后目标进程的Binder驱动会调用服务端,并将数据传递给它。
  3. 服务端处理完数据后,将结果写入reply,然后在传给Binder驱动。

因此我们要进行Binder调用,只要获取一个IBinder对象,调用它的transact方法,然后它就会调用到Binder实体的onTransact方法,返回对应的结果。

但是这样做起来比较繁琐:

  1. 要保证transact和onTransact方法中code是对应的,这样你才能调用到onTransact正确的处理逻辑。
  2. 我们每次都要手动地将数据设置到Parcel中,然后在另一个方法从Parcel中按照放入顺序一一取出来,这样才能使用。

AIDL (Android接口定义语言)

那么有没有一种简单地方式,将这些繁琐的操作都封装起来呢?

一种简单地方式就是定义一系列接口方法,每个接口方法对应一个code,按照方法中参数的顺序,将参数放入Parcel,然后在另一个方法中一一取出。这种方式就是aidl(Android Interface Definition Language)。

package com.binder.bindertest;
interface IMyService {
    void setName(String name);
    String getName();
}

简单定义了IMyService.aidl,下面看看工具帮我们生成的java类。

package com.binder.bindertest;

public interface IMyService extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder 
           implements com.binder.bindertest.IMyService {
        private static final java.lang.String DESCRIPTOR = 
             "com.binder.bindertest.IMyService";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.binder.bindertest.IMyService 
         * interface,generating a proxy if needed.
         */
        public static com.binder.bindertest.IMyService asInterface(
               android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.binder.bindertest.IMyService))) {
                return ((com.binder.bindertest.IMyService) iin);
            }
            return new com.binder.bindertest.IMyService.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_setName: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    this.setName(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_getName: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _result = this.getName();
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.binder.bindertest.IMyService {
            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 setName(java.lang.String name) 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.writeString(name);
                    mRemote.transact(Stub.TRANSACTION_setName, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public java.lang.String getName() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.lang.String _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getName, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        static final int TRANSACTION_setName = 
                (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_getName = 
               (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    public void setName(java.lang.String name) throws android.os.RemoteException;

    public java.lang.String getName() throws android.os.RemoteException;
}

IMyService

首先来看一下,IMyService继承了IInterface接口,但没有继承IBinder接口。

public interface IMyService extends android.os.IInterface {
}

public interface IInterface
{
    public IBinder asBinder();
}

这个接口非常简单,就是返回一个IBinder对象,因此它的子类中肯定有IBinder这个成员变量。所以IMyService是采用的组合的方式,通过IBinder这个成员属性的transact方法,来发送Binder请求的。

代理类Proxy

private static class Proxy implements com.binder.bindertest.IMyService {
            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 setName(java.lang.String name) 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.writeString(name);
                    mRemote.transact(Stub.TRANSACTION_setName, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public java.lang.String getName() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.lang.String _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getName, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

这个Proxy类有一个mRemote成员变量,通过它来进行Binder请求,它实现IMyService方法,只是将方法中的参数,存放到_data中,然后调用transact方法,最后再从_reply中取出结果值,返回给调用处。

抽象类Stub

    public static abstract class Stub extends android.os.Binder implements 
                 com.binder.bindertest.IMyService {
     private static final java.lang.String DESCRIPTOR = 
                "com.binder.bindertest.IMyService";
      public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

 }

继承自Binder类,说明它要实现onTransact方法,作为服务端处理客户端transact方法发送来的消息。它implements了IMyService接口,它并没有真正实现IMyService接口方法,而是由它子类去实现这些方法。
DESCRIPTOR:这个常量作为Parcel的验证参数。

      public static com.binder.bindertest.IMyService asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.binder.bindertest.IMyService))) 
           {
                return ((com.binder.bindertest.IMyService) iin);
            }
            return new com.binder.bindertest.IMyService.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

asInterface方法并不是Binder中的方法,它返回一个IMyService对象的实例,目前来看这个IMyService对象有两种类型的子实例:

  1. Stub这个抽样类子类的实例,它就是Binder实体,那么就不用通过Binder机制了,直接调用Binder实体对应方法了。
  2. Proxy这个类的实例。那么它就要调用IBinder的transact方法,通过Binder驱动,接着调用到Stub的onTransact方法,最后服务端实例对应的方法。
@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_setName: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    this.setName(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_getName: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _result = this.getName();
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

根据code码,调用不同的方法,最后将结果写入reply中。

通过aidl,我们就将Binder请求中一些繁琐的参数准备细节都封装起来了,我们只需要实现接口方法就行了。

自定义远程service

下面我们用一个自定义远程service的例子,来详细说明一下。

package com.binder.bindertest;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;

public class MyService extends Service {
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("zhang", "onCreate   pid=="+ Process.myPid());
    }

    private IBinder binder = new IMyService.Stub() {

        private String name;
        @Override
        public void setName(String name) throws RemoteException {
            this.name = name;
            Log.e("zhang", "setName  name==  "+name+"   pid=="+ Process.myPid());
        }

        @Override
        public String getName() throws RemoteException {
            Log.e("zhang", "getName  name==  "+name+"   pid=="+ Process.myPid());
            return name;
        }
    };
}

自定义一个MyService,在onBind方法中返回一个IMyService.Stub对象。它是Binder子类,实现了IMyService接口的方法。

package com.binder.bindertest;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bindService();
            }
        });
    }

    private void bindService() {
        Intent intent = new Intent(this, MyService.class);
        bindService(intent, connection, BIND_AUTO_CREATE);
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e("zhang", "onServiceConnected start pid=="+ Process.myPid());
            IMyService myService = IMyService.Stub.asInterface(service);
            try {
                myService.setName("zhang");
                String result = myService.getName();
                Log.e("zhang", "onServiceConnected result=="+result+"  pid=="+ Process.myPid());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(connection);
    }
}

通过bindService方法启动并绑定自定义的Service,然后在ServiceConnection的onServiceConnected获取我们想要的IBinder对象。

主要这个IBinder对象,根据所在进程不同,值不一样。

  1. 如果MainActivity和MyService在同一个进程,那么这个IBinder对象就是MyService onBind方法返回的那个IBinder实例。
  2. 如果MainActivity和MyService不在同一个进程,那么这个IBinder对象就是返回的那个IBinder实例代理对象。
    所以调用asInterface方法获取的结果也是不一样的。
    <service
            android:name=".MyService"
            android:process=":remote"
            >
            <intent-filter>
                <action android:name="com.binder.bindertest.MyService" />
            </intent-filter>
        </service>

最后注意在AndroidManifest.xml文件中将<service 修改成上面方式。
这样当点击按钮时,会发现MainActivity和MyService中调用Process.myPid()方法获取的pid是不一样的,但是它们实现了数据交互。

各种系统服务

在android中各种系统服务就是通过Binder机制进行信息交互的。来看看它们是怎么实现的。就以InputMethodManager为例:

InputMethodManager

public static InputMethodManager getInstance() {
        synchronized (InputMethodManager.class) {
            if (sInstance == null) {
                try {
                    sInstance = new InputMethodManager(Looper.getMainLooper());
                } catch (ServiceNotFoundException e) {
                    throw new IllegalStateException(e);
                }
            }
            return sInstance;
        }
    }

调用InputMethodManager构造函数方法。

InputMethodManager(Looper looper) throws ServiceNotFoundException {
        this(IInputMethodManager.Stub.asInterface(
                ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE)), looper);
    }

它也有个IInputMethodManager接口,定义了对InputMethodManager操作一系列方法,通过IBinder对象向InputMethodManager的服务端进行请求,而它的IBinder对象是通过ServiceManager获取。

ServiceManager

public static IBinder getServiceOrThrow(String name) throws ServiceNotFoundException {
        final IBinder binder = getService(name);
        if (binder != null) {
            return binder;
        } else {
            throw new ServiceNotFoundException(name);
        }
    }

调用getService方法,如果得到的binder对象是空,就抛出异常。

public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return Binder.allowBlocking(getIServiceManager().getService(name));
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }

先从缓存sCache中获取,如果获取不到,那么就要通过IServiceManager对象来获取了。

public interface IServiceManager extends IInterface
{
    public IBinder getService(String name) throws RemoteException;
   
    public IBinder checkService(String name) throws RemoteException;

    public void addService(String name, IBinder service, boolean allowIsolated) 
      throws RemoteException;

    public String[] listServices() throws RemoteException;

    public void setPermissionController(IPermissionController controller)
            throws RemoteException;
    
    static final String descriptor = "android.os.IServiceManager";
}
  1. IServiceManager是一个接口,继承了IInterface(就相当于我们自定义的IMyService),
  2. ServiceManagerNative类继承了Binder实现了IServiceManager(就相当于Stub)
  3. ServiceManagerProxy实现了IServiceManager(就相当于Proxy)。这两个类都在ServiceManagerNative.java文件中。
private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }
        // Find the service manager
        sServiceManager = ServiceManagerNative
                .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
        return sServiceManager;
    }

可以看出IServiceManager中所需要的远程代理IBinder实例,是由BinderInternal.getContextObject()方法返回的,而这个方法是通过jni从native端获取的。

小结

由此可以得出,每个系统服务Service,都有一个IXXX接口(例如InputMethodManager对应IInputMethodManager),这个接口定义了操作本服务一系列方法,这个接口的实例中有一个IBinder属性,通过它来调用远程Service真正实现的方法。而IBinder这个实例是通过IServiceManager获取的。
而IServiceManager它对应的实例ServiceManagerProxy也是一个代理对象。它也是通过Binder机制,从服务端ServiceManager中获取这个IBinder对象的。而服务端ServiceManager是在native层实现的,下一章我们会说明的。

推荐阅读更多精彩内容