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

Android 平台 Binder 机制 简介

程序员文章站 2024-03-23 23:46:46
...

Binder : android 平台的一种IPC机制,在kernel中封装消息规则,在用户空间提供接口对消息规则进一步封装,以达到IPC通信的目的。
Android 平台中的基本组件,Activity,Service,BroadcastReceiver,ContentProvider,都是基于Binder进行IPC通讯。

下面以ContentProvider为例进行说明Binder的通信机制。

Androdid平台一个App可以访问另外一个App中的数据库:


Android 平台 Binder 机制 简介

  • AMS: ActivityManagerService
  • App2: 实现数据库服务的应用
  • App1: 访问数据库的应用
  • Binder驱动:Binder驱动层支持
  • IContentProvider:数据库服务跨进程访问接口

数据库跨进程访问基本流程:

  1. App2启动之后,会将数据库的IContentProvider接口publish到AMS,即BpBinder
  2. App1从AMS中得到数据库的IContentProvider接口,将其封装,保存在本地,即BpBinder
  3. 得到接口之后,就可以通过IContentProvider接口访问App2中的数据,,不必经过AMS

Step 1:App2启动并将数据库publish到AMS

  • 应用启动,install provider:
private void handleBindApplication(AppBindData data) {
    if (!data.restrictedBackupMode) {
                List<ProviderInfo> providers = data.providers;
                if (providers != null) {
                    installContentProviders(app, providers);
                    // For process that contains content providers, we want to
                    // ensure that the JIT is enabled "at some point".
                    mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
                }
            }
}

    private void installContentProviders(
            Context context, List<ProviderInfo> providers) {
        final ArrayList<IActivityManager.ContentProviderHolder> results =
            new ArrayList<IActivityManager.ContentProviderHolder>();

        for (ProviderInfo cpi : providers) {
            if (DEBUG_PROVIDER) {
                StringBuilder buf = new StringBuilder(128);
                buf.append("Pub ");
                buf.append(cpi.authority);
                buf.append(": ");
                buf.append(cpi.name);
                Log.i(TAG, buf.toString());
            }
            IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
            if (cph != null) {
                cph.noReleaseNeeded = true;
                results.add(cph);
            }
        }

        try {
            ActivityManagerNative.getDefault().publishContentProviders(
                getApplicationThread(), results);
        } catch (RemoteException ex) {
        }
    }
  • 将ContentProvider publish到 AMS
    public void publishContentProviders(IApplicationThread caller,
            List<ContentProviderHolder> providers) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeTypedList(providers);
        mRemote.transact(PUBLISH_CONTENT_PROVIDERS_TRANSACTION, data, reply, 0);
        reply.readException();
        data.recycle();
        reply.recycle();
    }

Step 2:App1从AMS中得到数据库的IContentProvider接口

  • 获取数据库接口一般通过如下语句:
ContentResolver resolver = context.getContentResolver();

resolver.query(...);
  • ContentResolver 的实现位于ContextImpl.java ApplicationContentResolver
private static final class ApplicationContentResolver extends ContentResolver {
        @Override
        protected IContentProvider acquireProvider(Context context, String auth) {
            return mMainThread.acquireProvider(context,
                    ContentProvider.getAuthorityWithoutUserId(auth),
                    resolveUserIdFromAuthority(auth), true);
        }
}

  • query 流程中会通过 acquiryProvider 得到 IContentProvider 接口:
    public ContentProviderHolder getContentProvider(IApplicationThread caller,
            String name, int userId, boolean stable) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(name);
        data.writeInt(userId);
        data.writeInt(stable ? 1 : 0);
        mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
        reply.readException();
        int res = reply.readInt();
        ContentProviderHolder cph = null;
        if (res != 0) {
            cph = ContentProviderHolder.CREATOR.createFromParcel(reply);
        }
        data.recycle();
        reply.recycle();
        return cph;
    }

Step 3:得到接口之后,通过IContentProvider接口访问App2中的数据库数据

上面大致说了一下IPC通信的基本流程,具体通过Binder传递Binder对象下面进一步说明。

1、服务端Binder对象
服务端的Binder对象,这里是ContentProvider都是继承自Binder,对java层来说。

class Transport extends ContentProviderNative
abstract public class ContentProviderNative extends Binder implements IContentProvider

可以看到这个ContentProvider中的Transport就是一个Binder。
既然是一个Binder,需要了解一下这个Binder对象的初始化过程:

public class Binder implements IBinder{
    public Binder() {
        init();//这是一个native方法
    }
    private native final void init();
}

native实现
static void android_os_Binder_init(JNIEnv* env, jobject obj)
{
    JavaBBinderHolder* jbh = new JavaBBinderHolder();
    jbh->incStrong((void*)android_os_Binder_init);
    env->SetLongField(obj, gBinderOffsets.mObject, (jlong)jbh);
}

这里的 JavaBBinderHolder 在进行进程间通信的时候或调用get方法,得到一个BBinder:

    sp<JavaBBinder> get(JNIEnv* env, jobject obj)
    {
        AutoMutex _l(mLock);
        sp<JavaBBinder> b = mBinder.promote();
        if (b == NULL) {
            b = new JavaBBinder(env, obj);
            mBinder = b;
            ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%" PRId32 "\n",
                 b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());
        }

        return b;
    }

class JavaBBinder : public BBinder

也就是说,我们说的java层的Binder都有一个Native对应的BBinder。
Binder作为服务端,除非died,否则应该一直等待client发来消息,那么这个Binder是如何实现等待呢?
这就涉及到App启动过程中线程池的开启,App都是zygote进行fork出来的,在初始化的时候会开启线程池:

virtual void onZygoteInit()
{
    sp<ProcessState> proc = ProcessState::self();
    ALOGV("App process: starting thread pool.\n");
    proc->startThreadPool();
}
class PoolThread : public Thread
{
public:
    PoolThread(bool isMain)
        : mIsMain(isMain)
    {
    }

protected:
    virtual bool threadLoop()
    {
        IPCThreadState::self()->joinThreadPool(mIsMain);
        return false;
    }

    const bool mIsMain;
};

void IPCThreadState::joinThreadPool(bool isMain)
{
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
    do {
        result = getAndExecuteCommand();
    } while (result != -ECONNREFUSED && result != -EBADF);
}
status_t IPCThreadState::getAndExecuteCommand()
{
    result = talkWithDriver();
    result = executeCommand(cmd);
}

talkWithDriver会利用系统调用ioctl告诉kernel BC_ENTER_LOOPER,就是说我服务端准备好了。
当收到client的消息之后,就调用onTransact,也就是 JavaBBinder的onTransact

virtual status_t onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
{
        jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
            code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
}

private boolean execTransact(int code, long dataObj, long replyObj,
            int flags) {

    res = onTransact(code, data, reply, flags);
}

就调用到Binder的 onTransact,解析命令,执行对应的函数。
2、Client BpBinder 对象
待续。。。

相关标签: android