Merge "libbinder: setMinSchedulerPolicy" am: 3309b5e8f2 am: 026ea3a306 am: 289ef51442 am: 4f7b706b82 am: bc0f8043dc
Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1365301
Change-Id: I637ed9170fe4260d538a88acb2ee0e0380acd2c9
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index e0fb543..6ca3b16 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -24,6 +24,7 @@
#include <binder/IShellCallback.h>
#include <binder/Parcel.h>
+#include <linux/sched.h>
#include <stdio.h>
namespace android {
@@ -133,6 +134,8 @@
// unlocked objects
bool mRequestingSid = false;
sp<IBinder> mExtension;
+ int mPolicy = SCHED_NORMAL;
+ int mPriority = 0;
// for below objects
Mutex mLock;
@@ -279,6 +282,47 @@
return e->mExtension;
}
+void BBinder::setMinSchedulerPolicy(int policy, int priority) {
+ switch (policy) {
+ case SCHED_NORMAL:
+ LOG_ALWAYS_FATAL_IF(priority < -20 || priority > 19, "Invalid priority for SCHED_NORMAL: %d", priority);
+ break;
+ case SCHED_RR:
+ case SCHED_FIFO:
+ LOG_ALWAYS_FATAL_IF(priority < 1 || priority > 99, "Invalid priority for sched %d: %d", policy, priority);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unrecognized scheduling policy: %d", policy);
+ }
+
+ Extras* e = mExtras.load(std::memory_order_acquire);
+
+ if (e == nullptr) {
+ // Avoid allocations if called with default.
+ if (policy == SCHED_NORMAL && priority == 0) {
+ return;
+ }
+
+ e = getOrCreateExtras();
+ if (!e) return; // out of memory
+ }
+
+ e->mPolicy = policy;
+ e->mPriority = priority;
+}
+
+int BBinder::getMinSchedulerPolicy() {
+ Extras* e = mExtras.load(std::memory_order_acquire);
+ if (e == nullptr) return SCHED_NORMAL;
+ return e->mPolicy;
+}
+
+int BBinder::getMinSchedulerPriority() {
+ Extras* e = mExtras.load(std::memory_order_acquire);
+ if (e == nullptr) return 0;
+ return e->mPriority;
+}
+
pid_t BBinder::getDebugPid() {
return getpid();
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 5ea56de..8fd59ba 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -20,6 +20,7 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <linux/sched.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
@@ -188,16 +189,18 @@
return OK;
}
+static constexpr inline int schedPolicyMask(int policy, int priority) {
+ return (priority & FLAT_BINDER_FLAG_PRIORITY_MASK) | ((policy & 3) << FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT);
+}
+
status_t Parcel::flattenBinder(const sp<IBinder>& binder)
{
flat_binder_object obj;
+ obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
- if (IPCThreadState::self()->backgroundSchedulingDisabled()) {
- /* minimum priority for all nodes is nice 0 */
- obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
- } else {
- /* minimum priority for all nodes is MAX_NICE(19) */
- obj.flags = 0x13 | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ int schedBits = 0;
+ if (!IPCThreadState::self()->backgroundSchedulingDisabled()) {
+ schedBits = schedPolicyMask(SCHED_NORMAL, 19);
}
if (binder != nullptr) {
@@ -213,6 +216,13 @@
obj.handle = handle;
obj.cookie = 0;
} else {
+ int policy = local->getMinSchedulerPolicy();
+ int priority = local->getMinSchedulerPriority();
+
+ if (policy != 0 || priority != 0) {
+ // override value, since it is set explicitly
+ schedBits = schedPolicyMask(policy, priority);
+ }
if (local->isRequestingSid()) {
obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
}
@@ -226,6 +236,8 @@
obj.cookie = 0;
}
+ obj.flags |= schedBits;
+
return finishFlattenBinder(binder, obj);
}
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 74e52db..f3fea16 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -72,6 +72,22 @@
// This must be called before the object is sent to another process. Not thread safe.
void setExtension(const sp<IBinder>& extension);
+ // This must be called before the object is sent to another process. Not thread safe.
+ //
+ // This function will abort if improper parameters are set. This is like
+ // sched_setscheduler. However, it sets the minimum scheduling policy
+ // only for the duration that this specific binder object is handling the
+ // call in a threadpool. By default, this API is set to SCHED_NORMAL/0. In
+ // this case, the scheduling priority will not actually be modified from
+ // binder defaults. See also IPCThreadState::disableBackgroundScheduling.
+ //
+ // Appropriate values are:
+ // SCHED_NORMAL: -20 <= priority <= 19
+ // SCHED_RR/SCHED_FIFO: 1 <= priority <= 99
+ void setMinSchedulerPolicy(int policy, int priority);
+ int getMinSchedulerPolicy();
+ int getMinSchedulerPriority();
+
pid_t getDebugPid();
protected:
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 40de2db..917751e 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -50,6 +50,9 @@
static char *binderserversuffix;
static char binderserverarg[] = "--binderserver";
+static constexpr int kSchedPolicy = SCHED_RR;
+static constexpr int kSchedPriority = 7;
+
static String16 binderLibTestServiceName = String16("test.binderLib");
enum BinderLibTestTranscationCode {
@@ -75,6 +78,7 @@
BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION,
BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION,
BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION,
+ BINDER_LIB_TEST_GET_SCHEDULING_POLICY,
BINDER_LIB_TEST_ECHO_VECTOR,
BINDER_LIB_TEST_REJECT_BUF,
};
@@ -1015,6 +1019,22 @@
EXPECT_EQ(NO_ERROR, ret2);
}
+TEST_F(BinderLibTest, SchedPolicySet) {
+ sp<IBinder> server = addServer();
+ ASSERT_TRUE(server != nullptr);
+
+ 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(kSchedPriority, priority);
+}
+
+
TEST_F(BinderLibTest, VectorSent) {
Parcel data, reply;
sp<IBinder> server = addServer();
@@ -1332,6 +1352,16 @@
reply->writeInt32(IPCThreadState::self()->getCallingWorkSourceUid());
return NO_ERROR;
}
+ case BINDER_LIB_TEST_GET_SCHEDULING_POLICY: {
+ int policy = 0;
+ sched_param param;
+ if (0 != pthread_getschedparam(pthread_self(), &policy, ¶m)) {
+ return UNKNOWN_ERROR;
+ }
+ reply->writeInt32(policy);
+ reply->writeInt32(param.sched_priority);
+ return NO_ERROR;
+ }
case BINDER_LIB_TEST_ECHO_VECTOR: {
std::vector<uint64_t> vector;
auto err = data.readUint64Vector(&vector);
@@ -1368,6 +1398,8 @@
{
sp<BinderLibTestService> testService = new BinderLibTestService(index);
+ testService->setMinSchedulerPolicy(kSchedPolicy, kSchedPriority);
+
/*
* Normally would also contain functionality as well, but we are only
* testing the extension mechanism.