Loading libs/binder/ndk/test/Android.bp +11 −0 Original line number Original line Diff line number Diff line Loading @@ -59,6 +59,9 @@ cc_test { name: "libbinder_ndk_unit_test", name: "libbinder_ndk_unit_test", defaults: ["test_libbinder_ndk_test_defaults"], defaults: ["test_libbinder_ndk_test_defaults"], srcs: ["libbinder_ndk_unit_test.cpp"], srcs: ["libbinder_ndk_unit_test.cpp"], static_libs: [ "IBinderNdkUnitTest-ndk_platform", ], test_suites: ["general-tests"], test_suites: ["general-tests"], require_root: true, require_root: true, Loading Loading @@ -93,3 +96,11 @@ aidl_interface { "IBinderVendorDoubleLoadTest.aidl", "IBinderVendorDoubleLoadTest.aidl", ], ], } } aidl_interface { name: "IBinderNdkUnitTest", srcs: [ "IBinderNdkUnitTest.aidl", "IEmpty.aidl", ], } libs/binder/ndk/test/IBinderNdkUnitTest.aidl 0 → 100644 +27 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 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. */ // This AIDL is to test things that can't be tested in CtsNdkBinderTestCases // because it requires libbinder_ndk implementation details or APIs not // available to apps. Please prefer adding tests to CtsNdkBinderTestCases // over here. import IEmpty; interface IBinderNdkUnitTest { void takeInterface(IEmpty test); void forceFlushCommands(); } libs/binder/ndk/test/IEmpty.aidl 0 → 100644 +17 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 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. */ interface IEmpty { } libs/binder/ndk/test/libbinder_ndk_unit_test.cpp +78 −3 Original line number Original line Diff line number Diff line Loading @@ -14,6 +14,8 @@ * limitations under the License. * limitations under the License. */ */ #include <aidl/BnBinderNdkUnitTest.h> #include <aidl/BnEmpty.h> #include <android-base/logging.h> #include <android-base/logging.h> #include <android/binder_ibinder_jni.h> #include <android/binder_ibinder_jni.h> #include <android/binder_manager.h> #include <android/binder_manager.h> Loading @@ -21,6 +23,10 @@ #include <gtest/gtest.h> #include <gtest/gtest.h> #include <iface/iface.h> #include <iface/iface.h> // warning: this is assuming that libbinder_ndk is using the same copy // of libbinder that we are. #include <binder/IPCThreadState.h> #include <sys/prctl.h> #include <sys/prctl.h> #include <chrono> #include <chrono> #include <condition_variable> #include <condition_variable> Loading @@ -29,7 +35,38 @@ using ::android::sp; using ::android::sp; constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest"; class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest { ndk::ScopedAStatus takeInterface(const std::shared_ptr<aidl::IEmpty>& empty) { (void)empty; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus forceFlushCommands() { // warning: this is assuming that libbinder_ndk is using the same copy // of libbinder that we are. android::IPCThreadState::self()->flushCommands(); return ndk::ScopedAStatus::ok(); } }; int generatedService() { ABinderProcess_setThreadPoolMaxThreadCount(0); auto service = ndk::SharedRefBase::make<MyBinderNdkUnitTest>(); binder_status_t status = AServiceManager_addService(service->asBinder().get(), kBinderNdkUnitTestService); if (status != STATUS_OK) { LOG(FATAL) << "Could not register: " << status << " " << kBinderNdkUnitTestService; } ABinderProcess_joinThreadPool(); return 1; // should not return } // manually-written parceling class considered bad practice class MyFoo : public IFoo { class MyFoo : public IFoo { binder_status_t doubleNumber(int32_t in, int32_t* out) override { binder_status_t doubleNumber(int32_t in, int32_t* out) override { *out = 2 * in; *out = 2 * in; Loading @@ -43,7 +80,7 @@ class MyFoo : public IFoo { } } }; }; int service(const char* instance) { int manualService(const char* instance) { ABinderProcess_setThreadPoolMaxThreadCount(0); ABinderProcess_setThreadPoolMaxThreadCount(0); // Strong reference to MyFoo kept by service manager. // Strong reference to MyFoo kept by service manager. Loading Loading @@ -225,16 +262,54 @@ TEST(NdkBinder, AddServiceMultipleTimes) { EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2)); EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2)); } } TEST(NdkBinder, SentAidlBinderCanBeDestroyed) { static volatile bool destroyed = false; static std::mutex dMutex; static std::condition_variable cv; class MyEmpty : public aidl::BnEmpty { virtual ~MyEmpty() { destroyed = true; cv.notify_one(); } }; std::shared_ptr<MyEmpty> empty = ndk::SharedRefBase::make<MyEmpty>(); ndk::SpAIBinder binder(AServiceManager_getService(kBinderNdkUnitTestService)); std::shared_ptr<aidl::IBinderNdkUnitTest> service = aidl::IBinderNdkUnitTest::fromBinder(binder); EXPECT_FALSE(destroyed); service->takeInterface(empty); service->forceFlushCommands(); empty = nullptr; // give other binder thread time to process commands { using namespace std::chrono_literals; std::unique_lock<std::mutex> lk(dMutex); cv.wait_for(lk, 1s, [] { return destroyed; }); } EXPECT_TRUE(destroyed); } int main(int argc, char* argv[]) { int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); ::testing::InitGoogleTest(&argc, argv); if (fork() == 0) { if (fork() == 0) { prctl(PR_SET_PDEATHSIG, SIGHUP); prctl(PR_SET_PDEATHSIG, SIGHUP); return service(IFoo::kInstanceNameToDieFor); return manualService(IFoo::kInstanceNameToDieFor); } if (fork() == 0) { prctl(PR_SET_PDEATHSIG, SIGHUP); return manualService(IFoo::kSomeInstanceName); } } if (fork() == 0) { if (fork() == 0) { prctl(PR_SET_PDEATHSIG, SIGHUP); prctl(PR_SET_PDEATHSIG, SIGHUP); return service(IFoo::kSomeInstanceName); return generatedService(); } } ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks Loading Loading
libs/binder/ndk/test/Android.bp +11 −0 Original line number Original line Diff line number Diff line Loading @@ -59,6 +59,9 @@ cc_test { name: "libbinder_ndk_unit_test", name: "libbinder_ndk_unit_test", defaults: ["test_libbinder_ndk_test_defaults"], defaults: ["test_libbinder_ndk_test_defaults"], srcs: ["libbinder_ndk_unit_test.cpp"], srcs: ["libbinder_ndk_unit_test.cpp"], static_libs: [ "IBinderNdkUnitTest-ndk_platform", ], test_suites: ["general-tests"], test_suites: ["general-tests"], require_root: true, require_root: true, Loading Loading @@ -93,3 +96,11 @@ aidl_interface { "IBinderVendorDoubleLoadTest.aidl", "IBinderVendorDoubleLoadTest.aidl", ], ], } } aidl_interface { name: "IBinderNdkUnitTest", srcs: [ "IBinderNdkUnitTest.aidl", "IEmpty.aidl", ], }
libs/binder/ndk/test/IBinderNdkUnitTest.aidl 0 → 100644 +27 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 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. */ // This AIDL is to test things that can't be tested in CtsNdkBinderTestCases // because it requires libbinder_ndk implementation details or APIs not // available to apps. Please prefer adding tests to CtsNdkBinderTestCases // over here. import IEmpty; interface IBinderNdkUnitTest { void takeInterface(IEmpty test); void forceFlushCommands(); }
libs/binder/ndk/test/IEmpty.aidl 0 → 100644 +17 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 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. */ interface IEmpty { }
libs/binder/ndk/test/libbinder_ndk_unit_test.cpp +78 −3 Original line number Original line Diff line number Diff line Loading @@ -14,6 +14,8 @@ * limitations under the License. * limitations under the License. */ */ #include <aidl/BnBinderNdkUnitTest.h> #include <aidl/BnEmpty.h> #include <android-base/logging.h> #include <android-base/logging.h> #include <android/binder_ibinder_jni.h> #include <android/binder_ibinder_jni.h> #include <android/binder_manager.h> #include <android/binder_manager.h> Loading @@ -21,6 +23,10 @@ #include <gtest/gtest.h> #include <gtest/gtest.h> #include <iface/iface.h> #include <iface/iface.h> // warning: this is assuming that libbinder_ndk is using the same copy // of libbinder that we are. #include <binder/IPCThreadState.h> #include <sys/prctl.h> #include <sys/prctl.h> #include <chrono> #include <chrono> #include <condition_variable> #include <condition_variable> Loading @@ -29,7 +35,38 @@ using ::android::sp; using ::android::sp; constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest"; class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest { ndk::ScopedAStatus takeInterface(const std::shared_ptr<aidl::IEmpty>& empty) { (void)empty; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus forceFlushCommands() { // warning: this is assuming that libbinder_ndk is using the same copy // of libbinder that we are. android::IPCThreadState::self()->flushCommands(); return ndk::ScopedAStatus::ok(); } }; int generatedService() { ABinderProcess_setThreadPoolMaxThreadCount(0); auto service = ndk::SharedRefBase::make<MyBinderNdkUnitTest>(); binder_status_t status = AServiceManager_addService(service->asBinder().get(), kBinderNdkUnitTestService); if (status != STATUS_OK) { LOG(FATAL) << "Could not register: " << status << " " << kBinderNdkUnitTestService; } ABinderProcess_joinThreadPool(); return 1; // should not return } // manually-written parceling class considered bad practice class MyFoo : public IFoo { class MyFoo : public IFoo { binder_status_t doubleNumber(int32_t in, int32_t* out) override { binder_status_t doubleNumber(int32_t in, int32_t* out) override { *out = 2 * in; *out = 2 * in; Loading @@ -43,7 +80,7 @@ class MyFoo : public IFoo { } } }; }; int service(const char* instance) { int manualService(const char* instance) { ABinderProcess_setThreadPoolMaxThreadCount(0); ABinderProcess_setThreadPoolMaxThreadCount(0); // Strong reference to MyFoo kept by service manager. // Strong reference to MyFoo kept by service manager. Loading Loading @@ -225,16 +262,54 @@ TEST(NdkBinder, AddServiceMultipleTimes) { EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2)); EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2)); } } TEST(NdkBinder, SentAidlBinderCanBeDestroyed) { static volatile bool destroyed = false; static std::mutex dMutex; static std::condition_variable cv; class MyEmpty : public aidl::BnEmpty { virtual ~MyEmpty() { destroyed = true; cv.notify_one(); } }; std::shared_ptr<MyEmpty> empty = ndk::SharedRefBase::make<MyEmpty>(); ndk::SpAIBinder binder(AServiceManager_getService(kBinderNdkUnitTestService)); std::shared_ptr<aidl::IBinderNdkUnitTest> service = aidl::IBinderNdkUnitTest::fromBinder(binder); EXPECT_FALSE(destroyed); service->takeInterface(empty); service->forceFlushCommands(); empty = nullptr; // give other binder thread time to process commands { using namespace std::chrono_literals; std::unique_lock<std::mutex> lk(dMutex); cv.wait_for(lk, 1s, [] { return destroyed; }); } EXPECT_TRUE(destroyed); } int main(int argc, char* argv[]) { int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); ::testing::InitGoogleTest(&argc, argv); if (fork() == 0) { if (fork() == 0) { prctl(PR_SET_PDEATHSIG, SIGHUP); prctl(PR_SET_PDEATHSIG, SIGHUP); return service(IFoo::kInstanceNameToDieFor); return manualService(IFoo::kInstanceNameToDieFor); } if (fork() == 0) { prctl(PR_SET_PDEATHSIG, SIGHUP); return manualService(IFoo::kSomeInstanceName); } } if (fork() == 0) { if (fork() == 0) { prctl(PR_SET_PDEATHSIG, SIGHUP); prctl(PR_SET_PDEATHSIG, SIGHUP); return service(IFoo::kSomeInstanceName); return generatedService(); } } ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks Loading