Loading libs/binder/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -192,6 +192,7 @@ cc_library { header_libs: [ "libbinder_headers", "libandroid_runtime_vm_headers", ], export_header_lib_headers: [ Loading libs/binder/RpcSession.cpp +60 −0 Original line number Diff line number Diff line Loading @@ -18,16 +18,20 @@ #include <binder/RpcSession.h> #include <dlfcn.h> #include <inttypes.h> #include <poll.h> #include <pthread.h> #include <unistd.h> #include <string_view> #include <android-base/macros.h> #include <android_runtime/vm.h> #include <binder/Parcel.h> #include <binder/RpcServer.h> #include <binder/Stability.h> #include <jni.h> #include <utils/String8.h> #include "RpcSocketAddress.h" Loading Loading @@ -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) { sp<RpcConnection>& connection = setupResult.connection; if (setupResult.status == OK) { JavaThreadAttacher javaThreadAttacher; while (true) { status_t status = session->state()->getAndExecuteCommand(connection, session, RpcState::CommandType::ANY); Loading libs/binder/tests/binderRpcTest.cpp +37 −0 Original line number Diff line number Diff line Loading @@ -1218,6 +1218,43 @@ TEST(BinderRpc, Shutdown) { << "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 int main(int argc, char** argv) { Loading Loading
libs/binder/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -192,6 +192,7 @@ cc_library { header_libs: [ "libbinder_headers", "libandroid_runtime_vm_headers", ], export_header_lib_headers: [ Loading
libs/binder/RpcSession.cpp +60 −0 Original line number Diff line number Diff line Loading @@ -18,16 +18,20 @@ #include <binder/RpcSession.h> #include <dlfcn.h> #include <inttypes.h> #include <poll.h> #include <pthread.h> #include <unistd.h> #include <string_view> #include <android-base/macros.h> #include <android_runtime/vm.h> #include <binder/Parcel.h> #include <binder/RpcServer.h> #include <binder/Stability.h> #include <jni.h> #include <utils/String8.h> #include "RpcSocketAddress.h" Loading Loading @@ -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) { sp<RpcConnection>& connection = setupResult.connection; if (setupResult.status == OK) { JavaThreadAttacher javaThreadAttacher; while (true) { status_t status = session->state()->getAndExecuteCommand(connection, session, RpcState::CommandType::ANY); Loading
libs/binder/tests/binderRpcTest.cpp +37 −0 Original line number Diff line number Diff line Loading @@ -1218,6 +1218,43 @@ TEST(BinderRpc, Shutdown) { << "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 int main(int argc, char** argv) { Loading