在ActivityThread中发现了一个ApplicationThread对象,这个对象是AMS回调app进程的binder服务端;在android的源码中IApplicationThread.aidl是一个aidl接口,android O源码编译,在out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/core/java/android/app/目前下面找到了IApplicationThread.java和IActivityManager.java文件, IApplicationThread.aidl文件会生成一个IApplicationThread.java文件,实际上在这个文件中主要是
public interface IApplicationThread extends android.os.IInterface {
aidl的函数声明列表
public static abstract class Stub extends android.os.Binder implements *.IApplicationThread {
asInterface静态函数,返回proxy实例对象
asBinder public函数,返回当前stub
onTransact public函数,接收数据,调用stub的子类实现的aidl的函数
private static class Proxy implements *.IApplicationThread {
asBinder public函数,返回Ibinder实例
aidl的函数实现,在这些函数里面使用ibinder对象transact发送数据给servie端
}
}
}
我靠是一个interface,并不是class;而且interface2个内部类,stub和proxy,stub是服务端的工作部分,proxy是client使用的代理。
由IActivityManager.attachApplication(mAppThread);说起,
1.IActivityManager是ams的client,在调用attachApplication方法时,会将传入的参数IApplicationThread类型,使用asBinder函数将IApplicationThread转换为stub的接口类型Ibinder,使用binder发送到AMS端,在AMS收到Ibinder对象后,使用asInterface静态函数获取IApplicationThread的client代理对象,那么AMS就获取了ApplicationThread的client端对象,使用这个对象回调到ApplicationThread进程,
实现跨进程通信。这里可以理解为在ApplicationThread端拿到AMS的client代理访问AMS,AMS拿到ApplicationThread的clinet代理访问ApplicationThread。
因此要在app层使用binder通讯,考虑activity和service binder流程注意事项:
1. 毫无疑问需要test.aidl文件
2. 为了实际意义上的跨进程通讯,需要给service指定process属性,确保service和activity不再一个进程
3.在service端,需要将service和aidl文件关联起来,为了使得二者取得联系需要继承abstract test.stub 类,并创建一个实例,在onBiner方法中返回这个实例
4.在client端,使用bindservice启动servie,在callback里面使用返回的IBinder对象作为参数,调用stub的静态方法asInterface,获取服务端在client的代理,使用这个代理直接调用aidl的方法,就可以实现跨进程调用。
基于http://blog.csdn.net/jelly_fang/article/details/50488915这个blog看了下细节
研究下bindservice究竟在做什么? bindservice的过程分析(多进程模型下):
1.bindservice在启动进程中创建一个IServiceConnection(作为ams回调的service端)
2.binder通信将IServiceConnection发送到ams bindservice,
3.ams socket通信,Zygote启动art虚拟机进程
4.art进程binder 到ams启动app层对应的service代码(这里art进程和ams进程来回binder交互)
5.在art进程调用service的onbind方法,获取serviec 代码中实现的IBinder对象,通过binder发送给AMS
6.AMS找到IServiceConnection对象,binder到初始的启动进程中,一路回调到onServiceConnected方法,
7.启动进程的通过onServiceConnected获取到IBinder对象,使用service对应的Stub.asInterface(binder)方法获取service的proxy对象,使用proxy对象实现了跨进程通信为什么拿着IBinder不可以直接调用service的函数(需要解读binder模块的数据发送实现,才可以具体解释):
不过根据虚拟机内存区域的构成可以分析:因为类对象的方法一般保存在方法区,类对象中保存的一般都只是方法对应的地址,方法调用就是直接跳转到对应方法的地址执行;而经过binder通许后,进程切换了,继续使用前一个进程的地址来执行方法必然是非法的,因为不同进程是运行在不同的地址空间中的。保存的数据信息是可以拷贝,正常读取,但是如果是一些地址信息跨进程拷贝了实际上也是没有意义的。
client:_data.writeStrongBinder((((caller!=null))?(caller.asBinder()):(null)));
service:_arg0 = android.app.IApplicationThread.Stub.asInterface(data.readStrongBinder());
client端的数据经过binder发送后,发送对象是IBinder使用的writeStrongBinder方法,发送过去的东西到了service端即使依然是一个Ibinder对象,但是代表的含义应该有了改变,并不是原来的对象,使用这个对象去访问service的方法,必然是非法的。。
PS:发现一个可以跨进程发送消息的类Messenger
https://www.cnblogs.com/lzjsky/p/4938256.html这个链接包含例子。