欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

360 Replugin Binder实现原理

程序员文章站 2022-04-13 11:30:33
...

     在安卓日常app开发过程中一般自定义Service并实现Binder, 且常用的ActivityManager/WindowManager/TelephonyManager最终都是通过ServiceManager.getService取到IBinder对象。 

       那么是不是离开Service, 就用不了Binder了呢? 在看Replugin源码前, 我是这么认为的。 但Replugin告诉我还有另一种使用方式。

       Replugin有一个核心类ServiceProvider, 实现了ServiceManager的getService功能。 原来Cursor还能传Binder对象。 我们知道Content Provider可以实现跨进程通讯, Replugin就是利用这个特性实现的跨进程拿到IBinder(或本地代理)。

360 Replugin Binder实现原理

 

       打开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参数。

      ServiceProvider的query函数返回的是ServiceChannelCursor对象, 其实就是对sServiceChannelImpl的封装。

    static MatrixCursor sServiceChannelCursor = ServiceChannelCursor.makeCursor(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方式实现跨进程通讯。

    

  

相关标签: Replugin Binder