Merge changes Id2c1d0dc,I654fcd2c
* changes:
libbinder: Add binder already sent checks
libbinder: +2 bytes in BBinder from stability rep
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index fa77593..509ee0e 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -102,6 +102,28 @@
*/
int android_getprocnetwork(net_handle_t *network) __INTRODUCED_IN(31);
+/**
+ * Binds domain name resolutions performed by this process to |network|.
+ * android_setprocnetwork takes precedence over this setting.
+ *
+ * To clear a previous process binding, invoke with NETWORK_UNSPECIFIED.
+ * On success 0 is returned. On error -1 is returned, and errno is set.
+ *
+ * Available since API level 31.
+ */
+int android_setprocdns(net_handle_t network) __INTRODUCED_IN(31);
+
+/**
+ * Gets the |network| to which domain name resolutions are bound on the
+ * current process.
+ *
+ * Returns 0 on success, or -1 setting errno to EINVAL if a null pointer is
+ * passed in.
+ *
+ * Available since API level 31.
+ */
+int android_getprocdns(net_handle_t *network) __INTRODUCED_IN(31);
+
/**
* Perform hostname resolution via the DNS servers associated with |network|.
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 47dd32e..d421060 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -129,8 +129,7 @@
return checkCallingPermission(permission, nullptr, nullptr);
}
-static String16 _permission("permission");
-
+static StaticString16 _permission(u"permission");
bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid)
{
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 1f97293..93f1529 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -134,6 +134,15 @@
void RpcState::dump() {
std::lock_guard<std::mutex> _l(mNodeMutex);
+ dumpLocked();
+}
+
+void RpcState::terminate() {
+ std::unique_lock<std::mutex> _l(mNodeMutex);
+ terminate(_l);
+}
+
+void RpcState::dumpLocked() {
ALOGE("DUMP OF RpcState %p", this);
ALOGE("DUMP OF RpcState (%zu nodes)", mNodeForAddress.size());
for (const auto& [address, node] : mNodeForAddress) {
@@ -161,10 +170,10 @@
ALOGE("END DUMP OF RpcState");
}
-void RpcState::terminate() {
+void RpcState::terminate(std::unique_lock<std::mutex>& lock) {
if (SHOULD_LOG_RPC_DETAIL) {
ALOGE("RpcState::terminate()");
- dump();
+ dumpLocked();
}
// if the destructor of a binder object makes another RPC call, then calling
@@ -172,20 +181,20 @@
// mNodeMutex is no longer taken.
std::vector<sp<IBinder>> tempHoldBinder;
- {
- std::lock_guard<std::mutex> _l(mNodeMutex);
- mTerminated = true;
- for (auto& [address, node] : mNodeForAddress) {
- sp<IBinder> binder = node.binder.promote();
- LOG_ALWAYS_FATAL_IF(binder == nullptr, "Binder %p expected to be owned.", binder.get());
+ mTerminated = true;
+ for (auto& [address, node] : mNodeForAddress) {
+ sp<IBinder> binder = node.binder.promote();
+ LOG_ALWAYS_FATAL_IF(binder == nullptr, "Binder %p expected to be owned.", binder.get());
- if (node.sentRef != nullptr) {
- tempHoldBinder.push_back(node.sentRef);
- }
+ if (node.sentRef != nullptr) {
+ tempHoldBinder.push_back(node.sentRef);
}
-
- mNodeForAddress.clear();
}
+
+ mNodeForAddress.clear();
+
+ lock.unlock();
+ tempHoldBinder.clear(); // explicit
}
RpcState::CommandData::CommandData(size_t size) : mSize(size) {
@@ -341,14 +350,15 @@
uint64_t asyncNumber = 0;
if (!address.isZero()) {
- std::lock_guard<std::mutex> _l(mNodeMutex);
+ std::unique_lock<std::mutex> _l(mNodeMutex);
if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races
auto it = mNodeForAddress.find(address);
LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(), "Sending transact on unknown address %s",
address.toString().c_str());
if (flags & IBinder::FLAG_ONEWAY) {
- asyncNumber = it->second.asyncNumber++;
+ asyncNumber = it->second.asyncNumber;
+ if (!nodeProgressAsyncNumber(&it->second, _l)) return DEAD_OBJECT;
}
}
@@ -458,9 +468,8 @@
addr.toString().c_str());
it->second.timesRecd--;
- if (it->second.timesRecd == 0 && it->second.timesSent == 0) {
- mNodeForAddress.erase(it);
- }
+ LOG_ALWAYS_FATAL_IF(nullptr != tryEraseNode(it),
+ "Bad state. RpcState shouldn't own received binder");
}
RpcWireHeader cmd = {
@@ -698,13 +707,7 @@
// last refcount dropped after this transaction happened
if (it == mNodeForAddress.end()) return OK;
- // note - only updated now, instead of later, so that other threads
- // will queue any later transactions
-
- // TODO(b/183140903): support > 2**64 async transactions
- // (we can do this by allowing asyncNumber to wrap, since we
- // don't expect more than 2**64 simultaneous transactions)
- it->second.asyncNumber++;
+ if (!nodeProgressAsyncNumber(&it->second, _l)) return DEAD_OBJECT;
if (it->second.asyncTodo.size() == 0) return OK;
if (it->second.asyncTodo.top().asyncNumber == it->second.asyncNumber) {
@@ -799,22 +802,40 @@
LOG_ALWAYS_FATAL_IF(it->second.sentRef == nullptr, "Inconsistent state, lost ref for %s",
addr.toString().c_str());
- sp<IBinder> tempHold;
-
it->second.timesSent--;
- if (it->second.timesSent == 0) {
- tempHold = it->second.sentRef;
- it->second.sentRef = nullptr;
-
- if (it->second.timesRecd == 0) {
- mNodeForAddress.erase(it);
- }
- }
-
+ sp<IBinder> tempHold = tryEraseNode(it);
_l.unlock();
tempHold = nullptr; // destructor may make binder calls on this session
return OK;
}
+sp<IBinder> RpcState::tryEraseNode(std::map<RpcAddress, BinderNode>::iterator& it) {
+ sp<IBinder> ref;
+
+ if (it->second.timesSent == 0) {
+ ref = std::move(it->second.sentRef);
+
+ if (it->second.timesRecd == 0) {
+ LOG_ALWAYS_FATAL_IF(!it->second.asyncTodo.empty(),
+ "Can't delete binder w/ pending async transactions");
+ mNodeForAddress.erase(it);
+ }
+ }
+
+ return ref;
+}
+
+bool RpcState::nodeProgressAsyncNumber(BinderNode* node, std::unique_lock<std::mutex>& lock) {
+ // 2**64 =~ 10**19 =~ 1000 transactions per second for 585 million years to
+ // a single binder
+ if (node->asyncNumber >= std::numeric_limits<decltype(node->asyncNumber)>::max()) {
+ ALOGE("Out of async transaction IDs. Terminating");
+ terminate(lock);
+ return false;
+ }
+ node->asyncNumber++;
+ return true;
+}
+
} // namespace android
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index d448938..81ff458 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -113,6 +113,9 @@
void terminate();
private:
+ void dumpLocked();
+ void terminate(std::unique_lock<std::mutex>& lock);
+
// Alternative to std::vector<uint8_t> that doesn't abort on allocation failure and caps
// large allocations to avoid being requested from allocating too much data.
struct CommandData {
@@ -195,6 +198,16 @@
// (no additional data specific to remote binders)
};
+ // checks if there is any reference left to a node and erases it. If erase
+ // happens, and there is a strong reference to the binder kept by
+ // binderNode, this returns that strong reference, so that it can be
+ // dropped after any locks are removed.
+ sp<IBinder> tryEraseNode(std::map<RpcAddress, BinderNode>::iterator& it);
+ // true - success
+ // false - state terminated, lock gone, halt
+ [[nodiscard]] bool nodeProgressAsyncNumber(BinderNode* node,
+ std::unique_lock<std::mutex>& lock);
+
std::mutex mNodeMutex;
bool mTerminated = false;
// binders known by both sides of a session