• 深入理解任何Binder Client都可以直接通过ServiceManager的0这个Binder句柄创建一个BpBinde


    ServiceManager是安卓中一个重要的类,用于管理所有的系统服务,维护着系统服务和客户端的binder通信。
    对此陌生的可以先看系统服务与ServiceManager来了解应用层是如何使用ServiceManager的。
    我们可以通过 ServiceManager.getService(String name)来获取服务,返回的是一个Binder对象,用于与系统做远程通信

    public static IBinder getService(String name) {
        try {
             IBinder service = sCache.get(name);
             if (service != null) {
                 return service;
             } else {
                 return getIServiceManager().getService(name);
             }
        } catch (RemoteException e) {
             Log.e(TAG, "error in getService", e);
        }
        return null;
    }

    这里的sCache是一个Map,如果cache中有这个Binder对象就直接返回了,如果没有就调用getIServiceManager().getService(name)来获取

    private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
        return sServiceManager;
        }
    
        // Find the service manager
        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
    }

    可以看到这里返回了一个IServiceManager,它也是一个Binder对象,最终获取服务用的就是这个Binder对象。
    并且是通过BinderInternal.getContextObject()来拿到Binder对象的。

    /**
    * Return the global "context object" of the system. This is usually
    * an implementation of IServiceManager, which you can use to find
    * other services.
    */
    public static final native IBinder getContextObject();

    它实现在frameworks/base/core/jni/android_util_Binder.cpp文件中:

    static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
    {
        sp b = ProcessState::self()->getContextObject(NULL);
        return javaObjectForIBinder(env, b);
    }

    这里应该不难理解,先获取一个native层的IBinder,再将该对象转换成Java Object返回给调用者,在Java层拿到的应该是一个ServiceManagerProxy对象。
    先看第一部获取native层的IBinder对象:

    sp b = ProcessState::self()->getContextObject(NULL);

    在ProcessState的构造函数中,会通过open文件操作函数打开设备文件/dev/binder,并且返回来的设备文件描述符保存在成员变量mDriverFD中,供后续在IPCThreadState中使用
    需要注意的是这里传了一个NULL,也就是0,下面会提到它的作用:
    [ProcessState.cpp]

    sp ProcessState::getContextObject(const sp& /*caller*/)
    {
        return getStrongProxyForHandle(0);
    }
    
    sp ProcessState::getStrongProxyForHandle(int32_t handle)
    {
        sp result;
    
        AutoMutex _l(mLock);
    
        handle_entry* e = lookupHandleLocked(handle);
    
        if (e != NULL) {
            IBinder* b = e->binder;
            if (b == NULL || !e->refs->attemptIncWeak(this)) {
                if (handle == 0) {
                    Parcel data;
                    status_t status = IPCThreadState::self()->transact(
                            0, IBinder::PING_TRANSACTION, data, NULL, 0);
                    if (status == DEAD_OBJECT)
                       return NULL;
                }
    
                b = new BpBinder(handle); 
                e->binder = b;
                if (b) e->refs = b->getWeakRefs();
                result = b;
            } else {
                // This little bit of nastyness is to allow us to add a primary
                // reference to the remote proxy when this team doesn't have one
                // but another team is sending the handle to us.
                result.force_set(b);
                e->refs->decWeak(this);
            }
        }
    
        return result;
    }

    可以看到,最终返回的对象是:b = new BpBinder(handle); 并将handler传了进去
    这里的handler即是之前传进来的0,代表一个句柄,这个句柄是有特殊意义的。
    我们知道在Java层有两类Binder,一个是Binder对象用于服务端建立的对象,一个是BinderProxy是客户端取到的Binder对象。
    native层也有两类Binder,一个是BpBinder,一个是BBinder:
    BpBinder是客户端用来与Server交互的代理类,p即Proxy的意思,
    BBinder则是proxy交互的目的端,
    并且他们是一一对应的。
    继续回到代码,创建了一个BpBinder对象,传进去的hande为0,那么他是怎么找到对应的BBinder的呢?
    事实上,handle代表了通信的目的端,这个0代表的就是ServiceManager所对应的BBinder。
    继续往下看,通过上面获取的对象创建一个Java层的Binder对象并返回:
    [android_util_Binder.cpp]

    return javaObjectForIBinder(env, b)

    继续看创建Java层对象的过程:
    [android_util_Binder.cpp]

    jobject javaObjectForIBinder(JNIEnv* env, const sp& val)
    {
        if (val == NULL) return NULL;
    
        if (val->checkSubclass(&gBinderOffsets)) {
            // One of our own!
            jobject object = static_cast<JavaBBinder*>(val.get())->object();
            LOGDEATH("objectForBinder {936b63963a8c9f2b24063da536a495a32039ff9ed9d82cacc18dd4741407c351}p: it's our own {936b63963a8c9f2b24063da536a495a32039ff9ed9d82cacc18dd4741407c351}p!
    ", val.get(), object);
            return object;
        }
    
        // For the rest of the function we will hold this lock, to serialize
        // looking/creation/destruction of Java proxies for native Binder proxies.
        AutoMutex _l(mProxyLock);
    
        // Someone else's...  do we know about it?
        jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
        if (object != NULL) {
            jobject res = jniGetReferent(env, object);
            if (res != NULL) {
                ALOGV("objectForBinder {936b63963a8c9f2b24063da536a495a32039ff9ed9d82cacc18dd4741407c351}p: found existing {936b63963a8c9f2b24063da536a495a32039ff9ed9d82cacc18dd4741407c351}p!
    ", val.get(), res);
                return res;
            }
            LOGDEATH("Proxy object {936b63963a8c9f2b24063da536a495a32039ff9ed9d82cacc18dd4741407c351}p of IBinder {936b63963a8c9f2b24063da536a495a32039ff9ed9d82cacc18dd4741407c351}p no longer in working set!!!", object, val.get());
            android_atomic_dec(&gNumProxyRefs);
            val->detachObject(&gBinderProxyOffsets);
            env->DeleteGlobalRef(object);
        }
    
        object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
        if (object != NULL) {
            LOGDEATH("objectForBinder {936b63963a8c9f2b24063da536a495a32039ff9ed9d82cacc18dd4741407c351}p: created new proxy {936b63963a8c9f2b24063da536a495a32039ff9ed9d82cacc18dd4741407c351}p !
    ", val.get(), object);
            // The proxy holds a reference to the native object.
            env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
            val->incStrong((void*)javaObjectForIBinder);
    
            // The native object needs to hold a weak reference back to the
            // proxy, so we can retrieve the same proxy if it is still active.
            jobject refObject = env->NewGlobalRef(
                    env->GetObjectField(object, gBinderProxyOffsets.mSelf));
            val->attachObject(&gBinderProxyOffsets, refObject,
                    jnienv_to_javavm(env), proxy_cleanup);
    
            // Also remember the death recipients registered on this proxy
            sp drl = new DeathRecipientList;
            drl->incStrong((void*)javaObjectForIBinder);
            env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast(drl.get()));
    
            // Note that a new object reference has been created.
            android_atomic_inc(&gNumProxyRefs);
            incRefsCreated(env);
        }
    
        return object;
    }

    可以看到有两处返回语句,跳过第一处取缓存对象,直接往下看:

    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);

    这里创建了一个BinderProxy对象,这时候这个对象与Native层用于通信的BpBinder没有任何关系,继续往下看:

    env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());

    这里是把BpBinder对象的地址赋值给了BinderProxy对象的mObject字段,通过这种手段将Java层的对象与Native层的对象关联在了一起。
    然后我们操作Java层BinderProxy对象的native方法的时候,就能定位到对应的BpBinder对象了。
    并且把这个Java层的对象放到了BpBinder对象中,之后就不用再次创建了:

    jobject refObject = env->NewGlobalRef(
            env->GetObjectField(object, gBinderProxyOffsets.mSelf));
    val->attachObject(&gBinderProxyOffsets, refObject,
          jnienv_to_javavm(env), proxy_cleanup);

    回到Java层代码,我们通过下面代码来获取一个可以调用的ServiceManager对象:

    sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());

    看过Android IPC 机制的应该知道,这里返回的是一个ServiceManagerProxy对象,里面持有一个名为面Remote的IBiner对象,从上面可以看到这个mRemote就是之前拿到的BinderProxy,真正进行进程间通信的时候会调用BinderProxy的transact方法,然后在它的内部调用transactNative方法。

    再次来到native层,调用如下方法:
    [android_util_Binder.cpp]

    static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
            jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
    {
        //...
    
        IBinder* target = (IBinder*)
            env->GetLongField(obj, gBinderProxyOffsets.mObject);
        if (target == NULL) {
            jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");
            return JNI_FALSE;
        }
        bool time_binder_calls;
        int64_t start_millis;
        if (kEnableBinderSample) {
            time_binder_calls = should_time_binder_calls();
            if (time_binder_calls) {
                start_millis = uptimeMillis();
            }
        }
        status_t err = target->transact(code, *data, reply, flags);
        if (kEnableBinderSample) {
            if (time_binder_calls) {
                conditionally_log_binder_call(start_millis, target, code);
            }
        }
        if (err == NO_ERROR) {
            return JNI_TRUE;
        } else if (err == UNKNOWN_TRANSACTION) {
            return JNI_FALSE;
        }
        signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/, data->dataSize());
        return JNI_FALSE;
    }

    为什么是这个方法呢?这里在简单的书一下jni,有静态注册和动态注册两种方法,这里用的是动态注册,会用到如下定义:

    static const JNINativeMethod gBinderProxyMethods[] = {
         /* name, signature, funcPtr */
        {"pingBinder",          "()Z", (void*)android_os_BinderProxy_pingBinder},
        {"isBinderAlive",       "()Z", (void*)android_os_BinderProxy_isBinderAlive},
        {"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor},
        {"transactNative",      "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
        {"linkToDeath",         "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
        {"unlinkToDeath",       "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
        {"destroy",             "()V", (void*)android_os_BinderProxy_destroy},
    };

    包括Java层方法名,方法签名,调用的函数指针。
    这里不过多展开了,继续:

    IBinder* target = (IBinder*)env->GetLongField(obj, gBinderProxyOffsets.mObject);

    可以看到这里用到了之前保存在BinderProxy中的的mObject字段,拿到了原始的BpBinder对象。
    然后调用BpBinder对象的transact方法:

    status_t err = target->transact(code, *data, reply, flags);

    下面看BpBinder的transact方法:
    [BpBinder.cpp]

    tatus_t BpBinder::transact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    {
        // Once a binder has died, it will never come back to life.
        if (mAlive) {
            status_t status = IPCThreadState::self()->transact(
                mHandle, code, data, reply, flags);
            if (status == DEAD_OBJECT) mAlive = 0;
            return status;
        }
    
        return DEAD_OBJECT;
    }

    BpBinder只是一个转发工具,最终由IPCThreadState执行:

    status_t status = IPCThreadState::self()->transact(mHandle, code, data, reply, flags);

    并且带上了代表BBinder对象的mHandle。
    [IPCThreadState.cpp]

    status_t IPCThreadState::transact(int32_t handle,uint32_t code, const Parcel& data,Parcel* reply, uint32_t flags)
    {
        status_t err = data.errorCheck();
        flags |= TF_ACCEPT_FDS;
        if (err == NO_ERROR) {
            LOG_ONEWAY(">>>> SEND from pid {936b63963a8c9f2b24063da536a495a32039ff9ed9d82cacc18dd4741407c351}d uid {936b63963a8c9f2b24063da536a495a32039ff9ed9d82cacc18dd4741407c351}d {936b63963a8c9f2b24063da536a495a32039ff9ed9d82cacc18dd4741407c351}s", getpid(), getuid(),
                (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
            err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
        }
        if (err != NO_ERROR) {
            if (reply) reply->setError(err);
            return (mLastError = err);
        }
        if ((flags & TF_ONE_WAY) == 0) {
            #if 0
            if (code == 4) { // relayout
                ALOGI(">>>>>> CALLING transaction 4");
            } else {
                ALOGI(">>>>>> CALLING transaction {936b63963a8c9f2b24063da536a495a32039ff9ed9d82cacc18dd4741407c351}d", code);
            }
            #endif
            if (reply) {
                err = waitForResponse(reply);
            } else {
                Parcel fakeReply;
                err = waitForResponse(&fakeReply);
            }
            #if 0
            if (code == 4) { // relayout
                ALOGI("<<<<<< RETURNING transaction 4");
            } else {
                ALOGI("<<<<<< RETURNING transaction {936b63963a8c9f2b24063da536a495a32039ff9ed9d82cacc18dd4741407c351}d", code);
            }
            #endif
            
            IF_LOG_TRANSACTIONS() {
                TextOutput::Bundle _b(alog);
                alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
                    << handle << ": ";
                if (reply) alog << indent << *reply << dedent << endl;
                else alog << "(none requested)" << endl;
            }
        } else {
            err = waitForResponse(NULL, NULL);
        }
        
        return err;
    }

    有两个方法调用需要关注:

    err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    err = waitForResponse(NULL, NULL);

    一个是写数据,一个是等待相应。在此之前假设我们知道:
    每个线程都有一个IPCThreadState,每个IPCThreadState中都有一个mIn、一个mOut,其中mIn是用来接收来自Binder设备的数据的,而mOut则是用来存储发往Binder设备的数据的。
    先看写数据:

    status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
        int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
    {
        binder_transaction_data tr;
    
        tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
        tr.target.handle = handle;
        tr.code = code;
        tr.flags = binderFlags;
        tr.cookie = 0;
        tr.sender_pid = 0;
        tr.sender_euid = 0;
        const status_t err = data.errorCheck();
        if (err == NO_ERROR) {
            tr.data_size = data.ipcDataSize();
            tr.data.ptr.buffer = data.ipcData();
            tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
            tr.data.ptr.offsets = data.ipcObjects();
        } else if (statusBuffer) {
            tr.flags |= TF_STATUS_CODE;
            *statusBuffer = err;
            tr.data_size = sizeof(status_t);
            tr.data.ptr.buffer = reinterpret_cast(statusBuffer);
            tr.offsets_size = 0;
            tr.data.ptr.offsets = 0;
        } else {
            return (mLastError = err);
        }
        
        mOut.writeInt32(cmd);
        mOut.write(&tr, sizeof(tr));
        
        return NO_ERROR;
    }

    特别注意这里:tr.target.handle = handle;通信的目标值是handle,也就是之前传的0;最后写入到mOut中;
    真正执行在waitForResponse方法中,这个方法是一个死循环,一直在读取mIn的数据,最后会根据code进行分发,调用executeCommand方法,
    在executeCommand方法内部获取BBinder调用transact:

    error = reinterpret_cast(tr.cookie)->transact(tr.code, buffer,&reply, tr.flags);

    这里的mIn与mOut便是真正的进程间通信,可以查看IPCThreadState::talkWithDriver方法与Binder驱动通信,使用ioctl方式的方式读写/dev/binder虚拟设备。
    关于Binder的深入分析,下次有机会再分享。
    那么ServiceManager的服务是如何注册的呢?
    在native层可以通过下面代码获取IServiceManager:

    spsm = defaultServiceManager()

     然后各个服务模块会通过IServiceManager的addService方法将各自的模块注册到系统这个唯一的ServiceManager中
    [IServiceManager.cpp]

    sp defaultServiceManager()
    {
        if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
        {
            AutoMutex _l(gDefaultServiceManagerLock);
            while (gDefaultServiceManager == NULL) {
                gDefaultServiceManager = interface_cast(
                    ProcessState::self()->getContextObject(NULL));
                if (gDefaultServiceManager == NULL)
                    sleep(1);
            }
        }
        return gDefaultServiceManager;
    }

    可以看到这个是单例,通过下面代码初始化:

    gDefaultServiceManager = interface_cast(ProcessState::self()->getContextObject(NULL));

    PocessState::self()->getContextObject(NULL)这个之前分析过了获取的是ServiceManager的BpBinder对象,
    然后转换成BpServiceManager对象供其他服务模块使用,这里用到了模板函数和宏定义最终返回的是 new BpServiceManager(ProcessState::self()->getContextObject(NULL))。

  • 相关阅读:
    ole辅助类sqlhelperaccess
    Asp.net中常用的26个性能优化方法
    MVP模式的相关知识
    ASP.NET AJAX入门系列
    非常实用]Asp.net常用的51个代码
    一步一步学Silverlight 系列文章
    .NET设计模式系列文章
    Asp.net添加上传进度条
    asp.net 用ajax实现文件上传
    增加弹出层的拖拽功能
  • 原文地址:https://www.cnblogs.com/mingfeng002/p/11499077.html
Copyright © 2020-2023  润新知