Skip to content

Commit d5fc446

Browse files
author
Yu-Ting Tseng
committed
Binder API for freeze state change notification.
Bug: 338097747 Change-Id: Iac340abc7a1a0700148cded9adb0451b8a4eae73 Test: atest BinderLibTest
1 parent ac72879 commit d5fc446

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
@@ -557,6 +557,123 @@ void BpBinder::sendObituary()
557557
}
558558
}
559559

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

691812
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
@@ -951,6 +982,33 @@ status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy)
951982
return NO_ERROR;
952983
}
953984

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

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

libs/binder/ProcessState.cpp

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

5858
// -------------------------------------------------------------------------
5959

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

6281
using namespace android::binder::impl;
@@ -472,27 +491,20 @@ bool ProcessState::isThreadPoolStarted() const {
472491

473492
#define DRIVER_FEATURES_PATH "/dev/binderfs/features/"
474493
bool ProcessState::isDriverFeatureEnabled(const DriverFeature feature) {
475-
static const char* const names[] = {
476-
[static_cast<int>(DriverFeature::ONEWAY_SPAM_DETECTION)] =
477-
DRIVER_FEATURES_PATH "oneway_spam_detection",
478-
[static_cast<int>(DriverFeature::EXTENDED_ERROR)] =
479-
DRIVER_FEATURES_PATH "extended_error",
480-
};
481-
int fd = open(names[static_cast<int>(feature)], O_RDONLY | O_CLOEXEC);
482-
char on;
483-
if (fd == -1) {
484-
ALOGE_IF(errno != ENOENT, "%s: cannot open %s: %s", __func__,
485-
names[static_cast<int>(feature)], strerror(errno));
486-
return false;
494+
// Use static variable to cache the results.
495+
if (feature == DriverFeature::ONEWAY_SPAM_DETECTION) {
496+
static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "oneway_spam_detection");
497+
return enabled;
487498
}
488-
if (read(fd, &on, sizeof(on)) == -1) {
489-
ALOGE("%s: error reading to %s: %s", __func__,
490-
names[static_cast<int>(feature)], strerror(errno));
491-
close(fd);
492-
return false;
499+
if (feature == DriverFeature::EXTENDED_ERROR) {
500+
static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "extended_error");
501+
return enabled;
493502
}
494-
close(fd);
495-
return on == '1';
503+
if (feature == DriverFeature::FREEZE_NOTIFICATION) {
504+
static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "freeze_notification");
505+
return enabled;
506+
}
507+
return false;
496508
}
497509

498510
status_t ProcessState::enableOnewaySpamDetection(bool enable) {

0 commit comments

Comments
 (0)