libbinder: support inheriting realtime priority

gotta go fast

Bug: 170420170
Test: atest binderLibTest
Change-Id: I2f2c6cb35ebf463d90b517e134b9ea3114764af6
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index f2d223d..d964d25 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -133,6 +133,7 @@
 public:
     // unlocked objects
     bool mRequestingSid = false;
+    bool mInheritRt = false;
     sp<IBinder> mExtension;
     int mPolicy = SCHED_NORMAL;
     int mPriority = 0;
@@ -327,6 +328,27 @@
     return e->mPriority;
 }
 
+bool BBinder::isInheritRt() {
+    Extras* e = mExtras.load(std::memory_order_acquire);
+
+    return e && e->mInheritRt;
+}
+
+void BBinder::setInheritRt(bool inheritRt) {
+    Extras* e = mExtras.load(std::memory_order_acquire);
+
+    if (!e) {
+        if (!inheritRt) {
+            return;
+        }
+
+        e = getOrCreateExtras();
+        if (!e) return; // out of memory
+    }
+
+    e->mInheritRt = inheritRt;
+}
+
 pid_t BBinder::getDebugPid() {
     return getpid();
 }
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index a7d8df2..3330a2e 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -222,6 +222,9 @@
             if (local->isRequestingSid()) {
                 obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
             }
+            if (local->isInheritRt()) {
+                obj.flags |= FLAT_BINDER_FLAG_INHERIT_RT;
+            }
             obj.hdr.type = BINDER_TYPE_BINDER;
             obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
             obj.cookie = reinterpret_cast<uintptr_t>(local);
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index d6da397..7079544 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -87,6 +87,11 @@
     int                 getMinSchedulerPolicy();
     int                 getMinSchedulerPriority();
 
+    // Whether realtime scheduling policies are inherited.
+    bool                isInheritRt();
+    // This must be called before the object is sent to another process. Not thread safe.
+    void                setInheritRt(bool inheritRt);
+
     pid_t               getDebugPid();
 
 protected:
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index ad4729d..0f7d159 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -30,6 +30,7 @@
 #include <binder/IServiceManager.h>
 
 #include <private/binder/binder_module.h>
+#include <linux/sched.h>
 #include <sys/epoll.h>
 #include <sys/prctl.h>
 
@@ -53,6 +54,7 @@
 
 static constexpr int kSchedPolicy = SCHED_RR;
 static constexpr int kSchedPriority = 7;
+static constexpr int kSchedPriorityMore = 8;
 
 static String16 binderLibTestServiceName = String16("test.binderLib");
 
@@ -1088,6 +1090,25 @@
     EXPECT_EQ(kSchedPriority, priority);
 }
 
+TEST_F(BinderLibTest, InheritRt) {
+    sp<IBinder> server = addServer();
+    ASSERT_TRUE(server != nullptr);
+
+    const struct sched_param param {
+        .sched_priority = kSchedPriorityMore,
+    };
+    EXPECT_EQ(0, sched_setscheduler(getpid(), SCHED_RR, &param));
+
+    Parcel data, reply;
+    status_t ret = server->transact(BINDER_LIB_TEST_GET_SCHEDULING_POLICY, data, &reply);
+    EXPECT_EQ(NO_ERROR, ret);
+
+    int policy = reply.readInt32();
+    int priority = reply.readInt32();
+
+    EXPECT_EQ(kSchedPolicy, policy & (~SCHED_RESET_ON_FORK));
+    EXPECT_EQ(kSchedPriorityMore, priority);
+}
 
 TEST_F(BinderLibTest, VectorSent) {
     Parcel data, reply;
@@ -1460,6 +1481,8 @@
 
         testService->setMinSchedulerPolicy(kSchedPolicy, kSchedPriority);
 
+        testService->setInheritRt(true);
+
         /*
          * Normally would also contain functionality as well, but we are only
          * testing the extension mechanism.
diff --git a/libs/binder/tests/fuzzers/BinderFuzzFunctions.h b/libs/binder/tests/fuzzers/BinderFuzzFunctions.h
index 9ac65bb..69f1b9d 100644
--- a/libs/binder/tests/fuzzers/BinderFuzzFunctions.h
+++ b/libs/binder/tests/fuzzers/BinderFuzzFunctions.h
@@ -37,8 +37,8 @@
                                   bbinder->isRequestingSid();
                               },
                               [](FuzzedDataProvider* fdp, const sp<BBinder>& bbinder) -> void {
-                                  bool request_sid = fdp->ConsumeBool();
-                                  bbinder->setRequestingSid(request_sid);
+                                  bool requestSid = fdp->ConsumeBool();
+                                  bbinder->setRequestingSid(requestSid);
                               },
                               [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
                                   bbinder->getExtension();
@@ -63,6 +63,13 @@
                               [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
                                   bbinder->getMinSchedulerPriority();
                               },
+                              [](FuzzedDataProvider* fdp, const sp<BBinder>& bbinder) -> void {
+                                  bool inheritRt = fdp->ConsumeBool();
+                                  bbinder->setInheritRt(inheritRt);
+                              },
+                              [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
+                                  bbinder->isInheritRt();
+                              },
                               [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
                                   bbinder->getDebugPid();
                               }};