Android跨進(jìn)程通信IPC整體內(nèi)容如下
- 1、Android跨進(jìn)程通信IPC之1——Linux基礎(chǔ)
- 2忽洛、Android跨進(jìn)程通信IPC之2——Bionic
- 3匣距、Android跨進(jìn)程通信IPC之3——關(guān)于"JNI"的那些事
- 4、Android跨進(jìn)程通信IPC之4——AndroidIPC基礎(chǔ)1
- 4莲趣、Android跨進(jìn)程通信IPC之4——AndroidIPC基礎(chǔ)2
- 5虑啤、Android跨進(jìn)程通信IPC之5——Binder的三大接口
- 6隙弛、Android跨進(jìn)程通信IPC之6——Binder框架
- 7、Android跨進(jìn)程通信IPC之7——Binder相關(guān)結(jié)構(gòu)體簡(jiǎn)介
- 8狞山、Android跨進(jìn)程通信IPC之8——Binder驅(qū)動(dòng)
- 9全闷、Android跨進(jìn)程通信IPC之9——Binder之Framework層C++篇1
- 9、Android跨進(jìn)程通信IPC之9——Binder之Framework層C++篇2
- 10萍启、Android跨進(jìn)程通信IPC之10——Binder之Framework層Java篇
- 11总珠、Android跨進(jìn)程通信IPC之11——AIDL
- 12、Android跨進(jìn)程通信IPC之12——Binder補(bǔ)充
- 13伊约、Android跨進(jìn)程通信IPC之13——Binder總結(jié)
- 14姚淆、Android跨進(jìn)程通信IPC之14——其他IPC方式
- 15孕蝉、Android跨進(jìn)程通信IPC之15——感謝
8 屡律、Binder對(duì)象的寫(xiě)入
前面說(shuō)完了基本的數(shù)據(jù)傳輸流程,心里有了一個(gè)大致的流程降淮,再來(lái)看一下Binder對(duì)象的傳輸超埋。首先需要對(duì)Binder有一個(gè)概念,就是每一個(gè)java端的Binder對(duì)象(服務(wù)端)在初始化時(shí)都會(huì)對(duì)應(yīng)一個(gè)native對(duì)象佳鳖,類(lèi)型是BBinder霍殴,它繼承于IBinder類(lèi)
時(shí)序圖如下:
通過(guò) Parcel的writeStrongBinder方法將Binder對(duì)象序列化:
(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),這個(gè)方法對(duì)應(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);
}
}
}
這里說(shuō)下ibinderForJavaObject()函數(shù)来庭,返回的是BBinder對(duì)象(實(shí)際上是JavaBBinder,它繼承自BBinder) 后面講解Binder的時(shí)候再詳細(xì)說(shuō)
然后調(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);
}
這塊代碼很簡(jiǎn)單月弛,主要是調(diào)用了flatten_binder()函數(shù)
這里說(shuō)一下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不為空
//寫(xiě)入JavaBBinder將對(duì)應(yīng)這一段
obj.type = BINDER_TYPE_BINDER;
// 弱引用對(duì)象
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
// this 對(duì)象贞绵,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厉萝,對(duì)兩種Binder采取了兩種不同的方式。
- Binder如果是JavaBBinder,則它的localBinder會(huì)返回localBinder谴垫。
- Binder如果是BpBinder章母,則它的localBinder會(huì)返回null
通過(guò)上文我們知道ibinderForJavaObject就返回JavaBBinder。所以我們知道走入分支二
flat_binder_object是Binder寫(xiě)入對(duì)象的結(jié)構(gòu)體翩剪,它對(duì)應(yīng)著B(niǎo)inder胳施。
- flat_binder_object的handle表示Binder對(duì)象在Binder驅(qū)動(dòng)中的標(biāo)志,比如ServiceManager的handle為0肢专。
- flat_binder_object的type表示當(dāng)前傳輸?shù)腂inder是本地的(同進(jìn)程)舞肆,還是一個(gè)Proxy(跨進(jìn)程)。
通過(guò)上面代碼我們知道這里取得的flat_binder_object對(duì)應(yīng)的值如下
- type為BINDER_TYPE_BINDER
- binder為reinterpret_cast(local->getWeakRefs());
- cookie為reinterpret_cast(local)
binder博杖,cookie保存著B(niǎo)inder對(duì)象的指針椿胯。最后調(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寫(xiě)入到out里面里面剃根,最終寫(xiě)入到Binder驅(qū)動(dòng)中哩盲,那我們繼續(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ù)寫(xiě)入
*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ù)
這里面有三個(gè)分支廉油,我們就來(lái)依次說(shuō)下
- 如果mData和mObjects空間足夠,則走分支一
- 如果mData空間不足苗傅,則擴(kuò)展空間抒线,growData()函數(shù)看前面
- 如果mObjects空間不足,則擴(kuò)展空間渣慕,和mData空間擴(kuò)展基本相似
調(diào)用 * reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val; 寫(xiě)入mObject
最后調(diào)用finishWrite()函數(shù)嘶炭,就是調(diào)整調(diào)整 mDataPos 和 mDataSize,上面已經(jīng)說(shuō)過(guò)了逊桦,我就跟蹤了眨猎。至此整體寫(xiě)入流程已經(jīng)完成了。
9 强经、Binder對(duì)象的讀出
Parcel對(duì)象的讀出睡陪,首先還是在Parcel.java這個(gè)類(lèi)里面,對(duì)應(yīng)的方法是
時(shí)序圖如下:
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);
而這個(gè)native方法又對(duì)應(yīng)這個(gè)JNI的一個(gè)方法兰迫,通過(guò)上文我們知道,對(duì)應(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;
}
這個(gè)函數(shù)里面先調(diào)用了Parcel-Native的readStrongBinder()函數(shù)码秉,然后又用這個(gè)函數(shù)的返回值作為參數(shù)調(diào)用了javaObjectForIBinder()函數(shù)逮矛。那我們就依次來(lái)看一下。
9.4 readStrongBinder()函數(shù)
代碼在Parcel.cpp 1134行
sp<IBinder> Parcel::readStrongBinder() const
{
sp<IBinder> val;
unflatten_binder(ProcessState::self(), *this, &val);
return val;
}
我們看到這個(gè)函數(shù)什么也沒(méi)做转砖,主要就是調(diào)用了unflatten_binder()函數(shù)须鼎。
readStrongBinder 其實(shí)挺簡(jiǎn)單的鲸伴,是本地的可以直接用,遠(yuǎn)程的那個(gè) getStrongProxyForHandle 也是放到后面 ServiceManager 再細(xì)說(shuō)晋控。到這里目標(biāo)進(jìn)程就收到原始進(jìn)程傳遞過(guò)來(lái)的 binder 對(duì)象了汞窗,然后可以轉(zhuǎn)化為 binder 的 interface 調(diào)用對(duì)應(yīng)的 IPC 接口。
PS:
這里說(shuō)下赡译,ProcessState::self()函數(shù)是返回的ProcessState的對(duì)象
那我們?cè)賮?lái)看下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的話,要通過(guò)handle構(gòu)造一個(gè)遠(yuǎn)程的代理對(duì)象
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
這里說(shuō)下這里的兩個(gè)分支
- BINDER_TYPE_BINDER分支:是Bn意味著是同一個(gè)進(jìn)程
- BINDER_TYPE_HANDLE分支:是Bp意味著是跨進(jìn)程
我們?cè)賮?lái)分下一下這個(gè)函數(shù)蝌焚,主要就是兩個(gè)兩個(gè)流程
- 1裹唆、從Binder驅(qū)動(dòng)中讀取一個(gè)flat_binder_object對(duì)象flat
- 2、根據(jù)flat對(duì)象的type值來(lái)分別處理只洒。如果是BINDER_TYPE_BINDER许帐,則使用cookie中的值,強(qiáng)制轉(zhuǎn)換成指針毕谴。如果是BINDER_TYPE_HANDLE成畦,則使用Proxy,即通過(guò)getStringProxyForHandle()函數(shù)涝开,并根據(jù)handle創(chuàng)建BpBinder循帐。
ProcessState::getStrongProxyForHandle()函數(shù)后續(xù)講解Binder的時(shí)候再詳細(xì)講解,這里就不說(shuō)了舀武。那我們來(lái)看一下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;
}
這行代碼很簡(jiǎn)單拄养,就是返回NO_ERROR。這時(shí)候我們回到了javaObjectForIBinder()函數(shù)奕剃。
9.7 javaObjectForIBinder()函數(shù)
javaObjectgForBinder與ibinderForJavaObject相對(duì)應(yīng)的衷旅,把IBinder對(duì)象轉(zhuǎn)換成對(duì)應(yīng)的Java層的Object。這個(gè)函數(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)) {
//如果是本地的,那么會(huì)直接進(jìn)入這個(gè)部分代碼茄袖,因?yàn)檫@個(gè)val
//是寫(xiě)入的時(shí)候的同一個(gè)對(duì)象操软,gBinderOffsets也是一致的。如
//果val是一種Poxy對(duì)象宪祥,則不然聂薪,會(huì)繼續(xù)往下執(zhí)行,找到一個(gè)
//Proxy對(duì)象
// 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沒(méi)有帶proxy過(guò)來(lái)
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)建一個(gè)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;
}
- 首先判斷是不是同一個(gè)進(jìn)程蝗羊,如果是同一個(gè)進(jìn)程藏澳,則val是JavaBBinder。那么在checkSubclass()函數(shù)中耀找,它所包含的gBinderOffsets指針參數(shù)傳入的gBinderOffsets的指針必然是同一個(gè)值翔悠,則滿足if條件业崖,直接將指針強(qiáng)制轉(zhuǎn)化為JavaBBinder,返回對(duì)應(yīng)的jobject蓄愁。如果是不是同一個(gè)進(jìn)程双炕,那么val也就是BpBinder。
- 其次撮抓,在BpBinder對(duì)象中查找是否保存相關(guān)的BinderProxy的對(duì)象妇斤,如果有,向Java層返回這個(gè)對(duì)象丹拯。如果沒(méi)有站超,則創(chuàng)建一個(gè)BinderProxy對(duì)象,并將新創(chuàng)建的BinderProxy對(duì)象乖酬,attach到BpBinder對(duì)象中顷编。
在構(gòu)造Java對(duì)象的時(shí)候,上面用到了 binderproxy_offsets_t 結(jié)構(gòu)體 剑刑,那我們就來(lái)看下這個(gè)結(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ī)啟動(dòng)的時(shí)候(即在 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));
}
通過(guò)上面代碼我們知道這個(gè)類(lèi)型是android.os.BinderProxy施掏,也就是說(shuō)代理端Java層的對(duì)象是android.os.BinderProxy
9.8 總結(jié)
結(jié)合下面的關(guān)系圖钮惠,我們得出下面的邏輯關(guān)系:
- 每個(gè)進(jìn)程都會(huì)保存多個(gè)當(dāng)前調(diào)用過(guò)的BpBinder對(duì)象
- 每個(gè)BpBinder對(duì)象都會(huì)保存與之對(duì)應(yīng)的Java層的BinderProxy
將創(chuàng)建的BinderProxy attach到BpBinder的意義在于,通過(guò)這種方式七芭,Java應(yīng)用層偏飯獲取同一個(gè)Service的IBinder時(shí)素挽,獲取的是同一個(gè)BinderProxy。
10 Parcel讀取寫(xiě)入總結(jié)
- 上面介紹了Parcel整個(gè)寫(xiě)入讀取的流程狸驳,最后代替Binder傳輸?shù)氖?br> flat_binder_object预明。在Parcel-Native中,根據(jù)跨進(jìn)程和非跨進(jìn)程耙箍,flat_binder_object的值是不一樣的:跨進(jìn)程的時(shí)候flat_binder_object的type是BINDER_TYPE_HANDLE撰糠;非跨進(jìn)程的時(shí)候flat_binder_object的type是BINDER_TYPE_BINDER。在這里可以發(fā)現(xiàn)跨進(jìn)程與非跨進(jìn)程的時(shí)候傳輸數(shù)據(jù)的區(qū)別辩昆≡睦遥客戶端的Parcel讀取Binder的時(shí)候,根據(jù)flat_binder_object的type值進(jìn)行區(qū)分對(duì)待,返回不同的內(nèi)容。而寫(xiě)入的時(shí)候也是一樣的筒溃,根據(jù)是否是Proxy摸吠,來(lái)決定寫(xiě)入HANDLE還是BINDER。最終這些內(nèi)容都會(huì)通過(guò)ioctl與Binder驅(qū)動(dòng)進(jìn)行數(shù)據(jù)通信。所以最終處理不同進(jìn)程間的Binder數(shù)據(jù)傳輸處理也只能是Binder驅(qū)動(dòng)了。
- Binder對(duì)象傳入Binder驅(qū)動(dòng)最底層是轉(zhuǎn)化為flat_binder_object傳遞的。Parcel是根據(jù)從驅(qū)動(dòng)中讀取的數(shù)據(jù)做出不同的處理瑞躺,如果從Binder驅(qū)動(dòng)中取出的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層為原來(lái)的Service的Binder對(duì)象(相同進(jìn)程)嘱么。
- 在 /frameworks/base/core/jni/android_util_Binder.cpp 中有兩個(gè)函數(shù)分別是ibinderForJavaObject()函數(shù)與javaObjectForIBinder()函數(shù)是相互對(duì)應(yīng)的狮含,一個(gè)是把Native中對(duì)應(yīng)的IBinder對(duì)象化為Java對(duì)象,一個(gè)是將Java的對(duì)象轉(zhuǎn)為化Native中對(duì)應(yīng)的IBinder對(duì)象
五曼振、智能指針
Java和C/C++的一個(gè)重大區(qū)別几迄,就是它沒(méi)有"指針"的概念,這并不代表Java不需要只用指針冰评,而是將這個(gè)"超級(jí)武器隱藏了"映胁。如果大家使用C/C++開(kāi)發(fā)過(guò)一些大型項(xiàng)目,就會(huì)知道一個(gè)比較頭疼的問(wèn)題——指針異常甲雅。所以Java以其他更"安全"的形式向開(kāi)發(fā)人員提供了隱形的"指針"解孙,使得用戶既能享受到指針的強(qiáng)大功能,又能盡量避免指針帶來(lái)的問(wèn)題抛人。
(一)弛姜、C/C++中常見(jiàn)的指針問(wèn)題
1、指針沒(méi)有初始化
對(duì)指針進(jìn)行初始化是程序員必須養(yǎng)成的良好習(xí)慣妖枚,也是指針問(wèn)題中最容易解決和控制的一個(gè)問(wèn)題
2廷臼、new了對(duì)象沒(méi)有及時(shí)delete
動(dòng)態(tài)分配內(nèi)存的對(duì)象,其實(shí)聲明周期的控制不當(dāng)常常會(huì)引起不少麻煩绝页。如果只有一個(gè)程序員在維護(hù)時(shí)荠商,問(wèn)題通常不大,因?yàn)橹灰晕⒘粜木涂梢詫?shí)現(xiàn)new和delete的配套操作续誉;但是如果一個(gè)大型工程(特別是多滴協(xié)同研發(fā)的軟件項(xiàng)目)莱没,由于溝通的不及時(shí)或者人員素質(zhì)的殘差不起,就很可能會(huì)出現(xiàn)動(dòng)態(tài)分配的內(nèi)存沒(méi)有回收的情況——造成的內(nèi)存泄露問(wèn)題往往是致命的屈芜。
3郊愧、野指針
假設(shè)1:我們new了一個(gè)對(duì)象A,并將指針ptr指向這個(gè)新是對(duì)象(即ptr= new )井佑。當(dāng)對(duì)A使用結(jié)束后,我們也主動(dòng)delete了A眠寿,但是唯一沒(méi)做的是將ptr指針置空躬翁,那么可能出現(xiàn)什么問(wèn)題?沒(méi)錯(cuò)盯拱,就是野指針盒发。因此如果有"第三方"視圖用ptr來(lái)使用內(nèi)存對(duì)象例嘱,它首先通過(guò)判斷發(fā)現(xiàn)ptr不為空,自然而然的就認(rèn)為這個(gè)對(duì)象還是存在的宁舰,其結(jié)果就是導(dǎo)致死機(jī)拼卵。
假設(shè)2:假設(shè)ptr1和ptr2都指向?qū)ο驛,后來(lái)我們通過(guò)ptr1釋放了A的內(nèi)存空間蛮艰,并且將ptr1也置為null腋腮;但是ptr2并不知道它所指向的內(nèi)存對(duì)象已經(jīng)不存在了,此時(shí)如果ptr2來(lái)訪問(wèn)A也會(huì)導(dǎo)致死機(jī)
(二)壤蚜、我們?cè)O(shè)計(jì)的解決方案
上面分析了C/C++指針的問(wèn)題即寡。如果讓我們?cè)O(shè)計(jì)Android的智能指針,怎么做才能防止以上幾個(gè)問(wèn)題袜刷?解決方案思路如下:
- 問(wèn)題1的解決方案:這個(gè)簡(jiǎn)單聪富,只要讓指針在創(chuàng)建時(shí)設(shè)置為null即可
- 問(wèn)題2的解決方案:比較復(fù)雜,既然是智能指針就為意味著它應(yīng)該是一個(gè)"雷鋒"著蟹,盡可能自動(dòng)的實(shí)現(xiàn)new和delete的相應(yīng)工作墩蔓,那什么時(shí)候應(yīng)該delete一個(gè)內(nèi)存對(duì)象呢?肯定是"不需要的時(shí)候"(其實(shí)是個(gè)廢話)萧豆。那怎么來(lái)分別什么是"需要"和"不需要"奸披?在C/C++中,我們一般認(rèn)為:當(dāng)一個(gè)指針指向一個(gè)object的時(shí)候炕横,這個(gè)內(nèi)存對(duì)象就是"需要"的源内,當(dāng)這個(gè)指針接觸了與內(nèi)存對(duì)象的關(guān)系,我們就認(rèn)為這個(gè)內(nèi)存對(duì)象已經(jīng)"不需要"了份殿。所以我們想到用一個(gè)布爾類(lèi)型變量來(lái)保存即可膜钓。
- 問(wèn)題3的解決方案:?jiǎn)栴}又來(lái)了,當(dāng)有兩個(gè)指針及兩個(gè)以上指針同時(shí)使用這個(gè)內(nèi)存怎么辦卿嘲,用布爾類(lèi)型肯定是不行的颂斜。所以我們要用一個(gè)計(jì)數(shù)器來(lái)記錄這個(gè)內(nèi)存對(duì)象"被需要"的個(gè)數(shù)即可,當(dāng)這個(gè)計(jì)數(shù)器遞減到零時(shí)拾枣,就說(shuō)明這個(gè)內(nèi)存對(duì)象應(yīng)該"壽終正寢"了沃疮。這就是在很多領(lǐng)域了都得到廣泛應(yīng)用的"引用計(jì)數(shù)"的概念。如下圖
那Android到底是怎么設(shè)計(jì)的梅肤?
(三)司蔬、Android智能指針的原理
重點(diǎn)強(qiáng)調(diào) :
智能指針是一個(gè)對(duì)象,而不是一個(gè)指針姨蝴。
- Android設(shè)計(jì)了基類(lèi)RefBase俊啼,用以管理引用數(shù),所有類(lèi)必須從RefBase派生左医,RefBase是所有對(duì)象的始祖授帕。
- 設(shè)計(jì)模板類(lèi)sp同木、wp,用以引用實(shí)際對(duì)象跛十,sp強(qiáng)引用和wp弱引用彤路。sp、wp聲明為棧對(duì)象芥映,作用域結(jié)束時(shí)洲尊,自動(dòng)釋放,自動(dòng)調(diào)用機(jī)析構(gòu)函數(shù)屏轰。因此可以在sp颊郎、wp的構(gòu)造函數(shù)中,增加引用計(jì)數(shù)霎苗,在析構(gòu)函數(shù)中姆吭,減少引用計(jì)數(shù)。
- 專(zhuān)門(mén)設(shè)計(jì)weakref_impl類(lèi)唁盏,該類(lèi)是RefBase的累不累内狸,用來(lái)做真正的引用數(shù)管理,都有mRef來(lái)管理
Android智能指針的關(guān)系圖:
(四)厘擂、Android智能指針的源碼位置
android中的智能指針的主要代碼是:RefBase.h和RefBase.cpp StrongPointer.h 這三個(gè)文件昆淡,他們分別位于:
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刽严,很多人會(huì)以為是StrongPointer的縮寫(xiě)昂灵。與sp對(duì)應(yīng)的是wp,我們將會(huì)在下一節(jié)講解舞萄。
先來(lái)看下源碼:
///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;
};
通過(guò)閱讀源碼眨补,我們知道這個(gè)sp類(lèi)的設(shè)計(jì)和我們之前想象的基本一致,比如運(yùn)算符的實(shí)現(xiàn)為:
//system/core/include/utils/StrongPointer.h 157行
template<typename T>
sp<T>& sp<T>::operator =(T* other) {
if (other)
other->incStrong(this); //增加引用計(jì)數(shù)
if (m_ptr)
m_ptr->decStrong(this); // 減少引用計(jì)數(shù)
m_ptr = other;
return *this;
}
上面的diamante同時(shí)考慮了對(duì)一個(gè)智能指針重復(fù)賦值的情況倒脓。即當(dāng)m_ptr不為空時(shí)撑螺,要先撤銷(xiāo)它之前指向的內(nèi)存對(duì)象,然后才能賦予其新值崎弃。另外為sp分配一個(gè)內(nèi)存對(duì)象甘晤,不一定要通過(guò)操作運(yùn)算符(比如等號(hào)),它的構(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); //因?yàn)槭菢?gòu)造函數(shù)线婚,所以不同擔(dān)心mptr之前已經(jīng)賦值過(guò)
}
這時(shí)候m_ptr就不用先置為null,可以直接指向目標(biāo)對(duì)象盆均。而析構(gòu)函數(shù)的做法和我們的預(yù)想也是一樣酌伊。
template<typename T>
sp<T>::~sp() {
if (m_ptr)
m_ptr->decStrong(this);
}
(六)、弱指針wp
1缀踪、弱引用產(chǎn)生的背景:
在前面討論之智能指針的"設(shè)計(jì)理念"時(shí)居砖,其實(shí)是以強(qiáng)指針為原型逐步還原出智能指針作者的"意圖',那么"弱指針"又由什么作用?
其實(shí)弱指針主要是為了解決一個(gè)問(wèn)題驴娃?那是什么問(wèn)題那奏候?有這么一種情況:父對(duì)象指向子對(duì)象child,然后子對(duì)象又指向父對(duì)象唇敞,這就存在了虛幻引用的現(xiàn)象蔗草。比如有兩個(gè)class
struct Parent
{
Child *myson;
}
struct Child
{
Parent *myfather;
}
這樣就會(huì)產(chǎn)生上面的問(wèn)題。如果不考慮智能指針疆柔,這樣的情況不會(huì)導(dǎo)致任何問(wèn)題咒精,但是在智能指針的場(chǎng)景下,就要注意了旷档,因?yàn)镻arent指向了Child模叙,所以Child的引用計(jì)數(shù)器不為零。同時(shí)又由于Child指向了Parent鞋屈,所以Parent的引用器不會(huì)為零范咨。這有點(diǎn)類(lèi)似于Java中的死鎖了。因?yàn)閮?nèi)存回收者返現(xiàn)兩者都是"被需要"的狀態(tài)厂庇,當(dāng)然不能釋放渠啊,從而形成了惡性循環(huán)。
為了解決上面這個(gè)問(wèn)題权旷,產(chǎn)生了"弱引用"替蛉。具體措施如下:
Parent使用強(qiáng)指針來(lái)引用Child,而Child只使用弱引用來(lái)指向父Parent類(lèi)拄氯。雙方規(guī)定當(dāng)強(qiáng)引用計(jì)數(shù)器為0時(shí)躲查,不論弱引用是否為0,都可以delete自己(Android系統(tǒng)中這個(gè)規(guī)定是可以調(diào)整的坤邪,后面有介紹)熙含。這樣只要一方得到了釋放了,就可以成功避免死鎖艇纺。當(dāng)然這樣就會(huì)造成野指針怎静。是的,比如Parent因?yàn)橐驗(yàn)閺?qiáng)指針計(jì)數(shù)器計(jì)數(shù)已經(jīng)到0了黔衡,根據(jù)規(guī)則生命周期就結(jié)束了蚓聘。但是此時(shí)Child還持有父類(lèi)的弱引用,顯然如果Child此時(shí)用這個(gè)指針訪問(wèn)Parent會(huì)引發(fā)致命的問(wèn)題盟劫。為了別面這個(gè)問(wèn)題夜牡,我們還規(guī)定: 弱指針必須先升級(jí)為強(qiáng)指針,才能訪問(wèn)它所指向的目標(biāo)對(duì)象。
所以我們也可以說(shuō)塘装,若指針的主要使用就是解決循環(huán)引用的問(wè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; //升級(jí)為強(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;
};
通過(guò)和sp相比僚碎,我們發(fā)現(xiàn)有如下區(qū)別:
- 除了指向目標(biāo)對(duì)象的m_ptr外,wp另外有一個(gè)m_refs指針阴幌,類(lèi)型為weakref_type勺阐。
- 沒(méi)有重載 " -> " 、" * " 等運(yùn)算符矛双。
- 有一個(gè)prmote方法將wp提升為sp渊抽。
- 目標(biāo)對(duì)象的父類(lèi)不是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);
}
通過(guò)和強(qiáng)指針的中的構(gòu)造函數(shù)進(jìn)行對(duì)比懒闷,我們發(fā)現(xiàn),wp并沒(méi)有直接增加目標(biāo)對(duì)象的引用計(jì)數(shù)值徙瓶,而是調(diào)用了createWeak()函數(shù)毛雇。這個(gè)函數(shù)是RefBase類(lèi)的
那我們來(lái)看下RefBase類(lèi)
3.1RefBase類(lèi)
在代碼在RefBase.h 69行
class RefBase
{
public:
void incStrong(const void* id) const; //增加強(qiáng)引用計(jì)數(shù)器的值
void decStrong(const void* id) const; //減少?gòu)?qiáng)引用計(jì)數(shù)器的值
void forceIncStrong(const void* id) const;
//! DEBUGGING ONLY: Get current strong ref count.
int32_t getStrongCount() const;
class weakref_type //嵌套類(lèi),wp中用到的就是這個(gè)類(lèi)
{
public:
RefBase* refBase() const;
void incWeak(const void* id); //增加弱引用計(jì)數(shù)器的值
void decWeak(const void* id); //減少弱引用計(jì)數(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嵌套了一個(gè)重要的類(lèi)weakref_type侦镇,也就是前面的m_refs指針?biāo)鶎俚念?lèi)型灵疮。RefBase中還有一個(gè)mRefs的成員變量,類(lèi)型為weakref_impl壳繁。從名稱(chēng)上來(lái)看震捣,它應(yīng)該是weak_type的實(shí)現(xiàn)類(lèi)。
3.2 weakref_impl類(lèi)
在代碼在RefBase.cpp 64行
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
volatile int32_t mStrong; //強(qiáng)引用計(jì)數(shù)器的值
volatile int32_t mWeak; //弱引用計(jì)數(shù)器的值
RefBase* const mBase;
volatile int32_t mFlags;
#if !DEBUG_REFS //非Debug模式下闹炉,DEBUG_REFS是個(gè)宏
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
};
- 從開(kāi)頭的幾個(gè)變量大概可以猜出weakref_impl所做的工作蒿赢,其中mStrong用于強(qiáng)引用計(jì)數(shù),mWeak用于弱引用計(jì)數(shù)渣触。宏DEBUG_REFS用于指示release或debug版本羡棵,可以看出,在release版本下嗅钻,addStrongRef,removeStrongRef相關(guān)的一系列方法都沒(méi)有具體實(shí)現(xiàn)皂冰,也就是說(shuō),這些方法實(shí)際上是用于調(diào)試的养篓,我們?cè)诜治鰰r(shí)完全可以用戶例會(huì)秃流。這樣一來(lái),整體分析也清晰了很多柳弄。
- Debug和Release版本都將mStrong初始化為INITIAL_STRONG_VALUE舶胀。這個(gè)值定義如下:
在代碼在RefBase.cpp 640行
#define INITIAL_STRONG_VALUE (1<<28)
而mWeak則初始化為0。上面的代碼并沒(méi)有引用計(jì)數(shù)器相關(guān)控制的實(shí)現(xiàn),真正有用的代碼在類(lèi)聲明的外面嚣伐。比如我們?cè)趙p構(gòu)造函數(shù)中遇到的createWeak函數(shù)糖赔,那讓我們來(lái)看一下RefBase::createWeak()函數(shù)
3.3 RefBase::createWeak()函數(shù)
在代碼在RefBase.cpp 572行
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
mRefs->incWeak(id); //增加弱引用計(jì)數(shù)
return mRefs; //直接返回weakref_type對(duì)象
}
這個(gè)函數(shù)先增加了mRefs(也就是weak_impl類(lèi)型成員變量)中的弱引用計(jì)數(shù)值,然后返回這個(gè)mRefs纤控。
3.4 wp與RefBase
關(guān)于類(lèi)的關(guān)系圖如下
- 首先 wp中的m_ptr還是要指向目標(biāo)對(duì)象(繼承自RefBase)挂捻。RefBase提供了弱引用控制以及其他新的功能。
- 其次 因?yàn)镽efBase需要處理多種計(jì)數(shù)類(lèi)型船万,所以RefBase不直接使用int來(lái)保存應(yīng)用計(jì)數(shù)器中的計(jì)數(shù)值,而是采用了weakref_type的計(jì)數(shù)器骨田。另外wp也同時(shí)保存了這個(gè)計(jì)數(shù)器的地址耿导,也就是wp中的m_refs和RefBase中的mRefs都指向了計(jì)數(shù)器。其中wp是通過(guò)構(gòu)造函數(shù)中調(diào)用目標(biāo)對(duì)象的createWeak來(lái)獲取計(jì)數(shù)器地址的态贤,而計(jì)數(shù)器本身是由RefBase在構(gòu)造時(shí)創(chuàng)建的舱呻。
- 整個(gè)wp機(jī)制看起來(lái)很復(fù)雜,但與強(qiáng)指針相比實(shí)際上只是啟動(dòng)了一個(gè)新的計(jì)數(shù)器weakref_impl而已悠汽,其他所有工作都是圍繞如何操作這個(gè)計(jì)數(shù)器而展開(kāi)的箱吕。雖然weakref_impl是RefBase的成員變量,但是wp也可以直接控制它柿冲,所以整個(gè)邏輯顯得稍微有點(diǎn)混亂茬高。
在createWeak中,mRefs通過(guò)incWeak增加了計(jì)數(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);
}
這個(gè)函數(shù)真真的有用的語(yǔ)句就是android_atomic_inc(&impl->mWeak); 怎栽,它增加了mWeak計(jì)數(shù)器的值,而其他都與調(diào)試有關(guān)宿饱。
這樣當(dāng)wp構(gòu)造完成以后熏瞄,RefBase所持有的weakref_type計(jì)算器中的mWeak就為1。后面如果有新的wp指向這個(gè)目標(biāo)對(duì)象谬以,mWeak還會(huì)持續(xù)增加强饮。
上面是wp增加引用的邏輯,那么如果sp指向它會(huì)怎么樣为黎?上面我們已經(jīng)說(shuō)了sp會(huì)調(diào)用目標(biāo)對(duì)象的incStrong方法來(lái)增加強(qiáng)引用計(jì)數(shù)器的值邮丰,當(dāng)目標(biāo)對(duì)象繼承自RefBase時(shí),這個(gè)函數(shù)實(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); //增加弱引用計(jì)數(shù)值
refs->addStrongRef(id);
const int32_t c = android_atomic_inc(&refs->mStrong); //增加強(qiáng)引用計(jì)數(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();
}
其實(shí)核心就兩行代碼
refs->incWeak(id);
const int32_t c = android_atomic_inc(&refs->mStrong);
其實(shí)也就是同時(shí)增加弱引用和強(qiáng)引用的計(jì)數(shù)器的值柠座。然后還要判斷目標(biāo)對(duì)象是不是第一次被引用,其中C的變量得到的是"增加之前的值"片橡,因而如果等于INITIAL_STRONG_VALUE就說(shuō)明是第一次妈经。這時(shí)候一方面回調(diào)onFirseRef通過(guò)對(duì)象自己被引用,另一方面要對(duì)mStrong值做下小調(diào)整。因?yàn)閙Strong先是被置為INITIAL_STRONG_VALUE=1<<28吹泡,那么當(dāng)一次增加時(shí)骤星,它就是1<<28+1,所以還要再次減掉INITIAL_STRONG_VALUE才能得到1爆哑。
4洞难、對(duì)象釋放
現(xiàn)在我們?cè)賮?lái)分析下目標(biāo)對(duì)象在什么情況下會(huì)被釋放。無(wú)非就是考察減少?gòu)?qiáng)弱引用時(shí)系統(tǒng)所遵循的規(guī)則揭朝,如下所示是decStrong的情況队贱。
在代碼在RefBase.cpp 341行
void RefBase::decStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->removeStrongRef(id);
//減少?gòu)?qiáng)引用計(jì)數(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) {
//減少?gòu)?qiáng)引用計(jì)數(shù)器的值已經(jīng)降為0
//通知事件
refs->mBase->onLastStrongRef(id);
if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
//刪除對(duì)象
delete this;
}
}
//減少弱引用計(jì)數(shù)器的值
refs->decWeak(id);
}
整體流程如下:
- 首先減少mStrong計(jì)數(shù)器。
- 如果發(fā)現(xiàn)已經(jīng)減到0(即c==1)潭袱,就要回調(diào)onLastStrongRef通知這一事件柱嫌,然后執(zhí)行刪除操作(如果標(biāo)志是OBJECT_LIFETIME_STRONG)。
- 最后減少弱引用計(jì)數(shù)器的值
PS:特別注意屯换,減少弱引用計(jì)數(shù)器的值還要同時(shí)減少弱引用計(jì)數(shù)器的值编丘,即最后decWeak(id)。
4.1彤悔、decWeak()函數(shù)
在代碼在RefBase.cpp 400行嘉抓,實(shí)現(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;
}
}
}
通過(guò)閱讀上面的代碼,我們發(fā)現(xiàn)
- 首先 顯示減少mWeak計(jì)數(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)志是一個(gè)枚舉類(lèi),代碼如下
在代碼在RefBase.h 132行
//! Flags for extendObjectLifetime()
enum {
OBJECT_LIFETIME_STRONG = 0x0000,
OBJECT_LIFETIME_WEAK = 0x0001,
OBJECT_LIFETIME_MASK = 0x0001
};
每個(gè)目標(biāo)對(duì)象都可以通過(guò)以下方法來(lái)更改它的引用規(guī)則
在代碼在RefBase.cpp 609行
void RefBase::extendObjectLifetime(int32_t mode)
{
android_atomic_or(mode, &mRefs->mFlags);
}
所以實(shí)際上就是改變了mFlags標(biāo)志值——默認(rèn)情況下它是0望拖,即OBJECT_LIFETIME_STRONG渺尘。釋放規(guī)則則受強(qiáng)引用控制的情況。有的人可能會(huì)想说敏,既然是強(qiáng)引用控制鸥跟,那么弱引用還要干什么?理論上它確實(shí)可以直接返回了盔沫,不過(guò)還有些特殊情況医咨。前面在incString函數(shù)里,我們看到它同時(shí)增加了強(qiáng)架诞、弱引用計(jì)數(shù)值拟淮。而增加弱引用是不會(huì)同時(shí)增加強(qiáng)引用的,這說(shuō)明弱引用的值一定會(huì)大于強(qiáng)引用值谴忧。當(dāng)程序走到這里很泊,弱引用數(shù)值一定為0角虫,而強(qiáng)引用的的值有兩種可能:
- 一種是強(qiáng)引用值為INITIAL_STRONG_VALUE,說(shuō)明這個(gè)目標(biāo)對(duì)象沒(méi)有被強(qiáng)引用過(guò)委造,也就是說(shuō)沒(méi)有辦法靠強(qiáng)引用指針來(lái)釋放目標(biāo)戳鹅,所以需要 delete impl->mBase
- 另外一種就是在有強(qiáng)引用的情況下,此時(shí)要delete impl昏兆,而目標(biāo)對(duì)象會(huì)由強(qiáng)引用的decStrong來(lái)釋放枫虏。
那么為什么在這里delete這個(gè)是計(jì)數(shù)器?weakref_impl既然是由RefBase創(chuàng)建的爬虱,那么按道理來(lái)說(shuō)應(yīng)該由它來(lái)刪除隶债。實(shí)際上RefBase也想做這個(gè)工作,只是力不從心饮潦。其析構(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í)行順序來(lái)看mWeak值還不為0继蜡,因而并不會(huì)被執(zhí)行。
如果弱引用控制下的判斷規(guī)則(即OBJECT_LIFTIME_WEAK)逛腿,其實(shí)和decStrong中的處理一樣稀并,要首先回調(diào)通知目標(biāo)對(duì)象這一時(shí)間,然后才能執(zhí)行刪除操作单默。
5碘举、總結(jié)
關(guān)于Android的智能指針就分析到這里,我們總結(jié)一下:
- 1搁廓、智能指針?lè)譃閺?qiáng)指針sp和弱指針wp
- 2引颈、通常情況下目標(biāo)對(duì)象的父類(lèi)是RefBase——這個(gè)基類(lèi)提供了一個(gè)weakref_impl類(lèi)型的引用計(jì)數(shù)器,可以同時(shí)進(jìn)行強(qiáng)弱引用的控制(內(nèi)部由mStrong和mWeak提供計(jì)數(shù))
- 3境蜕、當(dāng)incStrong增加強(qiáng)引用蝙场,也會(huì)增加弱引用
- 4、當(dāng)incWeak時(shí)只增加弱引用計(jì)數(shù)
- 5粱年、使用者可以通過(guò)extendObjectLifetime設(shè)置引用計(jì)數(shù)器的規(guī)則售滤,不同規(guī)則下對(duì)刪除目標(biāo)對(duì)象的時(shí)機(jī)判斷也是不一樣的
- 6、使用者可以根據(jù)程序需求來(lái)選擇合適的智能指針類(lèi)型和計(jì)數(shù)器規(guī)則