Allow error/abort for non-oneway calls.
Low-level processes like init might not want to make blocking calls.
This provides the mechanism to programmatically enforce that.
Test: enable ERROR_BLOCKING on process and look at callstacks
Bug: 36424585
Change-Id: I6dad33271108768f8bfc4723bf3eeddbf9720395
diff --git a/IPCThreadState.cpp b/IPCThreadState.cpp
index c7c71be..9910d4f 100644
--- a/IPCThreadState.cpp
+++ b/IPCThreadState.cpp
@@ -25,6 +25,7 @@
#include <hwbinder/binder_kernel.h>
#include <android-base/macros.h>
+#include <utils/CallStack.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
#include <utils/threads.h>
@@ -635,6 +636,16 @@
}
if ((flags & TF_ONE_WAY) == 0) {
+ if (UNLIKELY(mCallRestriction != ProcessState::CallRestriction::NONE)) {
+ if (mCallRestriction == ProcessState::CallRestriction::ERROR_IF_NOT_ONEWAY) {
+ ALOGE("Process making non-oneway call but is restricted.");
+ CallStack::logStack("non-oneway call", CallStack::getCurrent(10).get(),
+ ANDROID_LOG_ERROR);
+ } else /* FATAL_IF_NOT_ONEWAY */ {
+ LOG_ALWAYS_FATAL("Process may not make oneway calls.");
+ }
+ }
+
#if 0
if (code == 4) { // relayout
ALOGI(">>>>>> CALLING transaction 4");
@@ -757,7 +768,8 @@
mStrictModePolicy(0),
mLastTransactionBinderFlags(0),
mIsLooper(false),
- mIsPollingThread(false) {
+ mIsPollingThread(false),
+ mCallRestriction(mProcess->mCallRestriction) {
pthread_setspecific(gTLS, this);
clearCaller();
mIn.setDataCapacity(256);
diff --git a/ProcessState.cpp b/ProcessState.cpp
index 84fb8f7..e9e63cb 100644
--- a/ProcessState.cpp
+++ b/ProcessState.cpp
@@ -231,6 +231,12 @@
return mMmapSize;
}
+void ProcessState::setCallRestriction(CallRestriction restriction) {
+ LOG_ALWAYS_FATAL_IF(IPCThreadState::selfOrNull(), "Call restrictions must be set before the threadpool is started.");
+
+ mCallRestriction = restriction;
+}
+
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
const size_t N=mHandleToObject.size();
@@ -419,6 +425,7 @@
, mSpawnThreadOnStart(true)
, mThreadPoolSeq(1)
, mMmapSize(mmap_size)
+ , mCallRestriction(CallRestriction::NONE)
{
if (mDriverFD >= 0) {
// mmap the binder, providing a chunk of virtual address space to receive transactions.
diff --git a/include/hwbinder/IPCThreadState.h b/include/hwbinder/IPCThreadState.h
index f2112c0..65f458d 100644
--- a/include/hwbinder/IPCThreadState.h
+++ b/include/hwbinder/IPCThreadState.h
@@ -174,6 +174,8 @@
std::vector<std::function<void(void)>> mPostCommandTasks;
IPCThreadStateBase *mIPCThreadStateBase;
+
+ ProcessState::CallRestriction mCallRestriction;
};
}; // namespace hardware
diff --git a/include/hwbinder/ProcessState.h b/include/hwbinder/ProcessState.h
index f02b003..c42d8a8 100644
--- a/include/hwbinder/ProcessState.h
+++ b/include/hwbinder/ProcessState.h
@@ -77,6 +77,19 @@
// It does NOT include local strong references to the node
ssize_t getStrongRefCountForNodeByHandle(int32_t handle);
size_t getMmapSize();
+
+ enum class CallRestriction {
+ // all calls okay
+ NONE,
+ // log when calls are blocking
+ ERROR_IF_NOT_ONEWAY,
+ // abort process on blocking calls
+ FATAL_IF_NOT_ONEWAY,
+ };
+ // Sets calling restrictions for all transactions in this process. This must be called
+ // before any threads are spawned.
+ void setCallRestriction(CallRestriction restriction);
+
private:
friend class IPCThreadState;
@@ -124,6 +137,8 @@
bool mSpawnThreadOnStart;
volatile int32_t mThreadPoolSeq;
const size_t mMmapSize;
+
+ CallRestriction mCallRestriction;
};
}; // namespace hardware