分析CmProcess跨進程通信的實現(xiàn)
一、基礎(chǔ)知識準(zhǔn)備
1.1、多進程
Android多進程概念:一般一個 app 只有一個進程,所有的 components 都運行在同一個進程中,進程名稱就是 app 包名。但是每一個進程都有內(nèi)存的限制,如果一個進程的內(nèi)存超過了這個限制的時候就會報 OOM 錯誤。為了解決內(nèi)存限制的問題,Android 引入了多進程的概念,將占用內(nèi)存的操作放在一個單獨的進程中分擔(dān)主進程的壓力。
多進程的好處:
- 分擔(dān)主進程的內(nèi)存壓力。
- 常駐后臺任務(wù)。
- 守護進程,主進程和守護進程相互監(jiān)視,有一方被殺就重新啟動它。
- 多么塊,對有風(fēng)險的模塊放在單獨進程,崩潰后不會影響主進程的運行。
多進程的缺點:
- Applicaton的重新創(chuàng)建,每個進程有自己獨立的virtual machine,每次創(chuàng)建新的進程就像創(chuàng)建一個新的Application
- 靜態(tài)成員變量和單例模式失效,每個進程有自己獨立的虛擬機,不同虛擬機在內(nèi)存分配上有不同的地址空間,這就導(dǎo)致不同虛擬機在訪問同一個對象時會產(chǎn)生多分副本。
- SharedPreference的可靠性下降,不支持多進程
- 線程同步機制失效
1.2、Bundle類
bundle 定義 bundle 是一個 final 類,final 類通常功能是完整的,它們不能被繼承。Java 中有許多類是 final 的,譬如 String, Interger 以及其他包裝類。
public final class Bundle extends BaseBundle implements Cloneable, Parcelable
bundle 傳遞的數(shù)據(jù)可以是 boolean、byte、int、long、float、double、string 等基本類型或它們對應(yīng)的數(shù)組,也可以是對象或?qū)ο髷?shù)組。但是如果傳遞對象或?qū)ο髷?shù)組,該對象必須實現(xiàn) Serializable 或 Parcelable 接口。由 Bundle 定義我們也可以看到其實現(xiàn)了 Parcelable 接口,所以支持實現(xiàn)了Parcelable 接口的對象。
因此當(dāng)我們在一個進程中啟動了另外一個進程的 Activity、Service、Receiver,我們就可以在 Bundle 中附加我們需要傳輸給遠(yuǎn)程進程的信息(前提是能夠被序列化)并通過 Intent 發(fā)送出去。
二、代碼解析
2.1、AIDL接口
1、IEventReceiver:事件接收器
// 事件接受器
interface IEventReceiver {
// 這里的 event 是 bundle 類型
void onEventReceive(String key,in Bundle event);
}
2、IPCCallback:看名字也可以看出來是跨進程 callback
interface IPCCallback {
// result 也是 bundle
void onSuccess(in Bundle result);
void onFail(String reason);
}
3、IServiceFetcher:獲取服務(wù)的。可以再此進行注冊。
interface IServiceFetcher { // service 是 Ibinder 類型
android.os.IBinder getService(java.lang.String name); // 注冊服務(wù)
void addService(java.lang.String name, android.os.IBinder service); // 添加回調(diào)
void addEventListener(java.lang.String name, android.os.IBinder service); // 移除 service
void removeService(java.lang.String name); // 移除回調(diào)
void removeEventListener(java.lang.String name); // 發(fā)送消息
void post(String key,in Bundle result);
}
2.2、啟動分析
根據(jù)代碼可知,咱們有三個進程,分別是:
- com.ipc.code:vc :TestActivity 運行所在的進程;這是屬于用戶測的。
- com.ipc.code:vm : 也就是BinderProvider 存在的進程;IPCBus 也在該進程,主要是用于保存和傳遞數(shù)據(jù)
- com.ipc.code :MainActivity 主進程;
也就是每個進程在初始化的時候,都會走一遍Application 的初始化,因此如果需要對進程做啥操作,可以判斷出具體的進程,然后做一些額外的操作。對于 CmProcess ,所有進程的初始化邏輯都是一樣的。
public class App extends Application {
private static final String TAG = "App";
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// 先啟動主進程,之后才啟動其他進程
VCore.init(base);
}
}
啟動過程中,會主動為每個進程注冊回調(diào),注意是每個進程。
該 init 方法最終會走入到下面的方法中:
public void startup(Context context) {
if (!isStartUp) {
// 在主線程啟動,每個進程都有一個自己的主線程
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("VirtualCore.startup() must called in main thread.");
}
ServiceManagerNative.SERVICE_CP_AUTH = context.getPackageName() + "." + ServiceManagerNative.SERVICE_DEF_AUTH;
this.context = context;
// 傳入了一個 cache 實例,這個實例是只有主線程有的
IPCBus.initialize(new IServerCache() {
@Override
public void join(String serverName, IBinder binder) {
ServiceManagerNative.addService(serverName, binder);
}
@Override
public void joinLocal(String serverName, Object object) {
ServiceCache.addLocalService(serverName,object);
}
@Override
public void removeService(String serverName) {
ServiceManagerNative.removeService(serverName);
}
@Override
public void removeLocalService(String serverName) {
ServiceCache.removeLocalService(serverName);
}
@Override
public IBinder query(String serverName) {
return ServiceManagerNative.getService(serverName);
}
@Override
public Object queryLocal(String serverName) {
return ServiceCache.getLocalService(serverName);
}
@Override
public void post(String key,Bundle bundle) {
ServiceManagerNative.post(key,bundle);
}
}); // 這里是根據(jù)進程名字添加注冊的事件接收器
ServiceManagerNative.addEventListener(AppUtil.getProcessName(context, Process.myPid()), EventReceiver.getInstance());
isStartUp = true;
}
}
這里整個邏輯很簡單,就是在主線程初始化了IPCBus,然后給該進程注冊了一個事件分發(fā)的監(jiān)聽。
三、EventReceiver
public class EventReceiver extends IEventReceiver.Stub {
private static final String TAG = "EventReceiver";
private static final EventReceiver EVENT_RECEIVER = new EventReceiver();
private EventReceiver(){}
public static final EventReceiver getInstance(){
return EVENT_RECEIVER;
}
@Override
public void onEventReceive(String key,Bundle event) {
EventCenter.onEventReceive(key,event);
}
}
整個類的代碼很簡單。但是要注意的是,其繼承了IEventReceiver.Stub,說明他具有跨進程傳輸?shù)哪芰?。主要就是通過EventCenter 來分發(fā)消息。
由于每個進程都會走一遍初始化邏輯,所以每個進程都注冊了事件的接收。
四、ServiceManagerNative
從名字也可以看出來,這個跟我們平時看到的ServiceManager 很像。主要就是用來獲取 service 和注冊 listener 的。
public static void addEventListener(String name, IBinder service) {
IServiceFetcher fetcher = getServiceFetcher();
if (fetcher != null) {
try {
fetcher.addEventListener(name, service);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
首先是調(diào)用getServiceFetcher 來獲取最終保存服務(wù)的 fetcher。
注冊回調(diào)的時候,會先獲取是否存在 (binder)ServiceFetcher ,在將其轉(zhuǎn)化為本地 binder;這樣 ServiceFetcher 的管理器就可以用了。
private static IServiceFetcher getServiceFetcher() {
if (sFetcher == null || !sFetcher.asBinder().isBinderAlive()) {
synchronized (ServiceManagerNative.class) {
Context context = VirtualCore.get().getContext();
Bundle response = new ProviderCall.Builder(context, SERVICE_CP_AUTH).methodName("@").call();
if (response != null) {
IBinder binder = BundleCompat.getBinder(response, "_VM_|_binder_");
linkBinderDied(binder);
sFetcher = IServiceFetcher.Stub.asInterface(binder);
}
}
}
return sFetcher;
}
首先是看ProviderCall.Builder(context, SERVICE_CP_AUTH).methodName("@").call(),他最終會調(diào)用下面的方法:
//ContentProviderCompat
public static Bundle call(Context context, Uri uri, String method, String arg, Bundle extras) {
// 這里還區(qū)分了版本
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
return context.getContentResolver().call(uri, method, arg, extras);
}
ContentProviderClient client = crazyAcquireContentProvider(context, uri); // 這里會不斷重試最終會獲得對 BinderProvider 的引用
Bundle res = null;
try {
// 通過約定好的方法名字獲得bindle
res = client.call(method, arg, extras);
} catch (RemoteException e) {
e.printStackTrace();
} finally {
releaseQuietly(client);
}
return res;
}
五、BinderProvider
下面看下 BinderProvider 的 call 方法。
新建了一個 bundle 對象,然后將 binder 保存在里面。注意這是通過跨進程調(diào)用,最終將 bundle 傳回主進程,然后拿到了ServiceFetcher 的 binder,并將其轉(zhuǎn)為本地 binder。
可以發(fā)現(xiàn)這里對于方法名是 "@" 時,就會返回 bundle ,否則就是返回 null 。
public Bundle call(String method, String arg, Bundle extras) {
if ("@".equals(method)) {
Bundle bundle = new Bundle();
BundleCompat.putBinder(bundle, "_VM_|_binder_", mServiceFetcher);
return bundle;
}
return null;
}
簡單來說,就是大家都通過 binderProvider 這個進程來保存對于回調(diào)的注冊,保存是基于進城名字來的,因此可以保證不會被覆蓋。
此處的mServiceFetcher 是BinderProvider 內(nèi)部內(nèi)的實例,但是其繼承了IServiceFetcher.Stub,因此也就有了跨進程的能力。
到這里,理一下前面的邏輯:
ServiceManagerNative.addEventListener(AppUtil.getProcessName(context, Process.myPid()), EventReceiver.getInstance());
某個進程的主線程調(diào)用這個方法,所做的具體事情如下:
1.通過 binder 拿到了binderProvider 中的 IServiceFetcher.Stub 的實例;
2.向IServiceFetcher.Stub 注冊回調(diào),該回調(diào)最終會被保存binderProvider 進程里面。
六、BinderProvider 啟動分析
上面介紹了其是怎么將 listener 注冊到 binderProvider 進程的,但是并沒有講到接下去我們看下 BinderProvider 的啟動過程,
下圖是ContentProvider 的啟動流程。當(dāng)我們在主進程想獲取 server 的時候,這時候,會看看 provider 存不存在,沒有的就會進行啟動,同時會走 Application 的初始化邏輯,

具體我們可以看下面這個啟動流程圖:

- Application 的 attachBaseContext 方法是優(yōu)先執(zhí)行的;
- ContentProvider 的 onCreate的方法 比 Application的onCreate的方法先執(zhí)行;
- Activity、Service 的 onCreate 方法以及 BroadcastReceiver 的 onReceive 方法,是在 MainApplication 的 onCreate 方法之后執(zhí)行的;
- 調(diào)用流程為: Application 的 attachBaseContext ---> ContentProvider 的 onCreate ----> Application 的 onCreate ---> Activity、Service 等的 onCreate(Activity 和 Service 不分先后);
這里主要是梳理了下 provider 的啟動過程,并沒有很細(xì)講,但是有必要了解一下。
七、MainActivity
接下去,開始看MainActivity 里面的代碼。
調(diào)用registerService 注冊服務(wù),傳入IPayManager.class 和MainActivity;記得MainActivity 也實現(xiàn)了IPayManager 接口。
VCore.getCore().registerService(IPayManager.class, this);
看下,里面的具體代碼邏輯
// Vcore
public VCore registerService(Class<?> interfaceClass, Object server){
if (VirtualCore.get().getContext() == null){
return this;
}
Object o = IPCBus.getLocalService(interfaceClass);
// 如果是第一次調(diào)用就會返回空
IBinder service = ServiceManagerNative.getService(interfaceClass.getName());
if (service != null && o != null){
return this;
}
IPCBus.registerLocal(interfaceClass,server);
// 這里的注冊就是把 server 保存到 binder 中
IPCBus.register(interfaceClass,server);
return this;
}
這里使用了一個registerLocal和register 方法,但是本質(zhì)上兩個方法是有區(qū)別的。registerLocal 意思很明確,就是本地ServiceCache保存一份。但是register,確實做了一些額外的操作。
public static void register(Class<?> interfaceClass, Object server) {
checkInitialized();
// 這里主要是獲取一個 binder,或者換句話來說,采用 binder 來保存相關(guān)數(shù)據(jù)
ServerInterface serverInterface = new ServerInterface(interfaceClass);
// 這里就是把 binder 保存到 binderProvider
TransformBinder binder = new TransformBinder(serverInterface, server);
sCache.join(serverInterface.getInterfaceName(), binder);
}
首先這里創(chuàng)建了一個ServerInterface 實例,該實例內(nèi)部保存了傳過了來的接口和接口的方法,并將方法和 code 聯(lián)系在一起。
public ServerInterface(Class<?> interfaceClass) {
this.interfaceClass = interfaceClass;
Method[] methods = interfaceClass.getMethods();
codeToInterfaceMethod = new SparseArray<>(methods.length);
methodToIPCMethodMap = new HashMap<>(methods.length);
for (int i = 0; i < methods.length; i++) {// 這里每一個方法都有一個 code
int code = Binder.FIRST_CALL_TRANSACTION + i;// 組成一個 ipcMenhod
IPCMethod ipcMethod = new IPCMethod(code, methods[i], interfaceClass.getName());
codeToInterfaceMethod.put(code, ipcMethod);// 保存他們的映射關(guān)系
methodToIPCMethodMap.put(methods[i], ipcMethod);
}
}
同時利用TransformBinder 將接口和 實例保存到 binder 中。再將 binder 和 接口名字 保存到ServiceCache 中。
注冊完以后,下面是調(diào)用獲取本地服務(wù):
// 其實 service 本質(zhì)還是這個 MainActivity IPayManager service = VCore.getCore().getLocalService(IPayManager.class);
最后注冊了一個回調(diào):
VCore.getCore().subscribe("key", new EventCallback() {
@Override
public void onEventCallBack(Bundle event) {
}
});
最終EventCenter 會保存相關(guān)信息;
八、TestActivity
最后啟動 TestActivity ,這個是在另一個進程。在 onCreate 里面調(diào)用下面的方法:
IPayManager service = VCore.getCore().getService(IPayManager.class);
進程剛剛創(chuàng)建,我們看看是怎么獲取服務(wù)的:
// Vcore
public <T> T getService(Class<T> ipcClass){
T localService = IPCBus.getLocalService(ipcClass);
if (localService != null){
return localService;
}
return VManager.get().getService(ipcClass);
}
這里很明確,本地肯定是沒有的,因此,最后會從 VManager 中獲?。?/p>
// VManager
public <T> T getService(Class<T> ipcClass) {
T t = IPCBus.get(ipcClass);
if (t != null){
return t;
}
IPCSingleton<T> tipcSingleton = mIPCSingletonArrayMap.get(ipcClass);
if (tipcSingleton == null){
tipcSingleton = new IPCSingleton<>(ipcClass);
mIPCSingletonArrayMap.put(ipcClass,tipcSingleton);
}
return tipcSingleton.get();
}
接下去我們看下IPCSingleton 相關(guān)邏輯
// IPCSingleton
public T get() {
if (instance == null) {
synchronized (this) {
if (instance == null) {
instance = IPCBus.get(ipcClass);
}
}
}
return instance;
}
這是一個單例,目的也很明確,就是只獲取一次,可以看到后面又調(diào)到了 IPCBus 里面。
// IPCBus
public static <T> T get(Class<?> interfaceClass) {
checkInitialized();
ServerInterface serverInterface = new ServerInterface(interfaceClass);
// 這里獲取的 binder 應(yīng)該是 TransformBinder
IBinder binder = sCache.query(serverInterface.getInterfaceName());
if (binder == null) {
return null;
}
// 這里使用了動態(tài)代理
return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new IPCInvocationBridge(serverInterface, binder));
}
這里采用了動態(tài)代理創(chuàng)造了一個實例,最終返回的實例被保存在一個單例中。
可以看到,這里回去查找存不存在 binder。
// VirtualCore
public IBinder query(String serverName) {
return ServiceManagerNative.getService(serverName);
}
還是通過ServiceManagerNative 來獲取的 service;這里又回到我們之前分析過的邏輯。先從 binderProvider 獲取fetcher, 也就是 ServiceFetcher。
IServiceFetcher fetcher = getServiceFetcher();
它也會從ServiceFetcher 中獲取到 binder ,而這個 binder 就是之前我們保存的TransformBinder 。拿到這個之后,還是一樣,將其轉(zhuǎn)化為該進程的本地 binder .
// BinderProvider
private class ServiceFetcher extends IServiceFetcher.Stub {
最后,我們通過動態(tài)代理的形式,創(chuàng)建了一個 IPayManager 的實例。
return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new IPCInvocationBridge(serverInterface, binder));
這里需要注意的是IPCInvocationBridge 繼承自InvocationHandler。
拿到后,開始調(diào)用對應(yīng)的方法:
if (service != null){
Log.d(TAG, "onCreate: shentest before vcore " + AppUtil.getAppName(this));
// 首先這個 service 是跨進程調(diào)用的,怎么才通知到其他組件?這里大家可以思考下
service.pay(5000, new BaseCallback() {
@Override
public void onSucceed(Bundle result) {
textview.setText(result.getString("pay"));
Bundle bundle = new Bundle();
bundle.putString("name", "DoDo");
VCore.getCore().post("key",bundle);
}
@Override
public void onFailed(String reason) {
}
});
}
調(diào)用 service.pay 的時候,就會調(diào)用動態(tài)代理中的 invoke 方法:
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
IPCMethod ipcMethod = serverInterface.getIPCMethod(method);
if (ipcMethod == null) {
throw new IllegalStateException("Can not found the ipc method : " + method.getDeclaringClass().getName() + "@" + method.getName());
} // 這里很關(guān)鍵
return ipcMethod.callRemote(binder, args);
}
首先根據(jù)方法名獲得ipcMethod,里面保存了方法的 code,接口名字,參數(shù),返回值。接著調(diào)用了 ipcMethod.callRemote, 該方法又會調(diào)用:
// IPCMethod
// 這個方法很重要,需要理解其實現(xiàn)過程
public Object callRemote(IBinder server, Object[] args) throws RemoteException {
Parcel data = Parcel.obtain(); // 獲取一個新的 parcel 對象
Parcel reply = Parcel.obtain();
Object result;
try {
data.writeInterfaceToken(interfaceName);
data.writeArray(args); // 這里 server 就是 transformBinder
server.transact(code, data, reply, 0);
reply.readException();
result = readValue(reply);
if (resultConverter != null) {
result = resultConverter.convert(result);
}
} finally {
data.recycle();
reply.recycle();
}
return result;
}
code 變量用于標(biāo)識客戶端期望調(diào)用服務(wù)端的哪個函數(shù),因此,雙方需要約定一組 int 值,不同的值代表不同的服務(wù)端函數(shù),該值和客戶端的 transact() 函數(shù)中第一個參數(shù) code 的值是一致的。
enforceInterface() 是為了某種校驗,它與客戶端的 writeInterfaceToken() 對應(yīng),具體見下一小節(jié)。
readString() 用于從包裹中取出一個字符串。如果該 IPC 調(diào)用的客戶端期望返回一些結(jié)果,則可以在返回包裹 reply 中調(diào)用 Parcel 提供的相關(guān)函數(shù)寫入相應(yīng)的結(jié)果。 Parcel.writeXXX();
現(xiàn)在要看的是怎么通過 binder 一步一步拿到參數(shù)。
使用 Parcel 一般是通過 Parcel.obtain() 從對象池中獲取一個新的 Parcel 對象,如果對象池中沒有則直接 new 的 Parcel 則直接創(chuàng)建新的一個 Parcel 對象,并且會自動創(chuàng)建一個Parcel-Native 對象。
writeInterfaceToken 用于寫入 IBinder 接口標(biāo)志,所帶參數(shù)是 String 類型的,如 IServiceManager.descriptor = "android.os.IServiceManager"。
之前說的 code 在這里用上了,code 是一個私有變量,跟 method 綁定在一起的。
中間有個 server.transact(code, data, reply, 0); 該方法實現(xiàn)了跨進程調(diào)用,最終會走到 binderProvider 的下面onTransact方法:
// TransformBinder 運行在主進程
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { // 回調(diào)進來后,就到了 MainActivity 的進程
if (code == INTERFACE_TRANSACTION) {
reply.writeString(serverInterface.getInterfaceName());
return true;
}
IPCMethod method = serverInterface.getIPCMethod(code);
if (method != null) {
try {
method.handleTransact(server, data, reply);
} catch (Throwable e) {
e.printStackTrace();
}
return true;
}
return super.onTransact(code, data, reply, flags);
}
這里主要是根據(jù) code 來獲取到是哪個方法被調(diào)用了,下面才是真正的處理。
// IPCMethod
public void handleTransact(Object server, Parcel data, Parcel reply) {
data.enforceInterface(interfaceName); // 確保是目標(biāo)接口
Object[] parameters = data.readArray(getClass().getClassLoader());
if (parameters != null && parameters.length > 0) {
for (int i = 0; i < parameters.length; i++) {
if (converters[i] != null) {
parameters[i] = converters[i].convert(parameters[i]);
} // 如果參數(shù)里面包含有 binder
if (parameters[i] instanceof IBinder){
parameters[i] = IPCCallback.Stub.asInterface(((IBinder)parameters[i]));
}
}
}
try {
// 最終通過反射的形式實現(xiàn)了的調(diào)用
// 其實最主要的是通過 binder 拿到參數(shù),然后知道對方調(diào)用的是哪個方法。
// 現(xiàn)在要分析的是,他怎么將數(shù)據(jù)傳過來的
Object res = method.invoke(server, parameters);
reply.writeNoException();
reply.writeValue(res);
} catch (IllegalAccessException e) {
e.printStackTrace();
reply.writeException(e);
} catch (InvocationTargetException e) {
e.printStackTrace();
reply.writeException(e);
}
}
看看 convert 里面的操作:
public Object convert(Object param) {
if (param != null) {
if (asInterfaceMethod == null) {
synchronized (this) {
if (asInterfaceMethod == null) { // 找到 asInterface 方法
asInterfaceMethod = findAsInterfaceMethod(type);
}
}
}
try { // 因為 asInterface 方法是靜態(tài)方法,所以對象可以傳入空,最終轉(zhuǎn)變成所需要的參數(shù)類型
return asInterfaceMethod.invoke(null, param);
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
return null;
}
通過 convert 這個一調(diào)用,就轉(zhuǎn)變成我們所需要的參數(shù)了。
private static Method findAsInterfaceMethod(Class<?> type) {
for (Class<?> innerClass : type.getDeclaredClasses()) {
// public static class Stub extends Binder implements IType
if (Modifier.isStatic(innerClass.getModifiers())
&& Binder.class.isAssignableFrom(innerClass)
&& type.isAssignableFrom(innerClass)) {
// public static IType asInterface(android.os.IBinder obj)
for (Method method : innerClass.getDeclaredMethods()) {
if (Modifier.isStatic(method.getModifiers())) {
Class<?>[] types = method.getParameterTypes();
if (types.length == 1 && types[0] == IBinder.class) {
return method;
}
}
}
}
}
throw new IllegalStateException("Can not found the " + type.getName() + "$Stub.asInterface method.");
}
findAsInterfaceMethod 通過層層篩選,最終獲得需要的那個方法:
public static com.cmprocess.ipc.server.IPCCallback com.cmprocess.ipc.server.IPCCallback$Stub.asInterface(android.os.IBinder)
通過 invoke 方法,終將獲得了我們需要的類型。
這里 server 就是 mainActivity。在把對應(yīng)的參數(shù)傳進去即可。最終調(diào)到了mainActivity 里面的 pay 方法。
public void pay(final int count, final IPCCallback callBack) {
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(2000);
Bundle bundle = new Bundle();
bundle.putString("pay", count + 100 + "");
try {
// callback 也是一個binder
callBack.onSuccess(bundle);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}).start();
}
此處,callback 也是一個binder,調(diào)用成功后,發(fā)送了post。 其實最終也是調(diào)用了ServiceFetcher 。
// TestActivity
VCore.getCore().post("key",bundle);
其實也是通過 binder 來進行發(fā)送消息的。由于每個進程都注冊了消息回調(diào),因此,每個進程都會收到。
// ServiceCache
public static synchronized void sendEvent(String key,Bundle event){
if (sEventCache.isEmpty()){
return;
}
for (IBinder binder:sEventCache.values()){
IEventReceiver eventReceiver = IEventReceiver.Stub.asInterface(binder);
try {
eventReceiver.onEventReceive(key, event);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
EventReceiver 存在于每個進程,因此,對于 binderprovider 來說都是客戶端,其他進程則是服務(wù)端。最終 EventCenter 會根據(jù) KEY 值來做分發(fā)。
到這里整個流程就基本講完了。
不過我們發(fā)現(xiàn)還有兩個 service ,他們的作用是干嘛用的呢?感覺是用來保活的,防止 provider 死了。
以上就是分析CmProcess跨進程通信的實現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于CmProcess跨進程通信的資料請關(guān)注腳本之家其它相關(guān)文章!
- 詳解Android跨進程通信之AIDL
- Android實現(xiàn)跨進程接口回掉的方法
- Android AIDL實現(xiàn)兩個APP間的跨進程通信實例
- android使用AIDL跨進程通信(IPC)
- 詳解Android跨進程IPC通信AIDL機制原理
- Android AIDL實現(xiàn)跨進程通信的示例代碼
- Android 跨進程SharedPreferences異常詳解
- Android 跨進程通Messenger(簡單易懂)
- Android編程實現(xiàn)AIDL(跨進程通信)的方法詳解
- Android應(yīng)用程序四大組件之使用AIDL如何實現(xiàn)跨進程調(diào)用Service
相關(guān)文章
Android 快速實現(xiàn)狀態(tài)欄透明樣式的示例代碼
下面小編就為大家分享一篇Android 快速實現(xiàn)狀態(tài)欄透明樣式的示例代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01
Android實現(xiàn)史上最簡單自定義開關(guān)按鈕的方法
在平常的開發(fā)中按鈕是經(jīng)常使用到的控件之一,下面這篇文章主要給大家介紹了關(guān)于Android實現(xiàn)史上最簡單自定義開關(guān)按鈕的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04
詳解Android 在 ViewPager 中使用 Fragment 的懶加載
本篇文章主要介紹了Android 在 ViewPager 中使用 Fragment 的懶加載,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06
Android SharedPreferences四種操作模式使用詳解
這篇文章主要介紹了Android SharedPreferences四種操作模式使用詳解的相關(guān)資料,這里介紹了獲取Android SharedPreferences的兩種方法及比較,和操作模式的介紹,需要的朋友可以參考下2017-07-07

