赞
踩
近来看到爱奇艺发布了多进程的架构框架Andromeda。研究一下其多进程的通信方式。
具体github地址
通过此框架的初步分析
1.通过grade插件完善AndroidManifest.xml配置文件
2.通过ContentProvider传输binder对象
3.活动binder.stub对象
4.动态绑定进程service以及binder对象
5.多进程binder管理
其在利用自定义Gradle插件来插入DispatchService和DipatchProvider。
自定义的Gradle插件只会有app module上运行。
其会读取Manifest里面的内容并进行修改。
插件配置.png
1.查找遍历Manifest文件
void injectStubServiceToManifest(Project project) {
println "injectStubServiceToManifest"
//主目录
rootDirPath = project.rootDir.absolutePath
def android = project.extensions.getByType(AppExtension)
this.dispatcher = project.extensions.getByType(DispatcherExtension)
project.afterEvaluate {
android.applicationVariants.all { variant ->
if (pkgName == null) {
//获取包名
pkgName = getPackageName(variant)
println "pkgName:" + pkgName
}
//查找遍历Mainfest文件
variant.outputs.each { output ->
output.processManifest.doLast {
println "manifestOutputDirectory:" + output.processManifest.manifestOutputDirectory.absolutePath
//output.getProcessManifest().manifestOutputDirectory
output.processManifest.outputs.files.each { File file ->
//在gradle plugin 3.0.0之前,file是文件,且文件名为AndroidManifest.xml
//在gradle plugin 3.0.0之后,file是目录,且不包含AndroidManifest.xml,需要自己拼接
//除了目录和AndroidManifest.xml之外,还可能会包含manifest-merger-debug-report.txt等不相干的文件,过滤它
if ((file.name.equalsIgnoreCase("AndroidManifest.xml") && !file.isDirectory()) || file.isDirectory()) {
if (file.isDirectory()) {
//3.0.0之后,自己拼接AndroidManifest.xml
injectManifestFile(new File(file, "AndroidManifest.xml"))
} else {
//3.0.0之前,直接使用
injectManifestFile(file)
}
}
}
}
}
}
}
}
其内会写入三种文件
def static final STUB_SERVICE = 'org.qiyi.video.svg.stub.CommuStubService$CommuStubService'
xml.application {
int index = 0
//每个进程都声明使用这个CommuStubService文件
customProcessNames.each {
//加上序号,$CommuStuService会替换成数字
String serviceName = "${STUB_SERVICE}" + index.toString()
service("${NAME}": serviceName,
"${ENABLED}": "${TRUE}",
"${EXPORTED}": "${FALSE}",
"${PROCESS}": it
)
if (matchedServices == null) {
matchedServices = new HashMap<>()
}
matchedServices.put(it, serviceName)
++index
}
这里DipatcherService和DipatchProvider是binder的中转管理控件,默认配置到主进程。
//配置进程地址
this.dispatcher = project.extensions.getByType(DispatcherExtension)
//之后,写入DispatcherService和DispatcherProvider
def dispatcherProcess = dispatcher.process
println "dispatcher.process:" + dispatcher.process
if (dispatcherProcess != null && dispatcherProcess.length() > 0) {
service("${NAME}": DISPATCHER_SERVICE,
"${ENABLED}": "${TRUE}",
"${EXPORTED}": "${FALSE}",
"${PROCESS}": dispatcherProcess
)
provider(
"${AUTHORITIES}": getAuthority(),
"${EXPORTED}": "${FALSE}",
"${NAME}": DISPTACHER_PROVIDER,
"${ENABLED}": "${TRUE}",
"${PROCESS}": dispatcherProcess
)
} else {
service("${NAME}": DISPATCHER_SERVICE,
"${ENABLED}": "${TRUE}",
"${EXPORTED}": "${FALSE}"
)
provider(
"${AUTHORITIES}": getAuthority(),
"${EXPORTED}": "${FALSE}",
"${NAME}": DISPTACHER_PROVIDER,
"${ENABLED}": "${TRUE}"
)
}
正如通信所涉及的必要的几个步骤
1.注册
2.发其通信
3.binder间的相互绑定
4.binder间传输数据
注册流程
首先注册,通过公共的Andromeda入口注册提供远程沟通的服务
Andromeda.getInstance().registerRemoteService(IBuyApple.class, BuyAppleImpl.getInstance());
//RemoteTransfer
public static void registerRemoteService(Class serviceClass, T stubBinder) {
if (null == serviceClass || null == stubBinder) {
return;
}
RemoteTransfer.getInstance().registerStubService(serviceClass.getCanonicalName(), stubBinder);
}
//RemoteServiceTransfer
public void registerStubServiceLocked(String serviceCanonicalName, IBinder stubBinder,
Context context, IDispatcher dispatcherProxy, IRemoteTransfer.Stub stub) {
stubBinderCache.put(serviceCanonicalName, stubBinder);
if (dispatcherProxy == null) {
BinderWrapper wrapper = new BinderWrapper(stub.asBinder());
Intent intent = new Intent(context, DispatcherService.class);
intent.setAction(Constants.DISPATCH_REGISTER_SERVICE_ACTION);
intent.putExtra(Constants.KEY_REMOTE_TRANSFER_WRAPPER, wrapper);
intent.putExtra(Constants.KEY_BUSINESS_BINDER_WRAPPER, new BinderWrapper(stubBinder));
intent.putExtra(Constants.KEY_SERVICE_NAME, serviceCanonicalName);
setProcessInfo(intent, context);
ServiceUtils.startServiceSafely(context, intent);
} else {
try {
dispatcherProxy.registerRemoteService(serviceCanonicalName,
ProcessUtils.getProcessName(context), stubBinder);
} catch (RemoteException ex) {
ex.printStackTrace();
}
}
}
启动Service注册到DispatcherService当中
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent == null) {
return super.onStartCommand(intent, flags, startId);
}
Logger.d("DispatcherService-->onStartCommand,action:" + intent.getAction());
if (Constants.DISPATCH_REGISTER_SERVICE_ACTION.equals(intent.getAction())) {
//注册远程服务
registerRemoteService(intent);
} else if (Constants.DISPATCH_UNREGISTER_SERVICE_ACTION.equals(intent.getAction())) {
//注销远程服务
unregisterRemoteService(intent);
} else if (Constants.DISPATCH_EVENT_ACTION.equals(intent.getAction())) {
//传递数据
publishEvent(intent);
}
return super.onStartCommand(intent, flags, startId);
}
private void registerRemoteService(Intent intent) {
BinderWrapper wrapper = intent.getParcelableExtra(Constants.KEY_REMOTE_TRANSFER_WRAPPER);
BinderWrapper businessWrapper = intent.getParcelableExtra(Constants.KEY_BUSINESS_BINDER_WRAPPER);
String serviceCanonicalName = intent.getStringExtra(Constants.KEY_SERVICE_NAME);
int pid = intent.getIntExtra(Constants.KEY_PID, -1);
String processName = intent.getStringExtra(Constants.KEY_PROCESS_NAME);
try {
if (TextUtils.isEmpty(serviceCanonicalName)) {
//注意:RemoteTransfer.sendRegisterInfo()时,serviceCanonicalName为null,这是正常的,此时主要目的是reigsterAndReverseRegister()
Logger.e("service canonical name is null");
} else {
//注册到分发器上管理
Dispatcher.getInstance().registerRemoteService(serviceCanonicalName,
processName, businessWrapper.getBinder());
}
} catch (RemoteException ex) {
ex.printStackTrace();
} finally {
if (wrapper != null) {
registerAndReverseRegister(pid, wrapper.getBinder());
}
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。