概述

看看官方文档:
AIDL(Android 接口定义语言)与您可能使用过的其他 IDL 类似。 您可以利用它定义客户端与服务使用进程间通信 (IPC) 进行相互通信时都认可的编程接口。 在 Android 上,一个进程通常无法访问另一个进程的内存。 尽管如此,进程需要将其对象分解成操作系统能够识别的原语,并将对象编组成跨越边界的对象。 编写执行这一编组操作的代码是一项繁琐的工作,因此 Android 会使用 AIDL 来处理。

看到这我们就知道了aidl是什么了:Android 接口定义语言。它可以实现一种通信服务ipc。既然是语言,那么都支持什么数据类型?


// IMyAidlTestInterface.aidlpackage com.sim.aidlTest;// Declare any non-default types here with import statementsinterface IMyAidlTestInterface {    /**     * Demonstrates some basic types that you can use as parameters         * and return values in AIDL.     * /    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString);   }

这是由AndroidStudio自动生成的aidl,可以看到aidl支持的基本类型。int,long,boolean,float,double,String。
默认情况下,AIDL 支持下列数据类型:

  • Java 编程语言中的所有原语类型(如 int、long、char、boolean 等等)
  • String
  • CharSequence
  • List
    List 中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。 可选择将 List 用作“通用”类(例如,List)。另一端实际接收的具体类始终是 ArrayList,但生成的方法使用的是 List 接口。
  • Map
    Map 中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。 不支持通用 Map(如 Map

下面我们来看一下应用层aidl的使用,我认为aidl在使用时主要分为三步:

  1. 创建aidl接口
  2. 创建服务端
  3. 客户端调用

我创建了一个小的demo用来练习aidl的使用,下面是主要的代码:

步骤一:创建aidl接口

package com.sim.aidlTest;// Declare any non-default types here with import statementsinterface IMyAidlInterface {    void testMethod();  }

在接口中我只添加了一个方法。

步骤二:创建服务端

创建一个Service,Service中创建一个类继承AIDL接口中的Stub类并实现Stub中的抽象方法,最后不要忘记在onBind中返回这个类的对象。

public class MyAIDLService extends Service {    private static final String TAG = "MyAIDLService";    private final IMyAidlInterface.Stub mBinder=new IMyAidlInterface.Stub(){        @Override        public void testMethod() throws RemoteException {            Log.d(TAG,"testMethod: this is myAIDLTest");            }     };     @Override     public IBinder onBind(Intent intent) {           } }

步骤三:创建客户端

在客户端中绑定该Service,将Service返回的Binder对象转换成AIDL接口所属的类型,接着直接调用AIDL的方法。

private ServiceConnection mServiceConnection = new ServiceConnection() {    @Override    public void onServiceConnected(ComponentName name, IBinder service) {             Log.e(TAG, "onServiceConnected");         }     @Override    mMyAIDL = null;    }};
btnStartMethod.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View view) {        try {                     mMyAIDL.testMethod();        } catch (RemoteException e) {                    Toast.makeText(MainActivity.this, "服务被异常杀死,请重新开启。", Toast.LENGTH_SHORT).show();             }       }});

其实在系统中使用aidl只需多一步。
需要在Android.mk中加上aidl的路径。
LOCAL_SRC_FILES += aidl路径
以上就是aidl的使用方式。
这样实现的Service是可以跨应用绑定并通信的,只不过在使用时需要注意的是要将这个aidl文件拷贝到另一个应用中,并且要确保包名不能改变,然后就可以在新应用里绑定原应用的Service了。


添加系统服务

但是看完之后感觉,什么时候在系统中一用aidl?还是不是特别清晰。
接下来介绍一下如何添加系统服务。添加系统服务当然还是用到了aidl,所以我也先从添加aidl开始。

步骤1:在frameworks/base/core/java/android/os/目录下添加一个自定义的aidl文件,我添加了一个名为IMyTestSystemService.aidl的文件。

package android.os;interface IMyTestSystemService{    String getTestMethod();}

因为只是测试,所以只添加了一个方法。

步骤2:在frameworks/base/services/core/java/com/android/server/添加与aidl对应的Service文件

package com.android.server;import android.os.IMyTestSystemService;public class MyTestSystemService extends IMyTestSystemService.Stub {    private static String TAG = "MyTestSystemService";    public MyTestSystemService() {}    @Override    public String getTestMethod() {        return TAG+": getTestMethod()";    }}

步骤3:将MyTestSystemService加入到SystemtemServer启动进程。系统服务大都从SystemServer启动,如果想要添加的服务开机就启动那么就需要在SystemServer中添加启动逻辑。

为了方便引用,现在Context.java中添加了一个常量。
public static final String MY_TEST_SYSTEM_SERVICE = “my_test_system”;
然后在
frameworks/base/services/java/com/android/server/SystemServer.java中的startOtherService()方法中添加如下代码:

 try {                Slog.i(TAG,"My Test SystemService");                myTestService = new MyTestSystemService();                ServiceManager.addService(Context.MY_TEST_SYSTEM_SERVICE, myTestService);            } catch (Throwable e) {                Slog.e(TAG, "Failure starting My Test SystemService", e);            }

4.添加Manager文件frameworks/base/core/java/android/app/MyTestManager.java

public class MyTestManager {    IMyTestSystemService mService;    public MyTestManager(Context ctx,IMyTestSystemService service){        mService=service;    }    public String getTestMethod(){        try{            return mService.getTestMethod();        }catch(Exception e){            Log.e("MyTestManager",e.toString());            e.printStackTrace();        }         return null;    }}

在Manager文件中调用Service的方法

5.在SystemServiceRegistry.java中注册服务

registerService(Context. MY_TEST_SYSTEM_SERVICE, MyTestManager.class,                new CachedServiceFetcher() {                    @Override                    public MyTestManager createService(ContextImpl ctx) {                        IBinder b = ServiceManager.getService(Context. MY_TEST_SYSTEM_SERVICE);                        IMyTestSystemService service = IMyTestSystemService.Stub.asInterface(b);                        return new MyTestManager (ctx, service);                    }});

这段代码是添加在SystemServiceRegistry的静态代码块中的

6.在mk文件中添加aidl文件路径

frameworks/base/Android.mk

7.在external/sepolicy/service_contexts中添加:

my_test_system u:object_r:my_test_system_service:s0

8.在external/sepolicy/service.te中添加

service.te主要用来定义我们自己服务的类型,不同厂商的定制可能导致该路径不同在该文件中已经定义了很多service类型,只需要照着画就行了。
type my_test_system_service, system_api_service, system_server_service, service_manager_type;

9.完成上述步骤之后,需要make update-api

然后编译framework.jar,services.jar,以及boot.img。

在替换了新编译的文件后,可以自己进行测试,测试代码如下:

MyTestManager mTestManager = (MyTestManager)getSystemService(Context.MY_TEST_SYSTEM_SERVICE);        Log.e(“xijun","mTestManager : "+mTestManager);        Log.e(“xijun","mTestManager.getTestMethod() = "+mTestManager.getTestMethod());

获取到MyTestManager 对象后,通过调用其内部的方法来验证是否成功。
也可以通过命令 adb shell services list 来获取系统服务列表,查看自定义服务是否存在。


getSystemService()的流程

接下来我想说明一下getSystemService()的流程,在Activity内我们可以直接调用getSystemService()来获得系统服务,由于Activity继承自Context,所以这个方法实际上是Context留出来的接口。
Context源码:
public abstract Object getSystemService(@ServiceName @NonNull String name);
而这个方法的实现是写在ContextImpl里的,源码如下:

public Object getSystemService(String name) {            return SystemServiceRegistry.getSystemService(this, name);    }

SystemServiceRegistry这个类就是我们注册服务的类,其内部实现如下

public static Object getSystemService(ContextImpl ctx, String name) {                ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);                return fetcher != null ? fetcher.getService(ctx) : null;    }

这里我们可以看到他是从SYSTEM_SERVICE_FETCHERS中取出了一个ServiceFetcher类型的对象。
而在源码中SYSTEM_SERVICE_FETCHERS是一个HashMap,其定义如下

private static final HashMap<?>> SYSTEM_SERVICE_FETCHERS =            new HashMap<?>>();

而向这个Map中put值的方法如下:

private static  void registerService(String serviceName, Class serviceClass,          ServiceFetcher serviceFetcher) {        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher); }

这个方法就是我们注册服务的方法,也就是说如果想要在getSystemService时找到自定义的服务就需要在此处进行注册。
同时我们也看到这个HashMap中键值是servicename与serviceFetcher对象。这个ServiceFetcher是SystemServiceRegistry类中的一个接口,其内容如下:

static abstract interface ServiceFetcher<T> {        T getService(ContextImpl ctx);}

而我们在注册时传入的是一个CachedServiceFetcher对象,这是实现了ServiceFetcher接口的内部类

static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {        private final int mCacheIndex;        public CachedServiceFetcher() {            mCacheIndex = sServiceCacheSize++;        }        @Override        @SuppressWarnings("unchecked")        public final T getService(ContextImpl ctx) {            final Object[] cache = ctx.mServiceCache;            synchronized (cache) {                // Fetch or create the service.                Object service = cache[mCacheIndex];                if (service == null) {                    service = createService(ctx);                    cache[mCacheIndex] = service;                }                return (T)service;            }        }        public abstract T createService(ContextImpl ctx);    }

我们在创建CachedServiceFetcher时实现了其CreateService方法,SystemServiceRegistry中getSystemService()方法中调用到fetcher.getService(ctx)时,就会执行createService方法,也就是在这时创建了MyTestManager对象

总结

aidl的使用我认为可以把它分为两类:
一种是我们在应用层开发中的关于两个应用之间进程互相调用。
一种是系统开发中的进程间信息通讯。比如内核层面的进程和应用之间的调用。

比如添加系统服务这种。是系统开发之后供第三方应用调用。像上面模拟的getSystemService调用。提供了接口,让所有第三方调用。
但是为什么用这种方法,第三方应用而不是直接用Jni来直接调取?其实系统提供的这种getSystemService是提供给众多第三方的应用的。如果用Jni这种,只是会和其中的某一个第三方调用,其他第三方应用并没有提供接口来调用。
这是我的理解,如有错误之处,敬请指出。

相关文章:
你真的理解Android AIDL中的in,out,inout么?
Android:学习AIDL,这一篇文章就够了

更多相关文章

  1. android版PDA通过USB与.net应用程序通讯,实现离线版android应用同
  2. Android下的Java之interface接口泛型 动态获取泛型的类型
  3. 【android】音乐播放器之service服务设计
  4. 基于Android移动终端的搜索客户端应用【团队项目】
  5. Android:学习AIDL,这一篇文章就够了(下)
  6. Android无障碍服务三 创建辅助功能服务
  7. Android(安卓)错误信息捕获发送至服务器【整理】
  8. Android学习笔记:服务(Service)
  9. 个人简历制作——Android自动升级&个人“服务器”搭建

随机推荐

  1. 解析基于php伪静态的实现方法
  2. 了解php实现的支付宝网页支付功能【基于T
  3. php的字符串管理 zend_string
  4. PHP jpgraph库的配置及生成多种统计图表
  5. 详解PHP网页缓存技术优点及代码实例
  6. php之 Zend 内存管理器
  7. 速看!主流PHP框架性能非权威测试
  8. php如何进行内存调试
  9. 详解PHP中的OPcache 扩展
  10. PHP使用Closure创建匿名函数的方法介绍