binder: adopt BINDER_FREEZE api
The BINDER_FREEZE ioctl and related structures have been added to the
driver to notify binder of the frozen state of a process. This patch
introduces low-level user space handling for libbinder.
Bug: 143717177
Test: verified that binder transactions to a frozen app return ERR_FROZEN
Test: verified that transactions are correctly received by non-frozen apps
Co-developed-by: Todd Kjos <tkjos@google.com>
Change-Id: I31fed5ecb040f5ba5b8e27ab6a20c441964f32b4
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 9aaca65..0c71ed8 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -860,6 +860,10 @@
err = FAILED_TRANSACTION;
goto finish;
+ case BR_FROZEN_REPLY:
+ err = FAILED_TRANSACTION;
+ goto finish;
+
case BR_ACQUIRE_RESULT:
{
ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
@@ -1316,6 +1320,26 @@
}
}
+status_t IPCThreadState::freeze(pid_t pid, bool enable, uint32_t timeout_ms) {
+ struct binder_freeze_info info;
+ int ret = 0;
+
+ info.pid = pid;
+ info.enable = enable;
+ info.timeout_ms = timeout_ms;
+
+
+#if defined(__ANDROID__)
+ if (ioctl(self()->mProcess->mDriverFD, BINDER_FREEZE, &info) < 0)
+ ret = -errno;
+#endif
+
+ //
+ // ret==-EAGAIN indicates that transactions have not drained.
+ // Call again to poll for completion.
+ //
+ return ret;
+}
void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data,
size_t /*dataSize*/,
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 2bd39a7..cdeccea 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -34,7 +34,21 @@
public:
static IPCThreadState* self();
static IPCThreadState* selfOrNull(); // self(), but won't instantiate
-
+
+ // Freeze or unfreeze the binder interface to a specific process. When freezing, this method
+ // will block up to timeout_ms to process pending transactions directed to pid. Unfreeze
+ // is immediate. Transactions to processes frozen via this method won't be delivered and the
+ // driver will return BR_FROZEN_REPLY to the client sending them. After unfreeze,
+ // transactions will be delivered normally.
+ //
+ // pid: id for the process for which the binder interface is to be frozen
+ // enable: freeze (true) or unfreeze (false)
+ // timeout_ms: maximum time this function is allowed to block the caller waiting for pending
+ // binder transactions to be processed.
+ //
+ // returns: 0 in case of success, a value < 0 in case of error
+ static status_t freeze(pid_t pid, bool enabled, uint32_t timeout_ms);
+
sp<ProcessState> process();
status_t clearLastError();
diff --git a/libs/binder/include/private/binder/binder_module.h b/libs/binder/include/private/binder/binder_module.h
index c22be9f..7898928 100644
--- a/libs/binder/include/private/binder/binder_module.h
+++ b/libs/binder/include/private/binder/binder_module.h
@@ -36,6 +36,37 @@
#include <sys/ioctl.h>
#include <linux/android/binder.h>
+#ifndef BR_FROZEN_REPLY
+// Temporary definition of BR_FROZEN_REPLY. For production
+// this will come from UAPI binder.h
+#define BR_FROZEN_REPLY _IO('r', 18)
+#endif //BR_FROZEN_REPLY
+
+#ifndef BINDER_FREEZE
+/*
+ * Temporary definitions for freeze support. For the final version
+ * these will be defined in the UAPI binder.h file from upstream kernel.
+ */
+#define BINDER_FREEZE _IOW('b', 14, struct binder_freeze_info)
+
+struct binder_freeze_info {
+ //
+ // Group-leader PID of process to be frozen
+ //
+ uint32_t pid;
+ //
+ // Enable(1) / Disable(0) freeze for given PID
+ //
+ uint32_t enable;
+ //
+ // Timeout to wait for transactions to drain.
+ // 0: don't wait (ioctl will return EAGAIN if not drained)
+ // N: number of ms to wait
+ uint32_t timeout_ms;
+};
+#endif //BINDER_FREEZE
+
+
#ifdef __cplusplus
} // namespace android
#endif
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index f8ee32c..565338b 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -16,6 +16,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <fstream>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
@@ -77,6 +78,8 @@
BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION,
BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION,
BINDER_LIB_TEST_GET_SCHEDULING_POLICY,
+ BINDER_LIB_TEST_NOP_TRANSACTION_WAIT,
+ BINDER_LIB_TEST_GETPID,
BINDER_LIB_TEST_ECHO_VECTOR,
};
@@ -396,6 +399,40 @@
EXPECT_EQ(NO_ERROR, ret);
}
+TEST_F(BinderLibTest, Freeze) {
+ status_t ret;
+ Parcel data, reply, replypid;
+ std::ifstream freezer_file("/sys/fs/cgroup/freezer/cgroup.freeze");
+
+ //Pass test on devices where the freezer is not supported
+ if (freezer_file.fail()) {
+ GTEST_SKIP();
+ return;
+ }
+
+ std::string freezer_enabled;
+ std::getline(freezer_file, freezer_enabled);
+
+ //Pass test on devices where the freezer is disabled
+ if (freezer_enabled != "1") {
+ GTEST_SKIP();
+ return;
+ }
+
+ ret = m_server->transact(BINDER_LIB_TEST_GETPID, data, &replypid);
+ int32_t pid = replypid.readInt32();
+ EXPECT_EQ(NO_ERROR, ret);
+ for (int i = 0; i < 10; i++) {
+ EXPECT_EQ(NO_ERROR, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION_WAIT, data, &reply, TF_ONE_WAY));
+ }
+ EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, 1, 0));
+ EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, 1, 0));
+ EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, 1, 1000));
+ EXPECT_EQ(FAILED_TRANSACTION, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply));
+ EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, 0, 0));
+ EXPECT_EQ(NO_ERROR, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply));
+}
+
TEST_F(BinderLibTest, SetError) {
int32_t testValue[] = { 0, -123, 123 };
for (size_t i = 0; i < ARRAY_SIZE(testValue); i++) {
@@ -1147,6 +1184,12 @@
pthread_mutex_unlock(&m_serverWaitMutex);
return ret;
}
+ case BINDER_LIB_TEST_GETPID:
+ reply->writeInt32(getpid());
+ return NO_ERROR;
+ case BINDER_LIB_TEST_NOP_TRANSACTION_WAIT:
+ usleep(5000);
+ return NO_ERROR;
case BINDER_LIB_TEST_NOP_TRANSACTION:
return NO_ERROR;
case BINDER_LIB_TEST_DELAYED_CALL_BACK: {