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: {