diff options
| author | 2017-08-08 15:36:16 +0200 | |
|---|---|---|
| committer | 2017-08-11 20:40:49 +0000 | |
| commit | 0791fbf85aef8f40cee0821223c46afddd3fa464 (patch) | |
| tree | 6e15d9c4ae92cc31b42c27fcb5e2be963867a27a | |
| parent | 3c80f17536907ca8aad12e5b75c8f6d9ebf3bc52 (diff) | |
Don't lose BR_RELEASE/BR_DECREFS commands.
BR_RELEASE/BR_DECREFS commands are stored in mPendingStrongDerefs
and mPendingWeakDerefs, respectively. During processPendingDerefs(),
we actually execute the corresponding decStrong()/decWeak() operations.
The problem is that when we're done, we clear() the mPending vectors
without checking if new entries have been added to them. This can
happen, because decStrong()/decWeak() might cause destructors to run,
which in turn can invoke outgoing transactions that may result in
a BR_RELEASE/BR_DECREFS being queued.
Bug: 63079216
Test: binderLibTest
Change-Id: Ib1deca3f317f8b5068b4b9eddfc4219b9ec87740
| -rw-r--r-- | libs/binder/IPCThreadState.cpp | 33 |
1 files changed, 22 insertions, 11 deletions
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index d0cd8f2f22..90c96a2c01 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -465,22 +465,33 @@ status_t IPCThreadState::getAndExecuteCommand() void IPCThreadState::processPendingDerefs() { if (mIn.dataPosition() >= mIn.dataSize()) { - size_t numPending = mPendingWeakDerefs.size(); - if (numPending > 0) { - for (size_t i = 0; i < numPending; i++) { - RefBase::weakref_type* refs = mPendingWeakDerefs[i]; + /* + * The decWeak()/decStrong() calls may cause a destructor to run, + * which in turn could have initiated an outgoing transaction, + * which in turn could cause us to add to the pending refs + * vectors; so instead of simply iterating, loop until they're empty. + * + * We do this in an outer loop, because calling decStrong() + * may result in something being added to mPendingWeakDerefs, + * which could be delayed until the next incoming command + * from the driver if we don't process it now. + */ + while (mPendingWeakDerefs.size() > 0 || mPendingStrongDerefs.size() > 0) { + while (mPendingWeakDerefs.size() > 0) { + RefBase::weakref_type* refs = mPendingWeakDerefs[0]; + mPendingWeakDerefs.removeAt(0); refs->decWeak(mProcess.get()); } - mPendingWeakDerefs.clear(); - } - numPending = mPendingStrongDerefs.size(); - if (numPending > 0) { - for (size_t i = 0; i < numPending; i++) { - BBinder* obj = mPendingStrongDerefs[i]; + if (mPendingStrongDerefs.size() > 0) { + // We don't use while() here because we don't want to re-order + // strong and weak decs at all; if this decStrong() causes both a + // decWeak() and a decStrong() to be queued, we want to process + // the decWeak() first. + BBinder* obj = mPendingStrongDerefs[0]; + mPendingStrongDerefs.removeAt(0); obj->decStrong(mProcess.get()); } - mPendingStrongDerefs.clear(); } } } |