由淺入深 學習 Android Binder(三)- java binder深究(從java到native)

許佳佳233發表於2020-12-06

概述

前文地址:由淺入深 學習 Android Binder(二)- bindService流程

前文講到bindService流程,其中多次碰到用binder實現的IPC,有以下幾個:

  1. client程式 通過IPC 通知AMS程式去bindService
  2. AMS程式 通過IPC 通知server程式去bindService
  3. server程式 通過IPC 通知AMS程式bindService結果
  4. AMS程式 通過IPC 告訴client程式bindService結果

本文就選擇”client通知AMS程式“的過程繼續作深入,來探究下java層的binder究竟是什麼。(附上前文流程圖)

在這裡插入圖片描述

ContextImpl.bindServiceCommon()

client程式 通知IPC 去bindService,最終會走到ContextImpl. bindServiceCommon().

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
        IServiceConnection sd;
        if (conn == null) {
            throw new IllegalArgumentException("connection is null");
        }
        if (mPackageInfo != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        validateServiceIntent(service);
        try {
            IBinder token = getActivityToken();
            if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
                    && mPackageInfo.getApplicationInfo().targetSdkVersion
                    < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                flags |= BIND_WAIVE_PRIORITY;
            }
            service.prepareToLeaveProcess(this);
            int res = ActivityManager.getService().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
            if (res < 0) {
                throw new SecurityException(
                        "Not allowed to bind to service " + service);
            }
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

我們只需要關注其中一行程式碼即可。

            int res = ActivityManager.getService().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());

接著看下ActivityManager.getService()的邏輯:

ActivityManager.getService()

    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };

程式碼看到這,就可以確定是使用binder來實現的IPC了。ActivityManager.getService()實際返回的是IActivityManager。
又因為原始碼中只有ActivityManagerService實現了IActivityManager.Stub,因此,此處可以確定返回的是ActivityManagerService物件。

此處繼續深入,看下這個IActivityManager物件究竟是從哪裡獲取到的。
於是我們看下ServiceManager.getService()邏輯。

ServiceManager.getService()

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

這裡的邏輯是,先去快取中獲取,如果快取中沒有就返回rawGetService()。

既然是深究,那麼此處快取的邏輯也可以暫且不用看了。
直接進入到rawGetService().

ServiceManager.rawGetService()

    private static IBinder rawGetService(String name) throws RemoteException {
——————————————————省略
        final IBinder binder = getIServiceManager().getService(name);
        
——————————————————省略
        return binder;
}

直接進入到ServiceManager.rawGetService()。

ServiceManager.rawGetService()

    private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }

        // Find the service manager
        sServiceManager = ServiceManagerNative
                .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
        return sServiceManager;
    }

到這,可以看到返回的其實是ServiceManagerNative.asInterface()的返回值。

對AIDL有所瞭解就知道,asInterface()的內容大概如下:

  • 這個方法屬於aidl介面的內部類 Stub
  • 在同一程式中,就會直接返回Stub,如果在另一個程式中呼叫,就會返回將這個ibinder封裝好的Proxy物件。

對aidl不瞭解的可以看下前面的文章:由淺入深 學習 Android Binder(一)- AIDL

於是,雖然沒有看ServiceManagerNative的原始碼,但是其邏輯已經很清晰了。
我們只需要關注IBinder的來源就可以了,也就是BinderInternal.getContextObject()。

BinderInternal.getContextObject()

    /**
     * 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();

至此,可以發現IBinder物件其實是從native層獲取到的。
我們繼續看下JNI的程式碼。

android_util_Binder.android_os_BinderInternal_getContextObject()

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

這裡先通過ProcessState獲取到了一個native 層的IBinder強引用。
然後將這個native層的IBinder強引用傳入javaObjectForIBinder()方法,最終封裝成java層的IBinder然後返回。

此處先不深究ProcessState的邏輯,整個native層的binder有自己的一整套的邏輯,後面的文章會繼續探索。

我們可以先稍微看下javaObjectForIBinder()的大概邏輯。

android_util_Binder.javaObjectForIBinder()

// If the argument is a JavaBBinder, return the Java object that was used to create it.
// Otherwise return a BinderProxy for the IBinder. If a previous call was passed the
// same IBinder, and the original BinderProxy is still alive, return the same BinderProxy.
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    if (val == NULL) return NULL;

    if (val->checkSubclass(&gBinderOffsets)) {
        // It's a JavaBBinder created by ibinderForJavaObject. Already has Java object.
        jobject object = static_cast<JavaBBinder*>(val.get())->object();
        LOGDEATH("objectForBinder %p: it's our own %p!\n", 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(gProxyLock);

    BinderProxyNativeData* nativeData = gNativeDataCache;
    if (nativeData == nullptr) {
        nativeData = new BinderProxyNativeData();
    }
    // gNativeDataCache is now logically empty.
    jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
            gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
    if (env->ExceptionCheck()) {
        // In the exception case, getInstance still took ownership of nativeData.
        gNativeDataCache = nullptr;
        return NULL;
    }
    BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);
    if (actualNativeData == nativeData) {
        // New BinderProxy; we still have exclusive access.
        nativeData->mOrgue = new DeathRecipientList;
        nativeData->mObject = val;
        gNativeDataCache = nullptr;
        ++gNumProxies;
        if (gNumProxies >= gProxiesWarned + PROXY_WARN_INTERVAL) {
            ALOGW("Unexpectedly many live BinderProxies: %d\n", gNumProxies);
            gProxiesWarned = gNumProxies;
        }
    } else {
        // nativeData wasn't used. Reuse it the next time.
        gNativeDataCache = nativeData;
    }

    return object;
}
class JavaBBinder : public BBinder
{
public:
——————————————————省略
    jobject object() const
    {
        return mObject;
    }
——————————————————省略
private:
    JavaVM* const   mVM;
    jobject const   mObject;  // GlobalRef to Java Binder
};

這個方法中未知的細節很多,但是大致邏輯其實很簡單,對具體細節沒興趣的讀者直接看註釋就可以。
這個方法會返回兩種java物件:

  • JavaBBinder.mObject
    如果發現本地已經有了JavaBBinder,就返回JavaBBinder.mObject。這個object其實是java層的Binder。

  • BinderProxy
    如果發現本地沒有BinderProxy,就會呼叫java層的方法建立一個BinderProxy並返回。(BinderProxy是java層的android.os.BinderProxy)

至於這些物件在分別代表什麼,討論起來需要很大的篇幅。筆者後面的文章會繼續探索。

至此,我們已經大概瞭解了java 層的binder。
這個binder物件有可能是Binder,也有可能是BinderProxy。它與native的邏輯息息相關。

總結

本文從bindService 其中的一個IPC出發,一步步深究到native層。
旨在能給讀者一個新的思路去理解binder,也是從java到native層分析的一個過渡。

繼續探索

這篇文章後肯定還有很多疑問,比如:

  • JavaBBinder和BinderProxy具體是啥?
  • 到底什麼場景用哪個物件?
  • native層主要做了啥?

對這些問題有興趣的讀者可以自行觀看原始碼,或者 歡迎繼續關注筆者後續文章。

相關文章