360 Replugin Binder實現原理
在安卓日常app開發過程中一般自定義Service並實現Binder, 且常用的ActivityManager/WindowManager/TelephonyManager最終都是通過ServiceManager.getService取到IBinder物件。
那麼是不是離開Service, 就用不了Binder了呢? 在看Replugin原始碼前, 我是這麼認為的。 但Replugin告訴我還有另一種使用方式。
Replugin有一個核心類ServiceProvider, 實現了ServiceManager的getService功能。 原來Cursor還能傳Binder物件 。 我們知道Content Provider可以實現跨程序通訊, Replugin就是利用這個特性實現的跨程序拿到IBinder(或本地代理)。

image.png
開啟replugin-host-gradle工程, 可以看到是在宿主編譯時將ServiceProvider的註冊語句新增到AndroidManifest.xml。 程式碼在ComponentsGenerator.groovy。
// ServiceManager 服務框架 provider( "${name}":"com.qihoo360.mobilesafe.svcmanager.ServiceProvider", "${authorities}":"${applicationID}.svcmanager", "${exp}":"false", "${multiprocess}":"false", "${process}":"${pluginMgrProcessName}")
開啟replugin-host-lib工程裡的ServiceProvider.java,只有query函式返回了一個單例的sServiceChannelCursor物件。
public class ServiceProvider extends ContentProvider { private static final boolean DEBUG = BuildConfig.DEBUG; private static final String TAG = "ServerProvider"; public static final String AUTHORITY = IPC.getPackageName() + ".svcmanager"; public static final String PATH_SERVER_CHANNEL = "severchannel"; @Override public boolean onCreate() { if (DEBUG) { Log.d(TAG, "[onCreate]" + " App = " + getContext().getApplicationContext()); } return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { if (DEBUG) { Log.d(TAG, "[query] uri = " + (uri == null ? "null" : uri.toString())); } return ServiceChannelImpl.sServiceChannelCursor; } @Override public String getType(Uri uri) { return null; } @Override public Uri insert(Uri uri, ContentValues values) { return null; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { return 0; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { return 0; } }
在ServiceChannelImpl.java實現了IServiceChannel.Stub, 將引用賦值到sServiceChannelImpl。 Replugin裡的所有Binder的get/add都最終走到這裡, 這個sServiceChannel執行在UI程序或者:GuardService, 依賴於配置ServiceProvider的android:process引數。
static MatrixCursor sServiceChannelCursor = ServiceChannelCursor.makeCursor(sServiceChannelImpl);
ServiceProvider的query函式返回的是ServiceChannelCursor物件, 其實就是對sServiceChannelImpl的封裝。
我們看看ServiceChannelCursor做了什麼事情。
class ServiceChannelCursor extends MatrixCursor { public static final String SERVER_CHANNEL_BUNDLE_KEY = "servicechannel"; /* PACKAGE */static final String[] DEFAULT_COLUMNS = { "s" }; static final ServiceChannelCursor makeCursor(IBinder binder) { return new ServiceChannelCursor(DEFAULT_COLUMNS, binder); } static final IBinder getBinder(Cursor cursor) { Bundle bundle = cursor.getExtras(); //Java多型,執行當前類的getExtra函式體 bundle.setClassLoader(ParcelBinder.class.getClassLoader()); ParcelBinder parcelBinder = bundle.getParcelable(SERVER_CHANNEL_BUNDLE_KEY); return parcelBinder.getIbinder(); } Bundle mBinderExtra = new Bundle(); public ServiceChannelCursor(String[] columnNames, IBinder binder) { super(columnNames); mBinderExtra.putParcelable(SERVER_CHANNEL_BUNDLE_KEY, new ParcelBinder(binder)); //利用cursor可以傳遞Bundle物件的特性,將binder儲存到Bundle中 } @Override public Bundle getExtras() { return mBinderExtra; } }
IBinder的序列化/反序列化是通過自定義類ParcelBinder實現的。
class ParcelBinder implements Parcelable { private final IBinder mBinder; private ParcelBinder(Parcel source) { mBinder = source.readStrongBinder(); } public ParcelBinder(IBinder binder) { this.mBinder = binder; } public IBinder getIbinder() { return mBinder; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeStrongBinder(mBinder); } public static final Parcelable.Creator<ParcelBinder> CREATOR = new Parcelable.Creator<ParcelBinder>() { @Override public ParcelBinder createFromParcel(Parcel source) { return new ParcelBinder(source); } @Override public ParcelBinder[] newArray(int size) { return new ParcelBinder[size]; } }; }
最後, Replugin的QihooServiceManager的作用等同於android.os.ServiceManager, 區別是ServiceManager使用的Binder方式, 而Replugin使用了Content Provider方式實現跨程序通訊。