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文件。
该文件中自动生成了一个静态的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相关推荐
- 【Android 逆向】Android 权限 ( Android 逆向中使用的 android.permission 权限 | Android 系统中的 Linux 用户权限 )
文章目录 一.Android 逆向中使用的 android.permission 权限 二.Android 系统中的 Linux 用户权限 一.Android 逆向中使用的 android.permi ...
- android aidl权限,android AIDL
进程通讯AIDL,即Android Interface Definition Language(安卓接口定义语言),主要是用来跨进程访问,例如服务器端与客户端通信时,服务端与客户端如何收发数据需要通过 ...
- android组件权限,Android中Permission权限机制的具体使用
由上篇Android Permission权限机制引子,我们知道Android 通过在每台设备上实施了基于权限的安全策略来处理安全问题,采用权限来限制安装应用程序的能力.本篇文章继续来探讨和Andro ...
- android wifimanager权限,Android 6.0.1 - 权限问题= wifiManager.getScanResults()返回0
permissionsList.add()不起作用,但MainActivity.this.requestPermissions()正常工作.问题是它带来一个对话框询问用户是否允许位置权限.Androi ...
- android 访问权限,Android 使用情况访问权限
问题描述 添加了使用情况访问权限,如果不开启权限就不让进去,但是发现如果不开启,直接点击返回的话,会再次进入页面但是下面的列表数据不出现 问题出现的环境背景及自己尝试过哪些方法 第一次出现(进软件的时 ...
- android cta 权限,[Android][Framework]PackageManagerService处理应用权限流程
app种类 1.system app (有ApplicationInfo.FLAG_SYSTEM标记) 2.privileged app (有ApplicationInfo.FLAG_SYSTEM和A ...
- android ota权限,Android手机Root后不能接收OTA?
如今Android手机买回来之后第一件事除了检查手机是否有缺陷之后就是取得Android系统的ROOT权限.而现在网络上充斥着各种ROOT权限取得的方法,用户在家里就能够自己刷机升级,目前大多数的安致 ...
- android mediaplayer 权限,Android — 使用MediaPlayer进行音频播放
上一篇说到音频录制的时候我就知道肯定会有音频播放这个功能,果不其然后续播放的需求又给我加上了,因为之前是AMR格式,所以这里使用MediaPlayer进行播放,据ios说播放amr格式的音频还挺麻烦的 ...
- android afw 权限,Android权限汇总
Android P危险权限声明 Android p一些危险权限即使你是shareuid为system系统应用,在mainfest里声明,如果不在危险权限列表里声明,手机会无法启动 危险权限位置: /s ...
最新文章
- boost::coroutine2模块实现解析器的测试程序
- 可控硅失效现象_可控硅坏的原因有哪些
- IP地址的网络位与主机位
- 寒假作业 使用xmind脑图小结课程内容
- Page.ClientScript.RegisterStartupScript() 方法与Page.ClientScript.RegisterClientScriptBlock() 方法
- Python—语法基础(8) 分支、循环结构
- eclipse启动web项目时,spring会初始化两次
- mysql5.7版本windows的安装
- AndroidTV开发7实现仿小米电视和各种盒子TV焦点放大缩小效果
- 在think-cell数据表中,“撤消” (Ctrl+Z) 操作无效,怎么解决?
- 气球java游戏_团队游戏 气球
- linux下编译ts工程,linux下搭建生成HLS所需的.ts和.m3u8文件
- 【干货分享】一文详尽什么是春招?如何准备春招?互联网春招什么时候开始?
- 2021年英语六级翻译
- 原生table 边框重叠 粗细不一样等问题,秒懂,只需几秒就能完成
- c语言程序设计拉丁方阵结构图,C语言实例之拉丁方阵
- matplotlib画多个图并保存为PDF
- Misplaced \noalign. \hline 的解决方法
- 绿坝遭遇“剽窃门,美国加州一软件公司指控其剽窃他们的技术,并准备诉诸法律
- 谷歌浏览器如何清除自动填充表单数据??就是一登录进入就会将之前输入的内容自动输入进去进行清空