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方式实现跨进程通讯。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容