最近项目中引入一个组件化的框架CC,框架很新。我们抱着学习的态度欣赏这个框架的源码。
这只是一部分供我们使用的代码,他有部分源码是操纵字节码,将用户静态的组件,初始化加入自己的static静态代码段。
我们先从简单的开始分析,这个一个缓存的对象池。用到ConcurrentLinkedQueue并发队列做他的底层容器。两个接口Resetable,Initable分别对应,放入池中被reset和用所给的参数从池中取出一个初始化。get方法中,如果池中有就直接取出,否则在用户实现的newInstance方法中创建一个。
public abstract class ObjPool<T, R> {
protected ConcurrentLinkedQueue<T> list;
/**
* 创建一个对象池,不限制缓存数量
*/
public ObjPool() {
list = new ConcurrentLinkedQueue<>();
}
/**
* 从对象池中获取一个实例
* 优先从缓存中获取,如果缓存中没有实例,则创建一个实例并返回
* @param r 创建一个新实例需要的参数
* @return 获取的实例
*/
public T get(R r) {
T t = list.poll();
if (t == null) {
t = newInstance(r);
}
if (t != null && t instanceof Initable) {
((Initable<R>) t).init(r);
}
return t;
}
/**
* 接收一个实例放到对象池中
* @param t 要放入对象池的实例
*/
public void put(T t) {
if (t != null) {
if (t instanceof Resetable) {
((Resetable) t).reset();
}
list.offer(t);
}
}
/**
* 清空对象池
* 推荐在确定不再需要此对象池的时候调用此方法来清空缓存的实例
*/
public void clear() {
list.clear();
}
/**
* 创建新的实例
* @param r 创建对象所需的参数
* @return 新的实例
*/
protected abstract T newInstance(R r);
public interface Resetable {
void reset();
}
public interface Initable<R> {
void init(R r);
}
}
在项目中看到是aidl生成的java 文件,特地把源文件找出来,作者介绍是利用contentprovider做跨进程通信。一般都是把aidl文件放在client service两个项目中,通过bindService,获取binder对象,client用 xxx.Stub.Proxy对应的方法跨进程通信。这个项目唯一的区别可能是他这个binder是通过contentProvider(其实也是binder通信)跨进程传递,传递过来的仍然是原binder对象,这个是内部的Parcelable实现决定的。下次要分析下框架层这块的机理。
package com.billy.cc.core.component.remote;
// Declare any non-default types here with import statements
import com.billy.cc.core.component.remote.RemoteCCResult;
interface IRemoteCallback {
void callback(in RemoteCCResult remoteCCResult);
}
// com.billy.core.component.IProcessCrossCCService.aidl
package com.billy.cc.core.component.remote;
// Declare any non-default types here with import statements
import com.billy.cc.core.component.remote.RemoteCC;
import com.billy.cc.core.component.remote.RemoteCCResult;
import com.billy.cc.core.component.remote.IRemoteCallback;
interface IRemoteCCService {
void call(in RemoteCC remoteCC, in IRemoteCallback callback);
void cancel(String callId);
void timeout(String callId);
String getComponentProcessName(String componentName);
}
IRemoteCCService 这个是根据上面的aidl文件由系统生成,作者发布的时候格式化了代码,让我们看的比较清晰。IRemoteCCService继承于IInterface这个接口。像aidl文件声明的那样拥有四个业务接口。内部多了一个静态抽象类Stub,和一个内部静态类Stub.Proxy. Stub是相对于服务器端,一般我们都是继承它,实现具体的业务,在client-bindService中以onBind返回。而client拿到它时候在跨进程的情况下,用到Proxy作为自己的代理,借助binder,相当于远程调用Stub的实现类。一个应用可以创建多个进程,所以跨进程间远程调用,并返回结果,这个场景很常见。IRemoteCallback代码与IRemoteCCService没什么太多技术区别,我们就不贴了。下面我们着重分析框架自身功能的实现。即在服务端IRemoteCCService.Stub的具体现实。
public interface IRemoteCCService extends IInterface {
void call(RemoteCC var1, IRemoteCallback var2) throws RemoteException;
void cancel(String var1) throws RemoteException;
void timeout(String var1) throws RemoteException;
String getComponentProcessName(String var1) throws RemoteException;
public abstract static class Stub extends Binder implements IRemoteCCService {
private static final String DESCRIPTOR = "com.billy.cc.core.component.remote.IRemoteCCService";
static final int TRANSACTION_call = 1;
static final int TRANSACTION_cancel = 2;
static final int TRANSACTION_timeout = 3;
static final int TRANSACTION_getComponentProcessName = 4;
public Stub() {
this.attachInterface(this, "com.billy.cc.core.component.remote.IRemoteCCService");
}
public static IRemoteCCService asInterface(IBinder obj) {
if (obj == null) {
return null;
} else {
IInterface iin = obj.queryLocalInterface("com.billy.cc.core.component.remote.IRemoteCCService");
return (IRemoteCCService)(iin != null && iin instanceof IRemoteCCService ? (IRemoteCCService)iin : new IRemoteCCService.Stub.Proxy(obj));
}
}
public IBinder asBinder() {
return this;
}
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
String _arg0;
switch(code) {
case 1:
data.enforceInterface("com.billy.cc.core.component.remote.IRemoteCCService");
RemoteCC _arg0;
if (0 != data.readInt()) {
_arg0 = (RemoteCC)RemoteCC.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
IRemoteCallback _arg1 = com.billy.cc.core.component.remote.IRemoteCallback.Stub.asInterface(data.readStrongBinder());
this.call(_arg0, _arg1);
reply.writeNoException();
return true;
case 2:
data.enforceInterface("com.billy.cc.core.component.remote.IRemoteCCService");
_arg0 = data.readString();
this.cancel(_arg0);
reply.writeNoException();
return true;
case 3:
data.enforceInterface("com.billy.cc.core.component.remote.IRemoteCCService");
_arg0 = data.readString();
this.timeout(_arg0);
reply.writeNoException();
return true;
case 4:
data.enforceInterface("com.billy.cc.core.component.remote.IRemoteCCService");
_arg0 = data.readString();
String _result = this.getComponentProcessName(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
case 1598968902:
reply.writeString("com.billy.cc.core.component.remote.IRemoteCCService");
return true;
default:
return super.onTransact(code, data, reply, flags);
}
}
private static class Proxy implements IRemoteCCService {
private IBinder mRemote;
Proxy(IBinder remote) {
this.mRemote = remote;
}
public IBinder asBinder() {
return this.mRemote;
}
public String getInterfaceDescriptor() {
return "com.billy.cc.core.component.remote.IRemoteCCService";
}
public void call(RemoteCC remoteCC, IRemoteCallback callback) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken("com.billy.cc.core.component.remote.IRemoteCCService");
if (remoteCC != null) {
_data.writeInt(1);
remoteCC.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
_data.writeStrongBinder(callback != null ? callback.asBinder() : null);
this.mRemote.transact(1, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
public void cancel(String callId) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken("com.billy.cc.core.component.remote.IRemoteCCService");
_data.writeString(callId);
this.mRemote.transact(2, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
public void timeout(String callId) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken("com.billy.cc.core.component.remote.IRemoteCCService");
_data.writeString(callId);
this.mRemote.transact(3, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
public String getComponentProcessName(String componentName) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
String _result;
try {
_data.writeInterfaceToken("com.billy.cc.core.component.remote.IRemoteCCService");
_data.writeString(componentName);
this.mRemote.transact(4, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
}
}
RemoteCCService继承于IRemoteCCService.Stub,在别人帮他把通信做好的前提下,它来实现具体请求到了服务端,它要做什么。首先是一个内部静态单例Holder模式的写法。这个比我们常用的double check,多了一个延迟加载的特性。
/**
* 跨进程调用组件的Binder
* @author billy.qi
* @since 18/6/24 11:31
*/
public class RemoteCCService extends IRemoteCCService.Stub {
private Handler mainThreadHandler;
//-------------------------单例模式 start --------------
/** 单例模式Holder */
private static class RemoteCCServiceHolder {
private static final RemoteCCService INSTANCE = new RemoteCCService();
}
private RemoteCCService(){
mainThreadHandler = new Handler(Looper.getMainLooper());
}
/** 获取RemoteCCService的单例对象 */
public static RemoteCCService getInstance() {
return RemoteCCService.RemoteCCServiceHolder.INSTANCE;
}
//-------------------------单例模式 end --------------
@Override
public void call(final RemoteCC remoteCC, final IRemoteCallback callback) throws RemoteException {
if (isInvalidate()) {
return;
}
String componentName = remoteCC.getComponentName();
final String callId = remoteCC.getCallId();
if (CC.VERBOSE_LOG) {
CC.verboseLog(callId, "receive call from other process. RemoteCC: %s", remoteCC.toString());
}
if (!ComponentManager.hasComponent(componentName)) {
CC.verboseLog(callId, "There is no component found for name:%s in process:%s", componentName, CCUtil.getCurProcessName());
doCallback(callback, callId, CCResult.error(CCResult.CODE_ERROR_NO_COMPONENT_FOUND));
return;
}
final CC cc = CC.obtainBuilder(componentName)
.setActionName(remoteCC.getActionName())
.setParams(remoteCC.getParams())
.setCallId(remoteCC.getCallId())
.withoutGlobalInterceptor()
.build();
if (remoteCC.isMainThreadSyncCall()) {
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
CCResult ccResult = cc.call();
doCallback(callback, callId, ccResult);
}
});
} else {
cc.callAsync(new IComponentCallback() {
@Override
public void onResult(CC cc, CCResult result) {
doCallback(callback, callId, result);
}
});
}
}
private boolean isInvalidate() {
//未开启跨app调用时进行跨app调用视为无效调用
return !CC.isRemoteCCEnabled() && getCallingUid() != Process.myUid();
}
private static void doCallback(IRemoteCallback callback, String callId, CCResult ccResult) {
try {
RemoteCCResult remoteCCResult;
try{
remoteCCResult = new RemoteCCResult(ccResult);
if (CC.VERBOSE_LOG) {
CC.verboseLog(callId, "callback to other process. RemoteCCResult: %s", remoteCCResult.toString());
}
}catch(Exception e){
remoteCCResult = new RemoteCCResult(CCResult.error(CCResult.CODE_ERROR_REMOTE_CC_DELIVERY_FAILED));
if (CC.VERBOSE_LOG) {
CC.verboseLog(callId, "remote CC success. But result can not be converted for IPC. RemoteCCResult: %s", remoteCCResult.toString());
}
}
callback.callback(remoteCCResult);
} catch (RemoteException e) {
e.printStackTrace();
CC.verboseLog(callId, "remote doCallback failed!");
}
}
@Override
public void cancel(String callId) throws RemoteException {
if (isInvalidate()) {
return;
}
CC.cancel(callId);
}
@Override
public void timeout(String callId) throws RemoteException {
if (isInvalidate()) {
return;
}
CC.timeout(callId);
}
@Override
public String getComponentProcessName(String componentName) throws RemoteException {
if (isInvalidate()) {
return null;
}
return ComponentManager.getComponentProcessName(componentName);
}
private static final ConcurrentHashMap<String, IRemoteCCService> CACHE = new ConcurrentHashMap<>();
private static final byte[] LOCK = new byte[0];
private static Uri getDispatcherProviderUri(String processName) {
return Uri.parse("content://" + processName + "." + RemoteProvider.URI_SUFFIX + "/cc");
}
static IRemoteCCService get(String processNameTo) {
IRemoteCCService service = CACHE.get(processNameTo);
if (service == null && CC.getApplication() != null) {
synchronized (LOCK) {
service = CACHE.get(processNameTo);
if (service == null) {
service = getService(processNameTo);
if (service != null) {
CACHE.put(processNameTo, service);
}
}
}
}
return service;
}
static void remove(String processName) {
CACHE.remove(processName);
}
private static IRemoteCCService getService(String processNameTo) {
Cursor cursor = null;
try {
cursor = CC.getApplication().getContentResolver()
.query(getDispatcherProviderUri(processNameTo)
, RemoteProvider.PROJECTION_MAIN, null
, null, null
);
if (cursor == null) {
return null;
}
return RemoteCursor.getRemoteCCService(cursor);
} finally {
if (cursor != null) {
try {
cursor.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
CACHE是对进程名与对应的RemoteCCService的缓存。因为RemoteCCService这个获取过程是一个通过ContentProvider跨进程通信,比较好耗费资源,第二次会从CACHE直接获取,也算是个优化。
private static final ConcurrentHashMap<String, IRemoteCCService> CACHE = new ConcurrentHashMap<>();
private static final byte[] LOCK = new byte[0];
private static Uri getDispatcherProviderUri(String processName) {
return Uri.parse("content://" + processName + "." + RemoteProvider.URI_SUFFIX + "/cc");
}
static IRemoteCCService get(String processNameTo) {
IRemoteCCService service = CACHE.get(processNameTo);
if (service == null && CC.getApplication() != null) {
synchronized (LOCK) {
service = CACHE.get(processNameTo);
if (service == null) {
service = getService(processNameTo);
if (service != null) {
CACHE.put(processNameTo, service);
}
}
}
}
return service;
}
static void remove(String processName) {
CACHE.remove(processName);
}
private static IRemoteCCService getService(String processNameTo) {
Cursor cursor = null;
try {
cursor = CC.getApplication().getContentResolver()
.query(getDispatcherProviderUri(processNameTo)
, RemoteProvider.PROJECTION_MAIN, null
, null, null
);
if (cursor == null) {
return null;
}
return RemoteCursor.getRemoteCCService(cursor);
} finally {
if (cursor != null) {
try {
cursor.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
CC.isRemoteCCEnabled是我们项目中设置的。还判断了是否为同一个uid。
private boolean isInvalidate() {
//未开启跨app调用时进行跨app调用视为无效调用
return !CC.isRemoteCCEnabled() && getCallingUid() != Process.myUid();
}
cancel ,timeout使用了CC提供的静态方法。callId一般都是自动追加生成,干什么能没一个凭证id嘛。getComponentProcessName具体实现是在ComponentManager中,稍等分析。
@Override
public void cancel(String callId) throws RemoteException {
if (isInvalidate()) {
return;
}
CC.cancel(callId);
}
@Override
public void timeout(String callId) throws RemoteException {
if (isInvalidate()) {
return;
}
CC.timeout(callId);
}
@Override
public String getComponentProcessName(String componentName) throws RemoteException {
if (isInvalidate()) {
return null;
}
return ComponentManager.getComponentProcessName(componentName);
}
RemoteCC相当于一个业务bean。携带了参数,组件名,动作名(同一个组件的多个方法,),callId(自动生成的自身标识),是否主线程同步调用。以上是可被序列化的。call 方法首先对componentName的存在性进行验证,接着下面CC的写法类似我们用户程序员的写法,下面的if-else根据isMainThreadSyncCall在主线程或者在线程池中被调用。cc.callAsync实现中又委托ComponentManager具体实现提交线程池。CC相当于任务内容的实现,具体的任务执行又交给ComponentManager。
@Override
public void call(final RemoteCC remoteCC, final IRemoteCallback callback) throws RemoteException {
if (isInvalidate()) {
return;
}
String componentName = remoteCC.getComponentName();
final String callId = remoteCC.getCallId();
if (CC.VERBOSE_LOG) {
CC.verboseLog(callId, "receive call from other process. RemoteCC: %s", remoteCC.toString());
}
if (!ComponentManager.hasComponent(componentName)) {
CC.verboseLog(callId, "There is no component found for name:%s in process:%s", componentName, CCUtil.getCurProcessName());
doCallback(callback, callId, CCResult.error(CCResult.CODE_ERROR_NO_COMPONENT_FOUND));
return;
}
final CC cc = CC.obtainBuilder(componentName)
.setActionName(remoteCC.getActionName())
.setParams(remoteCC.getParams())
.setCallId(remoteCC.getCallId())
.withoutGlobalInterceptor()
.build();
if (remoteCC.isMainThreadSyncCall()) {
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
CCResult ccResult = cc.call();
doCallback(callback, callId, ccResult);
}
});
} else {
cc.callAsync(new IComponentCallback() {
@Override
public void onResult(CC cc, CCResult result) {
doCallback(callback, callId, result);
}
});
}
}
public class RemoteCC implements Parcelable {
private Map<String, Object> params;
private String componentName;
private String actionName;
private String callId;
private boolean isMainThreadSyncCall;
private Map<String, Object> localParams;
。。。。。
ComponentManager.call代码。我们具体把自己的业务包装成Component接口的现实。那一定就有疑问。到底在哪里被执行。上面分析了CC这个任务类被踢来踢去,最终到了ComponentManager.call脚下。这个框架的一个核心概念就是链式调用,而我们的任务执行算是最后一环ValidateInterceptor.getInstance()。 之前创建chain,根据cc.isWithoutGlobalInterceptor将全局的拦截链是否加进去。全局拦截和静态组件都一样是通过字节码处理技术,在事先static静态代码段中被初始化的。chain.addInterceptors(cc.getInterceptors())这个是用户在当次任务中设置一些拦截器。 chain.addInterceptor(ValidateInterceptor.getInstance());
顾名思义就是在真正执行前做的验证,通过了,我们定义的组件call当然就被调用了。
/**
* 组件调用统一入口
* @param cc 组件调用指令
* @return 组件调用结果(同步调用的返回值)
*/
static CCResult call(CC cc) {
String callId = cc.getCallId();
Chain chain = new Chain(cc);
if (!cc.isWithoutGlobalInterceptor()) {
chain.addInterceptors(INTERCEPTORS);
}
chain.addInterceptors(cc.getInterceptors());
// 有效性校验放在自定义拦截器之后执行,优先执行自定义拦截器,让其可以拦截到所有组件调用
// 执行实际调用的拦截器在校验有效性结束后再添加
chain.addInterceptor(ValidateInterceptor.getInstance());
ChainProcessor processor = new ChainProcessor(chain);
//异步调用,放到线程池中运行
if (cc.isAsync()) {
if (CC.VERBOSE_LOG) {
CC.verboseLog(callId, "put into thread pool");
}
CC_THREAD_POOL.submit(processor);
//异步调用时此方法返回null,CCResult通过callback回调
return null;
} else {
//同步调用,直接执行
CCResult ccResult;
try {
ccResult = processor.call();
} catch (Exception e) {
ccResult = CCResult.defaultExceptionResult(e);
}
if (CC.VERBOSE_LOG) {
CC.verboseLog(callId, "cc finished.CCResult:" + ccResult);
}
//同步调用的返回结果,永不为null,默认为CCResult.defaultNullResult()
return ccResult;
}
}
ValidateInterceptor类采用一样的Holder单例写法。一番验证后,根据组件的存在位置分别最后加入一环LocalCCInterceptor,RemoteCCInterceptor,SubProcessCCInterceptor 。
class ValidateInterceptor implements ICCInterceptor {
//-------------------------单例模式 start --------------
/** 单例模式Holder */
private static class ValidateInterceptorHolder {
private static final ValidateInterceptor INSTANCE = new ValidateInterceptor();
}
private ValidateInterceptor (){}
/** 获取ValidateInterceptor的单例对象 */
static ValidateInterceptor getInstance() {
return ValidateInterceptorHolder.INSTANCE;
}
//-------------------------单例模式 end --------------
@Override
public CCResult intercept(Chain chain) {
CC cc = chain.getCC();
String componentName = cc.getComponentName();
int code = 0;
Boolean notFoundInCurApp = null;
if (TextUtils.isEmpty(componentName)) {
//没有指定要调用的组件名称,中止运行
code = CCResult.CODE_ERROR_COMPONENT_NAME_EMPTY;
} else if (cc.getContext() == null) {
//context为null (没有设置context 且 CC中获取application失败)
code = CCResult.CODE_ERROR_CONTEXT_NULL;
} else {
if (!ComponentManager.hasComponent(componentName)) {
//当前进程中不包含此组件,查看一下其它进程中是否包含此组件
notFoundInCurApp = TextUtils.isEmpty(ComponentManager.getComponentProcessName(componentName));
if (notFoundInCurApp && !CC.isRemoteCCEnabled()) {
//本app内所有进程均没有指定的组件,并且设置了不会调用外部app的组件
code = CCResult.CODE_ERROR_NO_COMPONENT_FOUND;
CC.verboseLog(cc.getCallId(),"componentName=" + componentName
+ " is not exists and CC.enableRemoteCC is " + CC.isRemoteCCEnabled());
}
}
}
if (code != 0) {
return CCResult.error(code);
}
//执行完自定义拦截器,并且通过有效性校验后,再确定具体调用组件的方式
if (ComponentManager.hasComponent(componentName)) {
//调用当前进程中的组件
chain.addInterceptor(LocalCCInterceptor.getInstance());
} else {
if (notFoundInCurApp == null) {
notFoundInCurApp = TextUtils.isEmpty(ComponentManager.getComponentProcessName(componentName));
}
if (notFoundInCurApp) {
//调用设备上安装的其它app(组件单独运行的app)中的组件
chain.addInterceptor(RemoteCCInterceptor.getInstance());
} else {
//调用app内部子进程中的组件
chain.addInterceptor(SubProcessCCInterceptor.getInstance());
}
}
chain.addInterceptor(Wait4ResultInterceptor.getInstance());
// 执行上面添加的拦截器,开始执行组件调用
return chain.proceed();
}
}
LocalCCRunnable 这个就是封装我们任务的执行(跨越千山万水boolean callbackDelay = component.onCall(cc) 终于在这里被干了)。LocalCCInterceptor.intercept中对执行线程做了判断。分别提交到不同线程执行。
class LocalCCInterceptor implements ICCInterceptor {
//-------------------------单例模式 start --------------
/** 单例模式Holder */
private static class LocalCCInterceptorHolder {
private static final LocalCCInterceptor INSTANCE = new LocalCCInterceptor();
}
private LocalCCInterceptor (){}
/** 获取LocalCCInterceptor的单例对象 */
static LocalCCInterceptor getInstance() {
return LocalCCInterceptorHolder.INSTANCE;
}
//-------------------------单例模式 end --------------
@Override
public CCResult intercept(Chain chain) {
CC cc = chain.getCC();
IComponent component = ComponentManager.getComponentByName(cc.getComponentName());
if (component == null) {
CC.verboseLog(cc.getCallId(), "component not found in this app. maybe 2 reasons:"
+ "\n1. CC.enableRemoteCC changed to false"
+ "\n2. Component named \"%s\" is a IDynamicComponent but now is unregistered"
);
return CCResult.error(CCResult.CODE_ERROR_NO_COMPONENT_FOUND);
}
try {
String callId = cc.getCallId();
if (CC.VERBOSE_LOG) {
CC.verboseLog(callId, "start component:%s, cc: %s", component.getClass().getName(), cc.toString());
}
boolean shouldSwitchThread = false;
LocalCCRunnable runnable = new LocalCCRunnable(cc, component);
if (component instanceof IMainThread) {
//当前是否在主线程
boolean curIsMainThread = Looper.myLooper() == Looper.getMainLooper();
//该action是否应该在主线程运行
Boolean runOnMainThread = ((IMainThread) component).shouldActionRunOnMainThread(cc.getActionName(), cc);
//是否需要切换线程执行 component.onCall(cc) 方法
shouldSwitchThread = runOnMainThread != null && runOnMainThread ^ curIsMainThread;
if (shouldSwitchThread) {
runnable.setShouldSwitchThread(true);
if (runOnMainThread) {
//需要在主线程运行,但是当前线程不是主线程
ComponentManager.mainThread(runnable);
} else {
//需要在子线程运行,但当前线程不是子线程
ComponentManager.threadPool(runnable);
}
}
}
if (!shouldSwitchThread) {
//不需要切换线程,直接运行
runnable.run();
}
//兼容以下情况:
// 1. 不需要切换线程,但需要等待异步实现调用CC.sendCCResult(...)
// 2. 需要切换线程,等待切换后的线程调用组件后调用CC.sendCCResult(...)
if (!cc.isFinished()) {
chain.proceed();
}
} catch(Exception e) {
return CCResult.defaultExceptionResult(e);
}
return cc.getResult();
}
static class LocalCCRunnable implements Runnable {
private final String callId;
private CC cc;
private IComponent component;
private boolean shouldSwitchThread;
LocalCCRunnable(CC cc, IComponent component) {
this.cc = cc;
this.callId = cc.getCallId();
this.component = component;
}
void setShouldSwitchThread(boolean shouldSwitchThread) {
this.shouldSwitchThread = shouldSwitchThread;
}
@Override
public void run() {
if (cc.isFinished()) {
return;
}
try {
boolean callbackDelay = component.onCall(cc);
if (CC.VERBOSE_LOG) {
CC.verboseLog(callId, component.getName() + ":"
+ component.getClass().getName()
+ ".onCall(cc) return:" + callbackDelay
);
}
if (!callbackDelay && !cc.isFinished()) {
CC.logError("component.onCall(cc) return false but CC.sendCCResult(...) not called!"
+ "\nmaybe: actionName error"
+ "\nor if-else not call CC.sendCCResult"
+ "\nor switch-case-default not call CC.sendCCResult"
+ "\nor try-catch block not call CC.sendCCResult."
);
//没有返回结果,且不是延时回调(也就是说不会收到结果了)
setResult(CCResult.error(CCResult.CODE_ERROR_CALLBACK_NOT_INVOKED));
}
} catch(Exception e) {
setResult(CCResult.defaultExceptionResult(e));
}
}
private void setResult(CCResult result) {
if (shouldSwitchThread) {
//若出现线程切换
// LocalCCInterceptor.intercept会执行chain.proceed()进入wait状态
// 需要解除wait状态
cc.setResult4Waiting(result);
} else {
cc.setResult(result);
}
}
}
}
在SubProcessCCInterceptor实现中。ProcessCrossTask包装了跨进程的调用,所有的RemoteCCService获取都是通过我们上面说的ContentProvider那套。SubProcessCCInterceptor多了对cancel,timeout的判断。service.call(remoteCC, new IRemoteCallback.Stub()执行了跨进程的调用。
class SubProcessCCInterceptor implements ICCInterceptor {
private static final ConcurrentHashMap<String, IRemoteCCService> CONNECTIONS = new ConcurrentHashMap<>();
//-------------------------单例模式 start --------------
/** 单例模式Holder */
private static class SubProcessCCInterceptorHolder {
private static final SubProcessCCInterceptor INSTANCE = new SubProcessCCInterceptor();
}
SubProcessCCInterceptor(){}
/** 获取SubProcessCCInterceptor的单例对象 */
static SubProcessCCInterceptor getInstance() {
return SubProcessCCInterceptorHolder.INSTANCE;
}
//-------------------------单例模式 end --------------
@Override
public CCResult intercept(Chain chain) {
String componentName = chain.getCC().getComponentName();
String processName = ComponentManager.getComponentProcessName(componentName);
return multiProcessCall(chain, processName, CONNECTIONS);
}
CCResult multiProcessCall(Chain chain, String processName
, ConcurrentHashMap<String, IRemoteCCService> connectionCache) {
if (processName == null) {
return CCResult.error(CCResult.CODE_ERROR_NO_COMPONENT_FOUND);
}
CC cc = chain.getCC();
//主线程同步调用时,跨进程也要在主线程同步调用
boolean isMainThreadSyncCall = !cc.isAsync() && Looper.getMainLooper() == Looper.myLooper();
ProcessCrossTask task = new ProcessCrossTask(cc, processName, connectionCache, isMainThreadSyncCall);
ComponentManager.threadPool(task);
if (!cc.isFinished()) {
//执行 Wait4ResultInterceptor
chain.proceed();
//如果是提前结束的,跨进程通知被调用方
if (cc.isCanceled()) {
task.cancel();
} else if (cc.isTimeout()) {
task.timeout();
}
}
return cc.getResult();
}
protected IRemoteCCService getMultiProcessService(String processName) {
CC.log("start to get RemoteService from process %s", processName);
IRemoteCCService service = RemoteCCService.get(processName);
CC.log("get RemoteService from process %s %s!", processName, (service != null ? "success" : "failed"));
return service;
}
class ProcessCrossTask implements Runnable {
private final CC cc;
private final String processName;
private final ConcurrentHashMap<String, IRemoteCCService> connectionCache;
private final boolean isMainThreadSyncCall;
private IRemoteCCService service;
ProcessCrossTask(CC cc, String processName, ConcurrentHashMap<String, IRemoteCCService> connectionCache, boolean isMainThreadSyncCall) {
this.cc = cc;
this.processName = processName;
this.connectionCache = connectionCache;
this.isMainThreadSyncCall = isMainThreadSyncCall;
}
@Override
public void run() {
RemoteCC processCrossCC = new RemoteCC(cc, isMainThreadSyncCall);
call(processCrossCC);
}
private void call(RemoteCC remoteCC) {
try {
service = connectionCache.get(processName);
if (service == null) {
//app内部多进程
service = getMultiProcessService(processName);
if (service != null) {
connectionCache.put(processName, service);
}
}
if (cc.isFinished()) {
CC.verboseLog(cc.getCallId(), "cc is finished before call %s process", processName);
return;
}
if (service == null) {
CC.verboseLog(cc.getCallId(), "RemoteService is not found for process: %s", processName);
setResult(CCResult.error(CCResult.CODE_ERROR_NO_COMPONENT_FOUND));
return;
}
if (CC.VERBOSE_LOG) {
CC.verboseLog(cc.getCallId(), "start to call process:%s, RemoteCC: %s"
, processName, remoteCC.toString());
}
service.call(remoteCC, new IRemoteCallback.Stub() {
@Override
public void callback(RemoteCCResult remoteCCResult) throws RemoteException {
try {
if (CC.VERBOSE_LOG) {
CC.verboseLog(cc.getCallId(), "receive RemoteCCResult from process:%s, RemoteCCResult: %s"
, processName, remoteCCResult.toString());
}
setResult(remoteCCResult.toCCResult());
} catch(Exception e) {
e.printStackTrace();
setResult(CCResult.error(CCResult.CODE_ERROR_REMOTE_CC_DELIVERY_FAILED));
}
}
});
} catch (DeadObjectException e) {
connectionCache.remove(processName);
call(remoteCC);
} catch (Exception e) {
e.printStackTrace();
setResult(CCResult.error(CCResult.CODE_ERROR_REMOTE_CC_DELIVERY_FAILED));
}
}
void setResult(CCResult result) {
cc.setResult4Waiting(result);
}
void cancel() {
try {
service.cancel(cc.getCallId());
} catch (Exception e) {
e.printStackTrace();
}
}
void timeout() {
try {
service.timeout(cc.getCallId());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
RemoteCCInterceptor其实包含了SubProcessCCInterceptor,只不过多了唤醒,连接功能。在MAX_CONNECT_TIME_DURATION时间内尝试,最后调用SubProcessCCInterceptor.multiProcessCall.
class RemoteCCInterceptor extends SubProcessCCInterceptor {
private static final ConcurrentHashMap<String, IRemoteCCService> REMOTE_CONNECTIONS = new ConcurrentHashMap<>();
//-------------------------单例模式 start --------------
/** 单例模式Holder */
private static class RemoteCCInterceptorHolder {
private static final RemoteCCInterceptor INSTANCE = new RemoteCCInterceptor();
}
private RemoteCCInterceptor(){}
/** 获取{@link RemoteCCInterceptor}的单例对象 */
static RemoteCCInterceptor getInstance() {
return RemoteCCInterceptorHolder.INSTANCE;
}
//-------------------------单例模式 end --------------
@Override
public CCResult intercept(Chain chain) {
String processName = getProcessName(chain.getCC().getComponentName());
if (!TextUtils.isEmpty(processName)) {
return multiProcessCall(chain, processName, REMOTE_CONNECTIONS);
}
return CCResult.error(CCResult.CODE_ERROR_NO_COMPONENT_FOUND);
}
private String getProcessName(String componentName) {
String processName = null;
try {
for (Map.Entry<String, IRemoteCCService> entry : REMOTE_CONNECTIONS.entrySet()) {
try {
processName = entry.getValue().getComponentProcessName(componentName);
} catch(DeadObjectException e) {
String processNameTo = entry.getKey();
RemoteCCService.remove(processNameTo);
IRemoteCCService service = RemoteCCService.get(processNameTo);
if (service == null) {
String packageName = processNameTo.split(":")[0];
boolean wakeup = RemoteConnection.tryWakeup(packageName);
CC.log("wakeup remote app '%s'. success=%b.", packageName, wakeup);
if (wakeup) {
service = getMultiProcessService(processNameTo);
}
}
if (service != null) {
try {
processName = service.getComponentProcessName(componentName);
REMOTE_CONNECTIONS.put(processNameTo, service);
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
if (!TextUtils.isEmpty(processName)) {
return processName;
}
}
} catch(Exception e) {
e.printStackTrace();
}
return processName;
}
void enableRemoteCC() {
//监听设备上其它包含CC组件的app
listenComponentApps();
connect(RemoteConnection.scanComponentApps());
}
private static final String INTENT_FILTER_SCHEME = "package";
private void listenComponentApps() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addAction(Intent.ACTION_MY_PACKAGE_REPLACED);
intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
intentFilter.addDataScheme(INTENT_FILTER_SCHEME);
CC.getApplication().registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String packageName = intent.getDataString();
if (TextUtils.isEmpty(packageName)) {
return;
}
if (packageName.startsWith(INTENT_FILTER_SCHEME)) {
packageName = packageName.replace(INTENT_FILTER_SCHEME + ":", "");
}
String action = intent.getAction();
CC.log("onReceived.....pkg=" + packageName + ", action=" + action);
if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
REMOTE_CONNECTIONS.remove(packageName);
} else {
CC.log("start to wakeup remote app:%s", packageName);
if (RemoteConnection.tryWakeup(packageName)) {
ComponentManager.threadPool(new ConnectTask(packageName));
}
}
}
}, intentFilter);
}
private void connect(List<String> packageNames) {
if (packageNames == null || packageNames.isEmpty()) {
return;
}
for (String pkg : packageNames) {
ComponentManager.threadPool(new ConnectTask(pkg));
}
}
class ConnectTask implements Runnable {
String packageName;
ConnectTask(String packageName) {
this.packageName = packageName;
}
@Override
public void run() {
IRemoteCCService service = getMultiProcessService(packageName);
if (service != null) {
REMOTE_CONNECTIONS.put(packageName, service);
}
}
}
private static final int MAX_CONNECT_TIME_DURATION = 1000;
@Override
protected IRemoteCCService getMultiProcessService(String packageName) {
long start = System.currentTimeMillis();
IRemoteCCService service = null;
while (System.currentTimeMillis() - start < MAX_CONNECT_TIME_DURATION) {
service = RemoteCCService.get(packageName);
if (service != null) {
break;
}
SystemClock.sleep(50);
}
CC.log("connect remote app '%s' %s. cost time=%d"
, packageName
, service == null ? "failed" : "success"
, (System.currentTimeMillis() - start));
return service;
}
}
粗略的分析下CC框架中一些常见的技术点。我们将在自己的项目中继续尝试使用他,学习他。