轉http://blog.csdn.net/yulong0809/article/details/56841993。
最近一直在研究插件化的東西,我看了網上大多都是直接上來就開始講解原理然后寫個demo,這樣對于很多沒有入門的朋友不是很好的理解,下面我會通過自己的研究過程,一步一步循序漸進的將插件化需要的知識點都梳理一遍及講解,其實學習插件化的好處并不全因為它是一門熱門的技術,插件化涉及的知識點很多,可以讓我們對android的理解及境界上都會有一個質的飛躍,在我將所有設計的知識點都大概講一遍后會用一個demo來實現插件化,里面將設計所有講過的知識。
插件化其實就是動態加載,動態加載又包括了代碼加載和資源加載。
插件化最早出現是因為65535問題出現的,用于查分多個dex并動態加載dex來防止65535問題
現在很多公司用插件化來做模塊的動態加載,這樣既能實現web端一樣的隨時更新,還能減少apk包的體積,其實就是加載一個未安裝的apk。
熱修復,熱修復其實也是動態加載原理
換膚,使用動態的資源加載可以實現換膚功能
還可以通過hook系統的一些類做一些你想做的壞事。
任玉剛的:dynamic-load-apk,這個項目使用的是一種代理的方式去實現?
https://github.com/singwhatiwanna/dynamic-load-apk
360的:DroidPlugin,這個項目是通過hook系統類來實現?
https://github.com/Qihoo360/DroidPlugin
阿里的:andfix,用于對方法的修復,可以立即生效,不支持資源及類替換?
https://github.com/alibaba/AndFix
騰訊的:tinker,除了不支持立即生效,全部支持
https://github.com/Tencent/tinker
美團的:robust,不開源
代碼的加載,就是使用ClassLoader加載代碼
資源的加載,使用AssetManager的隱藏方法,addAsssetPath方法加入一個資源路徑來獲取這個資源的Resource資源
還有一個問題就是對四大組件的生命周期管理
在了解插件化之前首先需要了解及掌握的知識點?
一、Binder機制?
二、代理模式,?
三、反射?
四、類加載及dex加載?
五、應用啟動過程及類加載過程?
Binder機制:
其實Binder看你怎么去理解,如果從代碼角度的話他是一個類,如果從硬件角度的話他是一個驅動,如果從IPC角度的話他是一種通信機制,是framework層的各種ServiceManager的鏈接橋梁,?
我們知道我們平時使用的系統服務對象其實都是系統的,他們存在的進程和我們的應用并不在一個進程中,但是為什么我們能直接使用呢?其實就是因為Binder的存在,跨進程通信,再說大白話一點就是使用了我們經常說的aidl,Binder很復雜,這里只是為了插件化做鋪墊,想深入理解請自行查閱資料。
進程間通信過程
1.首先客戶端要鏈接服務端
2.然后服務端會返回一個客戶端的對象(代理對象)
3.然后客戶端使用這個代理對象其中的方法時,系統會先調用服務端的方法,然后將運算的結果返回給客戶端(要知道其實并不是用了這個對象的方法,而是去服務端里運算,然后在返回給客戶端的)
我們通過自己寫一個aidl,然后和系統的源碼進行對比
//我們自己寫的aidl的接口
//IMyAidlInterface.aidl
package com.huanju.chajianhuatest;
import com.huanju.chajianhuatest.aidlmode.TestBean;
interface IMyAidlInterface {
? ? /**
? ? * Demonstrates some basic types that you can use as parameters
? ? * and return values in AIDL.
? ? */
? ? void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
? ? ? ? ? ? double aDouble, String aString);
? ? String getS(in TestBean s);
? ? TestBean getInfoBean(out TestBean b);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
系統會幫我們自動創建一個IMyAidlInterface.java的文件,我們去看看
>
package com.huanju.chajianhuatest;
public interface IMyAidlInterface extends android.os.IInterface {
? ? public static abstract class Stub extends android.os.Binder implements com.huanju.chajianhuatest.IMyAidlInterface {
? ? ? ? private static final java.lang.String DESCRIPTOR = "com.huanju.chajianhuatest.IMyAidlInterface";
? ? ? ? public Stub() {
? ? ? ? ? ? this.attachInterface(this, DESCRIPTOR);
? ? ? ? }
? ? ? ? public static com.huanju.chajianhuatest.IMyAidlInterface asInterface(android.os.IBinder obj) {
? ? ? ? ? ? if ((obj == null)) {
? ? ? ? ? ? ? ? return null;
? ? ? ? ? ? }
? ? ? ? ? ? android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
? ? ? ? ? ? if (((iin != null) && (iin instanceof com.huanju.chajianhuatest.IMyAidlInterface))) {
? ? ? ? ? ? ? ? return ((com.huanju.chajianhuatest.IMyAidlInterface) iin);
? ? ? ? ? ? }
? ? ? ? ? ? return new com.huanju.chajianhuatest.IMyAidlInterface.Stub.Proxy(obj);
? ? ? ? }
? ? ? ? @Override
? ? ? ? public android.os.IBinder asBinder() {
? ? ? ? ? ? return this;
? ? ? ? }
? ? ? ? @Override
? ? ? ? public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
? ? ? ? ? ? switch (code) {
? ? ? ? ? ? ? ? case INTERFACE_TRANSACTION: {
? ? ? ? ? ? ? ? ? ? reply.writeString(DESCRIPTOR);
? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? case TRANSACTION_basicTypes: {
? ? ? ? ? ? ? ? ? ? data.enforceInterface(DESCRIPTOR);
? ? ? ? ? ? ? ? ? ? int _arg0;
? ? ? ? ? ? ? ? ? ? _arg0 = data.readInt();
? ? ? ? ? ? ? ? ? ? long _arg1;
? ? ? ? ? ? ? ? ? ? _arg1 = data.readLong();
? ? ? ? ? ? ? ? ? ? boolean _arg2;
? ? ? ? ? ? ? ? ? ? _arg2 = (0 != data.readInt());
? ? ? ? ? ? ? ? ? ? float _arg3;
? ? ? ? ? ? ? ? ? ? _arg3 = data.readFloat();
? ? ? ? ? ? ? ? ? ? double _arg4;
? ? ? ? ? ? ? ? ? ? _arg4 = data.readDouble();
? ? ? ? ? ? ? ? ? ? java.lang.String _arg5;
? ? ? ? ? ? ? ? ? ? _arg5 = data.readString();
? ? ? ? ? ? ? ? ? ? this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
? ? ? ? ? ? ? ? ? ? reply.writeNoException();
? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? case TRANSACTION_getS: {
? ? ? ? ? ? ? ? ? ? data.enforceInterface(DESCRIPTOR);
? ? ? ? ? ? ? ? ? ? com.huanju.chajianhuatest.aidlmode.TestBean _arg0;
? ? ? ? ? ? ? ? ? ? if ((0 != data.readInt())) {
? ? ? ? ? ? ? ? ? ? ? ? _arg0 = com.huanju.chajianhuatest.aidlmode.TestBean.CREATOR.createFromParcel(data);
? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? _arg0 = null;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? java.lang.String _result = this.getS(_arg0);
? ? ? ? ? ? ? ? ? ? reply.writeNoException();
? ? ? ? ? ? ? ? ? ? reply.writeString(_result);
? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? case TRANSACTION_getInfoBean: {
? ? ? ? ? ? ? ? ? ? data.enforceInterface(DESCRIPTOR);
? ? ? ? ? ? ? ? ? ? com.huanju.chajianhuatest.aidlmode.TestBean _arg0;
? ? ? ? ? ? ? ? ? ? _arg0 = new com.huanju.chajianhuatest.aidlmode.TestBean();
? ? ? ? ? ? ? ? ? ? com.huanju.chajianhuatest.aidlmode.TestBean _result = this.getInfoBean(_arg0);
? ? ? ? ? ? ? ? ? ? reply.writeNoException();
? ? ? ? ? ? ? ? ? ? if ((_result != null)) {
? ? ? ? ? ? ? ? ? ? ? ? reply.writeInt(1);
? ? ? ? ? ? ? ? ? ? ? ? _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? reply.writeInt(0);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? if ((_arg0 != null)) {
? ? ? ? ? ? ? ? ? ? ? ? reply.writeInt(1);
? ? ? ? ? ? ? ? ? ? ? ? _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? reply.writeInt(0);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? return super.onTransact(code, data, reply, flags);
? ? ? ? }
? ? ? ? private static class Proxy implements com.huanju.chajianhuatest.IMyAidlInterface {
? ? ? ? ? ? private android.os.IBinder mRemote;
? ? ? ? ? ? Proxy(android.os.IBinder remote) {
? ? ? ? ? ? ? ? mRemote = remote;
? ? ? ? ? ? }
? ? ? ? ? ? @Override
? ? ? ? ? ? public android.os.IBinder asBinder() {
? ? ? ? ? ? ? ? return mRemote;
? ? ? ? ? ? }
? ? ? ? ? ? public java.lang.String getInterfaceDescriptor() {
? ? ? ? ? ? ? ? return DESCRIPTOR;
? ? ? ? ? ? }
? ? ? ? ? ? @Override
? ? ? ? ? ? public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
? ? ? ? ? ? ? ? android.os.Parcel _data = android.os.Parcel.obtain();
? ? ? ? ? ? ? ? android.os.Parcel _reply = android.os.Parcel.obtain();
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? _data.writeInterfaceToken(DESCRIPTOR);
? ? ? ? ? ? ? ? ? ? _data.writeInt(anInt);
? ? ? ? ? ? ? ? ? ? _data.writeLong(aLong);
? ? ? ? ? ? ? ? ? ? _data.writeInt(((aBoolean) ? (1) : (0)));
? ? ? ? ? ? ? ? ? ? _data.writeFloat(aFloat);
? ? ? ? ? ? ? ? ? ? _data.writeDouble(aDouble);
? ? ? ? ? ? ? ? ? ? _data.writeString(aString);
? ? ? ? ? ? ? ? ? ? mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
? ? ? ? ? ? ? ? ? ? _reply.readException();
? ? ? ? ? ? ? ? } finally {
? ? ? ? ? ? ? ? ? ? _reply.recycle();
? ? ? ? ? ? ? ? ? ? _data.recycle();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? @Override
? ? ? ? ? ? public java.lang.String getS(com.huanju.chajianhuatest.aidlmode.TestBean s) throws android.os.RemoteException {
? ? ? ? ? ? ? ? android.os.Parcel _data = android.os.Parcel.obtain();
? ? ? ? ? ? ? ? android.os.Parcel _reply = android.os.Parcel.obtain();
? ? ? ? ? ? ? ? java.lang.String _result;
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? _data.writeInterfaceToken(DESCRIPTOR);
? ? ? ? ? ? ? ? ? ? if ((s != null)) {
? ? ? ? ? ? ? ? ? ? ? ? _data.writeInt(1);
? ? ? ? ? ? ? ? ? ? ? ? s.writeToParcel(_data, 0);
? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? _data.writeInt(0);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? mRemote.transact(Stub.TRANSACTION_getS, _data, _reply, 0);
? ? ? ? ? ? ? ? ? ? _reply.readException();
? ? ? ? ? ? ? ? ? ? _result = _reply.readString();
? ? ? ? ? ? ? ? } finally {
? ? ? ? ? ? ? ? ? ? _reply.recycle();
? ? ? ? ? ? ? ? ? ? _data.recycle();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return _result;
? ? ? ? ? ? }
? ? ? ? ? ? @Override
? ? ? ? ? ? public com.huanju.chajianhuatest.aidlmode.TestBean getInfoBean(com.huanju.chajianhuatest.aidlmode.TestBean b) throws android.os.RemoteException {
? ? ? ? ? ? ? ? android.os.Parcel _data = android.os.Parcel.obtain();
? ? ? ? ? ? ? ? android.os.Parcel _reply = android.os.Parcel.obtain();
? ? ? ? ? ? ? ? com.huanju.chajianhuatest.aidlmode.TestBean _result;
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? _data.writeInterfaceToken(DESCRIPTOR);
? ? ? ? ? ? ? ? ? ? mRemote.transact(Stub.TRANSACTION_getInfoBean, _data, _reply, 0);
? ? ? ? ? ? ? ? ? ? _reply.readException();
? ? ? ? ? ? ? ? ? ? if ((0 != _reply.readInt())) {
? ? ? ? ? ? ? ? ? ? ? ? _result = com.huanju.chajianhuatest.aidlmode.TestBean.CREATOR.createFromParcel(_reply);
? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? _result = null;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? if ((0 != _reply.readInt())) {
? ? ? ? ? ? ? ? ? ? ? ? b.readFromParcel(_reply);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? } finally {
? ? ? ? ? ? ? ? ? ? _reply.recycle();
? ? ? ? ? ? ? ? ? ? _data.recycle();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return _result;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
? ? ? ? static final int TRANSACTION_getS = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
? ? ? ? static final int TRANSACTION_getInfoBean = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
? ? }
? ? public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
? ? public java.lang.String getS(com.huanju.chajianhuatest.aidlmode.TestBean s) throws android.os.RemoteException;
? ? public com.huanju.chajianhuatest.aidlmode.TestBean getInfoBean(com.huanju.chajianhuatest.aidlmode.TestBean b) throws android.os.RemoteException;
}
看著代碼好像很多,但是其實沒什么,我們分析一下結構
1.我們根據上面的代碼,創建的類繼承了IInterface接口
2.內部類Stub繼承Binder
3.看asInterface方法,判斷如果不是一個進程會返回代理類
4.每個方法都對應一個id,用于在跨進程訪問時確定訪問的是哪個方法,通過transact方法再調用服務端的onTransact方法
我們再看一下系統的類,就看我們最熟悉的ActivityManager,要知道ActivityManager其實是ActivityManagerService在我們進程中的一個代理包裝類,他內部全部使用 ActivityManagerNative.getDefault()去進程操作,那么我么直接看 ActivityManagerNative的部分代碼
1.asInterface
? ? /** {@hide} */
public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
? ? /**
? ? * Cast a Binder object into an activity manager interface, generating
? ? * a proxy if needed.
? ? */
? ? static public IActivityManager asInterface(IBinder obj) {
? ? ? ? if (obj == null) {
? ? ? ? ? ? return null;
? ? ? ? }
? ? ? ? IActivityManager in =
? ? ? ? ? ? (IActivityManager)obj.queryLocalInterface(descriptor);
? ? ? ? if (in != null) {
? ? ? ? ? ? return in;
? ? ? ? }
? ? ? ? return new ActivityManagerProxy(obj);
? ? }
2.onTransact
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
? ? ? ? throws RemoteException {
? ? switch (code) {
? ? case START_ACTIVITY_TRANSACTION:
? ? {
? ? ? ? data.enforceInterface(IActivityManager.descriptor);
? ? ? ? IBinder b = data.readStrongBinder();
? ? ? ? IApplicationThread app = ApplicationThreadNative.asInterface(b);
? ? ? ? String callingPackage = data.readString();
? ? ? ? Intent intent = Intent.CREATOR.createFromParcel(data);
? ? ? ? String resolvedType = data.readString();
? ? ? ? IBinder resultTo = data.readStrongBinder();
? ? ? ? String resultWho = data.readString();
? ? ? ? int requestCode = data.readInt();
? ? ? ? int startFlags = data.readInt();
? ? ? ? ProfilerInfo profilerInfo = data.readInt() != 0
? ? ? ? ? ? ? ? ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
? ? ? ? Bundle options = data.readInt() != 0
? ? ? ? ? ? ? ? ? Bundle.CREATOR.createFromParcel(data) : null;
? ? ? ? int result = startActivity(app, callingPackage, intent, resolvedType,
? ? ? ? ? ? ? ? resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
? ? ? ? reply.writeNoException();
? ? ? ? reply.writeInt(result);
? ? ? ? return true;
? ? }
代碼太多我們就看這兩個就好了,有沒有感覺很熟悉,和我們自己寫的aidl幾乎沒有區別,他雖然叫做ActivityManagerNative,其實他就是我們自己寫的aidl里的內部類Stub。
下面我們分析一下aidl的運行過程
我們直接看如果是遠程的話返回了代理對象,我們看代理對象的方法,這個方法就是aidl結果定義的方法,看他怎么實現的?
>
@Override
? ? ? ? public com.huanju.chajianhuatest.aidlmode.TestBean getInfoBean(com.huanju.chajianhuatest.aidlmode.TestBean b) throws android.os.RemoteException {
? ? ? ? ? ? android.os.Parcel _data = android.os.Parcel.obtain();
? ? ? ? ? ? android.os.Parcel _reply = android.os.Parcel.obtain();
? ? ? ? ? ? com.huanju.chajianhuatest.aidlmode.TestBean _result;
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? _data.writeInterfaceToken(DESCRIPTOR);
? ? ? ? ? ? ? ? mRemote.transact(Stub.TRANSACTION_getInfoBean, _data, _reply, 0);
? ? ? ? ? ? ? ? _reply.readException();
? ? ? ? ? ? ? ? if ((0 != _reply.readInt())) {
? ? ? ? ? ? ? ? ? ? _result = com.huanju.chajianhuatest.aidlmode.TestBean.CREATOR.createFromParcel(_reply);
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? _result = null;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if ((0 != _reply.readInt())) {
? ? ? ? ? ? ? ? ? ? b.readFromParcel(_reply);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? } finally {
? ? ? ? ? ? ? ? _reply.recycle();
? ? ? ? ? ? ? ? _data.recycle();
? ? ? ? ? ? }
? ? ? ? ? ? return _result;
? ? ? ? }
? ? }
客戶端發起請求
1.首先創建輸出類型data
2.創建接受類型reply
3.創建需要的參數
4.將參數寫入data中
5.發起遠程調用,當前線程掛起調用mRemote.transact()方法,這個方法的實現在Binder中,他會調用服務端的onTransact方法,直到有返回結果
6.從_result中取回返回結果_result
服務端接到請求會走到onTransact方法,這個方法運行在服務端的Binder線程池中,我們再看看怎么實現的
>
? case TRANSACTION_getInfoBean: {
? ? ? ? ? ? ? ? data.enforceInterface(DESCRIPTOR);
? ? ? ? ? ? ? ? com.huanju.chajianhuatest.aidlmode.TestBean _arg0;
? ? ? ? ? ? ? ? _arg0 = new com.huanju.chajianhuatest.aidlmode.TestBean();
? ? ? ? ? ? ? ? com.huanju.chajianhuatest.aidlmode.TestBean _result = this.getInfoBean(_arg0);
? ? ? ? ? ? ? ? reply.writeNoException();
? ? ? ? ? ? ? ? if ((_result != null)) {
? ? ? ? ? ? ? ? ? ? reply.writeInt(1);
? ? ? ? ? ? ? ? ? ? _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? reply.writeInt(0);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if ((_arg0 != null)) {
? ? ? ? ? ? ? ? ? ? reply.writeInt(1);
? ? ? ? ? ? ? ? ? ? _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? reply.writeInt(0);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? }
1.通過id確定訪問哪個方法
2.然后從目標參數data取出需要的參數
3.然后調用請求的相應方法
4.將返回值寫入reply
5.返回true,這里需要說一下,如果返回false,代表客戶端訪問失敗,我們實際當中可根據這個特性來做遠程的校檢,畢竟我們的遠程方法并是不想讓任何人都可以訪問的。?
,通過id確定訪問哪個方法,然后從目標參數data取出需要的參數,然后調用相應方法,將返回值寫入reply,
好了,到這里Binder的通信過程就完了,其實我們看到了只要我們理解了我們自己寫的aidl的流程及原理,那么系統層的通信也是這樣的。下一篇我們繼續說代理模式及反射。