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

Commit 0397face authored by Jayant Chowdhary's avatar Jayant Chowdhary
Browse files

IPCThreadState: Add a public method to probe if a binder call is being served.



This can be useful when common code can be executed by both hwbinder and
binder threads, and, they want to access (hardware::)IPCThreadState
specific information. Eg: cameraserver.

This commit adds a vndk private library 'libbinderthreadstate' which
serves as common ground for both libbinder and libhwbinder to inform
them about the nature of the IPC call being served (if at all) on the current
thread.

Bug: 110364143

Test: Boot device, use GCA

Change-Id: Ifefb273c9a1f545417a82e9511a45bda00f701aa
Signed-off-by: default avatarJayant Chowdhary <jchowdhary@google.com>
parent 48ac1c65
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -119,6 +119,7 @@ cc_library_shared {
        "liblog",
        "libcutils",
        "libutils",
        "libbinderthreadstate",
    ],

    header_libs: [
+10 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#define LOG_TAG "IPCThreadState"

#include <binder/IPCThreadState.h>
#include <binderthreadstate/IPCThreadStateBase.h>

#include <binder/Binder.h>
#include <binder/BpBinder.h>
@@ -742,6 +743,7 @@ IPCThreadState::IPCThreadState()
    clearCaller();
    mIn.setDataCapacity(256);
    mOut.setDataCapacity(256);
    mIPCThreadStateBase = IPCThreadStateBase::self();
}

IPCThreadState::~IPCThreadState()
@@ -1082,6 +1084,9 @@ status_t IPCThreadState::executeCommand(int32_t cmd)
                "Not enough command data for brTRANSACTION");
            if (result != NO_ERROR) break;

            //Record the fact that we're in a binder call.
            mIPCThreadStateBase->pushCurrentState(
                IPCThreadStateBase::CallState::BINDER);
            Parcel buffer;
            buffer.ipcSetDataReference(
                reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
@@ -1129,6 +1134,7 @@ status_t IPCThreadState::executeCommand(int32_t cmd)
                error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
            }

            mIPCThreadStateBase->popCurrentState();
            //ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
            //     mCallingPid, origPid, origUid);

@@ -1192,6 +1198,10 @@ status_t IPCThreadState::executeCommand(int32_t cmd)
    return result;
}

bool IPCThreadState::isServingCall() const {
    return mIPCThreadStateBase->getCurrentBinderCallState() == IPCThreadStateBase::CallState::BINDER;
}

void IPCThreadState::threadDestructor(void *st)
{
        IPCThreadState* const self = static_cast<IPCThreadState*>(st);
+30 −0
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@ typedef int uid_t;
// ---------------------------------------------------------------------------
namespace android {

class IPCThreadStateBase;

class IPCThreadState
{
public:
@@ -89,6 +91,33 @@ public:
            // the maximum number of binder threads threads allowed for this process.
            void                blockUntilThreadAvailable();


            // Is this thread currently serving a binder call. This method
            // returns true if while traversing backwards from the function call
            // stack for this thread, we encounter a function serving a binder
            // call before encountering a hwbinder call / hitting the end of the
            // call stack.
            // Eg: If thread T1 went through the following call pattern
            //     1) T1 receives and executes hwbinder call H1.
            //     2) While handling H1, T1 makes binder call B1.
            //     3) The handler of B1, calls into T1 with a callback B2.
            // If isServingCall() is called during H1 before 3), this method
            // will return false, else true.
            //
            //  ----
            // | B2 | ---> While callback B2 is being handled, during 3).
            //  ----
            // | H1 | ---> While H1 is being handled.
            //  ----
            // Fig: Thread Call stack while handling B2
            //
            // This is since after 3), while traversing the thread call stack,
            // we hit a binder call before a hwbinder call / end of stack. This
            // method may be typically used to determine whether to use
            // hardware::IPCThreadState methods or IPCThreadState methods to
            // infer information about thread state.
            bool                isServingCall() const;

private:
                                IPCThreadState();
                                ~IPCThreadState();
@@ -128,6 +157,7 @@ private:
            uid_t               mCallingUid;
            int32_t             mStrictModePolicy;
            int32_t             mLastTransactionBinderFlags;
            IPCThreadStateBase  *mIPCThreadStateBase;
};

}; // namespace android
+44 −0
Original line number Diff line number Diff line
// Copyright (C) 2018 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

cc_library {
    name: "libbinderthreadstate",
    recovery_available: true,
    vendor_available: false,
    vndk: {
        enabled: true,
        support_system_process: true,
    },
    srcs: [
        "IPCThreadStateBase.cpp",
    ],

    shared_libs: [
        "libbase",
        "liblog",
        "libcutils",
        "libutils",
    ],

    export_include_dirs: ["include"],

    sanitize: {
        misc_undefined: ["integer"],
    },

    cflags: [
        "-Wall",
        "-Werror",
    ],
}
+89 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "IPCThreadStateBase"

#include <binderthreadstate/IPCThreadStateBase.h>
#include <android-base/macros.h>

#include <utils/Log.h>

#include <errno.h>
#include <inttypes.h>
#include <pthread.h>

namespace android {

static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
static bool gHaveTLS = false;
static pthread_key_t gTLS = 0;

IPCThreadStateBase::IPCThreadStateBase() {
    pthread_setspecific(gTLS, this);
}

IPCThreadStateBase* IPCThreadStateBase::self()
{
    if (gHaveTLS) {
restart:
        const pthread_key_t k = gTLS;
        IPCThreadStateBase* st = (IPCThreadStateBase*)pthread_getspecific(k);
        if (st) return st;
        return new IPCThreadStateBase;
    }

    pthread_mutex_lock(&gTLSMutex);
    if (!gHaveTLS) {
        int key_create_value = pthread_key_create(&gTLS, threadDestructor);
        if (key_create_value != 0) {
            pthread_mutex_unlock(&gTLSMutex);
            ALOGW("IPCThreadStateBase::self() unable to create TLS key, expect a crash: %s\n",
                    strerror(key_create_value));
            return nullptr;
        }
        gHaveTLS = true;
    }
    pthread_mutex_unlock(&gTLSMutex);
    goto restart;
}

void IPCThreadStateBase::pushCurrentState(CallState callState) {
    mCallStateStack.emplace(callState);
}

IPCThreadStateBase::CallState IPCThreadStateBase::popCurrentState() {
    ALOG_ASSERT(mCallStateStack.size > 0);
    CallState val = mCallStateStack.top();
    mCallStateStack.pop();
    return val;
}

IPCThreadStateBase::CallState IPCThreadStateBase::getCurrentBinderCallState() {
    if (mCallStateStack.size() > 0) {
        return mCallStateStack.top();
    }
    return CallState::NONE;
}

void IPCThreadStateBase::threadDestructor(void *st)
{
    IPCThreadStateBase* const self = static_cast<IPCThreadStateBase*>(st);
    if (self) {
        delete self;
    }
}

}; // namespace android
Loading