Android AIDL

Android系统中,各应用程序运行在各自的进程中,无法直接进行交互。为了实现进程间的通讯(IPC),Android提供了AIDL

Server方法进行处理。

AIDL(android

Interface defaultion language)主要分为服务端和客户端两个方面。而服务端主要是继承了Server。可以将AIDL服务端看作是个特殊的Service。

使用AIDL时,并非支持所有的数据类型。AIDL只支持以下六种数据类型:

1.

基本数据类型(void,int,char,long,double,boolean等基本数据类型)

2.

String和CharSequence;

3.

List:其中只支持ArrayList,而ArrayList中的每个元素都必须被AIDL所支持。

4.

Map:其中只支持HashMap,而HashMap中的每个元素都必须被AIDL所支持,包括Key和Value。

5.

Parcelable:支持的对象必须是经过Parcelable序列化的对象。

6.

AIDL:支持AIDL本身。

一.简单数据类型的AIDL

AIDL分为服务端和客户端两个方面。

服务端:创建一个Service,用来监听客户端的调用,并用来实现AIDL的接口函数。

客户端:绑定Service,并Service返回的Binder对象转换为AIDL接口。

创建过程:

1.

创建AIDL,并声明接口信息:

package

com.mzzhang.serviceforaidl.aidlTest;

interface

InvokeAidl {

int printInt();

String

printString(int a,String

b);

}

创建了一个文件后缀名为.ail的AIDL文件,该文件信息包括Package,interface和相关函数。其中值得注意的是该文件最好在单独的Package中,因为需要将该整个包copy到相应调用该服务的客户端中。

当创建完该AIDL文件后,在gen中会自动生成相对应的.java文件。

该文件中自动生成了一个静态的Stub类。而该类继承了Binder并实现了.aidl中定义的接口。

public static abstract

class

Stub

extends

android.os.Binder

implements com.mzzhang.serviceforaidl.aidlTest.InvokeAidl

从该类的定义可以看出,Serviece是通过Stub来实现该AIDL。而Stub是继承了Binder,所有AIDL最终是通过Binder进行进程通讯的。

2.

服务端Service的实现:

定义完AIDL接口后,需要创建Service来实现该接口。

package com.mzzhang.serviceforaidl;

import java.util.List;

import com.mzzhang.serviceforaidl.aidlTest.InvokeAidl.Stub;

import android.app.Service;

import android.content.Intent;

import android.os.IBinder;

import android.os.RemoteException;

import android.util.Log;

public class MainService extends Service {

private

static

final

String

TAG = "MainService";

private

InvokeBinder

_invokeBinder;

private

int

_times

= 0;

@Override

public

void

onCreate() {

super.onCreate();

_invokeBinder

=

new

InvokeBinder();

}

@Override

public

IBinder

onBind(Intent intent) {

return

_invokeBinder;

}

public

class

InvokeBinder

extends

Stub{

@Override

public

int

printInt()

throws

RemoteException

{

Log.d(TAG, "this is print int, the times is

:" +

_times);

_times++;

return

_times;

}

@Override

public

String

printString(int a, String b) throws RemoteException {

String s = "a is " + a +" b is "+b;

Return

s;

}

}

}

创建了一个MainService后,由于该Service为其他进行提供服务,因此需要采用BindService的方法。并在OnBind中return一个Binder对象。通过刚才对Stub的分析可以得知Stub是AIDL生成,并继承Binder对象。因此定义了一个继承Stub对象,并实现了该静态对象类的方法。因此onBind返回的是个Stub。

3.

注册AndroidMainFest.xml中信息

该Service为其他进程提供服务和数据,因此其他进程无法采用显式启动的方式访问到该Service因此需要在AndroidMainFext.xml中定义相关的Intet-filter信息,以提供其他进程进行访问。

<service

android:name="com.mzzhang.serviceforaidl.MainService">

<intent-filter>

<action android:name="com.mzzhang.serviceforaidl.service"/>

intent-filter>

service>

到此Service客户端的操作基本完成。

4.

Copy AIDL到需调用该AIDL的进程中:

客户端中采用的是BindServer的方法启动该应用,并返回了一个stub对象。但在客户端中对该Stub对象却是一无所知。因此需要通过将AIDL对应的文件copy到该客户端中,在客户端中自动生成一个Stub对象。因此在第1步中,提及最好将AIDL放在单独的一个包中。

5.

客户端的实现:

package com.mzzhang.aidlcustomer;

import com.mzzhang.serviceforaidl.aidlTest.InvokeAidl;

import android.app.Activity;

import android.app.Service;

import android.content.ComponentName;

import android.content.Intent;

import android.content.ServiceConnection;

import android.os.Bundle;

import android.os.RemoteException;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.TextView;

public class MainActivity extends Activity{

private

static

final

String

TAG = "MainActivity";

private

InvokeAidl

_invokeAidl

;

Button btn_get;

Button btn_show;

TextView tv_show;

StringBuilder sb;

@Override

protected

void

onCreate(Bundle

savedInstanceState)

{

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

btn_get

= (Button)

findViewById(R.id.btn_get);

btn_show

= (Button)

findViewById(R.id.btn_show);

tv_show

= (TextView)

findViewById(R.id.tv_show);

}

@Override

protected

void

onResume() {

super.onResume();

sb = new StringBuilder();

btn_get.setOnClickListener(new

OnClickListener()

{

@Override

public

void

onClick(View

v) {

Intent intent = new Intent();

intent.setAction("com.mzzhang.serviceforaidl.service");

bindService(intent, conn, Service.BIND_AUTO_CREATE);

}

});

btn_show.setOnClickListener(new

OnClickListener()

{

@Override

public

void

onClick(View

v) {

try

{

sb.append(_invokeAidl.printInt() + "\n");

sb.append(_invokeAidl.printString(1, "test")+ "\n");

tv_show.setText(sb.toString());

} catch (RemoteException

e) {

//

TODO

Auto-generated catch

block

e.printStackTrace();

}

}

});

}

private

ServiceConnection

conn

=

new

ServiceConnection()

{

@Override

public

void

onServiceDisconnected(ComponentName

name) {

}

@Override

public

void

onServiceConnected(ComponentName

name, IBinder service) {

_invokeAidl

=

InvokeAidl.Stub.asInterface(service);

}

};

}

在该客户端中采用的是bindService的方法,返回了一个ServiceConnect。

Intent intent = new Intent();

intent.setAction("com.mzzhang.serviceforaidl.service");

bindService(intent, conn, Service.BIND_AUTO_CREATE);

并在ServiceConnection中进行绑定。而采用的绑定方法为将IBinder转换为AIDL的Interface。InvokeAidl.Stub.asInterface(service)。

绑定后,直接通过绑定的对象调用该接口函数进行通信。

以上,便可实现一个简单的IPC。除了能传输基本数据类型的AIDL外,AIDL也可传输对象类型。

二.在进程中传递对象数据

1.

对象序列化

在进程中进行对象传递时,需要对对象进行序列化过程后,才能进行传递。例如该案例中创建一个Person对象类,并对其进行序列化,具体系列化过程见:。

2.

创建parcelable AIDL

由于AIDL并不支持自定义对象类,而对象类只实现Pacelable因此还需要创建一个parcelable的AIDL,供AIDL调用。

package

com.mzzhang.serviceforaidl.model;

parcelable Person;

3.

添加对象信息到AIDL中。

package

com.mzzhang.serviceforaidl.aidlTest;

import

com.mzzhang.serviceforaidl.model.Person;

interface

InvokeAidl {

void setPerson(in Person person);

Person getPerson();

}

其中需要import该person类的package位置。

我们需要注意的是,在使用对象为参数时,用到了in和out或inOut三种类型。In表示输入类型,out表示输出类型,inOut表示输入和输出类型。

4.

Copy AIDL与Person类

将AIDL和Person类都copy到需要调用的进程中。包括Person类创建的AIDL。

5.

在客户端中实现Person功能

_invokeAidl.setPerson(_person);

_person

= _invokeAidl.getPerson();

三.远程回调:

在使用进程时,我们需要考虑到的一点就是进程间的回调。通过Service创建一个回调方法供进程进行回调。

1.

创建回调AIDL。

package

com.mzzhang.serviceforaidl.aidlTest;

interface

IPersonListener {

void onSomeNeedCallBack();

}

2. 在AIDL中定义回调方法。

package

com.mzzhang.serviceforaidl.aidlTest;

import

com.mzzhang.serviceforaidl.aidlTest.IPersonListener;

interface

InvokeAidl {

void registerListener();

void unRegisterListener();

}

在该AIDL中创建了两个函数方法,分别为register和unRegister。

3.

Service操作

采用RemoteCallbackList方法进行操作。

privateRemoteCallbackList

_personListener;

并在Stub中注册监听事件

@Override

public void registerListener(IPersonListener

listener) throws RemoteException {

_personListener.register(listener);

Log.d(TAG, " some one call the register

Listener");

}

@Override

public void unRegisterListener(IPersonListener

listener) throws RemoteException {

_personListener.unregister(listener);

Log.d(TAG, " some one call the unRegister

Listener");

}

通过遍历RemoteCallbackList寻找Listener并进行操作。

int i = _personListener.beginBroadcast();

Log.d(TAG,

"the thread time is

" +

i);

while (i > 0) {

i--;

try

{

IPersonListener

l = _personListener.getBroadcastItem(i);

if(l!=null){

_person.setId(5555);

l.onSomeNeedCallBack(_person);

Log.d(TAG,

"some things to be

call!");

}

} catch (RemoteException

e) {

e.printStackTrace();

}

}

_personListener.finishBroadcast();

RemoteCallbackList是Android系统专门提供用于删除跨进程Listener的接口的。而该Listener接口在Android的底层是公用一个Binder对象,所有可实现在不同的进程中的Listener是同一个,从而避免了服务端和客户端注册和解绑的Listener为不同的对象。

四.权限设定

在默认的情况中,所有的AIDL都是可调用的。但在某些情况下,总是希望只有个别获得权限的进程才能使用,因此在使用AIDL时,我们需要为AIDL添加权限。

在服务端AndroidManifest.xml中添加权限。

<permission

android:name = "com.mzzhang.serviceforaidl.permission_server"

android:protectionLevel="normal"/>

1.

在服务端OnBinder中验证:

@Override

public

IBinder

onBind(Intent intent) {

int check =

checkCallingOrSelfPermission("com.mzzhang.serviceforaidl.permission_server");

if(check ==

PackageManager.PERMISSION_DENIED)

return

null;

return

_invokeBinder;

}

若客户端设定的权限为com.mzzhang.serviceforaidl.permission_server,则验证通过,否则验证不通过。

客户端权限:

在客户端AndroidMainfest.xml中设置该权限。

<uses-permission android:name="com.mzzhang.serviceforaidl.permission_server"/>

2.

在Stub中使用onTransact方法验证。该方法除了验证Permission外,还可通过验证getCallingUid和getCallingPid方法。

@Override

public

boolean

onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {

int

check

=

checkCallingOrSelfPermission("com.mzzhang.serviceforaidl.permission_server");

if(check ==

PackageManager.PERMISSION_DENIED)

return

false;

String packageName

=

null;

String[] packages =

getPackageManager().getPackagesForUid(getCallingUid());

if(packages!=null && packages.length > 0){

if(!packages[0].startsWith("com.mzzhang.serviceforaidl"))

return

false;

}

return

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

}

五.注意事项

1.

在使用List传递时最好使用CopyOnWriteArrayList来代替ArrayList该方法父类为list所有也支持AIDL。

2.

由于Service和Activity都属于UI线程,所有在操作相对较耗时的操作时,应该采用线程进行操作。

3.

对象序列化后,需要将对象再进行一次AIDL,其中parcelable为小写。

简单示例代码见:http://download.csdn.net/detail/zhezizhang/9633153

android aidl权限,Android AIDL相关推荐

  1. 【Android 逆向】Android 权限 ( Android 逆向中使用的 android.permission 权限 | Android 系统中的 Linux 用户权限 )

    文章目录 一.Android 逆向中使用的 android.permission 权限 二.Android 系统中的 Linux 用户权限 一.Android 逆向中使用的 android.permi ...

  2. android aidl权限,android AIDL

    进程通讯AIDL,即Android Interface Definition Language(安卓接口定义语言),主要是用来跨进程访问,例如服务器端与客户端通信时,服务端与客户端如何收发数据需要通过 ...

  3. android组件权限,Android中Permission权限机制的具体使用

    由上篇Android Permission权限机制引子,我们知道Android 通过在每台设备上实施了基于权限的安全策略来处理安全问题,采用权限来限制安装应用程序的能力.本篇文章继续来探讨和Andro ...

  4. android wifimanager权限,Android 6.0.1 - 权限问题= wifiManager.getScanResults()返回0

    permissionsList.add()不起作用,但MainActivity.this.requestPermissions()正常工作.问题是它带来一个对话框询问用户是否允许位置权限.Androi ...

  5. android 访问权限,Android 使用情况访问权限

    问题描述 添加了使用情况访问权限,如果不开启权限就不让进去,但是发现如果不开启,直接点击返回的话,会再次进入页面但是下面的列表数据不出现 问题出现的环境背景及自己尝试过哪些方法 第一次出现(进软件的时 ...

  6. android cta 权限,[Android][Framework]PackageManagerService处理应用权限流程

    app种类 1.system app (有ApplicationInfo.FLAG_SYSTEM标记) 2.privileged app (有ApplicationInfo.FLAG_SYSTEM和A ...

  7. android ota权限,Android手机Root后不能接收OTA?

    如今Android手机买回来之后第一件事除了检查手机是否有缺陷之后就是取得Android系统的ROOT权限.而现在网络上充斥着各种ROOT权限取得的方法,用户在家里就能够自己刷机升级,目前大多数的安致 ...

  8. android mediaplayer 权限,Android — 使用MediaPlayer进行音频播放

    上一篇说到音频录制的时候我就知道肯定会有音频播放这个功能,果不其然后续播放的需求又给我加上了,因为之前是AMR格式,所以这里使用MediaPlayer进行播放,据ios说播放amr格式的音频还挺麻烦的 ...

  9. android afw 权限,Android权限汇总

    Android P危险权限声明 Android p一些危险权限即使你是shareuid为system系统应用,在mainfest里声明,如果不在危险权限列表里声明,手机会无法启动 危险权限位置: /s ...

最新文章

  1. boost::coroutine2模块实现解析器的测试程序
  2. 可控硅失效现象_可控硅坏的原因有哪些
  3. IP地址的网络位与主机位
  4. 寒假作业 使用xmind脑图小结课程内容
  5. Page.ClientScript.RegisterStartupScript() 方法与Page.ClientScript.RegisterClientScriptBlock() 方法
  6. Python—语法基础(8) 分支、循环结构
  7. eclipse启动web项目时,spring会初始化两次
  8. mysql5.7版本windows的安装
  9. AndroidTV开发7实现仿小米电视和各种盒子TV焦点放大缩小效果
  10. 在think-cell数据表中,“撤消” (Ctrl+Z) 操作无效,怎么解决?
  11. 气球java游戏_团队游戏 气球
  12. linux下编译ts工程,linux下搭建生成HLS所需的.ts和.m3u8文件
  13. 【干货分享】一文详尽什么是春招?如何准备春招?互联网春招什么时候开始?
  14. 2021年英语六级翻译
  15. 原生table 边框重叠 粗细不一样等问题,秒懂,只需几秒就能完成
  16. c语言程序设计拉丁方阵结构图,C语言实例之拉丁方阵
  17. matplotlib画多个图并保存为PDF
  18. Misplaced \noalign. \hline 的解决方法
  19. 绿坝遭遇“剽窃门,美国加州一软件公司指控其剽窃他们的技术,并准备诉诸法律
  20. 谷歌浏览器如何清除自动填充表单数据??就是一登录进入就会将之前输入的内容自动输入进去进行清空

热门文章

  1. VMware中安装Windows 7操作系统
  2. 关于特别恶劣,特别流氓的软件卸载方法
  3. 荣耀平板v6鸿蒙2.0,华为鸿蒙系统2.0机型推荐,鸿蒙2.0支持机型一览
  4. 如何使用ArcGIS计算四至坐标
  5. Java项目:JSP停车场管理系统
  6. 城际出行报告:后滴滴时代的千亿蓝海
  7. 【Unity】【VR开发】为什么认为Quest和Unity组合是目前消费级VR开发的最佳组合
  8. UML类图、JAVA DesignMode 设计模式、设计原则
  9. Linux 字符串截取命令
  10. 链表排序算法(Java实现)