Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 229ec057 authored by Yu-Ting Tseng's avatar Yu-Ting Tseng Committed by Automerger Merge Worker
Browse files

Merge "Binder API for freeze state change notification." into main am: 187efe18 am: 7e47435f

parents 434d87c0 7e47435f
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -143,6 +143,22 @@ status_t IBinder::getExtension(sp<IBinder>* out) {
    return reply.readNullableStrongBinder(out);
}

status_t IBinder::addFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>& callback) {
    BpBinder* proxy = this->remoteBinder();
    if (proxy != nullptr) {
        return proxy->addFrozenStateChangeCallback(callback);
    }
    return INVALID_OPERATION;
}

status_t IBinder::removeFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>& callback) {
    BpBinder* proxy = this->remoteBinder();
    if (proxy != nullptr) {
        return proxy->removeFrozenStateChangeCallback(callback);
    }
    return INVALID_OPERATION;
}

status_t IBinder::getDebugPid(pid_t* out) {
    BBinder* local = this->localBinder();
    if (local != nullptr) {
+121 −0
Original line number Diff line number Diff line
@@ -566,6 +566,123 @@ void BpBinder::sendObituary()
    }
}

status_t BpBinder::addFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>& callback) {
    LOG_ALWAYS_FATAL_IF(isRpcBinder(),
                        "addFrozenStateChangeCallback() is not supported for RPC Binder.");
    LOG_ALWAYS_FATAL_IF(!kEnableKernelIpc, "Binder kernel driver disabled at build time");
    LOG_ALWAYS_FATAL_IF(ProcessState::self()->getThreadPoolMaxTotalThreadCount() == 0,
                        "addFrozenStateChangeCallback on %s but there are no threads "
                        "(yet?) listening to incoming transactions. See "
                        "ProcessState::startThreadPool "
                        "and ProcessState::setThreadPoolMaxThreadCount. Generally you should "
                        "setup the binder threadpool before other initialization steps.",
                        String8(getInterfaceDescriptor()).c_str());
    LOG_ALWAYS_FATAL_IF(callback == nullptr,
                        "addFrozenStateChangeCallback(): callback must be non-NULL");

    const sp<FrozenStateChangeCallback> strongCallback = callback.promote();
    if (strongCallback == nullptr) {
        return BAD_VALUE;
    }

    {
        RpcMutexUniqueLock _l(mLock);
        if (!mFrozen) {
            ALOGV("Requesting freeze notification: %p handle %d\n", this, binderHandle());
            IPCThreadState* self = IPCThreadState::self();
            status_t status = self->addFrozenStateChangeCallback(binderHandle(), this);
            if (status != NO_ERROR) {
                // Avoids logspam if kernel does not support freeze
                // notification.
                if (status != INVALID_OPERATION) {
                    ALOGE("IPCThreadState.addFrozenStateChangeCallback "
                          "failed with %s. %p handle %d\n",
                          statusToString(status).c_str(), this, binderHandle());
                }
                return status;
            }
            mFrozen = std::make_unique<FrozenStateChange>();
            if (!mFrozen) {
                std::ignore =
                        IPCThreadState::self()->removeFrozenStateChangeCallback(binderHandle(),
                                                                                this);
                return NO_MEMORY;
            }
        }
        if (mFrozen->initialStateReceived) {
            strongCallback->onStateChanged(wp<BpBinder>::fromExisting(this),
                                           mFrozen->isFrozen
                                                   ? FrozenStateChangeCallback::State::FROZEN
                                                   : FrozenStateChangeCallback::State::UNFROZEN);
        }
        ssize_t res = mFrozen->callbacks.add(callback);
        if (res < 0) {
            return res;
        }
        return NO_ERROR;
    }
}

status_t BpBinder::removeFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>& callback) {
    LOG_ALWAYS_FATAL_IF(isRpcBinder(),
                        "removeFrozenStateChangeCallback() is not supported for RPC Binder.");
    LOG_ALWAYS_FATAL_IF(!kEnableKernelIpc, "Binder kernel driver disabled at build time");

    RpcMutexUniqueLock _l(mLock);

    const size_t N = mFrozen ? mFrozen->callbacks.size() : 0;
    for (size_t i = 0; i < N; i++) {
        if (mFrozen->callbacks.itemAt(i) == callback) {
            mFrozen->callbacks.removeAt(i);
            if (mFrozen->callbacks.size() == 0) {
                ALOGV("Clearing freeze notification: %p handle %d\n", this, binderHandle());
                status_t status =
                        IPCThreadState::self()->removeFrozenStateChangeCallback(binderHandle(),
                                                                                this);
                if (status != NO_ERROR) {
                    ALOGE("Unexpected error from "
                          "IPCThreadState.removeFrozenStateChangeCallback: %s. "
                          "%p handle %d\n",
                          statusToString(status).c_str(), this, binderHandle());
                }
                mFrozen.reset();
            }
            return NO_ERROR;
        }
    }

    return NAME_NOT_FOUND;
}

void BpBinder::onFrozenStateChanged(bool isFrozen) {
    LOG_ALWAYS_FATAL_IF(isRpcBinder(), "onFrozenStateChanged is not supported for RPC Binder.");
    LOG_ALWAYS_FATAL_IF(!kEnableKernelIpc, "Binder kernel driver disabled at build time");

    ALOGV("Sending frozen state change notification for proxy %p handle %d, isFrozen=%s\n", this,
          binderHandle(), isFrozen ? "true" : "false");

    RpcMutexUniqueLock _l(mLock);
    if (!mFrozen) {
        return;
    }
    bool stateChanged = !mFrozen->initialStateReceived || mFrozen->isFrozen != isFrozen;
    if (stateChanged) {
        mFrozen->isFrozen = isFrozen;
        mFrozen->initialStateReceived = true;
        for (size_t i = 0; i < mFrozen->callbacks.size();) {
            sp<FrozenStateChangeCallback> callback = mFrozen->callbacks.itemAt(i).promote();
            if (callback != nullptr) {
                callback->onStateChanged(wp<BpBinder>::fromExisting(this),
                                         isFrozen ? FrozenStateChangeCallback::State::FROZEN
                                                  : FrozenStateChangeCallback::State::UNFROZEN);
                i++;
            } else {
                mFrozen->callbacks.removeItemsAt(i);
            }
        }
    }
}

void BpBinder::reportOneDeath(const Obituary& obit)
{
    sp<DeathRecipient> recipient = obit.recipient.promote();
@@ -695,6 +812,10 @@ void BpBinder::onLastStrongRef(const void* /*id*/) {
        if (ipc) ipc->clearDeathNotification(binderHandle(), this);
        mObituaries = nullptr;
    }
    if (mFrozen != nullptr) {
        std::ignore = IPCThreadState::self()->removeFrozenStateChangeCallback(binderHandle(), this);
        mFrozen.reset();
    }
    mLock.unlock();

    if (obits != nullptr) {
+96 −18
Original line number Diff line number Diff line
@@ -89,6 +89,8 @@ static const char* kReturnStrings[] = {
        "BR_FROZEN_REPLY",
        "BR_ONEWAY_SPAM_SUSPECT",
        "BR_TRANSACTION_PENDING_FROZEN",
        "BR_FROZEN_BINDER",
        "BR_CLEAR_FREEZE_NOTIFICATION_DONE",
};

static const char* kCommandStrings[] = {
@@ -108,7 +110,12 @@ static const char *kCommandStrings[] = {
        "BC_EXIT_LOOPER",
        "BC_REQUEST_DEATH_NOTIFICATION",
        "BC_CLEAR_DEATH_NOTIFICATION",
    "BC_DEAD_BINDER_DONE"
        "BC_DEAD_BINDER_DONE",
        "BC_TRANSACTION_SG",
        "BC_REPLY_SG",
        "BC_REQUEST_FREEZE_NOTIFICATION",
        "BC_CLEAR_FREEZE_NOTIFICATION",
        "BC_FREEZE_NOTIFICATION_DONE",
};

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

        case BR_FROZEN_BINDER: {
            const int32_t c = *cmd++;
            const int32_t h = *cmd++;
            const int32_t isFrozen = *cmd++;
            out << ": freeze cookie " << (void*)(uint64_t)c << " isFrozen: " << isFrozen;
        } break;

        case BR_CLEAR_FREEZE_NOTIFICATION_DONE: {
            const int32_t c = *cmd++;
            out << ": freeze cookie " << (void*)(uint64_t)c;
        } break;

        default:
            // no details to show for: BR_OK, BR_DEAD_REPLY,
            // BR_TRANSACTION_COMPLETE, BR_FINISHED
@@ -270,11 +289,23 @@ static const void* printCommand(std::ostream& out, const void* _cmd) {
            out << ": handle=" << h << " (death cookie " << (void*)(uint64_t)c << ")";
        } break;

        case BC_REQUEST_FREEZE_NOTIFICATION:
        case BC_CLEAR_FREEZE_NOTIFICATION: {
            const int32_t h = *cmd++;
            const int32_t c = *cmd++;
            out << ": handle=" << h << " (freeze cookie " << (void*)(uint64_t)c << ")";
        } break;

        case BC_DEAD_BINDER_DONE: {
            const int32_t c = *cmd++;
            out << ": death cookie " << (void*)(uint64_t)c;
        } break;

        case BC_FREEZE_NOTIFICATION_DONE: {
            const int32_t c = *cmd++;
            out << ": freeze cookie " << (void*)(uint64_t)c;
        } break;

        default:
            // no details to show for: BC_REGISTER_LOOPER, BC_ENTER_LOOPER,
            // BC_EXIT_LOOPER
@@ -953,6 +984,33 @@ status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy)
    return NO_ERROR;
}

status_t IPCThreadState::addFrozenStateChangeCallback(int32_t handle, BpBinder* proxy) {
    static bool isSupported =
            ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::FREEZE_NOTIFICATION);
    if (!isSupported) {
        return INVALID_OPERATION;
    }
    proxy->getWeakRefs()->incWeak(proxy);
    mOut.writeInt32(BC_REQUEST_FREEZE_NOTIFICATION);
    mOut.writeInt32((int32_t)handle);
    mOut.writePointer((uintptr_t)proxy);
    flushCommands();
    return NO_ERROR;
}

status_t IPCThreadState::removeFrozenStateChangeCallback(int32_t handle, BpBinder* proxy) {
    static bool isSupported =
            ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::FREEZE_NOTIFICATION);
    if (!isSupported) {
        return INVALID_OPERATION;
    }
    mOut.writeInt32(BC_CLEAR_FREEZE_NOTIFICATION);
    mOut.writeInt32((int32_t)handle);
    mOut.writePointer((uintptr_t)proxy);
    flushCommands();
    return NO_ERROR;
}

IPCThreadState::IPCThreadState()
      : mProcess(ProcessState::self()),
        mServingStackPointer(nullptr),
@@ -1487,6 +1545,26 @@ status_t IPCThreadState::executeCommand(int32_t cmd)
            proxy->getWeakRefs()->decWeak(proxy);
        } break;

        case BR_FROZEN_BINDER: {
            const struct binder_frozen_state_info* data =
                    reinterpret_cast<const struct binder_frozen_state_info*>(
                            mIn.readInplace(sizeof(struct binder_frozen_state_info)));
            if (data == nullptr) {
                result = UNKNOWN_ERROR;
                break;
            }
            BpBinder* proxy = (BpBinder*)data->cookie;
            bool isFrozen = mIn.readInt32() > 0;
            proxy->getPrivateAccessor().onFrozenStateChanged(data->is_frozen);
            mOut.writeInt32(BC_FREEZE_NOTIFICATION_DONE);
            mOut.writePointer(data->cookie);
        } break;

        case BR_CLEAR_FREEZE_NOTIFICATION_DONE: {
            BpBinder* proxy = (BpBinder*)mIn.readPointer();
            proxy->getWeakRefs()->decWeak(proxy);
        } break;

    case BR_FINISHED:
        result = TIMED_OUT;
        break;
+31 −19
Original line number Diff line number Diff line
@@ -56,6 +56,25 @@ const char* kDefaultDriver = "/dev/binder";

// -------------------------------------------------------------------------

namespace {
bool readDriverFeatureFile(const char* filename) {
    int fd = open(filename, O_RDONLY | O_CLOEXEC);
    char on;
    if (fd == -1) {
        ALOGE_IF(errno != ENOENT, "%s: cannot open %s: %s", __func__, filename, strerror(errno));
        return false;
    }
    if (read(fd, &on, sizeof(on)) == -1) {
        ALOGE("%s: error reading to %s: %s", __func__, filename, strerror(errno));
        close(fd);
        return false;
    }
    close(fd);
    return on == '1';
}

} // namespace

namespace android {

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

#define DRIVER_FEATURES_PATH "/dev/binderfs/features/"
bool ProcessState::isDriverFeatureEnabled(const DriverFeature feature) {
    static const char* const names[] = {
        [static_cast<int>(DriverFeature::ONEWAY_SPAM_DETECTION)] =
            DRIVER_FEATURES_PATH "oneway_spam_detection",
        [static_cast<int>(DriverFeature::EXTENDED_ERROR)] =
            DRIVER_FEATURES_PATH "extended_error",
    };
    int fd = open(names[static_cast<int>(feature)], O_RDONLY | O_CLOEXEC);
    char on;
    if (fd == -1) {
        ALOGE_IF(errno != ENOENT, "%s: cannot open %s: %s", __func__,
                 names[static_cast<int>(feature)], strerror(errno));
        return false;
    // Use static variable to cache the results.
    if (feature == DriverFeature::ONEWAY_SPAM_DETECTION) {
        static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "oneway_spam_detection");
        return enabled;
    }
    if (read(fd, &on, sizeof(on)) == -1) {
        ALOGE("%s: error reading to %s: %s", __func__,
                 names[static_cast<int>(feature)], strerror(errno));
        close(fd);
        return false;
    if (feature == DriverFeature::EXTENDED_ERROR) {
        static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "extended_error");
        return enabled;
    }
    close(fd);
    return on == '1';
    if (feature == DriverFeature::FREEZE_NOTIFICATION) {
        static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "freeze_notification");
        return enabled;
    }
    return false;
}

status_t ProcessState::enableOnewaySpamDetection(bool enable) {
+30 −0
Original line number Diff line number Diff line
@@ -32,4 +32,34 @@
#include <linux/android/binder.h>
#include <sys/ioctl.h>

struct binder_frozen_state_info {
    binder_uintptr_t cookie;
    __u32 is_frozen;
};

#ifndef BR_FROZEN_BINDER
// Temporary definition of BR_FROZEN_BINDER until UAPI binder.h includes it.
#define BR_FROZEN_BINDER _IOR('r', 21, struct binder_frozen_state_info)
#endif // BR_FROZEN_BINDER

#ifndef BR_CLEAR_FREEZE_NOTIFICATION_DONE
// Temporary definition of BR_CLEAR_FREEZE_NOTIFICATION_DONE until UAPI binder.h includes it.
#define BR_CLEAR_FREEZE_NOTIFICATION_DONE _IOR('r', 22, binder_uintptr_t)
#endif // BR_CLEAR_FREEZE_NOTIFICATION_DONE

#ifndef BC_REQUEST_FREEZE_NOTIFICATION
// Temporary definition of BC_REQUEST_FREEZE_NOTIFICATION until UAPI binder.h includes it.
#define BC_REQUEST_FREEZE_NOTIFICATION _IOW('c', 19, struct binder_handle_cookie)
#endif // BC_REQUEST_FREEZE_NOTIFICATION

#ifndef BC_CLEAR_FREEZE_NOTIFICATION
// Temporary definition of BC_CLEAR_FREEZE_NOTIFICATION until UAPI binder.h includes it.
#define BC_CLEAR_FREEZE_NOTIFICATION _IOW('c', 20, struct binder_handle_cookie)
#endif // BC_CLEAR_FREEZE_NOTIFICATION

#ifndef BC_FREEZE_NOTIFICATION_DONE
// Temporary definition of BC_FREEZE_NOTIFICATION_DONE until UAPI binder.h includes it.
#define BC_FREEZE_NOTIFICATION_DONE _IOW('c', 21, binder_uintptr_t)
#endif // BC_FREEZE_NOTIFICATION_DONE

#endif // _BINDER_MODULE_H_
Loading