Loading libs/binder/ndk/runtests.sh +9 −7 Original line number Diff line number Diff line Loading @@ -23,11 +23,12 @@ set -ex function run_libbinder_ndk_test() { adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server & local pid=$! trap "kill $pid" ERR adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client trap '' ERR kill $pid # avoid getService 1s delay for most runs, non-critical sleep 0.1 adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client; \ adb shell killall libbinder_ndk_test_server } [ "$1" != "--skip-build" ] && $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \ Loading @@ -40,4 +41,5 @@ adb sync data # very simple unit tests, tests things outside of the NDK as well run_libbinder_ndk_test atest android.binder.cts.NdkBinderTest # CTS tests (much more comprehensive, new tests should ideally go here) atest android.binder.cts libs/binder/ndk/test/Android.bp +3 −3 Original line number Diff line number Diff line Loading @@ -14,9 +14,6 @@ * limitations under the License. */ // This test is a unit test of the low-level API that is presented here. // Actual users should use AIDL to generate these complicated stubs. cc_defaults { name: "test_libbinder_ndk_defaults", shared_libs: [ Loading Loading @@ -55,6 +52,9 @@ cc_defaults { ], } // This test is a unit test of the low-level API that is presented here, // specifically the parts which are outside of the NDK. Actual users should // also instead use AIDL to generate these stubs. See android.binder.cts. cc_test { name: "libbinder_ndk_test_client", defaults: ["test_libbinder_ndk_test_defaults"], Loading libs/binder/ndk/test/iface.cpp +40 −13 Original line number Diff line number Diff line Loading @@ -18,10 +18,13 @@ #include <android/binder_manager.h> #include <iface/iface.h> #include <android/binder_auto_utils.h> using ::android::sp; using ::android::wp; const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo"; const char* IFoo::kInstanceNameToDieFor = "libbinder_ndk-test-IFoo-to-die"; const char* kIFooDescriptor = "my-special-IFoo-class"; struct IFoo_Class_Data { Loading Loading @@ -49,12 +52,18 @@ binder_status_t IFoo_Class_onTransact(AIBinder* binder, transaction_code_t code, switch (code) { case IFoo::DOFOO: { int32_t valueIn; int32_t valueOut; stat = AParcel_readInt32(in, &valueIn); if (stat != STATUS_OK) break; int32_t valueOut = foo->doubleNumber(valueIn); stat = foo->doubleNumber(valueIn, &valueOut); if (stat != STATUS_OK) break; stat = AParcel_writeInt32(out, valueOut); break; } case IFoo::DIE: { stat = foo->die(); break; } } return stat; Loading @@ -68,22 +77,36 @@ class BpFoo : public IFoo { BpFoo(AIBinder* binder) : mBinder(binder) {} virtual ~BpFoo() { AIBinder_decStrong(mBinder); } virtual int32_t doubleNumber(int32_t in) { virtual binder_status_t doubleNumber(int32_t in, int32_t* out) { binder_status_t stat = STATUS_OK; AParcel* parcelIn; CHECK(STATUS_OK == AIBinder_prepareTransaction(mBinder, &parcelIn)); stat = AIBinder_prepareTransaction(mBinder, &parcelIn); if (stat != STATUS_OK) return stat; stat = AParcel_writeInt32(parcelIn, in); if (stat != STATUS_OK) return stat; ::ndk::ScopedAParcel parcelOut; stat = AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, parcelOut.getR(), 0 /*flags*/); if (stat != STATUS_OK) return stat; CHECK(STATUS_OK == AParcel_writeInt32(parcelIn, in)); stat = AParcel_readInt32(parcelOut.get(), out); if (stat != STATUS_OK) return stat; AParcel* parcelOut; CHECK(STATUS_OK == AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, &parcelOut, 0 /*flags*/)); return stat; } int32_t out; CHECK(STATUS_OK == AParcel_readInt32(parcelOut, &out)); virtual binder_status_t die() { binder_status_t stat = STATUS_OK; AParcel* parcelIn; stat = AIBinder_prepareTransaction(mBinder, &parcelIn); AParcel_delete(parcelOut); ::ndk::ScopedAParcel parcelOut; stat = AIBinder_transact(mBinder, IFoo::DIE, &parcelIn, parcelOut.getR(), 0 /*flags*/); return out; return stat; } private: Loading Loading @@ -117,7 +140,7 @@ binder_status_t IFoo::addService(const char* instance) { return status; } sp<IFoo> IFoo::getService(const char* instance) { sp<IFoo> IFoo::getService(const char* instance, AIBinder** outBinder) { AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr if (binder == nullptr) { return nullptr; Loading @@ -128,6 +151,11 @@ sp<IFoo> IFoo::getService(const char* instance) { return nullptr; } if (outBinder != nullptr) { AIBinder_incStrong(binder); *outBinder = binder; } if (AIBinder_isRemote(binder)) { sp<IFoo> ret = new BpFoo(binder); // takes ownership of binder return ret; Loading @@ -143,7 +171,6 @@ sp<IFoo> IFoo::getService(const char* instance) { CHECK(held == binder); AIBinder_decStrong(held); // IFoo only keeps a weak reference to AIBinder, so we can drop this AIBinder_decStrong(binder); return ret; } libs/binder/ndk/test/include/iface/iface.h +14 −3 Original line number Diff line number Diff line Loading @@ -19,22 +19,33 @@ #include <android/binder_ibinder.h> #include <utils/RefBase.h> // warning: it is recommended to use AIDL output instead of this. binder_ibinder_utils.h and some of // the other niceties make sure that, for instance, binder proxies are always the same. They also // don't use internal Android APIs like refbase which are used here only for convenience. class IFoo : public virtual ::android::RefBase { public: static const char* kSomeInstanceName; static const char* kInstanceNameToDieFor; static AIBinder_Class* kClass; // Takes ownership of IFoo binder_status_t addService(const char* instance); static ::android::sp<IFoo> getService(const char* instance); static ::android::sp<IFoo> getService(const char* instance, AIBinder** outBinder = nullptr); enum Call { DOFOO = FIRST_CALL_TRANSACTION + 0, DIE = FIRST_CALL_TRANSACTION + 1, }; virtual ~IFoo(); virtual int32_t doubleNumber(int32_t in) = 0; virtual binder_status_t doubleNumber(int32_t in, int32_t* out) = 0; virtual binder_status_t die() = 0; private: AIBinder_Weak* mWeakBinder = nullptr; // maybe owns AIBinder // this variable is only when IFoo is local (since this test combines 'IFoo' and 'BnFoo'), not // for BpFoo. AIBinder_Weak* mWeakBinder = nullptr; }; libs/binder/ndk/test/main_client.cpp +65 −8 Original line number Diff line number Diff line Loading @@ -21,6 +21,10 @@ #include <gtest/gtest.h> #include <iface/iface.h> #include <chrono> #include <condition_variable> #include <mutex> using ::android::sp; constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; Loading @@ -34,7 +38,47 @@ constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; TEST(NdkBinder, DoubleNumber) { sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName); ASSERT_NE(foo, nullptr); EXPECT_EQ(2, foo->doubleNumber(1)); int32_t out; EXPECT_EQ(STATUS_OK, foo->doubleNumber(1, &out)); EXPECT_EQ(2, out); } void LambdaOnDeath(void* cookie) { auto onDeath = static_cast<std::function<void(void)>*>(cookie); (*onDeath)(); }; TEST(NdkBinder, DeathRecipient) { using namespace std::chrono_literals; AIBinder* binder; sp<IFoo> foo = IFoo::getService(IFoo::kInstanceNameToDieFor, &binder); ASSERT_NE(nullptr, foo.get()); ASSERT_NE(nullptr, binder); std::mutex deathMutex; std::condition_variable deathCv; bool deathRecieved = false; std::function<void(void)> onDeath = [&] { std::cerr << "Binder died (as requested)." << std::endl; deathRecieved = true; deathCv.notify_one(); }; AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath); EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&onDeath))); // the binder driver should return this if the service dies during the transaction EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die()); std::unique_lock<std::mutex> lock(deathMutex); EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; })); EXPECT_TRUE(deathRecieved); AIBinder_DeathRecipient_delete(recipient); AIBinder_decStrong(binder); } TEST(NdkBinder, RetrieveNonNdkService) { Loading @@ -52,9 +96,6 @@ void OnBinderDeath(void* cookie) { } TEST(NdkBinder, LinkToDeath) { ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications ABinderProcess_startThreadPool(); AIBinder* binder = AServiceManager_getService(kExistingNonNdkService); ASSERT_NE(nullptr, binder); Loading @@ -72,9 +113,14 @@ TEST(NdkBinder, LinkToDeath) { } class MyTestFoo : public IFoo { int32_t doubleNumber(int32_t in) override { LOG(INFO) << "doubleNumber " << in; return 2 * in; binder_status_t doubleNumber(int32_t in, int32_t* out) override { *out = 2 * in; LOG(INFO) << "doubleNumber (" << in << ") => " << *out; return STATUS_OK; } binder_status_t die() override { ADD_FAILURE() << "die called on local instance"; return STATUS_OK; } }; Loading @@ -87,7 +133,9 @@ TEST(NdkBinder, GetServiceInProcess) { sp<IFoo> getFoo = IFoo::getService(kInstanceName); EXPECT_EQ(foo.get(), getFoo.get()); EXPECT_EQ(2, getFoo->doubleNumber(1)); int32_t out; EXPECT_EQ(STATUS_OK, getFoo->doubleNumber(1, &out)); EXPECT_EQ(2, out); } TEST(NdkBinder, EqualityOfRemoteBinderPointer) { Loading Loading @@ -132,6 +180,15 @@ TEST(NdkBinder, AddServiceMultipleTimes) { EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2)); } int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks ABinderProcess_startThreadPool(); return RUN_ALL_TESTS(); } #include <android/binder_auto_utils.h> #include <android/binder_interface_utils.h> #include <android/binder_parcel_utils.h> Loading
libs/binder/ndk/runtests.sh +9 −7 Original line number Diff line number Diff line Loading @@ -23,11 +23,12 @@ set -ex function run_libbinder_ndk_test() { adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server & local pid=$! trap "kill $pid" ERR adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client trap '' ERR kill $pid # avoid getService 1s delay for most runs, non-critical sleep 0.1 adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client; \ adb shell killall libbinder_ndk_test_server } [ "$1" != "--skip-build" ] && $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \ Loading @@ -40,4 +41,5 @@ adb sync data # very simple unit tests, tests things outside of the NDK as well run_libbinder_ndk_test atest android.binder.cts.NdkBinderTest # CTS tests (much more comprehensive, new tests should ideally go here) atest android.binder.cts
libs/binder/ndk/test/Android.bp +3 −3 Original line number Diff line number Diff line Loading @@ -14,9 +14,6 @@ * limitations under the License. */ // This test is a unit test of the low-level API that is presented here. // Actual users should use AIDL to generate these complicated stubs. cc_defaults { name: "test_libbinder_ndk_defaults", shared_libs: [ Loading Loading @@ -55,6 +52,9 @@ cc_defaults { ], } // This test is a unit test of the low-level API that is presented here, // specifically the parts which are outside of the NDK. Actual users should // also instead use AIDL to generate these stubs. See android.binder.cts. cc_test { name: "libbinder_ndk_test_client", defaults: ["test_libbinder_ndk_test_defaults"], Loading
libs/binder/ndk/test/iface.cpp +40 −13 Original line number Diff line number Diff line Loading @@ -18,10 +18,13 @@ #include <android/binder_manager.h> #include <iface/iface.h> #include <android/binder_auto_utils.h> using ::android::sp; using ::android::wp; const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo"; const char* IFoo::kInstanceNameToDieFor = "libbinder_ndk-test-IFoo-to-die"; const char* kIFooDescriptor = "my-special-IFoo-class"; struct IFoo_Class_Data { Loading Loading @@ -49,12 +52,18 @@ binder_status_t IFoo_Class_onTransact(AIBinder* binder, transaction_code_t code, switch (code) { case IFoo::DOFOO: { int32_t valueIn; int32_t valueOut; stat = AParcel_readInt32(in, &valueIn); if (stat != STATUS_OK) break; int32_t valueOut = foo->doubleNumber(valueIn); stat = foo->doubleNumber(valueIn, &valueOut); if (stat != STATUS_OK) break; stat = AParcel_writeInt32(out, valueOut); break; } case IFoo::DIE: { stat = foo->die(); break; } } return stat; Loading @@ -68,22 +77,36 @@ class BpFoo : public IFoo { BpFoo(AIBinder* binder) : mBinder(binder) {} virtual ~BpFoo() { AIBinder_decStrong(mBinder); } virtual int32_t doubleNumber(int32_t in) { virtual binder_status_t doubleNumber(int32_t in, int32_t* out) { binder_status_t stat = STATUS_OK; AParcel* parcelIn; CHECK(STATUS_OK == AIBinder_prepareTransaction(mBinder, &parcelIn)); stat = AIBinder_prepareTransaction(mBinder, &parcelIn); if (stat != STATUS_OK) return stat; stat = AParcel_writeInt32(parcelIn, in); if (stat != STATUS_OK) return stat; ::ndk::ScopedAParcel parcelOut; stat = AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, parcelOut.getR(), 0 /*flags*/); if (stat != STATUS_OK) return stat; CHECK(STATUS_OK == AParcel_writeInt32(parcelIn, in)); stat = AParcel_readInt32(parcelOut.get(), out); if (stat != STATUS_OK) return stat; AParcel* parcelOut; CHECK(STATUS_OK == AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, &parcelOut, 0 /*flags*/)); return stat; } int32_t out; CHECK(STATUS_OK == AParcel_readInt32(parcelOut, &out)); virtual binder_status_t die() { binder_status_t stat = STATUS_OK; AParcel* parcelIn; stat = AIBinder_prepareTransaction(mBinder, &parcelIn); AParcel_delete(parcelOut); ::ndk::ScopedAParcel parcelOut; stat = AIBinder_transact(mBinder, IFoo::DIE, &parcelIn, parcelOut.getR(), 0 /*flags*/); return out; return stat; } private: Loading Loading @@ -117,7 +140,7 @@ binder_status_t IFoo::addService(const char* instance) { return status; } sp<IFoo> IFoo::getService(const char* instance) { sp<IFoo> IFoo::getService(const char* instance, AIBinder** outBinder) { AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr if (binder == nullptr) { return nullptr; Loading @@ -128,6 +151,11 @@ sp<IFoo> IFoo::getService(const char* instance) { return nullptr; } if (outBinder != nullptr) { AIBinder_incStrong(binder); *outBinder = binder; } if (AIBinder_isRemote(binder)) { sp<IFoo> ret = new BpFoo(binder); // takes ownership of binder return ret; Loading @@ -143,7 +171,6 @@ sp<IFoo> IFoo::getService(const char* instance) { CHECK(held == binder); AIBinder_decStrong(held); // IFoo only keeps a weak reference to AIBinder, so we can drop this AIBinder_decStrong(binder); return ret; }
libs/binder/ndk/test/include/iface/iface.h +14 −3 Original line number Diff line number Diff line Loading @@ -19,22 +19,33 @@ #include <android/binder_ibinder.h> #include <utils/RefBase.h> // warning: it is recommended to use AIDL output instead of this. binder_ibinder_utils.h and some of // the other niceties make sure that, for instance, binder proxies are always the same. They also // don't use internal Android APIs like refbase which are used here only for convenience. class IFoo : public virtual ::android::RefBase { public: static const char* kSomeInstanceName; static const char* kInstanceNameToDieFor; static AIBinder_Class* kClass; // Takes ownership of IFoo binder_status_t addService(const char* instance); static ::android::sp<IFoo> getService(const char* instance); static ::android::sp<IFoo> getService(const char* instance, AIBinder** outBinder = nullptr); enum Call { DOFOO = FIRST_CALL_TRANSACTION + 0, DIE = FIRST_CALL_TRANSACTION + 1, }; virtual ~IFoo(); virtual int32_t doubleNumber(int32_t in) = 0; virtual binder_status_t doubleNumber(int32_t in, int32_t* out) = 0; virtual binder_status_t die() = 0; private: AIBinder_Weak* mWeakBinder = nullptr; // maybe owns AIBinder // this variable is only when IFoo is local (since this test combines 'IFoo' and 'BnFoo'), not // for BpFoo. AIBinder_Weak* mWeakBinder = nullptr; };
libs/binder/ndk/test/main_client.cpp +65 −8 Original line number Diff line number Diff line Loading @@ -21,6 +21,10 @@ #include <gtest/gtest.h> #include <iface/iface.h> #include <chrono> #include <condition_variable> #include <mutex> using ::android::sp; constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; Loading @@ -34,7 +38,47 @@ constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; TEST(NdkBinder, DoubleNumber) { sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName); ASSERT_NE(foo, nullptr); EXPECT_EQ(2, foo->doubleNumber(1)); int32_t out; EXPECT_EQ(STATUS_OK, foo->doubleNumber(1, &out)); EXPECT_EQ(2, out); } void LambdaOnDeath(void* cookie) { auto onDeath = static_cast<std::function<void(void)>*>(cookie); (*onDeath)(); }; TEST(NdkBinder, DeathRecipient) { using namespace std::chrono_literals; AIBinder* binder; sp<IFoo> foo = IFoo::getService(IFoo::kInstanceNameToDieFor, &binder); ASSERT_NE(nullptr, foo.get()); ASSERT_NE(nullptr, binder); std::mutex deathMutex; std::condition_variable deathCv; bool deathRecieved = false; std::function<void(void)> onDeath = [&] { std::cerr << "Binder died (as requested)." << std::endl; deathRecieved = true; deathCv.notify_one(); }; AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath); EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&onDeath))); // the binder driver should return this if the service dies during the transaction EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die()); std::unique_lock<std::mutex> lock(deathMutex); EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; })); EXPECT_TRUE(deathRecieved); AIBinder_DeathRecipient_delete(recipient); AIBinder_decStrong(binder); } TEST(NdkBinder, RetrieveNonNdkService) { Loading @@ -52,9 +96,6 @@ void OnBinderDeath(void* cookie) { } TEST(NdkBinder, LinkToDeath) { ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications ABinderProcess_startThreadPool(); AIBinder* binder = AServiceManager_getService(kExistingNonNdkService); ASSERT_NE(nullptr, binder); Loading @@ -72,9 +113,14 @@ TEST(NdkBinder, LinkToDeath) { } class MyTestFoo : public IFoo { int32_t doubleNumber(int32_t in) override { LOG(INFO) << "doubleNumber " << in; return 2 * in; binder_status_t doubleNumber(int32_t in, int32_t* out) override { *out = 2 * in; LOG(INFO) << "doubleNumber (" << in << ") => " << *out; return STATUS_OK; } binder_status_t die() override { ADD_FAILURE() << "die called on local instance"; return STATUS_OK; } }; Loading @@ -87,7 +133,9 @@ TEST(NdkBinder, GetServiceInProcess) { sp<IFoo> getFoo = IFoo::getService(kInstanceName); EXPECT_EQ(foo.get(), getFoo.get()); EXPECT_EQ(2, getFoo->doubleNumber(1)); int32_t out; EXPECT_EQ(STATUS_OK, getFoo->doubleNumber(1, &out)); EXPECT_EQ(2, out); } TEST(NdkBinder, EqualityOfRemoteBinderPointer) { Loading Loading @@ -132,6 +180,15 @@ TEST(NdkBinder, AddServiceMultipleTimes) { EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2)); } int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks ABinderProcess_startThreadPool(); return RUN_ALL_TESTS(); } #include <android/binder_auto_utils.h> #include <android/binder_interface_utils.h> #include <android/binder_parcel_utils.h>