Binder通信与AIDL

本文详细解析了Android中的Binder通信架构及其与AIDL(Android Interface Definition Language)的关系。通过AIDL,开发者可以简化跨进程通信的实现。AIDL定义接口,自动生成服务端的Stub和客户端的Proxy类,实现 Binder 的调用。服务端通过继承Stub抽象类并实现接口方法,客户端通过ServiceManager获取BinderProxy,调用Proxy方法与服务端交互。AIDL使得不同应用间的进程通信变得简单,同时介绍了如何在Android Studio中使用AIDL以及ServiceManager的角色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    

系统服务依赖的是Binder构架。

 

Binder和BinderProxy直接继承IBinder。

 

通信:服务Proxy(如:ActivityManagerService)通过BinderProxy,再通过BpBinder,再将请求传到Binder驱动。Binder驱动通过ServiceManager得到注册的IBinder对应的JavaBBinder,再层层上到java层的真正服务对象。这样可以实现跨进程通信。

 

在以上的构架基础上,ADIL为我们简化了整个通信的搭建过程。

首先,你要定义一个aidl格式的文件,如:

package com.udnderstanding.samples;

interface ImyServer{

   int foo(String str);

}

这样就定义了一个名为IMyServer的Binder服务,并提供了一个可以跨Binder调用的接口foo()。

一个AIDL文件将被aidl工具解析成三个产物:

1.IMyServer接口:它仅仅用来在Java 中声明IMyServer.aidl中所声明的接口。

2.IMyServer.Stub类:这个继承自Binder类的抽象类实现了Bn端与Binder通信相关的代码

3.IMyServer.Stub.Proxy类。这个类实现了Bp端与Binder通信相关的代码。

在完成爱的了解析后,为了实现一个Bn端,开发者需要继承IMyServer.Stub类并实现其抽象方法。

每个MyServer实例都具有了作为Bn端的能力。

典型用法:

1.将MyServer类的实例通过ServiceManager.addService(String name, IBinder service)将其注册为一个系统服务。

2.在一个Android标准Service的onBind()方法中将其作为返回值使之可以被其他进程访问

3.通过binder调用将其传递给另外一个进程,使之成为一个跨进程的回调对象。

但是殊途同归,在Bp端所在进程中,一旦获取了IMyServer的BinderProxy(通过ServiceManager.geService()、onSrviceConnected()、或者其他方式),就可以通过如下方式获得一个IMyServer.Proxy:

//就是最终需要获得com.understanding.samples.IMyServer.Stub.Proxy,asInterface()返回就是这个类型

IMyServer remote = IMyServer.Stub.asInterface(binderProxy);

remote.foo("Hello AIDL");

 

 

 

下面是aidl工具自动解析成的文件。

public interface IMyServer extends android.os.IInterface{

    //自动生成一个内部类

    public static abstract class Stub extends android.os.Binder implements com.understanding.samples.IMyServer{

 

/********code:对应不同的方法,表示proxy所需调用的方法。

data:从proxy打包传过来的参数

在proxy发出请求后,最终会调用Stub的子类的onTransact()方法,而onTransact()中会调用foo(),所以子类需实现foo()

*/

          public boolena onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)

           throws android.os.RemoteException{

              switch(code){

                   ......

               case TRANSACTION_foo:{

                   ......//从data中读取参数_arg0

            //Stub类的子类需要实现foo()方法

                  int _result = this.foo(_arg0);

                  ......//向reply中写入_result

                  return true;

                    }

               }

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

        }

    

 

//调用了Bp端的foo对应会调用Bn端的foo。Bp端的foo()的逻辑是固定的,就是将传过来的参数打包传Bn端。

      private static class Proxy implements com.understanding.samples.IMyServer{

            ......//Proxy类的其他实现

           public int foo(java.lang.String str)

                 throws android.os.RemoteException{

              android.os.Parcel _data = android.os.Parcel.obtain();

             android.os.Parcel _reply = android.os.Parcel.obtain();

             int _result;

              try{

                  ......//将参数str写入_data

           //mRemot就是指向IMyServer Bn端的BinderProxy;可能会阻塞等待返回结果

                 mRemot.transact(Stub.TRANSCATION_foo, _data, reply, 0);

                 ......//从_replay中读取返回值_result

                    } finally{

                        ......

                    }

          return _result;

               }

                static final int TRANSACTION_foo = (android.os.Ibinder.FIRST_CALL_TRANSCATION + 0);

         }

 

    }

     //声明IMyServer所提供的接口。

     public int foo(java.lang.String str) throws android.os.RemoteException;

}

 

 

下面说说AIDL在AS上的操作:(以下demo参考自:http://blog.youkuaiyun.com/u011974987/article/details/51243539

首先在new file 中选择AIDL,会自动生成一个名为“aidl”与java文件夹同级的文件夹,aidl文件就放在该文件夹下。注意包名和java文件一样是文件夹的路径。

// IMyInterface.aidl
package com.example.zhangjinbiao.aidltest;

// Declare any non-default types here with import statements

interface IMyInterface {
    String getInfor(String s);
}

 

 

 

写一个Service,在Service中返回一个IBinder(就是服务端stub的子类),然后在使用的时候调用asInterface(IBinder)转为IMyInterface(IInterface),该方法最终会返回一个Proxy。所以客户端最终使用的是Proxy。

下面是客户进程代码:

 

public class MainActivity extends AppCompatActivity {


    public final static String TAG = "AIDLTEST_MainActivity";
    private IMyInterface myInterface;
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myInterface = IMyInterface.Stub.asInterface(service);
            Log.i(TAG, "连接Service 成功");
            try {
                String s = myInterface.getInfor("我是Activity传来的字符串");
                Log.i(TAG, "从Service得到的字符串:" + s);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG, "连接Service失败");
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startAndBindService();
    }
    private void startAndBindService() {
        Intent service = new Intent(MainActivity.this, MyService.class);
        //startService(service);
        bindService(service, serviceConnection, Context.BIND_AUTO_CREATE);
    }
}

 

注意:当客户端和服务端是在不同应用中的,那么IMyInterface怎么能被客户端代码访问到。所以此种情况必须要复

 

制一份aidl文件到客户端,这样就可以和服务端访问到同一份代码。两边的aidl必需是要一致的。这样,无论是使用哪一个aidl文件产生的类,都是一致且正确的。下面是android介绍AIDL的官方文档中的一句话:

The client must also have access to the interface class, so if the client and service are inseparate applications,

then the client'sapplication must have a copy of the.aidl filein itssrc/ directory (which generates the

android.os.Binderinterface—providingthe client access to the AIDL methods).

翻译:客户端还必须能够访问接口类,因此如果客户端和服务在单独的应用程序中,那么客户机的应用程序必须具

有一个副本 .aidl文件在其src /目录中(生成android . os.Binderinterface,提供客户端访问AIDL方法。

介绍类加载器的文章

 

下面是服务端进程代码:

 

 

public class MyService extends Service {

    public final static String TAG = "AIDLTEST_MyService";

    private IBinder binder = new IMyInterface.Stub() {
        @Override
        public String getInfor(String s) throws RemoteException {
            Log.i(TAG, s);
            return "我是 Service 返回的字符串";
        }
    };
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreat");
    }
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
}


需要在Manifest中声明:

 

 

<service
            android:name=".MyService"
            android:process="com.xu.remote" />

声明该Service在独立进程中。

 

 

下面是自动生成的IMyInterface.java文件:

 

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: /home/zhangjinbiao/AndroidStudioProject/AIDLTest/app/src/main/aidl/com/example/zhangjinbiao/aidltest/IMyInterface.aidl
 */
package com.example.zhangjinbiao.aidltest;
// Declare any non-default types here with import statements

public interface IMyInterface extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.zhangjinbiao.aidltest.IMyInterface
{
private static final java.lang.String DESCRIPTOR = "com.example.zhangjinbiao.aidltest.IMyInterface";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.example.zhangjinbiao.aidltest.IMyInterface interface,
 * generating a proxy if needed.
 */
public static com.example.zhangjinbiao.aidltest.IMyInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.zhangjinbiao.aidltest.IMyInterface))) {
return ((com.example.zhangjinbiao.aidltest.IMyInterface)iin);
}
return new com.example.zhangjinbiao.aidltest.IMyInterface.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_getInfor:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
java.lang.String _result = this.getInfor(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.zhangjinbiao.aidltest.IMyInterface
{
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 java.lang.String getInfor(java.lang.String s) 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);
_data.writeString(s);
mRemote.transact(Stub.TRANSACTION_getInfor, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_getInfor = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public java.lang.String getInfor(java.lang.String s) throws android.os.RemoteException;
}

 

 

 

 

 

 

注意:AIDL一般是阻塞式调用,就像调用一般方法一样,要非阻塞调用需要设置IBinder接口类中打FLAG_ONEWAY字段.,在native曾中涉及到Binder调用打基本是阻塞式,而java framework层一般非阻塞式的.

 

mRemote.transact(Stub.TRANSACTION_getInfor, _data, _reply, 0);

看这句,自动生成的AIDL文件,proxy调用时flag为0,即阻塞调用。如果要非阻塞调用,则需要改为1。

 

以ActivtyManagerService的binder通信深入Binder的工作原理

前面不是说了通过ServiceManager.geService()、onSrviceConnected()、或者其他方式可以

获得BinderProxy。ActivityManagerService正是使用ServiceManager.geService()来获得

BinderProxy,很容易让人觉得getService是获取到当初addService()注册的Binder。那么

ServiceManagerService的binder通信又是怎么获得BinderProxy的呢。

ActivityManagerService首先需要向ServiceManagerService注册:

 

public static void addService(String name, IBinder service){
//...
getIServiceManager.addService(name, service)
//..
}

getIServiceManager()获得的是一个IServiceManager,就是ServiceManagerNative.java中

 

的ServiceManagerProxy impliments IServiceManager.使用ServiceManagerNative.asInterface(IBinder)

静态方法创建并返回一个ServiceManagerProxy,而BinderProxy是ServiceManagerProxy的构造参数就,

因为要把消息传到binder驱动,是需要通过BinderProxy。

BinderProxy是一个final类,只有一个空参构造方法,本身没有绑定通信目标的信息,那么它是怎么知道他的

通信目标的呢?BinderProxy的mObject(long)成员保存着native对象的BpBinder的指针(对象地址),BpBinder

是知道对应的BBinder的,BpBinder和BBinder都是extends IBinder的,是两两对应,是通信通道的两端。

 

上面说的都客户端的,那么服务端呢,服务端是需要注册到Binder驱动的,通过ActivityServiceNative是通过

ServiceManagerNative#addService(IBinder)注册到Binder驱动的。java中的Binder对象并不是直接跟驱动

打交道的,Binder(该例中是ActivityManagerNative)的mOject:long成员持有一个native对象的指针JavaBBinderHolder,

JavaBBinderHolder对象又指向BBinder(JavaBBinder?),BBinder指向,打个圆圈可能跟垃圾回收有关。注册到

Binder驱动中的是BBinder。

当客户端请求时,从BBinder中传来请求到Binder中,启动Binder#execTransact(),其中会调用子类的onTransact(),

该例中就是AtivityManagerNative#onTransact(),会在里面根据请求参数调用客户端请求的那个方法。

那么服务端处理客户端请求是在哪个线程中执行呢?在zygote应用进程时,会创建一个处理binder请求的线程池,

所以服务端响应客户端binder请求是在服务端所在应用进程的binder线程中执行的。

 

ServiceManager的作用:

管理serivces,注册只是给个路径其他client,即其他进程方便获取到这个服务,注册到ServiceManager需要system或者root权限,又或者在allowed结构体中加入一个进程名称。而service和client的binder通信并不用通过ServiceManager的,ServiceManger也是能和binder通信的。

ActivityManagerService, PowerManagerService, WindowManagerService等服务是运行在system_server进程中的,每个服务都运行在不同线程中。照说通过binder驱动通信时,执行client访问的函数都是在binder线程池的线程中运行的,而没有一个binder线程对应一个服务,那么,怎样让属于某个服务的代码运行在服务所在线程呢,那就得把实际代码放在handler中,通过handler把消息从binder线程中传到服务线程中。Activity也是这么实现,WindowManagerService或者ActivityManagerService给ActivityThread发消息时,就是通过handler,使实际代码在主线程中执行。

 

binder线程池:

android系统中,通过binder进行IPC时,服务端总是会起一些Binder线程来响应客户端的请求。如下面的这个设备上,system_process进程中就可以看到许多名为"Binder_X"的线程。在androidjava app进程被创建起来时,它就会去建立一个线程池,来专门处理那些binder IPC事务。在frameworks/base/cmds/app_process/app_main.cpp中我们可以看到下面的这两个方法:

virtual void onStarted()

    {

        sp<ProcessState> proc = ProcessState::self();

        ALOGV("App process: starting thread pool.\n");

        proc->startThreadPool();

        AndroidRuntime* ar = AndroidRuntime::getRuntime();

        ar->callMain(mClassName, mClass, mArgC, mArgV);

        IPCThreadState::self()->stopProcess();

    }

    virtual void onZygoteInit()

    {

        // Re-enable tracing now that we're no longer in Zygote.

        atrace_set_tracing_enabled(true);

        sp<ProcessState> proc = ProcessState::self();

        ALOGV("App process: starting thread pool.\n");

        proc->startThreadPool();

    }

上面的proc->startThreadPool()这个调用创建的Binder线程池。在android binder的设计中,ProcessState被设计来直接与binder驱动进行通信。在之前分析ActivityManagerService的文章中,有提到ProcessState任何一个线程只要执行了IPCThreadState::self()->joinThreadPool(),就可以把自己变成一个binder线程

 

 

 

最后总结

实现binder通信,并不一定要AIDL,AIDL只是简化了搭建binder通信通道的过程。只要知道以下关键点即可:

* 定义一个接口如:IMyService,IServiceManager,IActivityManager,extends IInterface(有一个asBinder()接口),这些接口都是提供给客户端调用的方法

* 定义一个类,实现IMyService和Binder。这个类是用于实现实际业务逻辑的。除了实现IMyService中的方法外,

  最重要的是需要一个返回一个创建并返回一个Proxy给客户作为代理使用,还有实现onTransact(...)方法,这

  个方法根据参数选择调用IMyService中定义的接口方法。

* 定义一个Proxy,实现IMyService,然后Proxy实现IMyService的接口的原则是,打包数据发送到Binder驱动,

  让服务端(即上面说的那个类)的onTransact()知道怎么解析出方法参数和调用哪个方法。Proxy在创建的

  时候需要传入一个BinderProxy,这样才能和Binder驱动通信并确定通信目标(服务端)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值