这里以gityuan的代码作为示例
public class ClientDemo {
public static void main(String[] args) throws RemoteException {
System.out.println(“Client start”);
IBinder binder = ServiceManager.getService(“MyService”); //获取名为"MyService"的服务
IMyService myService = new MyServiceProxy(binder); //创建MyServiceProxy对象
myService.sayHello(“binder”); //通过MyServiceProxy对象调用接口的方法
System.out.println(“Client end”);
}
}
public class ServerDemo {
public static void main(String[] args) {
System.out.println(“MyService Start”);
Looper.prepareMainLooper(); //开启循环执行
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_FOREGROUND); //设置为前台优先级
ServiceManager.addService(“MyService”, new MyService());//注册服务
Looper.loop();
}
}
获取ServiceManager
在ServerDemo
中可以看到在获取服务之前,先要想ServiceManager添加服务ServiceManager.addService()
,既然有添加,那必定有一个地方去存储它,存储的地方就是ServiceManager,那么要怎么获取到ServiceManager呢?先从ServiceManager.addService()
开始,在开始之前先来看一下获取ServiceManager的UML图
类图
有几个特殊的类要解释一下
- BinderProxy,native binder的存储类,里面存储的是native binder的指针,并且不是由Java类初始化,是在JNI代码中加载和创建
- IServiceManager.Stub,这个是个抽象类,没有实现类,在平常使用Binder的时候一般都是继承它作为Binder实体类,但是IServiceManager是工作在native中的服务,所以Stub类不会被继承,这种方式也常见于获取C++ Binder服务的时候
ServiceManager.addService()
最终调用到addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)
,它里面的代码就一行
getIServiceManager().addService(name, service, allowIsolated, dumpPriority)
看到正主getIServiceManager()
了
ServiceManager.getIServiceManager()
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
这里使用的是单例模式,没有加线程保护,因为这个接口并不给应用使用,以及应用也不能直接操作addService()``getService()
等接口,所以getIServiceManager()
可以是认为运行在主线程中,没错,我们与ServiceManager的通信也是采用Binder,只是ServiceManager的Binder是有点特殊,我们先看ServiceManagerNative.asInterface()
这个方法
ServiceManagerNative.asInterface()
public static IServiceManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
// ServiceManager is never local
return new ServiceManagerProxy(obj);
}
直接创建了一个ServiceManagerProxy
对象
ServiceManagerProxy初始化
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
mServiceManager = IServiceManager.Stub.asInterface(remote);
}
mRemote = remote;
这个是老的方式,gityuan的Binder系列7-framework层分析,就是使用这种方式mServiceManager = IServiceManager.Stub.asInterface(remote);
是通过AIDL方式进行通信,显得更加简洁一点
这里说明一点AIDL并不等于Binder通信,它只是让Binder通信变得更加简单,就如同Retrofit和okhttp的关系,AIDL生成的java代码在out目录下,所以想要分析的话得要先编译过Android源码才行,具体的路径是out/soong/.intermediates/frameworks/base/framework-minus-apex/android_common/javac/shard30/classes/android/os/IServiceManager.class
使用AndroidStudio,IDEA或者反编译工具可以打开查看,如果想直接看的话我把它拷贝了一份IServiceManager.java
IServiceManager.Stub.asInterface()
public static IServiceManager asInterface(IBinder obj) {
if (obj == null) {
return null;
} else {
IInterface iin = obj.queryLocalInterface(“android.os.IServiceManager”);
return (IServiceManager)(iin != null && iin instanceof IServiceManager ? (IServiceManager)iin : new IServiceManager.Stub.Proxy(obj));
}
}
逻辑很简单
- 如果是相同进程,直接返回Binder对象,由于ServiceManager是单独处于一个进程,这里不会是相同进程,至于本地Service是怎么连接到的,我们稍后再讨论
- 如果不是相同进程,则创建
IServiceManager.Stub.Proxy
IServiceManager.Stub.Proxy初始化
Proxy(IBinder remote) {
this.mRemote = remote;
}
这个和ServiceManagerProxy老的初始化方式是不是一模一样,再来看看IServiceManager.Stub.Proxy.addService()
public void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(“android.os.IServiceManager”);
_data.writeString(name);
_data.writeStrongBinder(service);
_data.writeInt(allowIsolated ? 1 : 0);
_data.writeInt(dumpPriority);
boolean _status = this.mRemote.transact(3, _data, _reply, 0);
if (!_status && IServiceManager.Stub.getDefaultImpl() != null) {
IServiceManager.Stub.getDefaultImpl().addService(name, service, allowIsolated, dumpPriority);
return;
}
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
和老方式也基本一样,所以新方式只是自动生成了这部分代码,减少了代码量,让IPC看起来就是一个方法调用,但最终都是调用IBinder.transact()
方法进行IPC,接下来回到ServiceManager.getIServiceManager()
方法中,上面的只能算作是一些代码技巧而已,接下来就是Binder的核心,获取ServiceManager的IBinder
对象。
BinderInternal.getContextObject()
这是一个native方法,对应到android_util_Binder.cpp
的android_os_BinderInternal_getContextObject()
android_os_BinderInternal_getContextObject()
这里做了两件事情:
- 通过调用
ProcessState.getContextObject(NULL)
获取sp,注意这里传递的参数NULL,即要获取的是IServiceManager的Binder,这一步留作native Binder解析流程中详细阐述 - 调用
javaObjectForIBinder()
将IBinder转为java对象,即BinderProxy对象,转换的过程就是将IBinder的指针(long类型)存储在BinderProxy的mNativeData中
javaObjectForIBinder()
-
检查是不是Binder类型,这一步是判断是不是传入的是
JavaBBinder
类型 -
创建BinderProxyNativeData类型的指针,并初始化对应的字段
-
将其IBinder的智能指针引用放到BinderProxyNativeData.mObject当中
-
通过
CallStaticObjectMethod()
调用BinderProxy.getInstance()
并传递对应的参数,这里又引出了一个问题,**我们都知道调用一个类的静态方法是会触发类的加载,可以看到这里直接传的是gBinderProxyOffsets.mClass
,说明BinderProxy.class对象已经加载完成了,那么这个gBinderProxyOffsets
又是怎么初始化的呢?**答案是在虚拟机启动的时候就加载完成了,具体的调用栈大致如下
//AndroidRuntime.cpp,这部分是将函数指针进行绑定,使用宏的目的是为了方便DEBUG,可以定义不同的结构体,进行不同的初始化操作
#define REG_JNI(name) { name }
struct RegJNIRec {
int (mProc)(JNIEnv);
};
extern int register_android_os_Binder(JNIEnv* env);//申明函数,使用静态链接链入
static const RegJNIRec gRegJNI[] = {
…
REG_JNI(register_android_os_Binder),//宏展开就是结构体的初始化操作{register_android_os_Binder}
…
};
//AndroidRuntime.cpp,这部分在进程启动时调用
AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
int AndroidRuntime::startReg(JNIEnv* env)
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
//android_util_Binder.cpp
int register_android_os_Binder(JNIEnv* env)
static int int_register_android_os_BinderInternal(JNIEnv* env)
- 下面的代码没有看懂,但是关系不是很大
如此一来返回的就是BinderProxy
的对象实例,它也是实现了IBinder
的接口
BinderProxy.getInstance()
方法签名如下private static BinderProxy getInstance(long nativeData, long iBinder)
,是一个私有的静态方法,返回的是BinderProxy的对象实例,再来对比一下CallStaticObjectMethod(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get())
,应该会觉得很相似。前面两个参数gBinderProxyOffsets.mClass
和gBinderProxyOffsets.mGetInstance
代表的分别是BinderProxy.class对象以及getInstance的方法名字,具体的可以看static int int_register_android_os_BinderProxy(JNIEnv* env)
函数是怎么初始化gBinderProxyOffsets的字段的;后面两个参数就是getInstance的两个参数,将指针转成jlong类型传入到BinderProxy.getInstance()
当中。接下来看一下getInstance中的逻辑
- 看看有没有缓存的BinderProxy对象,有则直接返回,这里可以缓存BinderProxy的原因是BinderProxy<==>Binder是一一对应的,所以对于一个Binder服务来说,只需要要一个BinderProxy即可,所以可以是全局的
- 如果没有,则创建一个BinderProxy实例,并存入到缓存中
- 之后的BinderProxy的初始化只做了一件事,将传递过来的
BinderProxyNativeData
的指针对应的jlong,存入到mNativeData中,实现了BinderProxy和native binder的关联
以上就是获取IServiceManager整个过程,需要记住一点就是IServiceManager的所有接口,最终都是调用BinderProxy.transact()
方法中
ServiceManager.addService()
回到最开始添加服务的位置,方法签名如下
public static void addService(String name, IBinder service, boolean allowIsolated,int dumpPriority){
try {
getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
} catch (RemoteException e) {
Log.e(TAG, “error in addService”, e);
}
}
在获取到IserviceManager
之后的addService()
则会调用到AIDL生成的方法当中
IServiceManager.Proxy.addService()
这个方法的代码在上面有贴出,逻辑如下
- 获取Parcel对象,分为两种,传递数据的data和获取回复的reply
- 写入两个String对象,分别是token和服务名称
- 写入Binder对象,这里我们在下面进行讨论
- 调用
IBinder.transact()
方法,之前获取IServiceManager的时候就说过返回的是BinderProxy
的对象实例,所以看BinderProxy.transact()
方法
BinderProxy.transact()
- 判断是不是异步的Binder,这里有个变量
mWarnOnBlocking
,还记得之前在调用BinderInternal.getContextObject()
之后还做了一个操作Binder.allowBlocking(BinderInternal.getContextObject())
,这里会将mWarnOnBloking
置为false,所以这块逻辑一般都是走不到 - 是否添加Trace,主要是性能跟踪
- 接下来的一堆操作不是很理解是要干嘛的,最后是调用到
transactNative()
,这是个native方法,方法签名如下transactNative(int code, Parcel data, Parcel reply, int flags)
,对应android_util_Binder.cpp
的android_os_BinderProxy_transact()
android_os_BinderProxy_transact()
- 判断dataObj是否为NULL,所以即使不传任何数据,也要在调用
transact()
之前调用Parcel.obtain()
获取Parcel对象 - 将java端的Parcel对象转为native的Parcel,包括data和reply,转换的方式其实和BinderProxy很类似,之后我们再来讨论
- 之后调用
getBPNativeData()
将BinderProxy.mNativeData
转为指向BinderProxyNativeData
的指针,从而获取到sp - 之后调用native 的Binder的
transact()
方法进行,这部分留到native 的解析的时候再说
IServiceManager.getService()
其实是一样的逻辑,都是通过BinderProxy.tansact()
进行传递到 JNI再到native binder,包括开头的Demo中客户端调用sayHello()
向服务进行通信,是不是和addService()
很像,其中的逻辑是一模一样的。getService()
和addService()
唯一区别是对于reply的处理,getService()
需要获取native传回来的IBinder,我们接下来讨论Parcel的时候看一下
Parcel和Parceable
为什么要Parcelable
这里涉及到对象的深拷贝和浅拷贝,由于java对象都是通过引用来使用的,引用说白了还是指针。问题就在于此,浅拷贝只是将对象中的数据一字节一字节的拷贝,如果对象含有另一对象的引用,就会造成拷贝出来的对象指向同一个对象,这还只是其一,对于远程调用来说,如果只是浅拷贝,拷贝过来的对象中的引用根本就是null(进程的内存隔离)。
解决的方法就是深拷贝,所谓深拷贝就是将对象中引用不断的进行“解析”,怎么“解析”呢?不要忘记了Java中的8个基本类型,所有的java对象都是由这8个基本类型组成,“解析”之后就变成一个个有序的字节序列,说它有序是因为“解析”的过程要按照一定的顺序,不然就不能“反解析”了,“反解析“的过程就是将有序的字节序列变成对象的过程,这个“解析”的过程就是序列化,“反解析”的过程就是反序列化
Java中的序列话需要实现Serializeable以及设置一个serialVersionUID,不过由于Serializeable会产生大量的临时对象,所以Android序列化使用的都是Parceable
Spring全套教学资料
Spring是Java程序员的《葵花宝典》,其中提供的各种大招,能简化我们的开发,大大提升开发效率!目前99%的公司使用了Spring,大家可以去各大招聘网站看一下,Spring算是必备技能,所以一定要掌握。
目录:
部分内容:
Spring源码
- 第一部分 Spring 概述
- 第二部分 核心思想
- 第三部分 手写实现 IoC 和 AOP(自定义Spring框架)
- 第四部分 Spring IOC 高级应用
基础特性
高级特性 - 第五部分 Spring IOC源码深度剖析
设计优雅
设计模式
注意:原则、方法和技巧 - 第六部分 Spring AOP 应用
声明事务控制 - 第七部分 Spring AOP源码深度剖析
必要的笔记、必要的图、通俗易懂的语言化解知识难点
脚手框架:SpringBoot技术
它的目标是简化Spring应用和服务的创建、开发与部署,简化了配置文件,使用嵌入式web服务器,含有诸多开箱即用的微服务功能,可以和spring cloud联合部署。
Spring Boot的核心思想是约定大于配置,应用只需要很少的配置即可,简化了应用开发模式。
- SpringBoot入门
- 配置文件
- 日志
- Web开发
- Docker
- SpringBoot与数据访问
- 启动配置原理
- 自定义starter
微服务架构:Spring Cloud Alibaba
同 Spring Cloud 一样,Spring Cloud Alibaba 也是一套微服务解决方案,包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
- 微服务架构介绍
- Spring Cloud Alibaba介绍
- 微服务环境搭建
- 服务治理
- 服务容错
- 服务网关
- 链路追踪
- ZipKin集成及数据持久化
- 消息驱动
- 短信服务
- Nacos Confifig—服务配置
- Seata—分布式事务
- Dubbo—rpc通信
Spring MVC
目录:
部分内容:
相关阅读docs.qq.com/doc/DSmxTbFJ1cmN1R2dB
)]
[外链图片转存中…(img-yEzP5Kn1-1724604387676)]
Spring MVC
目录:
[外链图片转存中…(img-u8QYe0Gv-1724604387677)]
[外链图片转存中…(img-qREK2dKC-1724604387677)]
[外链图片转存中…(img-PqV0Yz5X-1724604387678)]
部分内容:
[外链图片转存中…(img-Y7bk7Xtc-1724604387678)]
[外链图片转存中…(img-EXUPV1wH-1724604387678)]
相关阅读docs.qq.com/doc/DSmxTbFJ1cmN1R2dB