summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Martijn Coenen <maco@google.com> 2017-08-08 15:36:16 +0200
committer Martijn Coenen <maco@google.com> 2017-08-11 20:40:49 +0000
commit0791fbf85aef8f40cee0821223c46afddd3fa464 (patch)
tree6e15d9c4ae92cc31b42c27fcb5e2be963867a27a
parent3c80f17536907ca8aad12e5b75c8f6d9ebf3bc52 (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.cpp33
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();
}
}
}