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

Commit 266aec23 authored by Yifan Hong's avatar Yifan Hong Committed by Automerger Merge Worker
Browse files

Merge "RpcSession attaches/detaches thread on JVM (second attempt)" am:...

Merge "RpcSession attaches/detaches thread on JVM (second attempt)" am: a2c63abe am: 1b796e62 am: c7a703cc am: 844837e8

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1767689

Change-Id: I5219e708ea58dc3882e4067218cf732617a74bb4
parents a0fa1b88 844837e8
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -189,6 +189,7 @@ cc_library {


    header_libs: [
    header_libs: [
        "libbinder_headers",
        "libbinder_headers",
        "libandroid_runtime_vm_headers",
    ],
    ],


    export_header_lib_headers: [
    export_header_lib_headers: [
+60 −0
Original line number Original line Diff line number Diff line
@@ -18,16 +18,20 @@


#include <binder/RpcSession.h>
#include <binder/RpcSession.h>


#include <dlfcn.h>
#include <inttypes.h>
#include <inttypes.h>
#include <poll.h>
#include <poll.h>
#include <pthread.h>
#include <unistd.h>
#include <unistd.h>


#include <string_view>
#include <string_view>


#include <android-base/macros.h>
#include <android-base/macros.h>
#include <android_runtime/vm.h>
#include <binder/Parcel.h>
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
#include <binder/RpcServer.h>
#include <binder/Stability.h>
#include <binder/Stability.h>
#include <jni.h>
#include <utils/String8.h>
#include <utils/String8.h>


#include "RpcSocketAddress.h"
#include "RpcSocketAddress.h"
@@ -297,10 +301,66 @@ RpcSession::PreJoinSetupResult RpcSession::preJoinSetup(base::unique_fd fd) {
    };
    };
}
}


namespace {
// RAII object for attaching / detaching current thread to JVM if Android Runtime exists. If
// Android Runtime doesn't exist, no-op.
class JavaThreadAttacher {
public:
    JavaThreadAttacher() {
        // Use dlsym to find androidJavaAttachThread because libandroid_runtime is loaded after
        // libbinder.
        auto vm = getJavaVM();
        if (vm == nullptr) return;

        char threadName[16];
        if (0 != pthread_getname_np(pthread_self(), threadName, sizeof(threadName))) {
            constexpr const char* defaultThreadName = "UnknownRpcSessionThread";
            memcpy(threadName, defaultThreadName,
                   std::min<size_t>(sizeof(threadName), strlen(defaultThreadName) + 1));
        }
        LOG_RPC_DETAIL("Attaching current thread %s to JVM", threadName);
        JavaVMAttachArgs args;
        args.version = JNI_VERSION_1_2;
        args.name = threadName;
        args.group = nullptr;
        JNIEnv* env;

        LOG_ALWAYS_FATAL_IF(vm->AttachCurrentThread(&env, &args) != JNI_OK,
                            "Cannot attach thread %s to JVM", threadName);
        mAttached = true;
    }
    ~JavaThreadAttacher() {
        if (!mAttached) return;
        auto vm = getJavaVM();
        LOG_ALWAYS_FATAL_IF(vm == nullptr,
                            "Unable to detach thread. No JavaVM, but it was present before!");

        LOG_RPC_DETAIL("Detaching current thread from JVM");
        if (vm->DetachCurrentThread() != JNI_OK) {
            mAttached = false;
        } else {
            ALOGW("Unable to detach current thread from JVM");
        }
    }

private:
    DISALLOW_COPY_AND_ASSIGN(JavaThreadAttacher);
    bool mAttached = false;

    static JavaVM* getJavaVM() {
        static auto fn = reinterpret_cast<decltype(&AndroidRuntimeGetJavaVM)>(
                dlsym(RTLD_DEFAULT, "AndroidRuntimeGetJavaVM"));
        if (fn == nullptr) return nullptr;
        return fn();
    }
};
} // namespace

void RpcSession::join(sp<RpcSession>&& session, PreJoinSetupResult&& setupResult) {
void RpcSession::join(sp<RpcSession>&& session, PreJoinSetupResult&& setupResult) {
    sp<RpcConnection>& connection = setupResult.connection;
    sp<RpcConnection>& connection = setupResult.connection;


    if (setupResult.status == OK) {
    if (setupResult.status == OK) {
        JavaThreadAttacher javaThreadAttacher;
        while (true) {
        while (true) {
            status_t status = session->state()->getAndExecuteCommand(connection, session,
            status_t status = session->state()->getAndExecuteCommand(connection, session,
                                                                     RpcState::CommandType::ANY);
                                                                     RpcState::CommandType::ANY);
+37 −0
Original line number Original line Diff line number Diff line
@@ -1218,6 +1218,43 @@ TEST(BinderRpc, Shutdown) {
            << "After server->shutdown() returns true, join() did not stop after 2s";
            << "After server->shutdown() returns true, join() did not stop after 2s";
}
}


TEST(BinderRpc, Java) {
#if !defined(__ANDROID__)
    GTEST_SKIP() << "This test is only run on Android. Though it can technically run on host on"
                    "createRpcDelegateServiceManager() with a device attached, such test belongs "
                    "to binderHostDeviceTest. Hence, just disable this test on host.";
#endif // !__ANDROID__
    sp<IServiceManager> sm = defaultServiceManager();
    ASSERT_NE(nullptr, sm);
    // Any Java service with non-empty getInterfaceDescriptor() would do.
    // Let's pick batteryproperties.
    auto binder = sm->checkService(String16("batteryproperties"));
    ASSERT_NE(nullptr, binder);
    auto descriptor = binder->getInterfaceDescriptor();
    ASSERT_GE(descriptor.size(), 0);
    ASSERT_EQ(OK, binder->pingBinder());

    auto rpcServer = RpcServer::make();
    rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
    unsigned int port;
    ASSERT_TRUE(rpcServer->setupInetServer(0, &port));
    auto socket = rpcServer->releaseServer();

    auto keepAlive = sp<BBinder>::make();
    ASSERT_EQ(OK, binder->setRpcClientDebug(std::move(socket), keepAlive));

    auto rpcSession = RpcSession::make();
    ASSERT_TRUE(rpcSession->setupInetClient("127.0.0.1", port));
    auto rpcBinder = rpcSession->getRootObject();
    ASSERT_NE(nullptr, rpcBinder);

    ASSERT_EQ(OK, rpcBinder->pingBinder());

    ASSERT_EQ(descriptor, rpcBinder->getInterfaceDescriptor())
            << "getInterfaceDescriptor should not crash system_server";
    ASSERT_EQ(OK, rpcBinder->pingBinder());
}

} // namespace android
} // namespace android


int main(int argc, char** argv) {
int main(int argc, char** argv) {