android aidl权限,Android AIDL

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文件。

a4c26d1e5885305701be709a3d33442f.png

该文件中自动生成了一个静态的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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值