diff options
-rw-r--r-- | libs/binder/IPCThreadState.cpp | 24 | ||||
-rw-r--r-- | libs/binder/include/binder/IPCThreadState.h | 16 | ||||
-rw-r--r-- | libs/binder/include/private/binder/binder_module.h | 31 | ||||
-rw-r--r-- | libs/binder/tests/binderLibTest.cpp | 43 |
4 files changed, 113 insertions, 1 deletions
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 9aaca65615..0c71ed81a4 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -860,6 +860,10 @@ status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) 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 @@ void IPCThreadState::threadDestructor(void *st) } } +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 2bd39a7759..cdecceae4f 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -34,7 +34,21 @@ class IPCThreadState 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 c22be9f786..7898928f9f 100644 --- a/libs/binder/include/private/binder/binder_module.h +++ b/libs/binder/include/private/binder/binder_module.h @@ -36,6 +36,37 @@ namespace android { #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 917751ef34..145c09940b 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> @@ -79,6 +80,8 @@ enum BinderLibTestTranscationCode { 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, BINDER_LIB_TEST_REJECT_BUF, }; @@ -399,6 +402,40 @@ TEST_F(BinderLibTest, NopTransaction) { 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++) { @@ -1178,6 +1215,12 @@ class BinderLibTestService : public BBinder 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: { |