Skip to content

Commit 187efe1

Browse files
Yu-Ting TsengGerrit Code Review
authored andcommitted
Merge "Binder API for freeze state change notification." into main
2 parents 2a98830 + d5fc446 commit 187efe1

13 files changed

Lines changed: 958 additions & 64 deletions

libs/binder/Binder.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,22 @@ status_t IBinder::getExtension(sp<IBinder>* out) {
143143
return reply.readNullableStrongBinder(out);
144144
}
145145

146+
status_t IBinder::addFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>& callback) {
147+
BpBinder* proxy = this->remoteBinder();
148+
if (proxy != nullptr) {
149+
return proxy->addFrozenStateChangeCallback(callback);
150+
}
151+
return INVALID_OPERATION;
152+
}
153+
154+
status_t IBinder::removeFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>& callback) {
155+
BpBinder* proxy = this->remoteBinder();
156+
if (proxy != nullptr) {
157+
return proxy->removeFrozenStateChangeCallback(callback);
158+
}
159+
return INVALID_OPERATION;
160+
}
161+
146162
status_t IBinder::getDebugPid(pid_t* out) {
147163
BBinder* local = this->localBinder();
148164
if (local != nullptr) {

libs/binder/BpBinder.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,123 @@ void BpBinder::sendObituary()
566566
}
567567
}
568568

569+
status_t BpBinder::addFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>& callback) {
570+
LOG_ALWAYS_FATAL_IF(isRpcBinder(),
571+
"addFrozenStateChangeCallback() is not supported for RPC Binder.");
572+
LOG_ALWAYS_FATAL_IF(!kEnableKernelIpc, "Binder kernel driver disabled at build time");
573+
LOG_ALWAYS_FATAL_IF(ProcessState::self()->getThreadPoolMaxTotalThreadCount() == 0,
574+
"addFrozenStateChangeCallback on %s but there are no threads "
575+
"(yet?) listening to incoming transactions. See "
576+
"ProcessState::startThreadPool "
577+
"and ProcessState::setThreadPoolMaxThreadCount. Generally you should "
578+
"setup the binder threadpool before other initialization steps.",
579+
String8(getInterfaceDescriptor()).c_str());
580+
LOG_ALWAYS_FATAL_IF(callback == nullptr,
581+
"addFrozenStateChangeCallback(): callback must be non-NULL");
582+
583+
const sp<FrozenStateChangeCallback> strongCallback = callback.promote();
584+
if (strongCallback == nullptr) {
585+
return BAD_VALUE;
586+
}
587+
588+
{
589+
RpcMutexUniqueLock _l(mLock);
590+
if (!mFrozen) {
591+
ALOGV("Requesting freeze notification: %p handle %d\n", this, binderHandle());
592+
IPCThreadState* self = IPCThreadState::self();
593+
status_t status = self->addFrozenStateChangeCallback(binderHandle(), this);
594+
if (status != NO_ERROR) {
595+
// Avoids logspam if kernel does not support freeze
596+
// notification.
597+
if (status != INVALID_OPERATION) {
598+
ALOGE("IPCThreadState.addFrozenStateChangeCallback "
599+
"failed with %s. %p handle %d\n",
600+
statusToString(status).c_str(), this, binderHandle());
601+
}
602+
return status;
603+
}
604+
mFrozen = std::make_unique<FrozenStateChange>();
605+
if (!mFrozen) {
606+
std::ignore =
607+
IPCThreadState::self()->removeFrozenStateChangeCallback(binderHandle(),
608+
this);
609+
return NO_MEMORY;
610+
}
611+
}
612+
if (mFrozen->initialStateReceived) {
613+
strongCallback->onStateChanged(wp<BpBinder>::fromExisting(this),
614+
mFrozen->isFrozen
615+
? FrozenStateChangeCallback::State::FROZEN
616+
: FrozenStateChangeCallback::State::UNFROZEN);
617+
}
618+
ssize_t res = mFrozen->callbacks.add(callback);
619+
if (res < 0) {
620+
return res;
621+
}
622+
return NO_ERROR;
623+
}
624+
}
625+
626+
status_t BpBinder::removeFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>& callback) {
627+
LOG_ALWAYS_FATAL_IF(isRpcBinder(),
628+
"removeFrozenStateChangeCallback() is not supported for RPC Binder.");
629+
LOG_ALWAYS_FATAL_IF(!kEnableKernelIpc, "Binder kernel driver disabled at build time");
630+
631+
RpcMutexUniqueLock _l(mLock);
632+
633+
const size_t N = mFrozen ? mFrozen->callbacks.size() : 0;
634+
for (size_t i = 0; i < N; i++) {
635+
if (mFrozen->callbacks.itemAt(i) == callback) {
636+
mFrozen->callbacks.removeAt(i);
637+
if (mFrozen->callbacks.size() == 0) {
638+
ALOGV("Clearing freeze notification: %p handle %d\n", this, binderHandle());
639+
status_t status =
640+
IPCThreadState::self()->removeFrozenStateChangeCallback(binderHandle(),
641+
this);
642+
if (status != NO_ERROR) {
643+
ALOGE("Unexpected error from "
644+
"IPCThreadState.removeFrozenStateChangeCallback: %s. "
645+
"%p handle %d\n",
646+
statusToString(status).c_str(), this, binderHandle());
647+
}
648+
mFrozen.reset();
649+
}
650+
return NO_ERROR;
651+
}
652+
}
653+
654+
return NAME_NOT_FOUND;
655+
}
656+
657+
void BpBinder::onFrozenStateChanged(bool isFrozen) {
658+
LOG_ALWAYS_FATAL_IF(isRpcBinder(), "onFrozenStateChanged is not supported for RPC Binder.");
659+
LOG_ALWAYS_FATAL_IF(!kEnableKernelIpc, "Binder kernel driver disabled at build time");
660+
661+
ALOGV("Sending frozen state change notification for proxy %p handle %d, isFrozen=%s\n", this,
662+
binderHandle(), isFrozen ? "true" : "false");
663+
664+
RpcMutexUniqueLock _l(mLock);
665+
if (!mFrozen) {
666+
return;
667+
}
668+
bool stateChanged = !mFrozen->initialStateReceived || mFrozen->isFrozen != isFrozen;
669+
if (stateChanged) {
670+
mFrozen->isFrozen = isFrozen;
671+
mFrozen->initialStateReceived = true;
672+
for (size_t i = 0; i < mFrozen->callbacks.size();) {
673+
sp<FrozenStateChangeCallback> callback = mFrozen->callbacks.itemAt(i).promote();
674+
if (callback != nullptr) {
675+
callback->onStateChanged(wp<BpBinder>::fromExisting(this),
676+
isFrozen ? FrozenStateChangeCallback::State::FROZEN
677+
: FrozenStateChangeCallback::State::UNFROZEN);
678+
i++;
679+
} else {
680+
mFrozen->callbacks.removeItemsAt(i);
681+
}
682+
}
683+
}
684+
}
685+
569686
void BpBinder::reportOneDeath(const Obituary& obit)
570687
{
571688
sp<DeathRecipient> recipient = obit.recipient.promote();
@@ -695,6 +812,10 @@ void BpBinder::onLastStrongRef(const void* /*id*/) {
695812
if (ipc) ipc->clearDeathNotification(binderHandle(), this);
696813
mObituaries = nullptr;
697814
}
815+
if (mFrozen != nullptr) {
816+
std::ignore = IPCThreadState::self()->removeFrozenStateChangeCallback(binderHandle(), this);
817+
mFrozen.reset();
818+
}
698819
mLock.unlock();
699820

700821
if (obits != nullptr) {

libs/binder/IPCThreadState.cpp

Lines changed: 96 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -89,26 +89,33 @@ static const char* kReturnStrings[] = {
8989
"BR_FROZEN_REPLY",
9090
"BR_ONEWAY_SPAM_SUSPECT",
9191
"BR_TRANSACTION_PENDING_FROZEN",
92+
"BR_FROZEN_BINDER",
93+
"BR_CLEAR_FREEZE_NOTIFICATION_DONE",
9294
};
9395

94-
static const char *kCommandStrings[] = {
95-
"BC_TRANSACTION",
96-
"BC_REPLY",
97-
"BC_ACQUIRE_RESULT",
98-
"BC_FREE_BUFFER",
99-
"BC_INCREFS",
100-
"BC_ACQUIRE",
101-
"BC_RELEASE",
102-
"BC_DECREFS",
103-
"BC_INCREFS_DONE",
104-
"BC_ACQUIRE_DONE",
105-
"BC_ATTEMPT_ACQUIRE",
106-
"BC_REGISTER_LOOPER",
107-
"BC_ENTER_LOOPER",
108-
"BC_EXIT_LOOPER",
109-
"BC_REQUEST_DEATH_NOTIFICATION",
110-
"BC_CLEAR_DEATH_NOTIFICATION",
111-
"BC_DEAD_BINDER_DONE"
96+
static const char* kCommandStrings[] = {
97+
"BC_TRANSACTION",
98+
"BC_REPLY",
99+
"BC_ACQUIRE_RESULT",
100+
"BC_FREE_BUFFER",
101+
"BC_INCREFS",
102+
"BC_ACQUIRE",
103+
"BC_RELEASE",
104+
"BC_DECREFS",
105+
"BC_INCREFS_DONE",
106+
"BC_ACQUIRE_DONE",
107+
"BC_ATTEMPT_ACQUIRE",
108+
"BC_REGISTER_LOOPER",
109+
"BC_ENTER_LOOPER",
110+
"BC_EXIT_LOOPER",
111+
"BC_REQUEST_DEATH_NOTIFICATION",
112+
"BC_CLEAR_DEATH_NOTIFICATION",
113+
"BC_DEAD_BINDER_DONE",
114+
"BC_TRANSACTION_SG",
115+
"BC_REPLY_SG",
116+
"BC_REQUEST_FREEZE_NOTIFICATION",
117+
"BC_CLEAR_FREEZE_NOTIFICATION",
118+
"BC_FREEZE_NOTIFICATION_DONE",
112119
};
113120

114121
static const int64_t kWorkSourcePropagatedBitIndex = 32;
@@ -203,6 +210,18 @@ static const void* printReturnCommand(std::ostream& out, const void* _cmd) {
203210
out << ": death cookie " << (void*)(uint64_t)c;
204211
} break;
205212

213+
case BR_FROZEN_BINDER: {
214+
const int32_t c = *cmd++;
215+
const int32_t h = *cmd++;
216+
const int32_t isFrozen = *cmd++;
217+
out << ": freeze cookie " << (void*)(uint64_t)c << " isFrozen: " << isFrozen;
218+
} break;
219+
220+
case BR_CLEAR_FREEZE_NOTIFICATION_DONE: {
221+
const int32_t c = *cmd++;
222+
out << ": freeze cookie " << (void*)(uint64_t)c;
223+
} break;
224+
206225
default:
207226
// no details to show for: BR_OK, BR_DEAD_REPLY,
208227
// BR_TRANSACTION_COMPLETE, BR_FINISHED
@@ -270,11 +289,23 @@ static const void* printCommand(std::ostream& out, const void* _cmd) {
270289
out << ": handle=" << h << " (death cookie " << (void*)(uint64_t)c << ")";
271290
} break;
272291

292+
case BC_REQUEST_FREEZE_NOTIFICATION:
293+
case BC_CLEAR_FREEZE_NOTIFICATION: {
294+
const int32_t h = *cmd++;
295+
const int32_t c = *cmd++;
296+
out << ": handle=" << h << " (freeze cookie " << (void*)(uint64_t)c << ")";
297+
} break;
298+
273299
case BC_DEAD_BINDER_DONE: {
274300
const int32_t c = *cmd++;
275301
out << ": death cookie " << (void*)(uint64_t)c;
276302
} break;
277303

304+
case BC_FREEZE_NOTIFICATION_DONE: {
305+
const int32_t c = *cmd++;
306+
out << ": freeze cookie " << (void*)(uint64_t)c;
307+
} break;
308+
278309
default:
279310
// no details to show for: BC_REGISTER_LOOPER, BC_ENTER_LOOPER,
280311
// BC_EXIT_LOOPER
@@ -953,6 +984,33 @@ status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy)
953984
return NO_ERROR;
954985
}
955986

987+
status_t IPCThreadState::addFrozenStateChangeCallback(int32_t handle, BpBinder* proxy) {
988+
static bool isSupported =
989+
ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::FREEZE_NOTIFICATION);
990+
if (!isSupported) {
991+
return INVALID_OPERATION;
992+
}
993+
proxy->getWeakRefs()->incWeak(proxy);
994+
mOut.writeInt32(BC_REQUEST_FREEZE_NOTIFICATION);
995+
mOut.writeInt32((int32_t)handle);
996+
mOut.writePointer((uintptr_t)proxy);
997+
flushCommands();
998+
return NO_ERROR;
999+
}
1000+
1001+
status_t IPCThreadState::removeFrozenStateChangeCallback(int32_t handle, BpBinder* proxy) {
1002+
static bool isSupported =
1003+
ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::FREEZE_NOTIFICATION);
1004+
if (!isSupported) {
1005+
return INVALID_OPERATION;
1006+
}
1007+
mOut.writeInt32(BC_CLEAR_FREEZE_NOTIFICATION);
1008+
mOut.writeInt32((int32_t)handle);
1009+
mOut.writePointer((uintptr_t)proxy);
1010+
flushCommands();
1011+
return NO_ERROR;
1012+
}
1013+
9561014
IPCThreadState::IPCThreadState()
9571015
: mProcess(ProcessState::self()),
9581016
mServingStackPointer(nullptr),
@@ -1487,6 +1545,26 @@ status_t IPCThreadState::executeCommand(int32_t cmd)
14871545
proxy->getWeakRefs()->decWeak(proxy);
14881546
} break;
14891547

1548+
case BR_FROZEN_BINDER: {
1549+
const struct binder_frozen_state_info* data =
1550+
reinterpret_cast<const struct binder_frozen_state_info*>(
1551+
mIn.readInplace(sizeof(struct binder_frozen_state_info)));
1552+
if (data == nullptr) {
1553+
result = UNKNOWN_ERROR;
1554+
break;
1555+
}
1556+
BpBinder* proxy = (BpBinder*)data->cookie;
1557+
bool isFrozen = mIn.readInt32() > 0;
1558+
proxy->getPrivateAccessor().onFrozenStateChanged(data->is_frozen);
1559+
mOut.writeInt32(BC_FREEZE_NOTIFICATION_DONE);
1560+
mOut.writePointer(data->cookie);
1561+
} break;
1562+
1563+
case BR_CLEAR_FREEZE_NOTIFICATION_DONE: {
1564+
BpBinder* proxy = (BpBinder*)mIn.readPointer();
1565+
proxy->getWeakRefs()->decWeak(proxy);
1566+
} break;
1567+
14901568
case BR_FINISHED:
14911569
result = TIMED_OUT;
14921570
break;

libs/binder/ProcessState.cpp

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,25 @@ const char* kDefaultDriver = "/dev/binder";
5656

5757
// -------------------------------------------------------------------------
5858

59+
namespace {
60+
bool readDriverFeatureFile(const char* filename) {
61+
int fd = open(filename, O_RDONLY | O_CLOEXEC);
62+
char on;
63+
if (fd == -1) {
64+
ALOGE_IF(errno != ENOENT, "%s: cannot open %s: %s", __func__, filename, strerror(errno));
65+
return false;
66+
}
67+
if (read(fd, &on, sizeof(on)) == -1) {
68+
ALOGE("%s: error reading to %s: %s", __func__, filename, strerror(errno));
69+
close(fd);
70+
return false;
71+
}
72+
close(fd);
73+
return on == '1';
74+
}
75+
76+
} // namespace
77+
5978
namespace android {
6079

6180
using namespace android::binder::impl;
@@ -484,27 +503,20 @@ bool ProcessState::isThreadPoolStarted() const {
484503

485504
#define DRIVER_FEATURES_PATH "/dev/binderfs/features/"
486505
bool ProcessState::isDriverFeatureEnabled(const DriverFeature feature) {
487-
static const char* const names[] = {
488-
[static_cast<int>(DriverFeature::ONEWAY_SPAM_DETECTION)] =
489-
DRIVER_FEATURES_PATH "oneway_spam_detection",
490-
[static_cast<int>(DriverFeature::EXTENDED_ERROR)] =
491-
DRIVER_FEATURES_PATH "extended_error",
492-
};
493-
int fd = open(names[static_cast<int>(feature)], O_RDONLY | O_CLOEXEC);
494-
char on;
495-
if (fd == -1) {
496-
ALOGE_IF(errno != ENOENT, "%s: cannot open %s: %s", __func__,
497-
names[static_cast<int>(feature)], strerror(errno));
498-
return false;
506+
// Use static variable to cache the results.
507+
if (feature == DriverFeature::ONEWAY_SPAM_DETECTION) {
508+
static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "oneway_spam_detection");
509+
return enabled;
499510
}
500-
if (read(fd, &on, sizeof(on)) == -1) {
501-
ALOGE("%s: error reading to %s: %s", __func__,
502-
names[static_cast<int>(feature)], strerror(errno));
503-
close(fd);
504-
return false;
511+
if (feature == DriverFeature::EXTENDED_ERROR) {
512+
static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "extended_error");
513+
return enabled;
505514
}
506-
close(fd);
507-
return on == '1';
515+
if (feature == DriverFeature::FREEZE_NOTIFICATION) {
516+
static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "freeze_notification");
517+
return enabled;
518+
}
519+
return false;
508520
}
509521

510522
status_t ProcessState::enableOnewaySpamDetection(bool enable) {

0 commit comments

Comments
 (0)