Android跨進(jìn)程通信IPC之4——AndroidIPC基礎(chǔ)2

Android跨進(jìn)程通信IPC整體內(nèi)容如下

8 、Binder對象的寫入

前面說完了基本的數(shù)據(jù)傳輸流程,心里有了一個大致的流程,再來看一下Binder對象的傳輸。首先需要對Binder有一個概念,就是每一個java端的Binder對象(服務(wù)端)在初始化時都會對應(yīng)一個native對象,類型是BBinder,它繼承于IBinder類

時序圖如下:

寫入Binder對象.jpeg

通過 Parcel的writeStrongBinder方法將Binder對象序列化:

(1)、Parcel.writeStrongBinder(IBinder)
//Parcel.java
    /**
     * Write an object into the parcel at the current dataPosition(),
     * growing dataCapacity() if needed.
     */
    public final void writeStrongBinder(IBinder val) {
        nativeWriteStrongBinder(mNativePtr, val);
    }

    private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);

我們看到writeStrongBinder(IBinder)內(nèi)部是調(diào)用了native的方法nativeWriteStrongBinder(long,IBinder),這個方法對應(yīng)JNI的android_os_Parcel_writeStrongBinder()函數(shù)

(2)、android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)

代碼在android_os_Parcel.cpp 298行

static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
        }
    }
}

這里說下ibinderForJavaObject()函數(shù),返回的是BBinder對象(實際上是JavaBBinder,它繼承自BBinder) 后面講解Binder的時候再詳細(xì)說

然后調(diào)用了Parcel-Native的writeStrongBinder函數(shù)

(3)、Parcel::writeStrongBinder

代碼在Parcel.cpp 872行

status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
    return flatten_binder(ProcessState::self(), val, this);
}

這塊代碼很簡單,主要是調(diào)用了flatten_binder()函數(shù)
這里說一下ProcessState::self() 是獲取ProcessState的單例方法

(4)、Parcel::flatten_binder(const sp<ProcessState>& /proc/, const sp<IBinder>& binder, Parcel* out)

代碼在Parcel.cpp 205行

status_t flatten_binder(const sp<ProcessState>& /*proc*/,
    const sp<IBinder>& binder, Parcel* out)
{
    flat_binder_object obj;
    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    if (binder != NULL) {
        //JavaBBinder返回的是this,也就是自己 
        IBinder *local = binder->localBinder();
        //不是本地進(jìn)程,即跨進(jìn)程
        if (!local) {
            //分支一,如果local為空
            BpBinder *proxy = binder->remoteBinder();
            if (proxy == NULL) {
                ALOGE("null proxy");
            }
            const int32_t handle = proxy ? proxy->handle() : 0;
            obj.type = BINDER_TYPE_HANDLE;
            obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
            obj.handle = handle;
            obj.cookie = 0;
        } else {
            //分支二,local不為空
            //寫入JavaBBinder將對應(yīng)這一段
            obj.type = BINDER_TYPE_BINDER;
             // 弱引用對象
            obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
            //  this 對象,BBinder本身
            obj.cookie = reinterpret_cast<uintptr_t>(local);
        }
    } else {
        obj.type = BINDER_TYPE_BINDER;
        obj.binder = 0;
        obj.cookie = 0;
    }
    return finish_flatten_binder(binder, obj, out);
}

這里主要是分別是本地Binder還是遠(yuǎn)程Binder,對兩種Binder采取了兩種不同的方式。

  • Binder如果是JavaBBinder,則它的localBinder會返回localBinder。
  • Binder如果是BpBinder,則它的localBinder會返回null

通過上文我們知道ibinderForJavaObject就返回JavaBBinder。所以我們知道走入分支二

flat_binder_object是Binder寫入對象的結(jié)構(gòu)體,它對應(yīng)著Binder。

  • flat_binder_object的handle表示Binder對象在Binder驅(qū)動中的標(biāo)志,比如ServiceManager的handle為0。
  • flat_binder_object的type表示當(dāng)前傳輸?shù)腂inder是本地的(同進(jìn)程),還是一個Proxy(跨進(jìn)程)。

通過上面代碼我們知道這里取得的flat_binder_object對應(yīng)的值如下

  • type為BINDER_TYPE_BINDER
  • binder為reinterpret_cast(local->getWeakRefs());
  • cookie為reinterpret_cast(local)

binder,cookie保存著Binder對象的指針。最后調(diào)用了finish_flatten_binder()函數(shù)

(5)、Parcel::finish_flatten_binder()函數(shù)

代碼在Parcel.cpp 199行

inline static status_t finish_flatten_binder(
    const sp<IBinder>& /*binder*/, const flat_binder_object& flat, Parcel* out)
{
    return out->writeObject(flat, false);
}

finish_flatten_binder()函數(shù)主要是調(diào)用writeObject()函數(shù)將flat_binder_object寫入到out里面里面,最終寫入到Binder驅(qū)動中,那我們繼續(xù)跟蹤writeObject()函數(shù)。

(6)、Parcel::writeObject()函數(shù)

代碼在Parcel.cpp 1035行

status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
{
    const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
    const bool enoughObjects = mObjectsSize < mObjectsCapacity;
    //分支一
    if (enoughData && enoughObjects) {
restart_write:
         // mObjects 數(shù)據(jù)寫入
        *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;

        // remember if it's a file descriptor
        if (val.type == BINDER_TYPE_FD) {
            if (!mAllowFds) {
                // fail before modifying our object index
                return FDS_NOT_ALLOWED;
            }
            mHasFds = mFdsKnown = true;
        }

        // Need to write meta-data?
        if (nullMetaData || val.binder != 0) {
            mObjects[mObjectsSize] = mDataPos;
            acquire_object(ProcessState::self(), val, this, &mOpenAshmemSize);
            mObjectsSize++;
        }

        return finishWrite(sizeof(flat_binder_object));
    }
    //分支二
    if (!enoughData) {
        const status_t err = growData(sizeof(val));
        if (err != NO_ERROR) return err;
    }
    //分支三
    if (!enoughObjects) {
        size_t newSize = ((mObjectsSize+2)*3)/2;
        if (newSize < mObjectsSize) return NO_MEMORY;   // overflow
        binder_size_t* objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
        if (objects == NULL) return NO_MEMORY;
        mObjects = objects;
        mObjectsCapacity = newSize;
    }

    goto restart_write;
}

finish_flatten_binder()函數(shù)主要是調(diào)用writeObject()函數(shù)

這里面有三個分支,我們就來依次說下

  • 如果mData和mObjects空間足夠,則走分支一
  • 如果mData空間不足,則擴(kuò)展空間,growData()函數(shù)看前面
  • 如果mObjects空間不足,則擴(kuò)展空間,和mData空間擴(kuò)展基本相似

調(diào)用 * reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val; 寫入mObject

最后調(diào)用finishWrite()函數(shù),就是調(diào)整調(diào)整 mDataPos 和 mDataSize,上面已經(jīng)說過了,我就跟蹤了。至此整體寫入流程已經(jīng)完成了。

9 、Binder對象的讀出

Parcel對象的讀出,首先還是在Parcel.java這個類里面,對應(yīng)的方法是

時序圖如下:

讀出Binder對象.png
9.1 Parcel.readStrongBinder()方法
    /**
     * Read an object from the parcel at the current dataPosition().
     */
    public final IBinder readStrongBinder() {
        return nativeReadStrongBinder(mNativePtr);
    }

我們看到readStrongBinder()方法內(nèi)部調(diào)用了native的nativeReadStrongBinder()方法,

9.2 Parcel.nativeReadStrongBinder()方法
    private static native IBinder nativeReadStrongBinder(long nativePtr);

而這個native方法又對應(yīng)這個JNI的一個方法,通過上文我們知道,對應(yīng)的是 /frameworks/base/core/jni/android_os_Parcel.cpp的android_os_Parcel_readStrongBinder()函數(shù)

9.3 android_os_Parcel_readStrongBinder()函數(shù)

代碼在android_os_Parcel.cpp 429行

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        return javaObjectForIBinder(env, parcel->readStrongBinder());
    }
    return NULL;
}

這個函數(shù)里面先調(diào)用了Parcel-Native的readStrongBinder()函數(shù),然后又用這個函數(shù)的返回值作為參數(shù)調(diào)用了javaObjectForIBinder()函數(shù)。那我們就依次來看一下。

9.4 readStrongBinder()函數(shù)

代碼在Parcel.cpp 1134行

sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
    unflatten_binder(ProcessState::self(), *this, &val);
    return val;
}

我們看到這個函數(shù)什么也沒做,主要就是調(diào)用了unflatten_binder()函數(shù)。

readStrongBinder 其實挺簡單的,是本地的可以直接用,遠(yuǎn)程的那個 getStrongProxyForHandle 也是放到后面 ServiceManager 再細(xì)說。到這里目標(biāo)進(jìn)程就收到原始進(jìn)程傳遞過來的 binder 對象了,然后可以轉(zhuǎn)化為 binder 的 interface 調(diào)用對應(yīng)的 IPC 接口。

PS:
這里說下,ProcessState::self()函數(shù)是返回的ProcessState的對象

那我們再來看下unflatten_binder()函數(shù)

9.5 unflatten_binder()函數(shù)

代碼在android_os_Parcel.cpp 293行

status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)
{
    const flat_binder_object* flat = in.readObject(false);

    if (flat) {
        switch (flat->type) {
            case BINDER_TYPE_BINDER:
                //如果是Bn的話,本地直接強(qiáng)轉(zhuǎn)
                *out = reinterpret_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            case BINDER_TYPE_HANDLE:
                //如果是Bp的話,要通過handle構(gòu)造一個遠(yuǎn)程的代理對象
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }
    }
    return BAD_TYPE;
}

這里說下這里的兩個分支

  • BINDER_TYPE_BINDER分支:是Bn意味著是同一個進(jìn)程
  • BINDER_TYPE_HANDLE分支:是Bp意味著是跨進(jìn)程

我們再來分下一下這個函數(shù),主要就是兩個兩個流程

  • 1、從Binder驅(qū)動中讀取一個flat_binder_object對象flat
  • 2、根據(jù)flat對象的type值來分別處理。如果是BINDER_TYPE_BINDER,則使用cookie中的值,強(qiáng)制轉(zhuǎn)換成指針。如果是BINDER_TYPE_HANDLE,則使用Proxy,即通過getStringProxyForHandle()函數(shù),并根據(jù)handle創(chuàng)建BpBinder。

ProcessState::getStrongProxyForHandle()函數(shù)后續(xù)講解Binder的時候再詳細(xì)講解,這里就不說了。那我們來看一下finish_unflatten_binder()

9.6 finish_unflatten_binder()函數(shù)

代碼在android_os_Parcel.cpp 286行

inline static status_t finish_unflatten_binder(
    BpBinder* /*proxy*/, const flat_binder_object& /*flat*/,
    const Parcel& /*in*/)
{
    return NO_ERROR;
}

這行代碼很簡單,就是返回NO_ERROR。這時候我們回到了javaObjectForIBinder()函數(shù)。

9.7 javaObjectForIBinder()函數(shù)

javaObjectgForBinder與ibinderForJavaObject相對應(yīng)的,把IBinder對象轉(zhuǎn)換成對應(yīng)的Java層的Object。這個函數(shù)是關(guān)鍵。
代碼在android_os_Parcel.cpp 547行

jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    if (val == NULL) return NULL; 
         // One of our own!
    if (val->checkSubclass(&gBinderOffsets)) {
          //如果是本地的,那么會直接進(jìn)入這個部分代碼,因為這個val
         //是寫入的時候的同一個對象,gBinderOffsets也是一致的。如
         //果val是一種Poxy對象,則不然,會繼續(xù)往下執(zhí)行,找到一個
         //Proxy對象
        // One of our own!
        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 of Java proxies for native Binder proxies.
    AutoMutex _l(mProxyLock);
    // Someone else's...  do we know about it?
     // BpBinder沒有帶proxy過來
    jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
    if (object != NULL) {
        jobject res = jniGetReferent(env, object);
        if (res != NULL) {
            ALOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
            return res;
        }
        LOGDEATH("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get());
        android_atomic_dec(&gNumProxyRefs);
        val->detachObject(&gBinderProxyOffsets);
        env->DeleteGlobalRef(object);
    }
      // 創(chuàng)建一個proxy  
    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
    if (object != NULL) {
        // 給object的相關(guān)字段賦值
        LOGDEATH("objectForBinder %p: created new proxy %p !\n", val.get(), object);
        // The proxy holds a reference to the native object.
         // 把BpBinder(0) 賦值給BinderProxy的mObject
        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<DeathRecipientList> drl = new DeathRecipientList;
        drl->incStrong((void*)javaObjectForIBinder);
        env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get()));
        // Note that a new object reference has been created.
        android_atomic_inc(&gNumProxyRefs);
        incRefsCreated(env);
    }
    return object;
}
  • 首先判斷是不是同一個進(jìn)程,如果是同一個進(jìn)程,則val是JavaBBinder。那么在checkSubclass()函數(shù)中,它所包含的gBinderOffsets指針參數(shù)傳入的gBinderOffsets的指針必然是同一個值,則滿足if條件,直接將指針強(qiáng)制轉(zhuǎn)化為JavaBBinder,返回對應(yīng)的jobject。如果是不是同一個進(jìn)程,那么val也就是BpBinder。
  • 其次,在BpBinder對象中查找是否保存相關(guān)的BinderProxy的對象,如果有,向Java層返回這個對象。如果沒有,則創(chuàng)建一個BinderProxy對象,并將新創(chuàng)建的BinderProxy對象,attach到BpBinder對象中。

在構(gòu)造Java對象的時候,上面用到了 binderproxy_offsets_t 結(jié)構(gòu)體 ,那我們就來看下這個結(jié)構(gòu)體

9.7.1 binderproxy_offsets_t 結(jié)構(gòu)體

代碼在android_os_Parcel.cpp 95行

static struct binderproxy_offsets_t
{
    // Class state.
    jclass mClass;
    jmethodID mConstructor;
    jmethodID mSendDeathNotice;

    // Object state.
    jfieldID mObject;
    jfieldID mSelf;
    jfieldID mOrgue;

} gBinderProxyOffsets;

gBinderProxyOffsets的初始化是在虛擬機(jī)啟動的時候(即在 AndroidRuntime::start),最終賦值是在android_os_Parcel.cpp 的中1254行的函數(shù)int_register_android_os_BinderProxy()中,代碼如下

static int int_register_android_os_BinderProxy(JNIEnv* env)
{
    jclass clazz = FindClassOrDie(env, "java/lang/Error");
1257    gErrorOffsets.mClass = MakeGlobalRefOrDie(env, clazz);

    clazz = FindClassOrDie(env, kBinderProxyPathName);
    gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    gBinderProxyOffsets.mConstructor = GetMethodIDOrDie(env, clazz, "<init>", "()V");
    gBinderProxyOffsets.mSendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
            "(Landroid/os/IBinder$DeathRecipient;)V");

    gBinderProxyOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
    gBinderProxyOffsets.mSelf = GetFieldIDOrDie(env, clazz, "mSelf",
                                                "Ljava/lang/ref/WeakReference;");
    gBinderProxyOffsets.mOrgue = GetFieldIDOrDie(env, clazz, "mOrgue", "J");

    clazz = FindClassOrDie(env, "java/lang/Class");
    gClassOffsets.mGetName = GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");

    return RegisterMethodsOrDie(
        env, kBinderProxyPathName,
        gBinderProxyMethods, NELEM(gBinderProxyMethods));
}

通過上面代碼我們知道這個類型是android.os.BinderProxy,也就是說代理端Java層的對象是android.os.BinderProxy

9.8 總結(jié)

結(jié)合下面的關(guān)系圖,我們得出下面的邏輯關(guān)系:

  • 每個進(jìn)程都會保存多個當(dāng)前調(diào)用過的BpBinder對象
  • 每個BpBinder對象都會保存與之對應(yīng)的Java層的BinderProxy

將創(chuàng)建的BinderProxy attach到BpBinder的意義在于,通過這種方式,Java應(yīng)用層偏飯獲取同一個Service的IBinder時,獲取的是同一個BinderProxy。

關(guān)系圖.png
10 Parcel讀取寫入總結(jié)
  • 上面介紹了Parcel整個寫入讀取的流程,最后代替Binder傳輸?shù)氖?br> flat_binder_object。在Parcel-Native中,根據(jù)跨進(jìn)程和非跨進(jìn)程,flat_binder_object的值是不一樣的:跨進(jìn)程的時候flat_binder_object的type是BINDER_TYPE_HANDLE;非跨進(jìn)程的時候flat_binder_object的type是BINDER_TYPE_BINDER。在這里可以發(fā)現(xiàn)跨進(jìn)程與非跨進(jìn)程的時候傳輸數(shù)據(jù)的區(qū)別。客戶端的Parcel讀取Binder的時候,根據(jù)flat_binder_object的type值進(jìn)行區(qū)分對待,返回不同的內(nèi)容。而寫入的時候也是一樣的,根據(jù)是否是Proxy,來決定寫入HANDLE還是BINDER。最終這些內(nèi)容都會通過ioctl與Binder驅(qū)動進(jìn)行數(shù)據(jù)通信。所以最終處理不同進(jìn)程間的Binder數(shù)據(jù)傳輸處理也只能是Binder驅(qū)動了。
  • Binder對象傳入Binder驅(qū)動最底層是轉(zhuǎn)化為flat_binder_object傳遞的。Parcel是根據(jù)從驅(qū)動中讀取的數(shù)據(jù)做出不同的處理,如果從Binder驅(qū)動中取出的flat_binder_object的type為BINDER_TYPE_HANDLE,則創(chuàng)建BpBinder,在Java層創(chuàng)建的BinderProxy返回,如果讀出的flat_binder_object的type為BINDER_TYPE_BINDER則直接使用cookie的指針,將它裝置轉(zhuǎn)為化JavaBBinder,在Java層為原來的Service的Binder對象(相同進(jìn)程)。
  • /frameworks/base/core/jni/android_util_Binder.cpp 中有兩個函數(shù)分別是ibinderForJavaObject()函數(shù)與javaObjectForIBinder()函數(shù)是相互對應(yīng)的,一個是把Native中對應(yīng)的IBinder對象化為Java對象,一個是將Java的對象轉(zhuǎn)為化Native中對應(yīng)的IBinder對象

五、智能指針

Java和C/C++的一個重大區(qū)別,就是它沒有"指針"的概念,這并不代表Java不需要只用指針,而是將這個"超級武器隱藏了"。如果大家使用C/C++開發(fā)過一些大型項目,就會知道一個比較頭疼的問題——指針異常。所以Java以其他更"安全"的形式向開發(fā)人員提供了隱形的"指針",使得用戶既能享受到指針的強(qiáng)大功能,又能盡量避免指針帶來的問題。

(一)、C/C++中常見的指針問題

1、指針沒有初始化

對指針進(jìn)行初始化是程序員必須養(yǎng)成的良好習(xí)慣,也是指針問題中最容易解決和控制的一個問題

2、new了對象沒有及時delete

動態(tài)分配內(nèi)存的對象,其實聲明周期的控制不當(dāng)常常會引起不少麻煩。如果只有一個程序員在維護(hù)時,問題通常不大,因為只要稍微留心就可以實現(xiàn)new和delete的配套操作;但是如果一個大型工程(特別是多滴協(xié)同研發(fā)的軟件項目),由于溝通的不及時或者人員素質(zhì)的殘差不起,就很可能會出現(xiàn)動態(tài)分配的內(nèi)存沒有回收的情況——造成的內(nèi)存泄露問題往往是致命的。

3、野指針

假設(shè)1:我們new了一個對象A,并將指針ptr指向這個新是對象(即ptr= new )。當(dāng)對A使用結(jié)束后,我們也主動delete了A,但是唯一沒做的是將ptr指針置空,那么可能出現(xiàn)什么問題?沒錯,就是野指針。因此如果有"第三方"視圖用ptr來使用內(nèi)存對象,它首先通過判斷發(fā)現(xiàn)ptr不為空,自然而然的就認(rèn)為這個對象還是存在的,其結(jié)果就是導(dǎo)致死機(jī)。
假設(shè)2:假設(shè)ptr1和ptr2都指向?qū)ο驛,后來我們通過ptr1釋放了A的內(nèi)存空間,并且將ptr1也置為null;但是ptr2并不知道它所指向的內(nèi)存對象已經(jīng)不存在了,此時如果ptr2來訪問A也會導(dǎo)致死機(jī)

(二)、我們設(shè)計的解決方案

上面分析了C/C++指針的問題。如果讓我們設(shè)計Android的智能指針,怎么做才能防止以上幾個問題?解決方案思路如下:

  • 問題1的解決方案:這個簡單,只要讓指針在創(chuàng)建時設(shè)置為null即可
  • 問題2的解決方案:比較復(fù)雜,既然是智能指針就為意味著它應(yīng)該是一個"雷鋒",盡可能自動的實現(xiàn)new和delete的相應(yīng)工作,那什么時候應(yīng)該delete一個內(nèi)存對象呢?肯定是"不需要的時候"(其實是個廢話)。那怎么來分別什么是"需要"和"不需要"?在C/C++中,我們一般認(rèn)為:當(dāng)一個指針指向一個object的時候,這個內(nèi)存對象就是"需要"的,當(dāng)這個指針接觸了與內(nèi)存對象的關(guān)系,我們就認(rèn)為這個內(nèi)存對象已經(jīng)"不需要"了。所以我們想到用一個布爾類型變量來保存即可。
  • 問題3的解決方案:問題又來了,當(dāng)有兩個指針及兩個以上指針同時使用這個內(nèi)存怎么辦,用布爾類型肯定是不行的。所以我們要用一個計數(shù)器來記錄這個內(nèi)存對象"被需要"的個數(shù)即可,當(dāng)這個計數(shù)器遞減到零時,就說明這個內(nèi)存對象應(yīng)該"壽終正寢"了。這就是在很多領(lǐng)域了都得到廣泛應(yīng)用的"引用計數(shù)"的概念。如下圖
引用計數(shù).png

那Android到底是怎么設(shè)計的?

(三)、Android智能指針的原理

重點強(qiáng)調(diào) :

智能指針是一個對象,而不是一個指針。
  • Android設(shè)計了基類RefBase,用以管理引用數(shù),所有類必須從RefBase派生,RefBase是所有對象的始祖。
  • 設(shè)計模板類sp、wp,用以引用實際對象,sp強(qiáng)引用和wp弱引用。sp、wp聲明為棧對象,作用域結(jié)束時,自動釋放,自動調(diào)用機(jī)析構(gòu)函數(shù)。因此可以在sp、wp的構(gòu)造函數(shù)中,增加引用計數(shù),在析構(gòu)函數(shù)中,減少引用計數(shù)。
  • 專門設(shè)計weakref_impl類,該類是RefBase的累不累,用來做真正的引用數(shù)管理,都有mRef來管理

Android智能指針的關(guān)系圖:


Android智能指針的關(guān)系圖.png

(四)、Android智能指針的源碼位置

android中的智能指針的主要代碼是:RefBase.h和RefBase.cpp StrongPointer.h 這三個文件,他們分別位于:

RefBase.cpp:Android源碼目錄 /system/core/libutils/RefBase.cp
RefBase.h:Android源碼目錄 /system/core/include/utils/RefBase.h
StrongPointer.h:Android源碼目錄/system/core/include/utils/StrongPointer.h

鏈接如下

(五)、強(qiáng)指針sp

看到sp,很多人會以為是StrongPointer的縮寫。與sp對應(yīng)的是wp,我們將會在下一節(jié)講解。
先來看下源碼:

///system/core/include/utils/StrongPointer.h    58行
template<typename T>
class sp {
public:
    inline sp() : m_ptr(0) { }
   
    sp(T* other);   //常用的構(gòu)造函數(shù)
    sp(const sp<T>& other); 
    template<typename U> sp(U* other);
    template<typename U> sp(const sp<U>& other);

    ~sp();    //析構(gòu)函數(shù)

    // Assignment

    sp& operator = (T* other);   // 重載運(yùn)算符"="
    sp& operator = (const sp<T>& other);

    template<typename U> sp& operator = (const sp<U>& other);  
    template<typename U> sp& operator = (U* other);

    //! Special optimization for use by ProcessState (and nobody else).
    void force_set(T* other);

    // Reset

    void clear();

    // Accessors

    inline  T&      operator* () const  { return *m_ptr; } // 重載運(yùn)算符 " * "
    inline  T*      operator-> () const { return m_ptr;  }  // 重載運(yùn)算符" -> "
    inline  T*      get() const         { return m_ptr; }

    // Operators

    COMPARE(==)
    COMPARE(!=)
    COMPARE(>)
    COMPARE(<)
    COMPARE(<=)
    COMPARE(>=)

private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;
    void set_pointer(T* ptr);
    T* m_ptr;
};

通過閱讀源碼,我們知道這個sp類的設(shè)計和我們之前想象的基本一致,比如運(yùn)算符的實現(xiàn)為:

//system/core/include/utils/StrongPointer.h    157行
template<typename T>
sp<T>& sp<T>::operator =(T* other) {
    if (other)
        other->incStrong(this);    //增加引用計數(shù)
    if (m_ptr)
        m_ptr->decStrong(this); // 減少引用計數(shù)
    m_ptr = other;
    return *this;
}

上面的diamante同時考慮了對一個智能指針重復(fù)賦值的情況。即當(dāng)m_ptr不為空時,要先撤銷它之前指向的內(nèi)存對象,然后才能賦予其新值。另外為sp分配一個內(nèi)存對象,不一定要通過操作運(yùn)算符(比如等號),它的構(gòu)造函數(shù)也是可以的。比如下面這段代碼

//system/core/include/utils/StrongPointer.h    112行
template<typename T> 
sp<T>::sp(T* other)
        : m_ptr(other) {
    if (other)
        other->incStrong(this); //因為是構(gòu)造函數(shù),所以不同擔(dān)心mptr之前已經(jīng)賦值過
}

這時候m_ptr就不用先置為null,可以直接指向目標(biāo)對象。而析構(gòu)函數(shù)的做法和我們的預(yù)想也是一樣。

template<typename T>
sp<T>::~sp() {
    if (m_ptr)
        m_ptr->decStrong(this);
}

(六)、弱指針wp

1、弱引用產(chǎn)生的背景:

在前面討論之智能指針的"設(shè)計理念"時,其實是以強(qiáng)指針為原型逐步還原出智能指針作者的"意圖',那么"弱指針"又由什么作用?

其實弱指針主要是為了解決一個問題?那是什么問題那?有這么一種情況:父對象指向子對象child,然后子對象又指向父對象,這就存在了虛幻引用的現(xiàn)象。比如有兩個class

struct Parent
{
    Child *myson;
}

struct Child
{
    Parent *myfather;
}

這樣就會產(chǎn)生上面的問題。如果不考慮智能指針,這樣的情況不會導(dǎo)致任何問題,但是在智能指針的場景下,就要注意了,因為Parent指向了Child,所以Child的引用計數(shù)器不為零。同時又由于Child指向了Parent,所以Parent的引用器不會為零。這有點類似于Java中的死鎖了。因為內(nèi)存回收者返現(xiàn)兩者都是"被需要"的狀態(tài),當(dāng)然不能釋放,從而形成了惡性循環(huán)。

為了解決上面這個問題,產(chǎn)生了"弱引用"。具體措施如下:

Parent使用強(qiáng)指針來引用Child,而Child只使用弱引用來指向父Parent類。雙方規(guī)定當(dāng)強(qiáng)引用計數(shù)器為0時,不論弱引用是否為0,都可以delete自己(Android系統(tǒng)中這個規(guī)定是可以調(diào)整的,后面有介紹)。這樣只要一方得到了釋放了,就可以成功避免死鎖。當(dāng)然這樣就會造成野指針。是的,比如Parent因為因為強(qiáng)指針計數(shù)器計數(shù)已經(jīng)到0了,根據(jù)規(guī)則生命周期就結(jié)束了。但是此時Child還持有父類的弱引用,顯然如果Child此時用這個指針訪問Parent會引發(fā)致命的問題。為了別面這個問題,我們還規(guī)定: 弱指針必須先升級為強(qiáng)指針,才能訪問它所指向的目標(biāo)對象。

所以我們也可以說,若指針的主要使用就是解決循環(huán)引用的問題。下面具體看看它和強(qiáng)指針的區(qū)別。我們先從代碼上看

2、wp的源碼解析:

代碼在RefBase.h 215行

template <typename T>
class wp
{
public:
    typedef typename RefBase::weakref_type weakref_type;

    inline wp() : m_ptr(0) { }

    wp(T* other);   //構(gòu)造函數(shù)
    wp(const wp<T>& other);
    wp(const sp<T>& other);
    template<typename U> wp(U* other);
    template<typename U> wp(const sp<U>& other);
    template<typename U> wp(const wp<U>& other);

    ~wp();

    // Assignment

    wp& operator = (T* other);    //運(yùn)算符重載
    wp& operator = (const wp<T>& other);
    wp& operator = (const sp<T>& other);

    template<typename U> wp& operator = (U* other);
    template<typename U> wp& operator = (const wp<U>& other);
    template<typename U> wp& operator = (const sp<U>& other);

    void set_object_and_refs(T* other, weakref_type* refs);

    // promotion to sp

    sp<T> promote() const;    //升級為強(qiáng)指針

    // Reset

    void clear();

    // Accessors

    inline  weakref_type* get_refs() const { return m_refs; }

    inline  T* unsafe_get() const { return m_ptr; }

    // Operators

    COMPARE_WEAK(==)
    COMPARE_WEAK(!=)
    COMPARE_WEAK(>)
    COMPARE_WEAK(<)
    COMPARE_WEAK(<=)
    COMPARE_WEAK(>=)

    inline bool operator == (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);
    }
    template<typename U>
    inline bool operator == (const wp<U>& o) const {
        return m_ptr == o.m_ptr;
    }

    inline bool operator > (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
    }
    template<typename U>
    inline bool operator > (const wp<U>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
    }

    inline bool operator < (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
    }
    template<typename U>
    inline bool operator < (const wp<U>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
    }
                         inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }
    template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
                         inline bool operator <= (const wp<T>& o) const { return !operator > (o); }
    template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
                         inline bool operator >= (const wp<T>& o) const { return !operator < (o); }
    template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }

private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;

    T*              m_ptr;
    weakref_type*   m_refs;
};

通過和sp相比,我們發(fā)現(xiàn)有如下區(qū)別:

  • 除了指向目標(biāo)對象的m_ptr外,wp另外有一個m_refs指針,類型為weakref_type。
  • 沒有重載 " -> " 、" * " 等運(yùn)算符。
  • 有一個prmote方法將wp提升為sp。
  • 目標(biāo)對象的父類不是LightRefBase,而是RefBase
3、wp的構(gòu)造函數(shù):
template<typename T>
wp<T>::wp(T* other)
    : m_ptr(other)
{
    if (other) m_refs = other->createWeak(this);
}

通過和強(qiáng)指針的中的構(gòu)造函數(shù)進(jìn)行對比,我們發(fā)現(xiàn),wp并沒有直接增加目標(biāo)對象的引用計數(shù)值,而是調(diào)用了createWeak()函數(shù)。這個函數(shù)是RefBase類的

那我們來看下RefBase類

3.1RefBase類

在代碼在RefBase.h 69行


class RefBase
{
public:
            void            incStrong(const void* id) const;   //增加強(qiáng)引用計數(shù)器的值
            void            decStrong(const void* id) const;  //減少強(qiáng)引用計數(shù)器的值

            void            forceIncStrong(const void* id) const;

            //! DEBUGGING ONLY: Get current strong ref count.
            int32_t         getStrongCount() const;

    class weakref_type   //嵌套類,wp中用到的就是這個類
    {
    public:
        RefBase*            refBase() const;

        void                incWeak(const void* id);   //增加弱引用計數(shù)器的值
        void                decWeak(const void* id);  //減少弱引用計數(shù)器的值

        // acquires a strong reference if there is already one.
        bool                attemptIncStrong(const void* id);

        // acquires a weak reference if there is already one.
        // This is not always safe. see ProcessState.cpp and BpBinder.cpp
        // for proper use.
        bool                attemptIncWeak(const void* id);

        //! DEBUGGING ONLY: Get current weak ref count.
        int32_t             getWeakCount() const;

        //! DEBUGGING ONLY: Print references held on object.
        void                printRefs() const;

        //! DEBUGGING ONLY: Enable tracking for this object.
        // enable -- enable/disable tracking
        // retain -- when tracking is enable, if true, then we save a stack trace
        //           for each reference and dereference; when retain == false, we
        //           match up references and dereferences and keep only the
        //           outstanding ones.

        void                trackMe(bool enable, bool retain);
    };

            weakref_type*   createWeak(const void* id) const;

            weakref_type*   getWeakRefs() const;

            //! DEBUGGING ONLY: Print references held on object.
    inline  void            printRefs() const { getWeakRefs()->printRefs(); }

            //! DEBUGGING ONLY: Enable tracking of object.
    inline  void            trackMe(bool enable, bool retain)
    {
        getWeakRefs()->trackMe(enable, retain);
    }

    typedef RefBase basetype;

protected:
                            RefBase();    //構(gòu)造函數(shù)
    virtual                 ~RefBase();   //析構(gòu)函數(shù)

    //! Flags for extendObjectLifetime()
    // 以下參數(shù)用于修改object的生命周期
    enum {
        OBJECT_LIFETIME_STRONG  = 0x0000,
        OBJECT_LIFETIME_WEAK    = 0x0001,
        OBJECT_LIFETIME_MASK    = 0x0001
    };

            void            extendObjectLifetime(int32_t mode);

    //! Flags for onIncStrongAttempted()
    enum {
        FIRST_INC_STRONG = 0x0001
    };

    virtual void            onFirstRef();
    virtual void            onLastStrongRef(const void* id);
    virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);
    virtual void            onLastWeakRef(const void* id);

private:
    friend class weakref_type;
    class weakref_impl;

                            RefBase(const RefBase& o);
            RefBase&        operator=(const RefBase& o);

private:
    friend class ReferenceMover;

    static void renameRefs(size_t n, const ReferenceRenamer& renamer);

    static void renameRefId(weakref_type* ref,
            const void* old_id, const void* new_id);

    static void renameRefId(RefBase* ref,
            const void* old_id, const void* new_id);

        weakref_impl* const mRefs;
};

RefBase嵌套了一個重要的類weakref_type,也就是前面的m_refs指針?biāo)鶎俚念愋汀efBase中還有一個mRefs的成員變量,類型為weakref_impl。從名稱上來看,它應(yīng)該是weak_type的實現(xiàn)類。

3.2 weakref_impl類

在代碼在RefBase.cpp 64行

class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
    volatile int32_t    mStrong;   //強(qiáng)引用計數(shù)器的值
    volatile int32_t    mWeak;   //弱引用計數(shù)器的值
    RefBase* const      mBase;      
    volatile int32_t    mFlags;

#if !DEBUG_REFS    //非Debug模式下,DEBUG_REFS是個宏

    weakref_impl(RefBase* base)
        : mStrong(INITIAL_STRONG_VALUE)
        , mWeak(0)
        , mBase(base)
        , mFlags(0)
    {
    }

    void addStrongRef(const void* /*id*/) { }
    void removeStrongRef(const void* /*id*/) { }
    void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
    void addWeakRef(const void* /*id*/) { }
    void removeWeakRef(const void* /*id*/) { }
    void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
    void printRefs() const { }
    void trackMe(bool, bool) { }

#else     //debug的情況下

    weakref_impl(RefBase* base)
        : mStrong(INITIAL_STRONG_VALUE)
        , mWeak(0)
        , mBase(base)
        , mFlags(0)
        , mStrongRefs(NULL)
        , mWeakRefs(NULL)
        , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
        , mRetain(false)
    {
    }

    ~weakref_impl()
    {
        bool dumpStack = false;
        if (!mRetain && mStrongRefs != NULL) {
            dumpStack = true;
            ALOGE("Strong references remain:");
            ref_entry* refs = mStrongRefs;
            while (refs) {
                char inc = refs->ref >= 0 ? '+' : '-';
                ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
                refs->stack.log(LOG_TAG);
#endif
                refs = refs->next;
            }
        }

        if (!mRetain && mWeakRefs != NULL) {
            dumpStack = true;
            ALOGE("Weak references remain!");
            ref_entry* refs = mWeakRefs;
            while (refs) {
                char inc = refs->ref >= 0 ? '+' : '-';
                ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
                refs->stack.log(LOG_TAG);
#endif
                refs = refs->next;
            }
        }
        if (dumpStack) {
            ALOGE("above errors at:");
            CallStack stack(LOG_TAG);
        }
    }

    void addStrongRef(const void* id) {
        //ALOGD_IF(mTrackEnabled,
        //        "addStrongRef: RefBase=%p, id=%p", mBase, id);
        addRef(&mStrongRefs, id, mStrong);
    }

    void removeStrongRef(const void* id) {
        //ALOGD_IF(mTrackEnabled,
        //        "removeStrongRef: RefBase=%p, id=%p", mBase, id);
        if (!mRetain) {
            removeRef(&mStrongRefs, id);
        } else {
            addRef(&mStrongRefs, id, -mStrong);
        }
    }

    void renameStrongRefId(const void* old_id, const void* new_id) {
        //ALOGD_IF(mTrackEnabled,
        //        "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
        //        mBase, old_id, new_id);
        renameRefsId(mStrongRefs, old_id, new_id);
    }

    void addWeakRef(const void* id) {
        addRef(&mWeakRefs, id, mWeak);
    }

    void removeWeakRef(const void* id) {
        if (!mRetain) {
            removeRef(&mWeakRefs, id);
        } else {
            addRef(&mWeakRefs, id, -mWeak);
        }
    }

    void renameWeakRefId(const void* old_id, const void* new_id) {
        renameRefsId(mWeakRefs, old_id, new_id);
    }

    void trackMe(bool track, bool retain)
    {
        mTrackEnabled = track;
        mRetain = retain;
    }

    void printRefs() const
    {
        String8 text;

        {
            Mutex::Autolock _l(mMutex);
            char buf[128];
            sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
            text.append(buf);
            printRefsLocked(&text, mStrongRefs);
            sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
            text.append(buf);
            printRefsLocked(&text, mWeakRefs);
        }

        {
            char name[100];
            snprintf(name, 100, DEBUG_REFS_CALLSTACK_PATH "/%p.stack", this);
            int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
            if (rc >= 0) {
                write(rc, text.string(), text.length());
                close(rc);
                ALOGD("STACK TRACE for %p saved in %s", this, name);
            }
            else ALOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
                      name, strerror(errno));
        }
    }

private:
    struct ref_entry
    {
        ref_entry* next;
        const void* id;
#if DEBUG_REFS_CALLSTACK_ENABLED
        CallStack stack;
#endif
        int32_t ref;
    };

    void addRef(ref_entry** refs, const void* id, int32_t mRef)
    {
        if (mTrackEnabled) {
            AutoMutex _l(mMutex);

            ref_entry* ref = new ref_entry;
            // Reference count at the time of the snapshot, but before the
            // update.  Positive value means we increment, negative--we
            // decrement the reference count.
            ref->ref = mRef;
            ref->id = id;
#if DEBUG_REFS_CALLSTACK_ENABLED
            ref->stack.update(2);
#endif
            ref->next = *refs;
            *refs = ref;
        }
    }

    void removeRef(ref_entry** refs, const void* id)
    {
        if (mTrackEnabled) {
            AutoMutex _l(mMutex);

            ref_entry* const head = *refs;
            ref_entry* ref = head;
            while (ref != NULL) {
                if (ref->id == id) {
                    *refs = ref->next;
                    delete ref;
                    return;
                }
                refs = &ref->next;
                ref = *refs;
            }

            ALOGE("RefBase: removing id %p on RefBase %p"
                    "(weakref_type %p) that doesn't exist!",
                    id, mBase, this);

            ref = head;
            while (ref) {
                char inc = ref->ref >= 0 ? '+' : '-';
                ALOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref);
                ref = ref->next;
            }

            CallStack stack(LOG_TAG);
        }
    }

    void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
    {
        if (mTrackEnabled) {
            AutoMutex _l(mMutex);
            ref_entry* ref = r;
            while (ref != NULL) {
                if (ref->id == old_id) {
                    ref->id = new_id;
                }
                ref = ref->next;
            }
        }
    }

    void printRefsLocked(String8* out, const ref_entry* refs) const
    {
        char buf[128];
        while (refs) {
            char inc = refs->ref >= 0 ? '+' : '-';
            sprintf(buf, "\t%c ID %p (ref %d):\n",
                    inc, refs->id, refs->ref);
            out->append(buf);
#if DEBUG_REFS_CALLSTACK_ENABLED
            out->append(refs->stack.toString("\t\t"));
#else
            out->append("\t\t(call stacks disabled)");
#endif
            refs = refs->next;
        }
    }

    mutable Mutex mMutex;
    ref_entry* mStrongRefs;
    ref_entry* mWeakRefs;

    bool mTrackEnabled;
    // Collect stack traces on addref and removeref, instead of deleting the stack references
    // on removeref that match the address ones.
    bool mRetain;

#endif
};
  • 從開頭的幾個變量大概可以猜出weakref_impl所做的工作,其中mStrong用于強(qiáng)引用計數(shù),mWeak用于弱引用計數(shù)。宏DEBUG_REFS用于指示release或debug版本,可以看出,在release版本下,addStrongRef,removeStrongRef相關(guān)的一系列方法都沒有具體實現(xiàn),也就是說,這些方法實際上是用于調(diào)試的,我們在分析時完全可以用戶例會。這樣一來,整體分析也清晰了很多。
  • Debug和Release版本都將mStrong初始化為INITIAL_STRONG_VALUE。這個值定義如下:

在代碼在RefBase.cpp 640行

#define INITIAL_STRONG_VALUE (1<<28)

而mWeak則初始化為0。上面的代碼并沒有引用計數(shù)器相關(guān)控制的實現(xiàn),真正有用的代碼在類聲明的外面。比如我們在wp構(gòu)造函數(shù)中遇到的createWeak函數(shù),那讓我們來看一下RefBase::createWeak()函數(shù)

3.3 RefBase::createWeak()函數(shù)

在代碼在RefBase.cpp 572行

RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
    mRefs->incWeak(id);  //增加弱引用計數(shù)
    return mRefs;  //直接返回weakref_type對象
}

這個函數(shù)先增加了mRefs(也就是weak_impl類型成員變量)中的弱引用計數(shù)值,然后返回這個mRefs。

3.4 wp與RefBase

關(guān)于類的關(guān)系圖如下


image.png
  • 首先 wp中的m_ptr還是要指向目標(biāo)對象(繼承自RefBase)。RefBase提供了弱引用控制以及其他新的功能。
  • 其次 因為RefBase需要處理多種計數(shù)類型,所以RefBase不直接使用int來保存應(yīng)用計數(shù)器中的計數(shù)值,而是采用了weakref_type的計數(shù)器。另外wp也同時保存了這個計數(shù)器的地址,也就是wp中的m_refs和RefBase中的mRefs都指向了計數(shù)器。其中wp是通過構(gòu)造函數(shù)中調(diào)用目標(biāo)對象的createWeak來獲取計數(shù)器地址的,而計數(shù)器本身是由RefBase在構(gòu)造時創(chuàng)建的。
  • 整個wp機(jī)制看起來很復(fù)雜,但與強(qiáng)指針相比實際上只是啟動了一個新的計數(shù)器weakref_impl而已,其他所有工作都是圍繞如何操作這個計數(shù)器而展開的。雖然weakref_impl是RefBase的成員變量,但是wp也可以直接控制它,所以整個邏輯顯得稍微有點混亂。

在createWeak中,mRefs通過incWeak增加了計數(shù)器的弱引用。代碼如下:
在代碼在RefBase.cpp 391行

void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->addWeakRef(id);
    const int32_t c __unused = android_atomic_inc(&impl->mWeak);
    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}

這個函數(shù)真真的有用的語句就是android_atomic_inc(&impl->mWeak); ,它增加了mWeak計數(shù)器的值,而其他都與調(diào)試有關(guān)。

這樣當(dāng)wp構(gòu)造完成以后,RefBase所持有的weakref_type計算器中的mWeak就為1。后面如果有新的wp指向這個目標(biāo)對象,mWeak還會持續(xù)增加。

上面是wp增加引用的邏輯,那么如果sp指向它會怎么樣?上面我們已經(jīng)說了sp會調(diào)用目標(biāo)對象的incStrong方法來增加強(qiáng)引用計數(shù)器的值,當(dāng)目標(biāo)對象繼承自RefBase時,這個函數(shù)實現(xiàn)是

3.5 incStrong()函數(shù)

在代碼在RefBase.cpp 572行

void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->incWeak(id);  //增加弱引用計數(shù)值

    refs->addStrongRef(id);
    const int32_t c = android_atomic_inc(&refs->mStrong);  //增加強(qiáng)引用計數(shù)器的值
    ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
#if PRINT_REFS
    ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    //判斷是否不是第一次
    if (c != INITIAL_STRONG_VALUE)  {
        //不是第一次,直接返回
        return;
    }
    android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
    refs->mBase->onFirstRef();
}

其實核心就兩行代碼

refs->incWeak(id);
const int32_t c = android_atomic_inc(&refs->mStrong); 

其實也就是同時增加弱引用和強(qiáng)引用的計數(shù)器的值。然后還要判斷目標(biāo)對象是不是第一次被引用,其中C的變量得到的是"增加之前的值",因而如果等于INITIAL_STRONG_VALUE就說明是第一次。這時候一方面回調(diào)onFirseRef通過對象自己被引用,另一方面要對mStrong值做下小調(diào)整。因為mStrong先是被置為INITIAL_STRONG_VALUE=1<<28,那么當(dāng)一次增加時,它就是1<<28+1,所以還要再次減掉INITIAL_STRONG_VALUE才能得到1。

4、對象釋放

現(xiàn)在我們再來分析下目標(biāo)對象在什么情況下會被釋放。無非就是考察減少強(qiáng)弱引用時系統(tǒng)所遵循的規(guī)則,如下所示是decStrong的情況。
在代碼在RefBase.cpp 341行

void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->removeStrongRef(id);
    //減少強(qiáng)引用計數(shù)器的值
    const int32_t c = android_atomic_dec(&refs->mStrong);
#if PRINT_REFS
    ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
    if (c == 1) {
        //減少強(qiáng)引用計數(shù)器的值已經(jīng)降為0
        //通知事件
        refs->mBase->onLastStrongRef(id);
        if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
             //刪除對象
            delete this;
        }
    }
    //減少弱引用計數(shù)器的值
    refs->decWeak(id);
}

整體流程如下:

  • 首先減少mStrong計數(shù)器。
  • 如果發(fā)現(xiàn)已經(jīng)減到0(即c==1),就要回調(diào)onLastStrongRef通知這一事件,然后執(zhí)行刪除操作(如果標(biāo)志是OBJECT_LIFETIME_STRONG)。
  • 最后減少弱引用計數(shù)器的值

PS:特別注意,減少弱引用計數(shù)器的值還要同時減少弱引用計數(shù)器的值,即最后decWeak(id)。

4.1、decWeak()函數(shù)

在代碼在RefBase.cpp 400行,實現(xiàn)代碼如下:

void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->removeWeakRef(id);
    //減少弱引用的值
    const int32_t c = android_atomic_dec(&impl->mWeak);
    ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
    if (c != 1) return;

    if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
        // This is the regular lifetime case. The object is destroyed
        // when the last strong reference goes away. Since weakref_impl
        // outlive the object, it is not destroyed in the dtor, and
        // we'll have to do it here.
        if (impl->mStrong == INITIAL_STRONG_VALUE) {
            // Special case: we never had a strong reference, so we need to
            // destroy the object now.
            delete impl->mBase;
        } else {
            // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
            delete impl;
        }
    } else {
        // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
        impl->mBase->onLastWeakRef(id);
        if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
            // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
            // is gone, we can destroy the object.
            delete impl->mBase;
        }
    }
}

通過閱讀上面的代碼,我們發(fā)現(xiàn)

  • 首先 顯示減少mWeak計數(shù)器的值
  • 其次 如果發(fā)現(xiàn)是0(即c==1),就直接返回
  • 如果發(fā)現(xiàn)不是0(即 c!=1),則根據(jù)LIFETIME標(biāo)志分別處理。
4.2、LIEFTIME的標(biāo)志

LIEFTIME的標(biāo)志是一個枚舉類,代碼如下
在代碼在RefBase.h 132行

    //! Flags for extendObjectLifetime()
    enum {
        OBJECT_LIFETIME_STRONG  = 0x0000,
        OBJECT_LIFETIME_WEAK    = 0x0001,
        OBJECT_LIFETIME_MASK    = 0x0001
    };

每個目標(biāo)對象都可以通過以下方法來更改它的引用規(guī)則

在代碼在RefBase.cpp 609行

void RefBase::extendObjectLifetime(int32_t mode)
{
    android_atomic_or(mode, &mRefs->mFlags);
}

所以實際上就是改變了mFlags標(biāo)志值——默認(rèn)情況下它是0,即OBJECT_LIFETIME_STRONG。釋放規(guī)則則受強(qiáng)引用控制的情況。有的人可能會想,既然是強(qiáng)引用控制,那么弱引用還要干什么?理論上它確實可以直接返回了,不過還有些特殊情況。前面在incString函數(shù)里,我們看到它同時增加了強(qiáng)、弱引用計數(shù)值。而增加弱引用是不會同時增加強(qiáng)引用的,這說明弱引用的值一定會大于強(qiáng)引用值。當(dāng)程序走到這里,弱引用數(shù)值一定為0,而強(qiáng)引用的的值有兩種可能:

  • 一種是強(qiáng)引用值為INITIAL_STRONG_VALUE,說明這個目標(biāo)對象沒有被強(qiáng)引用過,也就是說沒有辦法靠強(qiáng)引用指針來釋放目標(biāo),所以需要 delete impl->mBase
  • 另外一種就是在有強(qiáng)引用的情況下,此時要delete impl,而目標(biāo)對象會由強(qiáng)引用的decStrong來釋放。

那么為什么在這里delete這個是計數(shù)器?weakref_impl既然是由RefBase創(chuàng)建的,那么按道理來說應(yīng)該由它來刪除。實際上RefBase也想做這個工作,只是力不從心。其析構(gòu)函數(shù)如下:

在代碼在RefBase.cpp 588行

RefBase::~RefBase()
{
    if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
        // we never acquired a strong (and/or weak) reference on this object.
        delete mRefs;
    } else {
        // life-time of this object is extended to WEAK or FOREVER, in
        // which case weakref_impl doesn't out-live the object and we
        // can free it now.
        if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
            // It's possible that the weak count is not 0 if the object
            // re-acquired a weak reference in its destructor
            if (mRefs->mWeak == 0) {
                delete mRefs;
            }
        }
    }
    // for debugging purposes, clear this.
    const_cast<weakref_impl*&>(mRefs) = NULL;
}

在這種情況下,RefBase既然是有decStrong刪除的,那么從上面的decStrong的執(zhí)行順序來看mWeak值還不為0,因而并不會被執(zhí)行。
如果弱引用控制下的判斷規(guī)則(即OBJECT_LIFTIME_WEAK),其實和decStrong中的處理一樣,要首先回調(diào)通知目標(biāo)對象這一時間,然后才能執(zhí)行刪除操作。

5、總結(jié)

關(guān)于Android的智能指針就分析到這里,我們總結(jié)一下:

  • 1、智能指針分為強(qiáng)指針sp和弱指針wp
  • 2、通常情況下目標(biāo)對象的父類是RefBase——這個基類提供了一個weakref_impl類型的引用計數(shù)器,可以同時進(jìn)行強(qiáng)弱引用的控制(內(nèi)部由mStrong和mWeak提供計數(shù))
  • 3、當(dāng)incStrong增加強(qiáng)引用,也會增加弱引用
  • 4、當(dāng)incWeak時只增加弱引用計數(shù)
  • 5、使用者可以通過extendObjectLifetime設(shè)置引用計數(shù)器的規(guī)則,不同規(guī)則下對刪除目標(biāo)對象的時機(jī)判斷也是不一樣的
  • 6、使用者可以根據(jù)程序需求來選擇合適的智能指針類型和計數(shù)器規(guī)則
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容