做者:蒼王 時間:2018.6.1android
如下是我這個系列的相關文章,有興趣能夠參考一下,能夠給個喜歡或者關注個人文章。git
[Android]如何作一個崩潰率少於千分之三噶應用app--章節列表github
1.經過grade插件完善AndroidManifest.xml配置文件bash
2.經過ContentProvider傳輸binder對象架構
3.活動binder.stub對象app
4.動態綁定進程service以及binder對象框架
5.多進程binder管理ide
其在利用自定義Gradle插件來插入DispatchService和DipatchProvider。 自定義的Gradle插件只會有app module上運行。 其會讀取Manifest裏面的內容並進行修改。 svg
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 <T extends IBinder> 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());
}
}
}
複製代碼
ServiceDipatcher負責管理服務信息
@Override
public void registerRemoteServiceLocked(final String serviceCanonicalName, String processName,
IBinder binder) throws RemoteException {
Log.d(TAG, "ServiceDispatcher-->registerStubServiceLocked,serviceCanonicalName:" + serviceCanonicalName + ",pid:" + android.os.Process.myPid() + ",thread:" + Thread.currentThread().getName());
if (binder != null) {
binder.linkToDeath(new IBinder.DeathRecipient() {
@Override
public void binderDied() {
Logger.d("ServiceDispatcher-->binderDied,serviceCanonicalName:" + serviceCanonicalName);
BinderBean bean = remoteBinderCache.remove(serviceCanonicalName);
//實際上這裏是還沒實現線程同步,可是並不會影響執行結果,因此其實下面這句就沒有同步的必要。
if (bean != null) {
emergencyHandler.handleBinderDied(Andromeda.getAppContext(), bean.getProcessName());
}
}
}, 0);
remoteBinderCache.put(serviceCanonicalName, new BinderBean(binder, processName));
Logger.d("ServiceDispatcher-->registerRemoteServiceLocked(),binder is not null");
} else {
Log.d(TAG, "ServiceDispatcher-->registerRemoteServiceLocked(),binder is null");
}
}
複製代碼
最後須要完成反向綁定,意思是Dispatcher註冊能夠傳輸的binder對象,傳輸中心也須要綁定Dispatcher對象
/**
* 註冊和反向註冊
*
* @param pid
* @param transterBinder
*/
private void registerAndReverseRegister(int pid, IBinder transterBinder) {
Logger.d("DispatcherService-->registerAndReverseRegister,pid=" + pid + ",processName:" + ProcessUtils.getProcessName(pid));
IRemoteTransfer remoteTransfer = IRemoteTransfer.Stub.asInterface(transterBinder);
Dispatcher.getInstance().registerRemoteTransfer(pid, transterBinder);
if (remoteTransfer != null) {
Logger.d("now register to RemoteTransfer");
try {
remoteTransfer.registerDispatcher(Dispatcher.getInstance().asBinder());
} catch (RemoteException ex) {
ex.printStackTrace();
}
} else {
Logger.d("IdspatcherRegister IBinder is null");
}
}
複製代碼
在調用遠程的時候getRemoteSevice獲取目標的binder對象
IBuyApple buyApple = IBuyApple.Stub.asInterface(Andromeda.with(this).getRemoteService(IBuyApple.class));
複製代碼
遠程管理RemoteManager
@Override
public IBinder getRemoteService(Class<?> serviceClass) {
if (null == serviceClass) {
return null;
}
return getRemoteService(serviceClass.getCanonicalName());
}
@Override
public synchronized IBinder getRemoteService(String serviceCanonicalName) {
Logger.d(this.toString() + "-->getRemoteService,serviceName:" + serviceCanonicalName);
if (TextUtils.isEmpty(serviceCanonicalName)) {
return null;
}
BinderBean binderBean = RemoteTransfer.getInstance().getRemoteServiceBean(serviceCanonicalName);
String commuStubServiceName = ConnectionManager.getInstance().bindAction(appContext, binderBean.getProcessName());
commuStubServiceNames.add(commuStubServiceName);
return binderBean.getBinder();
}
複製代碼
RemoteDispatcher會調用DipatchProvider來獲取遠程的binder對象
@Override
public synchronized BinderBean getRemoteServiceBean(String serviceCanonicalName) {
Logger.d("RemoteTransfer-->getRemoteServiceBean,pid=" + android.os.Process.myPid() + ",thread:" + Thread.currentThread().getName());
//獲取binder包裝的對象
BinderBean cacheBinderBean = serviceTransfer.getIBinderFromCache(context, serviceCanonicalName);
if (cacheBinderBean != null) {
return cacheBinderBean;
}
if (null == dispatcherProxy) {
IBinder dispatcherBinder = getIBinderFromProvider();
if (null != dispatcherBinder) {
Logger.d("the binder from provider is not null");
dispatcherProxy = IDispatcher.Stub.asInterface(dispatcherBinder);
registerCurrentTransfer();
}
}
if (null == dispatcherProxy) {
sendRegisterInfo();
try {
wait(MAX_WAIT_TIME);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
if (serviceTransfer == null || dispatcherProxy == null) {
return null;
}
return serviceTransfer.getAndSaveIBinder(serviceCanonicalName, dispatcherProxy);
}
private IBinder getIBinderFromProvider() {
Logger.d("RemoteTransfer-->getIBinderFromProvider()");
Cursor cursor = null;
try {
//查詢出cursor對象
cursor = context.getContentResolver().query(getDispatcherProviderUri(), DispatcherProvider.PROJECTION_MAIN,
null, null, null);
if (cursor == null) {
return null;
}
//使用DispatcherCursor解包
return DispatcherCursor.stripBinder(cursor);
} finally {
IOUtils.closeQuietly(cursor);
}
}
複製代碼
DispatcherProvider使用的查詢返回
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Logger.d("DispatcherProvider-->query,uri:" + uri.getAuthority());
//DispatcherCursor封裝binder
return DispatcherCursor.generateCursor(Dispatcher.getInstance().asBinder());
}
//經過
public static DispatcherCursor generateCursor(IBinder binder) {
try {
DispatcherCursor cursor;
cursor = cursorCache.get(binder.getInterfaceDescriptor());
if (cursor != null) {
return cursor;
}
cursor = new DispatcherCursor(DEFAULT_COLUMNS, binder);
cursorCache.put(binder.getInterfaceDescriptor(), cursor);
return cursor;
} catch (RemoteException ex) {
return null;
}
}
//經過BinderWrapper來封裝binder
public DispatcherCursor(String[] columnNames, IBinder binder) {
super(columnNames);
binderExtras.putParcelable(KEY_BINDER_WRAPPER, new BinderWrapper(binder));
}
複製代碼
@Override
public synchronized IBinder getRemoteService(String serviceCanonicalName) {
Logger.d(this.toString() + "-->getRemoteService,serviceName:" + serviceCanonicalName);
if (TextUtils.isEmpty(serviceCanonicalName)) {
return null;
}
//獲取binder信息
BinderBean binderBean = RemoteTransfer.getInstance().getRemoteServiceBean(serviceCanonicalName);
//在binder綁定啓動的進程service
String commuStubServiceName = ConnectionManager.getInstance().bindAction(appContext, binderBean.getProcessName());
commuStubServiceNames.add(commuStubServiceName);
return binderBean.getBinder();
}
複製代碼
一開始介紹插入了CommuStubService對象,這裏經過StubServiceMatcher經過進程名來找到啓動的進程的service,而後將binder和service綁定到一塊兒
//這裏不能按照serviceCanonicalName來區分,而是要按照target service來劃分,若是targetService同樣,那就不必再綁定
public synchronized String bindAction(Context context, String serverProcessName) {
Logger.d("ConnectionManager-->bindAction,serverProcessName:" + serverProcessName);
//匹配對應的binder對應的Service(CommuStubService$0)
Intent intent = StubServiceMatcher.matchIntent(context, serverProcessName);
if (null == intent) {
Logger.d("match intent is null");
return null;
}
String commuStubServiceName = getCommuStubServiceName(intent);
ConnectionBean bean = connectionCache.get(commuStubServiceName);
if (null == bean) {
//服務鏈接
ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Logger.d("onServiceConnected,name:" + name.getShortClassName());
}
@Override
public void onServiceDisconnected(ComponentName name) {
Logger.d("onServiceDisconnected,name:" + name.getShortClassName());
}
};
bean = new ConnectionBean(connection);
connectionCache.put(commuStubServiceName, bean);
Logger.d("really start to bind");
//啓動服務
context.bindService(intent, connection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
} else {
bean.increaseRef();
}
return commuStubServiceName;
}
複製代碼
1.經過gradle插件來動態添加配置的四大組件資料
2.經過分發DispatchService服務來管理binder對象
3.經過Parcelable序列化傳輸binder
4.活用IBinder.Stub對象