AIDL(Android Interface Definition Language,Android接口描述语言)用于定义Client与service进行跨进程通信的编程接口。AIDL简化了IPC通信时数据交换的流程,而程序员只需关心接口的实现即可。

注意:只有你需要其他应用程序可以通过IPC接口调用service或者需要service可以处理多线程的情况时,才去使用AIDL。若非如此,(1)不需要处理跨进程的并发访问,可通过实现 Binder 接口;(2)需要使用IPC,但无需处理多线程的情况,可以选择使用 Messager

使用AIDL进行IPC通信时,需要注意:

  • 当前进程调用时,service与调用者在同一线程执行(通常这种情况,一般不使用AIDL进程IPC,而是通过使用 Binder 接口进行调用)
  • 如果是其他进程进行IPC调用(系统维护的一个当前进程的Thread Pool),这时可能同时出现多个IPC调用,因此必须确保AIDL接口是支持多线程(thread-safe)
  • oneway(异步,不会阻塞当前进程)关键字用于修改远程调用的具体行为。使用 oneway 时,远程调用不会阻塞,只是发送交易数据(transaction data),然后立即返回,而实现该接口的service最终会将其当作一个来自 Binder 线程池(Thread pool)普通的调用(regular call);如果oneway用于本地调用,则不会有任何影响,该调用始终是同步的

接下来,通过一个具体的示例说明如何用AIDL定义一个service,如何绑定该service,如何进行IPC的调用.

定义AIDL接口

.aidl接口的语法跟JAVA语言一样,其定义的方式与JAVA中的interface基本一致,主要区别是AIDL只能定义methods,不能定义数据或者static的methods。每个.aidl文件只能定义一个接口(interface)。AIDL支持以下数据类型:

  • 所有JAVA中的基本数据类型(primitive types),例如int,long,char,boolean
  • String/CharSequence
  • List
  • Map
  • android.os.parcelable 用于自定义数据类型

以下示例均基于Android Studio

在AS,右击项目,new –> ADIL,对其进行命名,可以看到在 src 目录下,生成了一个AIDL的目录,里面包含了刚才新建的.aidl文件:

    package com.jason.test.systemserviceaddingtest;    // Declare any non-default types here with import statements    interface IMathService {        /**         * get current process PID         */         int getPID();         /**         * add two value         */         int add(int x, int y);         /**         * mutiple two value         */         int multiply(int x, int y);    }*

实现AIDL接口

编译时,Android SDK工具会产生一个与 .aidl 同名的 .java 接口文件,该接口文件包含了一个名为 stub abstract class,其声明了 .aidl 文件里所有的methods,同时也定义一个 asInterface 的方法,它用 IBinder(作为参数传递给调用者的 onServiceConnected() 回调函数)作为参数,并返回一个stub接口的实例。我们可以通过扩展 .Stub 类,定义一个service:

    package com.jason.test.systemserviceaddingtest.service;    import android.os.*;    import android.os.Process;    import com.jason.test.systemserviceaddingtest.IMathService;    /**     * Created by Jason on 2016/7/11.     */     public class MathServiceImpl extends IMathService.Stub {        public static final String TAG = MathServiceImpl.class.getSimpleName();        @Override        public int getPID() throws RemoteException {            return Process.myPid();        }        @Override        public int add(int x, int y) throws RemoteException {            return x + y;        }        @Override        public int multiply(int x, int y) throws RemoteException {            return x * y;        }    }

MathServiceImpl为 service 定义了一个RPC(Remote Process Call),接下来只需要将该实例传递给调用者,即可实现与service的远程通信。

使用AIDL的注意事项

  • 调用不一定在Main Thread中执行,因此开始就要考虑如何处理多线程的情况
  • RPC调用默认支持同步。如果一个service花比较长的时间完成一个request,不要在主线程(UI thread)中调用,以免发生ANR(Application Not Responding),而是应该在另一个线程中进行调用
  • 在service中抛出的任何异常都不会返回给调用者client

将接口提供给Clients

将上述实现了的接口提供给clients,以便clients进行绑定:

    package com.jason.test.systemserviceaddingtest.service;    import android.app.Service;    import android.content.Intent;    import android.os.IBinder;    import android.util.Log;    /**     * Created by Jason on 2016/7/11.     */    public class MathService extends Service{        public static final String TAG = MathService.class.getSimpleName();        private final MathServiceImpl mServiceBinder =                new MathServiceImpl();        @Override        public void onCreate(){            Log.v(TAG,"onCreate()");            super.onCreate();        }        @Override        public IBinder onBind(Intent intent) {            Log.v(TAG,"onBind()");            return mServiceBinder;        }    }

当一个client通过调用 bindService() 连接这个service时,client对应的onServiceConnected() 的回调函数会接收到传自该service onBind() 函数的 mBinder 的实例(如果client与service在不同的应用中,则client所属的应用必须要有之前定义的.aidl文件的拷贝)。

调用IPC接口

调用service的IPC接口前,首先需要通过 ServiceConnection 将client与service进行绑定,具体参考下列代码:首先通过mServiceConnection将client(一个新的HandlerThread)与service进行绑定;作为示例,为避免APP出现ANR,创建了一个新的线程去执行service的调用。

  package com.jason.test.systemserviceaddingtest;    import android.content.ComponentName;    import android.content.Context;    import android.content.Intent;    import android.content.ServiceConnection;    import android.os.Handler;    import android.os.HandlerThread;    import android.os.IBinder;    import android.os.Looper;    import android.os.Message;    import android.os.RemoteException;    import android.support.v4.app.Fragment;    import android.os.Bundle;    import android.util.Log;    import android.view.LayoutInflater;    import android.view.View;    import android.view.ViewGroup;    import android.widget.Button;    import android.widget.Toast;    import com.jason.test.systemserviceaddingtest.service.MathService;    /**     * A placeholder fragment containing a simple view.     */    public class MainActivityFragment extends Fragment {    public static final String TAG = MainActivityFragment.class.getSimpleName();    public static final int EVENT_START_SERVICE = 0x01;    public static final int EVENT_STOP_SERVICE = 0x02;    public static final int EVENT_BIND_SUCCESS = 0x03;    private Context mContext;    private IMathService mMathService;    private Handler mHandler;    private Boolean mIsServiceBound = false;    private Button mStartBtn;    private Button mStopBtn;    public MainActivityFragment() {    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        Log.v(TAG,"onCreateView()");        mContext = getContext();        View fragment = inflater.inflate(R.layout.fragment_main, container, false);        mStartBtn = (Button)fragment.findViewById(R.id.start_service);        mStopBtn = (Button)fragment.findViewById(R.id.stop_service);        mStartBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                // start service thread                mServiceThread.start();                Message msg = mHandler.obtainMessage(EVENT_START_SERVICE);                mHandler.sendMessage(msg);            }        });        mStopBtn.setOnClickListener(new View.OnClickListener(){            @Override            public void onClick(View v){                Message msg = mHandler.obtainMessage(EVENT_STOP_SERVICE);                mHandler.sendMessage(msg);                // stop the service thread                if(!mIsServiceBound) {                    mServiceThread.quitSafely();                }            }        });        return fragment;    }    // 连接service后,回调函数会将IBinder传回给client    private ServiceConnection mServiceConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            mMathService = IMathService.Stub.asInterface(service);            Log.d(TAG,"onServiceConnected(): success");        }        @Override        public void onServiceDisconnected(ComponentName name) {            mMathService = null;            Log.d(TAG,"onServiceDisconnected(): success");        }    };    private void getMathOperations(){        int pid = 0;        int[] val = {203,230};        try{            pid = mMathService.getPID();            val[0] = mMathService.add(val[0],val[1]);            val[1] = mMathService.multiply(val[0],val[1]);        }catch (RemoteException e){            Log.e(TAG,"remote calling exception");        }        Toast.makeText(mContext,"pid = " + pid + " result is " + val[0] + "," + val[1],                Toast.LENGTH_LONG).show();    }    // 为防止APP出现ANR,启动新的线程调用service接口    private HandlerThread mServiceThread = new HandlerThread("ProcessInfoGettingService"){        @Override        public void start(){            //super.start();            mHandler = new Handler(Looper.myLooper()){                @Override                public void handleMessage(Message msg){                    switch (msg.what){                        case EVENT_START_SERVICE:                            bindService();                            break;                        case EVENT_STOP_SERVICE:                            unbindService();                            break;                        case EVENT_BIND_SUCCESS:                            getMathOperations();                        default:                            break;                    }                }            };        }        @Override        public void run(){            Log.d(TAG,"MathService is running");        }    };    // 绑定service    private void bindService(){        Log.v(TAG, "bindService()");        Intent service = new Intent(getContext(), MathService.class);        getContext().bindService(service, mServiceConnection, Context.BIND_AUTO_CREATE);        mIsServiceBound = true;        Toast.makeText(getContext(),"service is bound successfully",Toast.LENGTH_LONG).show();        // notify to calling        Message msg = mHandler.obtainMessage(EVENT_BIND_SUCCESS, Integer.valueOf(mIsServiceBound ? 1 : 0));        mHandler.sendMessageDelayed(msg,1*1000);    }    // 解绑service    private void unbindService(){        if(mIsServiceBound) {            mContext.unbindService(mServiceConnection);            mIsServiceBound = false;            Toast.makeText(getContext(),"service is unbound successfully",Toast.LENGTH_LONG).show();        }    }}

更多关于利用IPC进行数据传递的介绍请参考[2]
如何添加如 Telephony/Alarm/Window Manager 系统服务,请参考[1]

参考文献

  1. http://processors.wiki.ti.com/index.php/Android-Adding_SystemService
  2. https://developer.android.com/guide/components/aidl.html

更多相关文章

  1. Android(安卓)C++多线程-创建子线程
  2. android spinner修改 样式
  3. Android自定义控件进阶-打造Android自定义的下拉列表框控件
  4. Android(安卓)数据存储(一) Preference的使用
  5. 断点下载
  6. Android(安卓)面试题(5):谈谈 Handler 机制和原理?
  7. android fence sync
  8. Android开发艺术探索知识回顾——第2章 IPC机制:1、IPC 的基础知
  9. Android(安卓)使用Parcelable序列化对象

随机推荐

  1. 开发自己的监控系统三、移动篇(android)
  2. Android平台架构及特性(1)
  3. CTS bug排除
  4. 解决scrollview嵌套ImageView时,出现除顶
  5. Android封装SDK的使用
  6. 模拟器上安装Android(安卓)Market
  7. android是什么意思
  8. Android开发者必知的开发资源
  9. Android中MVC的具体体现
  10. android style(样式)和theme(主题)设置