AIDL 与Binder
来源:互联网 发布:梦三国2mac版本 编辑:程序博客网 时间:2024/06/02 20:08
前段时间自己学习binder记录的一些文字, 如果有不对的地方, 麻烦指正, 以便能更进一步学习。
一、RPC(Remote process comunication), 进程间通讯;
应用A欲访问或者获取服务端的数据, 可以通过AIDL来实现;
首先新建RemoteService.aidl文件, 将自己想获取的数据以返回值或者入参形式传入接口函数, 如:
interface RemoteService{
String fun1();
int fun2(in DemoClass demoObj); // 如果在eclipse中做, import会编译不过, 如果在Android源码中是可以的
int fun3(inout DemoClass demoObj); // 如果在eclipse中做, import会编译不过, 如果在Android源码中是可以的
int fun4(in byte[] inBuf, out byte[] outBuf, int len);
}
如果是在Android源码中, 编译后, out目录下可以找到对应的RemoteService.java文件, eclipse中编译则会在gen目录下自动生成对应RemoteService.java文件;
RemoteService.java 说明:
1.会有一个抽象内部类Stub, 是Binder的派生类, 实现RemoteService.aidl中的接口函数
publicstaticabstractclassStubextendsandroid.os.Binderimplementscom.example.binderlearn.RemoteService
2.privatestaticfinaljava.lang.StringDESCRIPTOR= "com.example.binderlearn.RemoteService";
DESCRIPTOR : 类描述字符串, 很重要, Binder绑定是通过这个描述字符串标志来通讯的;
3.publicStub() {
this.attachInterface(this,DESCRIPTOR);
}
抽象类的构造函数,attachInterface是Binder中的方法, 按函数说明看是联系接口和Binder的便捷方法;
4.publicstaticcom.example.binderlearn.RemoteService asInterface(android.os.IBinderobj){
if((obj==null)) {
returnnull;
}
android.os.IInterfaceiin=obj.queryLocalInterface(DESCRIPTOR);
if(((iin!=null) && (iininstanceofcom.example.binderlearn.RemoteService))) {
return((com.example.binderlearn.RemoteService)iin);
}
returnnewcom.example.binderlearn.RemoteService.Stub.Proxy(obj);
}
将IBinder对象转换成一个接口类型, 如果需要生成一个接口代理类;
5.publicandroid.os.IBinder asBinder() {
returnthis;
}
返回一个IBinder对象, 此处是返回当前的Stub;
6.publicbooleanonTransact(intcode, android.os.Parceldata,android.os.Parcelreply,intflags){
switch(code){
caseTRANSACTION_fun1:{
data.enforceInterface(DESCRIPTOR);
java.lang.String_result=this.fun1();
reply.writeNoException();
reply.writeString(_result);
returntrue;
}
}
.....
}
其中code为每个接口函数对应的编码, data是对应函数传入的参数组成的一个数据包, reply为函数执行完成后返回的结果数据包;
7.privatestaticclassProxyimplementscom.example.binderlearn.RemoteService {
privateandroid.os.IBindermRemote;
Proxy(android.os.IBinderremote) {
mRemote=remote;
}
@Override
publicjava.lang.String fun1 () throws android.os.RemoteException {
android.os.Parcel_data= android.os.Parcel.obtain();
android.os.Parcel_reply= android.os.Parcel.obtain();
java.lang.String_result;
try{
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_fun1,_data,_reply, 0);
_reply.readException();
_result=_reply.readString();
}finally{
_reply.recycle();
_data.recycle();
}
return_result;
}
......
}
接口RemoteService 的代理类, 实现各接口函数;构造函数是在Stub.asInterface中调用, 将asInterface中的入参IBinder obj对象
赋值给mRemote, mRemote是用于与Stub通讯;
8.staticfinalintTRANSACTION_fun1 = (android.os.IBinder.FIRST_CALL_TRANSACTION+ 0);
为接口函数编码, 将用于代理类与Stub.onTransact通讯的标识码;
9.新建类publicclassRemoteServiceImplextends RemoteService.Stub
是RemoteService.aidl生成的RemoteService.java中内部抽象类Stub的派生类, 完全实现接口方法,如:
@Override
publicString fun1() throws RemoteException {
//TODOAuto-generated method stub
return"AIDL 例子";
}
10.新建服务类
publicclassMyServiceextendsService {
privateStubserviceInfo= new RemoteServiceImpl();
@Override
publicIBinder onBind(Intent intent) {
//TODOAuto-generated method stub
returnserviceInfo;
}
}
在onBind中返回一个RemoteService.Stub实列;注:需要在AndroidManifest.xml中注册该服务;
11.在MainActivity的onCreate中新建Intent,设置意图的Action为10中的Myservice:
IntentmIntent=new Intent();
mIntent.setAction("com.example.binderlearn.MyService");
mIntent.setPackage(getPackageName());
然后bindService(mIntent,conn, Context.BIND_AUTO_CREATE);需要实列化conn, 其为ServiceConnection:
ServiceConnectionconn=newServiceConnection(){
@Override
publicvoidonServiceConnected(ComponentNamename,IBinderservice) {
//TODOAuto-generated method stub
mRemoteService= RemoteService.Stub.asInterface(service);
}
@Override
publicvoidonServiceDisconnected(ComponentNamename) {
}};
mRemoteService定义:privateRemoteServicemRemoteService;其为接口类RemoteService对象;
连接成功后mRemoteService实列化成功, 这样就可以调用mRemoteService.aidl中的函数了;
二、整个调用流程
bindService(mIntent,conn, Context.BIND_AUTO_CREATE);这段代码是通过Binder将服务与接口绑定, 绑定服务成功后将会调用
ServiceConnection中的回调函数,实例化接口类对象mRemoteService,调用接口函数fun1为例mRemoteService.fun1()数据走向是如下:
bindService成功将调用onServiceConnected(ComponentNamename, IBinderservice), 其中入参service是MyService中的serviceInfo,
mRemoteService= RemoteService.Stub.asInterface(service);这个将调用RemoteService.java中内部类Stub的asInterface方法,
mRemoteService将是接口RemoteService 的代理类, mRemoteService.fun1()将调用代理类中的fun1()方法,fun1()中
mRemote.transact(Stub.TRANSACTION_fun1,_data,_reply, 0),
它是一个native方法( frameworks/base/core/jni/android_util_Binder.cpp),里面进行了一系列的函数调用,它最终调用到了
talkWithDriver函数, 看这个函数的名字就知道,通信过程要交给驱动完成了;这个函数最后通过ioctl系统调用,Client
进程陷入内核态,Client调用add方法的线程挂起等待返回;驱动完成一系列的操作之后唤醒Server进程,调用了Server进
程本地对象的onTransact函数,将会调用到RemoteService内部类Stub的onTransact,根据code代码,将走case TRANSACTION_fun1分支,
分支中this.fun1()这段代码this是指向MyService中的serviceInfo,this.fun1()也即是调用RemoteServiceImpl中方法fun1(),
也即达到跨进程调用了;
三、bindService(Intent service, ServiceConnection conn, int flags)
Context.java中定义, 在ContextImpl.java中实现
public boolean bindService(Intent service, ServiceConnection conn,int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, Process.myUserHandle());
}
warnIfCallingFromSystemProcess是给出一个警告提示, Calling a method in the system process without a qualified user
bindServiceCommon(Intent service, ServiceConnection conn, int flags, UserHandle user)
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(), flags); // 这个过程会在主线程中进行
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
/* private void validateServiceIntent(Intent service) {
if (service.getComponent() == null && service.getPackage() == null) {
if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
IllegalArgumentException ex = new IllegalArgumentException(
"Service Intent must be explicit: " + service);
throw ex;
} else {
Log.w(TAG, "Implicit intents with startService are not safe: " + service
+ " " + Debug.getCallers(2, 3));
}
}
} //该函数是检查传进来的Intent是否合法,如果在onCreate中不mIntent.setPackage(getPackageName()); 这样设置将会报错:Service Intent must be explicit: */
try {
IBinder token = getActivityToken();
if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess(); // 把服务从应用的进程中移除掉
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
四、图框描述
五、注意事项
- 在同进程中调用AIDL接口,AIDL接口代码的执行将在调用该AIDL接口的线程中完成,如果在主UI线程中调用AIDL接口,那么AIDL接口代码的执行将会在这个主UI线程中完成。如果是其他线程,AIDL接口代码的执行将在service中完成。因此,如果仅仅是本进程中的线程访问该服务,你完全可以控制哪些线程将访问这个服务(但是如果是这样,那就完全没必要使用AIDL了,而采取Binder接口的方式更为合适)。
- 远程进程(其他线程)调用AIDL接口时,将会在AIDL所属的进程的线程池中分派一个线程来执行该AIDL代码,所以编写AIDL时,你必须准备好可能有未知线程访问、同一时间可能有多个调用发生(多个线程的访问),所以ADIL接口的实现必须是线程安全的。
- 可以用关键字oneway来标明远程调用的行为属性,如果使用了该关键字,那么远程调用将仅仅是调用所需的数据传输过来并立即返回,而不会等待结果的返回,也即是说不会阻塞远程线程的运行。AIDL接口将最终将获得一个从Binder线程池中产生的调用(和普通的远程调用类似)。如果关键字oneway在本地调用中被使用,将不会对函数调用有任何影响。
- 方法可以有0个或多个参数,可以使空返回值也可以返回所需的数据。
- 所有非原始数据类型的参数必须指定参数方向(是传入参数,还是传出参数),传入参数使用in关键字标记,传出参数使用out,传入传出参数使用inout。如果没有显示的指定,那么将缺省使用in。
- 在aidl文件中所有的注释都将会包含在生成的IBinder接口中(在Import和pacakge语句之上的注释除外)。
- aidl中只支持成员方法,不支持成员变量。
- java语言的原始数据类型(包括 int, long, char, boolen 等等)
- String
- CharSequence:该类是被TextView和其他控件对象使用的字符序列
- List:列表中的所有元素必须是在此列出的类型,包括其他AIDL生成的接口和可打包类型。List可以像一般的类(例如List<String>)那样使用,另一边接收的具体类一般是一个ArrayList,这些方法会使用List接口
- Map:Map中的所有元素必须是在此列出的类型,包括其他AIDL生成的接口和可打包类型。一般的maps(例如Map<String,Integer>)不被支持,另一边接收的具体类一般是一个HashMap,这些方法会使用Map接口。
- 对于其他的类型,在aidl中必须使用import导入,即使该类型和aidl处于同一包内。
- Binder是Android系统添加到Linux内核中的一个模块:Binder驱动,Linux原有内核中没有Binder, 有Socket、System V( 消息队列/共享内存/信号量)及管道;
- serviceManagerNative.java最终实现是在:service_manager.c, 该服务是一开机就启动的, 是在init.rc中所设置; service_manager.c中的main函数是死循环(函数:binder_loop),binder进程监听(BINDER_WRITE_READ)是否有客户端申请访问server, 如有请求就调用回调函数svcmgr_handler;所有service是以链表的形式存储(service_manager.c 中svclist);SystemServer.java中startOtherServices()的ServiceManager.addService(String name, IBinder service), 将服务添加进serviceManager的链表中即相当于启动了服务, 当客户端想调用该服务, binder将会checkService, 如果有则可以RPC调用该service的方法;
阅读全文
0 0
- Binder与AIDL服务
- Binder与AIDL服务
- AIDL 与 Binder机制
- android Binder与AIDL
- AIDL 与Binder
- binder与aidl机制区别
- AIDL与Binder的区别
- Binder AIDL
- Binder&AIDL
- AIDL与Binder详解_顾梁
- AIDL与Binder下篇_顾梁
- AIDL与Binder与Messenger的使用区别!
- IPC、Binder、AIDL与Intent之间区别与联系
- android aidl服务与Binder invocat…
- Android-AIDL,service,Binder,Bundles,Messenger,transact()与onTransact()函数
- Android 中的Binder跨进程通信机制与AIDL
- partial BINDER(AIDL)
- AIDL的Binder框架
- Angular 属性型指令 directive
- 使用半透明div覆盖图片的方法
- 1. Tornado的简介
- 2.jupyter的常用操作(上)
- 贝塞尔曲线
- AIDL 与Binder
- 出口商贸易融资工具:贸易项下风险参与
- Android高仿今日头条/QQ空间手势下拉关闭图片效果
- 冒泡排序、选择排序、插入排序
- cloudera目录功能
- JavaScript 实例:计算器
- 轻松实现windows和linux间的文件互传,简单粗暴!
- InterlliJ Debug方式启动:method breakpoints may dramatically show down debugging
- WPF自定义控件与样式增加备注版(1)-矢量字体图标(iconfont)