今天看6.0的Alooper 实现 发现和4.1的实现不一样,边缘化了AlooperRoster 类,4.1中ALooperRoster 作为消息传递的中心负责调度消息。M版本中ALooperRoster 只是负责looper 对象keep alive 目前重要的操作都在looper message 中完成。
详解一下unregisterStaleHandlers 函数:
ALooperRoster.cpp
void ALooperRoster::unregisterHandler(ALooper::handler_id handlerID) { 57 Mutex::Autolock autoLock(mLock); 58 59 ssize_t index = mHandlers.indexOfKey(handlerID); 60 61 if (index < 0) { 62 return; 63 } 64 65 const HandlerInfo &info = mHandlers.valueAt(index); 66 67 sp<AHandler> handler = info.mHandler.promote(); 68 69 if (handler != NULL) { 70 handler->setID(0, NULL); 71 } 72 73 mHandlers.removeItemsAt(index); 74} 75 76void ALooperRoster::unregisterStaleHandlers() { 77 78 Vector<sp<ALooper> > activeLoopers; 79 { 80 Mutex::Autolock autoLock(mLock); 81 82 for (size_t i = mHandlers.size(); i > 0;) { 83 i--; 84 const HandlerInfo &info = mHandlers.valueAt(i); 85 86 sp<ALooper> looper = info.mLooper.promote(); 87 if (looper == NULL) { 88 ALOGV("Unregistering stale handler %d", mHandlers.keyAt(i)); 89 mHandlers.removeItemsAt(i); 90 } else { 91 // At this point 'looper' might be the only sp<> keeping 92 // the object alive. To prevent it from going out of scope 93 // and having ~ALooper call this method again recursively 94 // and then deadlocking because of the Autolock above, add 95 // it to a Vector which will go out of scope after the lock 96 // has been released. 97 activeLoopers.add(looper); 98 } 99 } 100 } 101}
ALooper.cpp
72ALooper::ALooper() 73 : mRunningLocally(false) { 74 // clean up stale AHandlers. Doing it here instead of in the destructor avoids 75 // the side effect of objects being deleted from the unregister function recursively. 76 gLooperRoster.unregisterStaleHandlers(); 77} 78 79ALooper::~ALooper() { 80 stop(); 81 // stale AHandlers are now cleaned up in the constructor of the next ALooper to come along 82}
这个函数调用出现的原因是为了推迟Mutex::Autolock autoLock(mLock) 抢占,避免AutoLock 在调用栈中
递归加锁,发生死锁。
问题场景:
41AAA::AAA(pid_t pid) 42 : 49 mLooper(new ALooper), { 55 ALOGV("AAA(%p)", this); 56 mLooper->setName("AAA Looper"); 58 mLooper->start( 59 false, /* runOnCallingThread */ 60 true, /* canCallJava */ 61 PRIORITY_AUDIO); 62 63 mHandler = new Handler(pid); 64 mLooper->registerHandler(mHandler); 73} 74 75AAA::~AAA() { 76 ALOGV("~AAA(%p)", this); 77 mLooper->stop(); 79 mLooper->unregisterHandler(mHandler->id()); 81}
如果 ALooper 的构造函数和析构函数是下面的实现方式:
72ALooper::ALooper() 73 : mRunningLocally(false) { 77} 78 79ALooper::~ALooper() { 80 stop(); 81 gLooperRoster.unregisterHandler(handlerID); 82}
sp<AAA> testAAA = new testAAA();
testAAA.clear();
这段代码的执行过程分解应该是这样的:
sp<AAA> testAAA = new testAAA(); //调用testAAA构造函数--->Alooper 构造函数---->绑定Handler
testAAA.clear(); // 调用Alooper 析构函数--->调用stop()---->调用unregisterHandler(handlerId)--->
调用autoLock(mLock) 获取锁----> 调用 handler->setID(0, NULL) reset AHandler 和 Alooper
之间的联系---> 这时候ALooper 的引用计数为0触发Alooper 析构函数--->又一次调用到gLooperRoster.unregisterHandler(handlerID)--->再一次调用autoLock(mLock) 获取锁失败被线程挂起--->死锁。
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
我们需要打破其中一个条件;下面是实现是打破循环等待.
72ALooper::ALooper() 73 : mRunningLocally(false) { 74 // clean up stale AHandlers. Doing it here instead of in the destructor avoids 75 // the side effect of objects being deleted from the unregister function recursively. 76 gLooperRoster.unregisterStaleHandlers(); 77} 78 79ALooper::~ALooper() { 80 stop(); 81 // stale AHandlers are now cleaned up in the constructor of the next ALooper to come along 82}
在连续的栈帧调用中n层获得mlock 在栈帧n 释放之前n+1......都不能竞争同意吧锁。
目前的情况 testAAA中new Handler 正常思维是析构的时候要把Handler unregist ,unregist 会把与Handler相关的Alooper 关连断开,正常情况是这样的。但是异常情况是当handler 对Alooper 的引用断开之后,函数调用的方向转到ALooper 的析构,Alooper 也想释放与之相关的handler 会调用Handler unregist 。完了产生循环诉求了。
解决方案简单粗暴,Alooper 释放相关Handler 关系的操作,滞后到next Alooper 构造的时候。