Skip to content

guoke24/AidlDemo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Contents

[TOC]

概述

该 Github 项目有两个独立的项目, 一个是 AidlClient,代表客户端; 另一个是 AidlServer,代表服务端。

aidl 使用的三步曲:

  • client,server 端都是采用相同的 aidl
  • server 端,new 一个 Stub 实例,并实现 aidl 中定义的函数,然后在 onBind 函数中返回 IBinder 类型的该 Stub 实例。
  • client 端,实现发起绑定逻辑,并在绑定完成的回调中拿到 IBinder 类型的参数,并通过 Stub.asInterfac 函数转变为代理类实例,用 aidl 接口依赖。

下面以 AidlDemo 项目参考 为例进行分析。

两端都用同一个 Aidl

Client 端的 aidl 路径: /AidlDemo/AidlClient/app/src/main/aidl/com/guohao/aidl/server/IBookManager.aidl

Server 端的 aidl 路径: /AidlDemo/AidlServer/app/src/main/aidl/com/guohao/aidl/server/IBookManager.aidl

aidl 源码:

// IBookManager.aidl

package com.guohao.aidl.server;
interface IBookManager {

    int add(int num1,int num2);

    int wrong_add(int num1,int num2);

    int more_fun();
}

定义好的 aidl 接口,编译后会生成 java 文件:{工程根目录}/app/build/generated/source/aidl/debug/com/guohao/aidl/server/IBookManager.java

注意,该编译后会生成 java 文件也是两端都有的!

源码如下: 有点长,先看 IBookManager.java 接口的结构:

  • add 接口函数
  • wrong_add 接口函数
  • more_fun 接口函数
  • Stub 类
    • asBinder 函数
    • asInterface 函数,client 使用,把 server 的 IBinder 转成 Proxy
    • onTransact 函数,server 使用,接收 client 通信的回调
    • Proxy 类,client 使用
      • asBinder 函数
      • add 函数,向 Binder 驱动发送通信,继而转到 server 的 onTransact 函数
      • wrong_add 函数,同上
      • more_fun 函数,同上

具体源码:

// IBookManager.java

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: /Users/guohao/AS_Proj/AidlDemo/AidlServer/app/src/main/aidl/com/guohao/aidl/server/IBookManager.aidl
 */
package com.guohao.aidl.server;

public interface IBookManager extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.guohao.aidl.server.IBookManager {
    
        // 用于告诉 Binder 驱动,向哪个进程发起通信
        private static final java.lang.String DESCRIPTOR = "com.guohao.aidl.server.IBookManager";

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

        /**
         * Cast an IBinder object into an com.guohao.aidl.server.IBookManager interface,
         * generating a proxy if needed.
         */
        public static com.guohao.aidl.server.IBookManager asInterface(android.os.IBinder obj) {
            ...
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.guohao.aidl.server.IBookManager))) {
                return ((com.guohao.aidl.server.IBookManager) iin);
            }
            return new com.guohao.aidl.server.IBookManager.Stub.Proxy(obj);
        }

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

        // 在 server 端被调用,接收 client 通信的回调
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            java.lang.String descriptor = DESCRIPTOR;
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(descriptor);
                    return true;
                }
                case TRANSACTION_add: {
                    data.enforceInterface(descriptor);
                    int _arg0;
                    _arg0 = data.readInt();
                    int _arg1;
                    _arg1 = data.readInt();
                    int _result = this.add(_arg0, _arg1);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
                case TRANSACTION_wrong_add: {
                    ...
                    int _result = this.wrong_add(_arg0, _arg1);
                    ...
                    return true;
                }
                case TRANSACTION_more_fun: {
                    data.enforceInterface(descriptor);
                    int _result = this.more_fun();
                    ...
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        // 在 client 端持有实例,通过 mRemote.transact 函数向 Binder 驱动发起跨进程通信
        private static class Proxy implements com.guohao.aidl.server.IBookManager {
            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 int add(int num1, int num2) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(num1);
                    _data.writeInt(num2);
                    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public int wrong_add(int num1, int num2) throws android.os.RemoteException {
                ...
                try {
                    ...
                    mRemote.transact(Stub.TRANSACTION_wrong_add, _data, _reply, 0);
                    ...
                } finally {
                    ...
                }
                return _result;
            }

            @Override
            public int more_fun() throws android.os.RemoteException {
                ...
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_more_fun, _data, _reply, 0);
                    ...
                } finally {
                    ...
                }
                return _result;
            }
        }

        // mRemote.transact 函数时会使用的标志位,用于识别调用哪个函数
        static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_wrong_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        static final int TRANSACTION_more_fun = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
    }

    public int add(int num1, int num2) throws android.os.RemoteException;

    public int wrong_add(int num1, int num2) throws android.os.RemoteException;

    public int more_fun() throws android.os.RemoteException;
}

server端的实现

server 端的工作:

new 一个 Stub 实例,并实现 aidl 中定义的函数,然后在 onBind 函数中返回 IBinder 类型的该 Stub 实例

源码:

// AidlService.java

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

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        
        // 返回接口 IBookManager.Stub 实例
        return aidlServer;
    }

    // 声明并实现 IBookManager 接口的 stub 类实例
    IBookManager.Stub aidlServer = new IBookManager.Stub(){

        @Override
        public int add(int num1, int num2) throws RemoteException {
            Log.d("guohao","add...num1 = " + num1 + " ,num2 = " + num2 );
            return ( num1 + num2 );
        }

        @Override
        public int wrong_add(int num1, int num2) throws RemoteException {
            Log.d("guohao","wrong_add...num1 = " + num1 + " ,num2 = " + num2 );
            return ( num1 + num2 );
        }

        @Override
        public int more_fun() throws RemoteException {
            Log.d("guohao","more_fun..." );
            return 0;
        }

    };
    // end 声明并实现 接口的stub对象
}

client端的实现

client 端工作

实现发起绑定逻辑,并在绑定完成的回调中拿到 IBinder 类型的参数,并通过 Stub.asInterfac 函数转变为代理类实例,用 aidl 接口依赖。

源码:

// MainActivity.java

    private IBookManager mIBookManager;

    // 创建跟服务端的连接
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 获取远程服务Binder的代理:service
            Log.d("guohao","onServiceConnected");
            // service 转化为 本地的 mIBookManager 接口
            // asInterface 返回的是代理类 IBookManager.Stub.Proxy
            // 通过 IBookManager 接口依赖
            mIBookManager = IBookManager.Stub.asInterface(service);
            // 注意:本地的 IBookManager 接口,只定义了两个函数,
            // 而服务端的  IBookManager 接口,定义了三个函数,
            // 但是,这里不会因为函数不一致而报错
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d("guohao","onServiceDisconnected");
        }
    };
    // end 创建跟服务端的连接

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    // 发起绑定服务
    private boolean bindBookService(){
        Intent intent = new Intent();
        // 指定 action,要绑定的服务类,在服务端的清单文件里定义
        intent.setAction("com.guohao.aidl.server.aidlService");
        // 指定 包名,服务端的包名
        intent.setPackage("com.guohao.aidlserver");
        startService(intent);
        return bindService(intent, mConnection, BIND_AUTO_CREATE);
    }
    // end 发起绑定服务

    public void test(View v){
        Log.d("guohao","test2");
        // 调用 绑定服务
        boolean b = bindBookService();
        if(b){
            Toast.makeText(this,"bind succ",Toast.LENGTH_SHORT).show();
        }else{
            Toast.makeText(this,"bind fail",Toast.LENGTH_SHORT).show();
        }
    }

    public void test2(View v){
        Log.d("guohao","test2");
        if(mIBookManager == null) {
            Log.d("guohao","未绑定服务");
            Toast.makeText(this,"未绑定服务" ,Toast.LENGTH_SHORT).show();
            return;
        }
        try {
            // 发起 远程调用
            int res = mIBookManager.add(1,1);
            Log.d("guohao","res = " + res);
            Toast.makeText(this,"mIBookManager.add(1,1) = " + res,Toast.LENGTH_SHORT).show();

        } catch (RemoteException e) {
            Log.d("guohao","e = " + e.toString());
            e.printStackTrace();
        }

    }

时序图小结

简单的绑定过程:

其中 bindService 函数的 老罗的源码分析另一篇源码分析(图清楚)

小结:

mConnection 封装在 ServiceDispatcher 实例中, ServiceDispatcher 实例封装在 InnerConnection 实例中, AMS 中持有 InnerConnection 实例, 在 AMS 中通过 InnerConnection - ServiceDispatcher - RunConnection.run - mConnection.onServiceConnected 层层调用,通知绑定完成。


跨进程通信过程:

测试了接口不一致,不会报错

  • server 端的 IBookManager接口,函数声明为:
package com.guohao.aidl.server;
interface IBookManager {

    int add(int num1,int num2);

    int wrong_add(int num1,int num2);

    int more_fun();
}
  • client 端的 IBookManager接口,函数声明为:

interface IBookManager {

    int add(int num1,int num2);

    // 服务端定义了该函数会多一个参数 wrong_add(int num1,int num2)
    int wrong_add(int num1);
}
  • 结果:绑定服务不会报错,调用 wrong_add 函数也不会报错,缺失的参数 num2 默认为 0

拓展

Android系统服务(SystemService)简介 ,参考该文章,可以改造该 demo,把服务端添加到 systemserver 中;而客户端通过 ContextImpl 和 SystemServiceRegistry 静态注册,这样,每个 APP 都能通过 Context(ContextImpl)获取服务的代理类,然后跟服务通讯。

由此推论,SystemServiceRegistry 类是每个进程都有一个,静态代码块中创建并保存了很多注册在 SystemServer 中的服务的代理类,因为这些服务都是运行在 SystemServer 中,只要开着机就会一直存在,而每个进程(APP)可以很方便的通过 Context(ContextImpl) 获取其代理类(也称为客户端)。

About

一个包含两端通信的 AIDL Demo

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages