diff options
author | 2020-01-30 21:56:03 +0000 | |
---|---|---|
committer | 2020-01-30 21:56:03 +0000 | |
commit | 77d8f5b5d3a5e16ec9dd5b35d1e7c7e6d993eb2f (patch) | |
tree | bd1d9db1e3b757bef6ee6091864a9bb6222f6bed | |
parent | 40927e84e74442382a914b506905725db82e717d (diff) | |
parent | 169bb8f054f3ef88f5682472dd275facd35a838b (diff) |
Merge "libbinder_ndk: test Bp destruction"
-rw-r--r-- | libs/binder/ndk/test/Android.bp | 11 | ||||
-rw-r--r-- | libs/binder/ndk/test/IBinderNdkUnitTest.aidl | 27 | ||||
-rw-r--r-- | libs/binder/ndk/test/IEmpty.aidl | 17 | ||||
-rw-r--r-- | libs/binder/ndk/test/libbinder_ndk_unit_test.cpp | 81 |
4 files changed, 133 insertions, 3 deletions
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp index e598eec520..513d8c2eba 100644 --- a/libs/binder/ndk/test/Android.bp +++ b/libs/binder/ndk/test/Android.bp @@ -59,6 +59,9 @@ cc_test { name: "libbinder_ndk_unit_test", defaults: ["test_libbinder_ndk_test_defaults"], srcs: ["libbinder_ndk_unit_test.cpp"], + static_libs: [ + "IBinderNdkUnitTest-ndk_platform", + ], test_suites: ["general-tests"], require_root: true, @@ -93,3 +96,11 @@ aidl_interface { "IBinderVendorDoubleLoadTest.aidl", ], } + +aidl_interface { + name: "IBinderNdkUnitTest", + srcs: [ + "IBinderNdkUnitTest.aidl", + "IEmpty.aidl", + ], +} diff --git a/libs/binder/ndk/test/IBinderNdkUnitTest.aidl b/libs/binder/ndk/test/IBinderNdkUnitTest.aidl new file mode 100644 index 0000000000..6e8e463ff1 --- /dev/null +++ b/libs/binder/ndk/test/IBinderNdkUnitTest.aidl @@ -0,0 +1,27 @@ +/* + * 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(); +} diff --git a/libs/binder/ndk/test/IEmpty.aidl b/libs/binder/ndk/test/IEmpty.aidl new file mode 100644 index 0000000000..95e4341531 --- /dev/null +++ b/libs/binder/ndk/test/IEmpty.aidl @@ -0,0 +1,17 @@ +/* + * 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 { } diff --git a/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp index 8aba411101..51dd169ec0 100644 --- a/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include <aidl/BnBinderNdkUnitTest.h> +#include <aidl/BnEmpty.h> #include <android-base/logging.h> #include <android/binder_ibinder_jni.h> #include <android/binder_manager.h> @@ -21,6 +23,10 @@ #include <gtest/gtest.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 <chrono> #include <condition_variable> @@ -29,7 +35,38 @@ using ::android::sp; 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 { binder_status_t doubleNumber(int32_t in, int32_t* out) override { *out = 2 * in; @@ -43,7 +80,7 @@ class MyFoo : public IFoo { } }; -int service(const char* instance) { +int manualService(const char* instance) { ABinderProcess_setThreadPoolMaxThreadCount(0); // Strong reference to MyFoo kept by service manager. @@ -225,16 +262,54 @@ TEST(NdkBinder, AddServiceMultipleTimes) { 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[]) { ::testing::InitGoogleTest(&argc, argv); if (fork() == 0) { 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) { prctl(PR_SET_PDEATHSIG, SIGHUP); - return service(IFoo::kSomeInstanceName); + return generatedService(); } ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks |