Android 内核 - 01 Binder

来源:互联网 发布:禁止xp下载 安装软件 编辑:程序博客网 时间:2024/06/07 00:51

Binder 概述

Binder是一种架构,一种进程间通信(IPC)的机制,它工作在Linux内核层面,属于驱动层的一个模块。
但它其实并不是与硬件打交道,是上层消息转发的一个通道。工作在内核层效率更高。

pic_1


Binder的应用


在这种架构中有三个模块,服务端接口,Binder驱动,客户端接口。

服务端接口:是Binder的一个对象,向客户端提供服务,通过重载onTransact()接口来实现业务。

Binder驱动:当创建一个服务Binder对象后,它同时会在Binder驱动中创建一个Binder的mRemote对象。
                      当客户端需要Binder服务时,都是通过mRemote对象来获得的。这是一种代理方式。

客户端接口:客户端需要获取服务,必须获取远程服务的代理的引用。客户端实现自己的业务时可以获得服务端支持。




一个简单的Binder应用的实例


实例分为两部分 Server App 和 Client App,是两个独立的App程序。
Client会绑定一个Server的Service,将当前时间传递给Server,Server端收到后,再将它的时间添加在后面
返回给Client端。

Server 端
一个普通的Service类,其中包含了一个Binder子类。其中 Binder子类重载了onTransact函数用于处理Client端过来的请求。

public class SampleService extends Service{    private static final String TAG = "BINDServer";    private static final String DESCRIPTOR = "TESTING";      public ServiceBinder mBinder = new ServiceBinder();    private static int m_CallingTimes = 0;    @Override    public void onCreate()     {        Log.d(TAG, "SampleService::onCreate()");        super.onCreate();    }    @Override    public int onStartCommand(Intent intent, int flags, int startId)     {        Log.d(TAG, "SampleService::onStartCommand()");        return super.onStartCommand(intent, flags, startId);    }    @Override    public void onDestroy()     {        Log.d(TAG, "SampleService::onDestroy()");        super.onDestroy();    }    @Override    public IBinder onBind(Intent arg0)     {        return mBinder;    }    public class ServiceBinder extends Binder     {        protected boolean onTransact(int code, Parcel data, Parcel reply,                  int flags) throws RemoteException          {            Log.d(TAG, "ServiceBinder::onTransact() code=" + code);            String strResult = "";            switch (code)              {                case 0x01:                  {                      data.enforceInterface(DESCRIPTOR);                      String _arg0;                      _arg0 = data.readString();                    strResult = getInfo(_arg0, "===>");                    reply.writeNoException();                    reply.writeString(strResult);                    Log.d(TAG, "ServiceBinder::onTransact() result=" + strResult);                    return true;                  }                  default:                    break;            }            return super.onTransact(code, data, reply, flags);          }        public String getInfo(String strRecv, String strCode)        {            Date date = new Date();            String strResult = new String(date.toString());            strResult = m_CallingTimes + "::" + strRecv + strCode + strResult;            return strResult;        }    }}


Client 端
一个普通的Activity,它取得当前时间,并将当前时间的字符串打包发给Server端。

1)  它通过bindService函数取得了Server端Binder的对象。
    public void bindService(View view)
    {
        Log.d(TAG, "bindService");
        Intent intent = new Intent();  
        intent.setAction("com.example.bindersample.TestInterface");  

        boolean bindFlag = bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);  
        Log.e(TAG, "bindService() = " + bindFlag);
    }
Clinet端函数中通过setAction指定 <intent-filter> = com.example.bindersample.TestInterface 

这个Inter-filter是定义在Server端的AndroidManifest.xml中,定义了这个action android:name,系统就知道如何查找了
        <service android:name="SampleService">
            <intent-filter>
                <action android:name="com.example.bindersample.TestInterface" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>            
        </service>

2)  当Client取得了Binder对象后,可以调用它的 transact() 接口,来使用Service的服务了
boolean android.os.IBinder.transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException

关于参数的简单说明
int code:可以通过code告诉Server端提供不同类型的服务
Parcel data:传递给Server端的参数
Parcel reply:从Server端返回的参数
int flags:0 表示当前的操作是一个普通的RPC,如果是1 (ONE_WAY),则表示是一个one way 的RPC。

public class MainActivity extends Activity {    private static final String TAG = "BinderClient";    private IBinder mBinder;      private ServiceConnection mServiceConn = new ServiceConnection()      {          @Override          public void onServiceDisconnected(ComponentName name)          {              Log.d(TAG, "mServiceConn onServiceDisconnected");          }          @Override          public void onServiceConnected(ComponentName name, IBinder service)          {              Log.d(TAG, "mServiceConn onServiceConnected");                        mBinder = service;          }      };      public void bindService(View view)    {        Log.d(TAG, "bindService");        Intent intent = new Intent();          intent.setAction("com.example.bindersample.TestInterface");          boolean bindFlag = bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);          Log.e(TAG, "bindService() = " + bindFlag);    }    public void unbindService(View view)      {          unbindService(mServiceConn);      }    @Override    protected void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }    public void testClick(View view)    {        if (mBinder == null)          {              Log.d(TAG, "testClick() mBinder is NULL");         }        else          {              android.os.Parcel _data = android.os.Parcel.obtain();              android.os.Parcel _reply = android.os.Parcel.obtain();              String _result;            try              {                Date date = new Date();                _data.writeInterfaceToken("TESTING");                  _data.writeString(date.toString());                  mBinder.transact(0x01, _data, _reply, 0);                  _reply.readException();                  _result = _reply.readString();                  Toast.makeText(this, _result + "", Toast.LENGTH_SHORT).show();              }            catch (RemoteException e)              {                  e.printStackTrace();              }             finally              {                _reply.recycle();                  _data.recycle();              }          }      }  }


Binder运行的基本流程


  • 获取Binder对象

1)  Server端的Service需要被启动,并且Server端的Binder对象实现了public IBinder onBind(Intent arg0)  接口
      可以将它的Binder对象提供给外部。

2)  Client端需要调用bindService接口,来获取Server端的Binder对象的引用。
      public void bindService(View view)      {          Log.d(TAG, "bindService");          Intent intent = new Intent();            intent.setAction("com.example.bindersample.TestInterface");            boolean bindFlag = bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);            Log.e(TAG, "bindService() = " + bindFlag);      }

public boolean bindService (Intent serviceServiceConnection conn, int flags) 

Intent service:指定Client端需要的Service, 系统通过intent.setAction("com.example.bindersample.TestInterface");  
                          中的名字会找到指定的Service。
而Client端指定的这个Action name是在Server端的AndroidManifest.xml中定义的。
        <service android:name="SampleService">            <intent-filter>                <action android:name="com.example.bindersample.TestInterface" />                <category android:name="android.intent.category.DEFAULT" />            </intent-filter>                    </service>

ServiceConnection conn:它的两个接口是由系统进行回调的,主要是当Service 连接后和断开后会被执行。
    private ServiceConnection mServiceConn = new ServiceConnection()  
    {  
        @Override  
        public void onServiceDisconnected(ComponentName name)  
        {   }  
        @Override  
        public void onServiceConnected(ComponentName name, IBinder service)  
        {   }  
    };  

在实例程序中,当Client与Server连接后,在onServiceConnected接口中可以取得Server端Binder的引用。

pic_2


  • Client 与 Server交互

1)  Client 组织好数据包裹后,调用 Binder引用的transact方法
2)  他会通知 Binder Driver有消息需要传递了,Binder会阻塞当前的Client线程
3)  Binder Driver会找到Server的远程对象,并将Client的数据包裹传递给Server
4)  Server收到通知,在onTransact中可以对包裹进行处理,如果需要也可以将处理后的数据再返回Client端。
5)  Server处理完成后,通知Binder Driver,Binder Driver会使客户端线程得以返回,并继续以运行。

pic_3

关于 android.os.Parcel


它是Server端和Client端用来传递数据的包裹
1)  获得包裹  android.os.Parcel.obtain();  

Retrieve a new Parcel object from the pool. 使用pool的方式效率一定是比创建/释放的方式要高许多。


2)  接口名字 android.os.Parcel.enforceInterface(String interfaceName) 和 
          android.os.Parcel.writeInterfaceToken(String interfaceName)

可以通过这两个接口来为包裹设置名字,以保证他们在同一个Session中。


3)  拆包裹  android.os.Parcel.readString();
这里当然不光是String,还可以readInt,readDouble等等,可以根据封包的顺序来拆包。
注意: 关于 readException();  

API的解释 :

Special function for reading an exception result from the header of a parcelto be used after receiving the result of a transaction.  This will throw the exception for you if it had been written to the Parcel,  otherwise return and let you read the normal result data from the Parcel.



4)  封包裹 android.os.Parcel.writeString();
这里当然不光是String,还可以Int,Double等等,与拆包对应。





0 0
原创粉丝点击