Hermes跨进程通讯——源码解析
Posted 夜辉疾风
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hermes跨进程通讯——源码解析相关的知识,希望对你有一定的参考价值。
源码分析
核心类
//typecenter对象专门用于缓存
private static final TypeCenter TYPE_CENTER = TypeCenter.getInstance();
//Channel对象用于绑定和解绑跨进程的service
private static final Channel CHANNEL = Channel.getInstance();
//发送各种实体对象的基类
com.library.hermes.sender.Sender
//动态代理实现类,通过反射调用方法
com.library.hermes.internal.HermesInvocationHandler
//返回的结果对象
com.library.hermes.internal.Reply
//发送的结果对象
com.library.hermes.internal.Mail
//各种包装类
com.library.hermes.wrapper
init(Context);
//初始化获得当前app的application对象
public void init(Context context)
if (sContext != null)
return;
sContext = context.getApplicationContext();
register();
当前方法在主进程中注册
/**
* 如果方法的返回类型与方法的接口返回类型一致,则不不需要在本地进程中注册类!
* 但是,如果方法的返回类型与方法的返回类型不完全相同,则应该注册该方法。
*
* @param clazz
*/
public static void register(Class<?> clazz)
//检查是否有context对象,没有则抛出异常
checkInit();
//注册该class,跟踪到TypeCenter.register(Class)方法
//该方法主要是缓存当前的class和class下的method
TYPE_CENTER.register(clazz);
//检查是否传递进来了context对象
private static void checkInit()
if (sContext == null)
throw new IllegalStateException("Hermes has not been initialized.");
onnectApp();
当前方法在子进程中调用,用于绑定一个跨进程服务
/**
* 其他进程需要调用该方法进行连接操作
*
* @param context 当前进程的context
* @param packageName 主进程的包名
* @param service 主进程中注册的service,这个service继承HermesService,需要在清单文件中注册
**/
public static void connectApp(Context context, String packageName, Class<? extends HermesService> service)
//如果两个进程在同一个app中看,则这里不会再初始化;
//如果两个进程再不同的app中,则这里的connectApp()方法依然会去调用init(context)方法
init(context);
//进行绑定操作,进入绑定操作,看Channel->bind
CHANNEL.bind(context.getApplicationContext(), packageName, service);
Channel.bind(Context,String,CLass<? extends HermesService>)
/**
* 子进程中去绑定
*
* @param context 当前进程的context对象
* @param packageName 主进程的包名,如果是同一个进程,则不需要传递。如果是不同的app则需要传递
* @param service 注册的service
*/
public void bind(Context context, String packageName, Class<? extends HermesService> service)
//跨进程连接对象,实现了ServiceConnection接口
HermesServiceConnection connection;
//同步锁
synchronized (this)
//获得绑定状态,判断当前service是否已经绑定
if (getBound(service))
//如果已经绑定了则不需要重复操作
return;
//判断当前service是否在绑定中状态
Boolean binding = mBindings.get(service);
if (binding != null && binding)
//如果已经在绑定中了,则也不需要重复操作
return;
//没有缓存到绑定中,则需要进行缓存,这里表示该service正在进行绑定
mBindings.put(service, true);
//new一个跨进程连接对象
connection = new HermesServiceConnection(service);
//将连接对象添加缓存
mHermesServiceConnections.put(service, connection);
//绑定服务,不同app,需要指定包名
Intent intent;
if (TextUtils.isEmpty(packageName))
intent = new Intent(context, service);
else
intent = new Intent();
intent.setClassName(packageName, service.getName());
//这里的绑定操作和aidl的绑定操作一致
context.bindService(intent, connection, Context.BIND_AUTO_CREATE);
HermesServiceConnection
/**
* hermesservice的连接服务,跨进程的连接和断开状态
*/
private class HermesServiceConnection implements ServiceConnection
//当前class作为缓存的标识
private Class<? extends HermesService> mClass;
//传递进来继承hermerservice的class
HermesServiceConnection(Class<? extends HermesService> service)
mClass = service;
/**
* 已经连接
*
* @param className 组件名称
* @param service 服务Binder
*/
@Override
public void onServiceConnected(ComponentName className, IBinder service)
//同步锁
synchronized (Channel.this)
//连接成功,则绑定状态缓存为true,表示已经绑定上了
mBounds.put(mClass, true);
//绑定中状态改成false,表示结束了绑定中状态
mBindings.put(mClass, false);
//这里得到IHermesService对象
//该对象和aidl自动生成的一致
IHermesService hermesService = IHermesService.Stub.asInterface(service);
//缓存起来
mHermesServices.put(mClass, hermesService);
//……
//已经连接给予回调
if (mListener != null)
mListener.onHermesConnected(mClass);
/**
* 已经断开
*
* @param className
*/
@Override
public void onServiceDisconnected(ComponentName className)
synchronized (Channel.this)
//清除缓存
mHermesServices.remove(mClass);
//绑定状态biancheng false
mBounds.put(mClass, false);
//绑定中状态变成false
mBindings.put(mClass, false);
if (mListener != null)
mListener.onHermesDisconnected(mClass);
setHermesListener();
添加连接监听,跨进程通讯连接成功或者失败都会回调
//Hermes:
public static void setHermesListener(HermesListener listener)
CHANNEL.setHermesListener(listener);
//Channel:
public void setHermesListener(HermesListener listener)
mListener = listener;
isConnected();
判断当前service是否连接
//Hermes:
public static boolean isConnected(Class<? extends HermesService> service)
return CHANNEL.isConnected(service);
//Channel:
public boolean isConnected(Class<? extends HermesService> service)
//从缓存中拿到当前service对应的IHermesService
IHermesService hermesService = mHermesServices.get(service);
//获得当前service的iBinder对象,获得pingBinder()的状态
return hermesService != null && hermesService.asBinder().pingBinder();
newInstance();
new一个实例对象
/**
* new一个对象的实例
*
* @param service 注册的service
* @param clazz 对象对应的接口
* @param parameters 构造方法的参数
* @param <T> 返回结果的泛型
* @return
*/
public static <T> T newInstanceInService(Class<? extends HermesService> service, Class<T> clazz, Object... parameters)
//检查service是否符合要求
//这里的判断很简单:1,不为null;2,必须是接口
TypeUtils.validateServiceInterface(clazz);
//检查当前service是否在缓存中已绑定
checkBound(service);
//以下是获得对象的关键代码,一些冗余代码直接省略
//将当前class包装成ObjectWrapper对象,new一个objectWrapper对象
ObjectWrapper object = new ObjectWrapper(clazz, ObjectWrapper.TYPE_OBJECT_TO_NEW);
//获得sender对象,这一步很关键
Sender sender = SenderDesignator.getPostOffice(service, SenderDesignator.TYPE_NEW_INSTANCE, object);
try
//发送new这个对象需要的参数并且返回一个Reply对象
Reply reply = sender.send(null, parameters);
if (reply != null && !reply.success())
Log.e(TAG, "Error occurs during creating instance. Error code: " + reply.getErrorCode());
Log.e(TAG, "Error message: " + reply.getMessage());
return null;
catch (HermesException e)
e.printStackTrace();
return null;
object.setType(ObjectWrapper.TYPE_OBJECT);
//返回一个通过代理反射到的对象
return getProxy(service, object);
ObjectWrapper
/**
* 构造方法
* @param clazz 对象对应的接口的class
* @param type 实例化方式,new,get
*/
public ObjectWrapper(Class<?> clazz, int type)
//不存在classid注解则为true
//获得当前clazz的名字
setName(!clazz.isAnnotationPresent(ClassId.class), TypeUtils.getClassId(clazz));
mClass = clazz;
mTimeStamp = TimeStampGenerator.getTimeStamp();
mType = type;
SenderDesignator.getPostOffice()
/**post
* @param service 跨进程的service
* @param type 实例化方式
* @param object 将接口class包装过的ObjectWrapper对象
* @return
*/
public static Sender getPostOffice(Class<? extends HermesService> service, int type, ObjectWrapper object)
//这里主要分析前两种,new和get
//因为当前方法是new,所以看InstanceCreatingSender()方法
switch (type)
case TYPE_NEW_INSTANCE:
return new InstanceCreatingSender(service, object);
case TYPE_GET_INSTANCE:
return new InstanceGettingSender(service, object);
case TYPE_GET_UTILITY_CLASS:
return new UtilityGettingSender(service, object);
case TYPE_INVOKE_METHOD:
return new ObjectSender(service, object);
default:
throw new IllegalArgumentException("Type " + type + " is not supported.");
InstanceCreatingSender(service, object)
/**
* new一个对象的发送方,这里是一个动态代理
*/
public class InstanceCreatingSender extends Sender
private Class<?>[] mConstructorParameterTypes;
public InstanceCreatingSender(Class<? extends HermesService> service, ObjectWrapper object)
super(service, object);
@Override
protected MethodWrapper getMethodWrapper(Method method, ParameterWrapper[] parameterWrappers)
//获取参数的长度
int length = parameterWrappers == null ? 0 : parameterWrappers.length;
//new一个用于存放参数的集合
mConstructorParameterTypes = new Class<?>[length];
//循环遍历出当前参数的所有class
for (int i = 0; i < length; ++i)
try
ParameterWrapper parameterWrapper = parameterWrappers[i];
mConstructorParameterTypes[i] = parameterWrapper == null ? null : parameterWrapper.getClassType();
catch (Exception e)
//new一个MethodWrapper
//返回一个methodWrapper对象
return new MethodWrapper(mConstructorParameterTypes);
Sender.send(method, parameters);
//发送并返回特定对象
public synchronized final Reply send(Method method, Object[] parameters) throws HermesException
//时间戳
mTimeStamp = TimeStampGenerator.getTimeStamp();
if (parameters == null)
parameters = new Object[0];
//获得当前方法,以及该方法的所有参数集合
ParameterWrapper[] parameterWrappers = getParameterWrappers(method, parameters);
//获得MethodWrapper对象
MethodWrapper methodWrapper = getMethodWrapper(method, parameterWrappers);
//注册该方法
registerClass(method);
//添加方法参数
setParameterWrappers(parameterWrappers);
//new一个mail对象,传递进来时间戳,ObjectWrapper,methodWrapper以及参数集合
Mail mail = new Mail(mTimeStamp, mObject, methodWrapper, mParameters);
mMethod = methodWrapper;
//发送,通过注册的Hermesservice发送mail对象
return CHANNEL.send(mService, mail);
Channel.send()
public Reply send(Class<? extends HermesService> service, Mail mail)
//从缓存中拿到跨进程对象Ihermesservice
IHermesService hermesService = mHermesServices.get(service);
try
if (hermesService == null)
return new Reply(ErrorCodes.SERVICE_UNAVAILABLE,
"Service Unavailable: Check whether you have connected Hermes.");
//发送mail对象,返回一个reply对象
//这里类似aidl的接口定义返回值
return hermesService.send(mail);
catch (RemoteException e)
return new Reply(ErrorCodes.REMOTE_EXCEPTION, "Remote Exception: Check whether "
+ "the process you are communicating with is still alive.");
Hermes.getProxy()
//使用java的动态代理获得对象
private static <T> T getProxy(Class<? extends HermesService> service, ObjectWrapper object)
//这里就是一个典型的java动态代理
Class<?> clazz = object.getObjectClass();
T proxy = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[]clazz,
new HermesInvocationHandler(service, object));
//在回收器中注册,以便于回收,这里不分析gc过程
HERMES_GC.register(service, proxy, object.getTimeStamp());
return proxy;
HermesInvocationHandler
public class HermesInvocationHandler implements InvocationHandler
private static final String TAG = "HERMES_INVOCATION";
private Sender mSender;
public HermesInvocationHandler(Class<? extends HermesService> service, ObjectWrapper object)
//通过 SenderDesignator.TYPE_INVOKE_METHOD类型获得ObjectSender对象
mSender = SenderDesignator.getPostOffice(service, SenderDesignator.TYPE_INVOKE_METHOD, object);
@Override
public Object invoke(Object proxy, Method method, Object[] objects)
try
//这里得到reply对象
Reply reply = mSender.send(method, objects);
if (reply == null)
return null;
if (reply.success())
//这里是序列化操作
return reply.getResult();
else
Log.e(TAG, "Error occurs. Error " + reply.getErrorCode() + ": " + reply.getMessage());
return null;
catch (HermesException e)
e.printStackTrace();
Log.e(TAG, "Error occurs. Error " + e.getErrorCode() + ": " + e.getErrorMessage());
return null;
disconnect()
public static void disconnect(Context context, Class<? extends HermesService> service)
CHANNEL.unbind(context.getApplicationContext(), service);
//取消绑定
public void unbind(Context context, Class<? extends HermesService> service)
synchronized (this)
//从缓存中拿到connection对象
Boolean bound = mBounds.get(service);
if (bound != null && bound)
HermesServiceConnection connection = mHermesServiceConnections.get(service);
if (connection != null)
//取消绑定
context.unbindService(connection);
mBounds.put(ser以上是关于Hermes跨进程通讯——源码解析的主要内容,如果未能解决你的问题,请参考以下文章