diff options
| author | 2019-08-02 20:04:19 +0000 | |
|---|---|---|
| committer | 2019-08-02 20:04:19 +0000 | |
| commit | 10e4cc4a536fd56d24efd72fcb5894c8a6f45eed (patch) | |
| tree | f9dcb5dd4dd7ba819535e5fcf4e0dbd86309de84 /libs | |
| parent | cd551fab41affb10b11bc6019741898694a123c8 (diff) | |
| parent | 7b10226a880b51591e192ff2c0415aa6fa50ce6d (diff) | |
Merge changes from topic "reland-binder-interface-stability" into stage-aosp-master
* changes:
Keep Parcel size stable.
Reland "Binder: support storing interface stability"
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/binder/Android.bp | 1 | ||||
| -rw-r--r-- | libs/binder/Binder.cpp | 3 | ||||
| -rw-r--r-- | libs/binder/BpBinder.cpp | 5 | ||||
| -rw-r--r-- | libs/binder/Parcel.cpp | 74 | ||||
| -rw-r--r-- | libs/binder/Stability.cpp | 117 | ||||
| -rw-r--r-- | libs/binder/TEST_MAPPING | 3 | ||||
| -rw-r--r-- | libs/binder/include/binder/Parcel.h | 17 | ||||
| -rw-r--r-- | libs/binder/include/binder/Stability.h | 71 | ||||
| -rw-r--r-- | libs/binder/tests/Android.bp | 15 | ||||
| -rw-r--r-- | libs/binder/tests/IBinderStabilityTest.aidl | 38 | ||||
| -rw-r--r-- | libs/binder/tests/binderStabilityTest.cpp | 245 |
11 files changed, 560 insertions, 29 deletions
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index b23094396c..c6ce576170 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -70,6 +70,7 @@ cc_library_shared { "ProcessInfoService.cpp", "ProcessState.cpp", "Static.cpp", + "Stability.cpp", "Status.cpp", "TextOutput.cpp", "IpPrefix.cpp", diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index bdf0f8ef9f..268c85e096 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -124,6 +124,7 @@ status_t BBinder::transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { data.setDataPosition(0); + data.setTransactingBinder(this); status_t err = NO_ERROR; switch (code) { @@ -135,8 +136,10 @@ status_t BBinder::transact( break; } + // In case this is being transacted on in the same process. if (reply != nullptr) { reply->setDataPosition(0); + reply->setTransactingBinder(this); } return err; diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 5ceb218b8b..57440d508d 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -216,6 +216,11 @@ status_t BpBinder::transact( status_t status = IPCThreadState::self()->transact( mHandle, code, data, reply, flags); if (status == DEAD_OBJECT) mAlive = 0; + + if (reply != nullptr) { + reply->setTransactingBinder(this); + } + return status; } diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 55374306f3..ba44c66020 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -77,6 +77,9 @@ static size_t pad_size(size_t s) { namespace android { +// many things compile this into prebuilts on the stack +static_assert(sizeof(Parcel) == 60 || sizeof(Parcel) == 120); + static pthread_mutex_t gParcelGlobalAllocSizeLock = PTHREAD_MUTEX_INITIALIZER; static size_t gParcelGlobalAllocSize = 0; static size_t gParcelGlobalAllocCount = 0; @@ -164,14 +167,34 @@ static void release_object(const sp<ProcessState>& proc, ALOGE("Invalid object type 0x%08x", obj.hdr.type); } -inline static status_t finish_flatten_binder( - const sp<IBinder>& /*binder*/, const flat_binder_object& flat, Parcel* out) +status_t Parcel::finishFlattenBinder( + const sp<IBinder>& binder, const flat_binder_object& flat) +{ + status_t status = writeObject(flat, false); + if (status != OK) return status; + + return writeInt32(internal::Stability::get(binder.get())); +} + +status_t Parcel::finishUnflattenBinder( + const sp<IBinder>& binder, sp<IBinder>* out) const { - return out->writeObject(flat, false); + int32_t stability; + status_t status = readInt32(&stability); + if (status != OK) return status; + + if (!internal::Stability::check(stability, mRequiredStability)) { + return BAD_TYPE; + } + + status = internal::Stability::set(binder.get(), stability); + if (status != OK) return status; + + *out = binder; + return OK; } -static status_t flatten_binder(const sp<ProcessState>& /*proc*/, - const sp<IBinder>& binder, Parcel* out) +status_t Parcel::flattenBinder(const sp<IBinder>& binder) { flat_binder_object obj; @@ -209,30 +232,24 @@ static status_t flatten_binder(const sp<ProcessState>& /*proc*/, obj.cookie = 0; } - return finish_flatten_binder(binder, obj, out); + return finishFlattenBinder(binder, obj); } -inline static status_t finish_unflatten_binder( - BpBinder* /*proxy*/, const flat_binder_object& /*flat*/, - const Parcel& /*in*/) +status_t Parcel::unflattenBinder(sp<IBinder>* out) const { - return NO_ERROR; -} - -static status_t unflatten_binder(const sp<ProcessState>& proc, - const Parcel& in, sp<IBinder>* out) -{ - const flat_binder_object* flat = in.readObject(false); + const flat_binder_object* flat = readObject(false); if (flat) { switch (flat->hdr.type) { - case BINDER_TYPE_BINDER: - *out = reinterpret_cast<IBinder*>(flat->cookie); - return finish_unflatten_binder(nullptr, *flat, in); - case BINDER_TYPE_HANDLE: - *out = proc->getStrongProxyForHandle(flat->handle); - return finish_unflatten_binder( - static_cast<BpBinder*>(out->get()), *flat, in); + case BINDER_TYPE_BINDER: { + sp<IBinder> binder = reinterpret_cast<IBinder*>(flat->cookie); + return finishUnflattenBinder(binder, out); + } + case BINDER_TYPE_HANDLE: { + sp<IBinder> binder = + ProcessState::self()->getStrongProxyForHandle(flat->handle); + return finishUnflattenBinder(binder, out); + } } } return BAD_TYPE; @@ -337,6 +354,10 @@ status_t Parcel::setDataCapacity(size_t size) return NO_ERROR; } +void Parcel::setTransactingBinder(const sp<IBinder>& binder) const { + mRequiredStability = internal::Stability::get(binder.get()); +} + status_t Parcel::setData(const uint8_t* buffer, size_t len) { if (len > INT32_MAX) { @@ -1032,7 +1053,7 @@ status_t Parcel::writeString16(const char16_t* str, size_t len) status_t Parcel::writeStrongBinder(const sp<IBinder>& val) { - return flatten_binder(ProcessState::self(), val, this); + return flattenBinder(val); } status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val) @@ -1978,7 +1999,7 @@ status_t Parcel::readStrongBinder(sp<IBinder>* val) const status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const { - return unflatten_binder(ProcessState::self(), *this, val); + return unflattenBinder(val); } sp<IBinder> Parcel::readStrongBinder() const @@ -2682,9 +2703,10 @@ void Parcel::initState() mObjectsCapacity = 0; mNextObjectHint = 0; mObjectsSorted = false; + mAllowFds = true; mHasFds = false; mFdsKnown = true; - mAllowFds = true; + mRequiredStability = internal::Stability::UNDECLARED; mOwner = nullptr; mOpenAshmemSize = 0; mWorkSourceRequestHeaderPosition = 0; diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp new file mode 100644 index 0000000000..d6d312a842 --- /dev/null +++ b/libs/binder/Stability.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2019 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. + */ + +#include <binder/Stability.h> + +namespace android { +namespace internal { + +void Stability::markCompilationUnit(IBinder* binder) { +#ifdef __ANDROID_VNDK__ +constexpr Stability::Level kLocalStability = Stability::Level::VENDOR; +#else +constexpr Stability::Level kLocalStability = Stability::Level::SYSTEM; +#endif + + status_t result = set(binder, kLocalStability); + LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object."); +} + +void Stability::markVintf(IBinder* binder) { + status_t result = set(binder, Level::VINTF); + LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object."); +} + +status_t Stability::set(IBinder* binder, int32_t stability) { + Level currentStability = get(binder); + + // null binder is always written w/ 'UNDECLARED' stability + if (binder == nullptr) { + if (stability == UNDECLARED) { + return OK; + } else { + ALOGE("Null binder written with stability %s.", stabilityString(stability).c_str()); + return BAD_TYPE; + } + } + + if (!isDeclaredStability(stability)) { + // There are UNDECLARED sets because some binder interfaces don't set their stability, and + // then UNDECLARED stability is sent on the other side. + if (stability != UNDECLARED) { + ALOGE("Can only set known stability, not %d.", stability); + return BAD_TYPE; + } + } + + if (currentStability != Level::UNDECLARED && currentStability != stability) { + ALOGE("Interface being set with %s but it is already marked as %s.", + stabilityString(stability).c_str(), stabilityString(stability).c_str()); + return BAD_TYPE; + } + + if (currentStability == stability) return OK; + + binder->attachObject( + reinterpret_cast<void*>(&Stability::get), + reinterpret_cast<void*>(stability), + nullptr /*cleanupCookie*/, + nullptr /*cleanup function*/); + + return OK; +} + +Stability::Level Stability::get(IBinder* binder) { + if (binder == nullptr) return UNDECLARED; + + return static_cast<Level>(reinterpret_cast<intptr_t>( + binder->findObject(reinterpret_cast<void*>(&Stability::get)))); +} + +bool Stability::check(int32_t provided, Level required) { + bool stable = (provided & required) == required; + + if (!isDeclaredStability(provided) && provided != UNDECLARED) { + ALOGE("Unknown stability when checking interface stability %d.", provided); + + stable = false; + } + + if (!stable) { + ALOGE("Interface with %s cannot accept interface with %s.", + stabilityString(required).c_str(), + stabilityString(provided).c_str()); + } + + return stable; +} + +bool Stability::isDeclaredStability(int32_t stability) { + return stability == VENDOR || stability == SYSTEM || stability == VINTF; +} + +std::string Stability::stabilityString(int32_t stability) { + switch (stability) { + case Level::UNDECLARED: return "undeclared stability"; + case Level::VENDOR: return "vendor stability"; + case Level::SYSTEM: return "system stability"; + case Level::VINTF: return "vintf stability"; + } + return "unknown stability " + std::to_string(stability); +} + +} // namespace internal +} // namespace stability
\ No newline at end of file diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index 01e57d361e..136bdb0b86 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -11,6 +11,9 @@ }, { "name": "binderLibTest" + }, + { + "name": "binderStabilityTest" } ] } diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index f5eee8771b..4e5f1aac46 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -33,6 +33,7 @@ #include <binder/IInterface.h> #include <binder/Parcelable.h> +#include <binder/Stability.h> // --------------------------------------------------------------------------- namespace android { @@ -67,7 +68,9 @@ public: status_t setDataSize(size_t size); void setDataPosition(size_t pos) const; status_t setDataCapacity(size_t size); - + + void setTransactingBinder(const sp<IBinder>& binder) const; + status_t setData(const uint8_t* buffer, size_t len); status_t appendFrom(const Parcel *parcel, @@ -419,7 +422,13 @@ private: void scanForFds() const; status_t validateReadData(size_t len) const; void updateWorkSourceRequestHeaderPosition() const; - + + status_t finishFlattenBinder(const sp<IBinder>& binder, + const flat_binder_object& flat); + status_t finishUnflattenBinder(const sp<IBinder>& binder, sp<IBinder>* out) const; + status_t flattenBinder(const sp<IBinder>& binder); + status_t unflattenBinder(sp<IBinder>* out) const; + template<class T> status_t readAligned(T *pArg) const; @@ -466,13 +475,15 @@ private: size_t mObjectsCapacity; mutable size_t mNextObjectHint; mutable bool mObjectsSorted; + bool mAllowFds; mutable bool mRequestHeaderPresent; mutable size_t mWorkSourceRequestHeaderPosition; mutable bool mFdsKnown; mutable bool mHasFds; - bool mAllowFds; + + mutable internal::Stability::Level mRequiredStability; release_func mOwner; void* mOwnerCookie; diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h new file mode 100644 index 0000000000..487f480d0e --- /dev/null +++ b/libs/binder/include/binder/Stability.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019 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. + */ + +#pragma once + +#include <binder/IBinder.h> +#include <string> + +namespace android { +namespace internal { + +// WARNING: These APIs are only ever expected to be called by auto-generated code. +// Instead of calling them, you should set the stability of a .aidl interface +class Stability final { +public: + // WARNING: This is only ever expected to be called by auto-generated code. You likely want to + // change or modify the stability class of the interface you are using. + // This must be called as soon as the binder in question is constructed. No thread safety + // is provided. + // E.g. stability is according to libbinder compilation unit + static void markCompilationUnit(IBinder* binder); + // WARNING: This is only ever expected to be called by auto-generated code. You likely want to + // change or modify the stability class of the interface you are using. + // This must be called as soon as the binder in question is constructed. No thread safety + // is provided. + // E.g. stability is according to libbinder_ndk or Java SDK AND the interface + // expressed here is guaranteed to be stable for multiple years (Stable AIDL) + static void markVintf(IBinder* binder); + +private: + // Parcel needs to store stability level since this is more efficient than storing and looking + // up the efficiency level of a binder object. So, we expose the underlying type. + friend ::android::Parcel; + + enum Level : int16_t { + UNDECLARED = 0, + + VENDOR = 0b000011, + SYSTEM = 0b001100, + VINTF = 0b111111, + }; + + // applies stability to binder if stability level is known + __attribute__((warn_unused_result)) + static status_t set(IBinder* binder, int32_t stability); + + static Level get(IBinder* binder); + + static bool check(int32_t provided, Level required); + + static bool isDeclaredStability(int32_t stability); + static std::string stabilityString(int32_t stability); + + Stability(); +}; + +} // namespace internal +} // namespace android diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 44a691d594..05db81e7b0 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -137,3 +137,18 @@ cc_test { ], test_suites: ["device-tests"], } + +cc_test { + name: "binderStabilityTest", + defaults: ["binder_test_defaults"], + srcs: [ + "binderStabilityTest.cpp", + "IBinderStabilityTest.aidl", + ], + + shared_libs: [ + "libbinder", + "libutils", + ], + test_suites: ["device-tests"], +} diff --git a/libs/binder/tests/IBinderStabilityTest.aidl b/libs/binder/tests/IBinderStabilityTest.aidl new file mode 100644 index 0000000000..7540ec9610 --- /dev/null +++ b/libs/binder/tests/IBinderStabilityTest.aidl @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 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. + */ + +// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS! +// THIS IS ONLY FOR TESTING! +interface IBinderStabilityTest { + // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS! + // THIS IS ONLY FOR TESTING! + void sendBinder(IBinder binder); + + // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS! + // THIS IS ONLY FOR TESTING! + IBinder returnNoStabilityBinder(); + + // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS! + // THIS IS ONLY FOR TESTING! + IBinder returnLocalStabilityBinder(); + + // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS! + // THIS IS ONLY FOR TESTING! + IBinder returnVintfStabilityBinder(); +} +// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS! +// THIS IS ONLY FOR TESTING! +// Construct and return a binder with a specific stability diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp new file mode 100644 index 0000000000..2b27a81a12 --- /dev/null +++ b/libs/binder/tests/binderStabilityTest.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2019 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. + */ + +#include <android/os/IServiceManager.h> +#include <binder/Binder.h> +#include <binder/IBinder.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/Parcel.h> +#include <binder/Stability.h> +#include <gtest/gtest.h> + +#include <sys/prctl.h> + +#include "BnBinderStabilityTest.h" +#include "BpBinderStabilityTest.h" + +using namespace android; +using android::binder::Status; +using android::os::IServiceManager; + +const String16 kNoStabilityServer = String16("binder_stability_test_service_low"); +const String16 kCompilationUnitServer = String16("binder_stability_test_service_compl"); +const String16 kVintfServer = String16("binder_stability_test_service_vintf"); + +sp<IBinder> getCompilationUnitStability() { + sp<IBinder> binder = new BBinder(); + // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS? + // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS + internal::Stability::markCompilationUnit(binder.get()); // <- BAD, NO! DO NOT COPY + return binder; +} + +sp<IBinder> getVintfStability() { + sp<IBinder> binder = new BBinder(); + // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS? + // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS + internal::Stability::markVintf(binder.get()); // <- BAD, NO! DO NOT COPY + return binder; +} + +// NO! NO! NO! Do not even think of doing something like this! +// This is for testing! If a class like this was actually used in production, +// it would ruin everything! +class BadStabilityTester : public BnBinderStabilityTest { +public: + Status sendBinder(const sp<IBinder>& /*binder*/) override { + return Status::ok(); + } + Status returnNoStabilityBinder(sp<IBinder>* _aidl_return) override { + *_aidl_return = new BBinder(); + return Status::ok(); + } + Status returnLocalStabilityBinder(sp<IBinder>* _aidl_return) override { + *_aidl_return = getCompilationUnitStability(); + return Status::ok(); + } + Status returnVintfStabilityBinder(sp<IBinder>* _aidl_return) override { + *_aidl_return = getVintfStability(); + return Status::ok(); + } + + static sp<IBinderStabilityTest> getNoStabilityServer() { + sp<IBinder> remote = new BadStabilityTester; + return new BpBinderStabilityTest(remote); + } + static sp<IBinderStabilityTest> getCompilationUnitStabilityServer() { + sp<IBinder> remote = new BadStabilityTester; + internal::Stability::markCompilationUnit(remote.get()); + return new BpBinderStabilityTest(remote); + } + static sp<IBinderStabilityTest> getVintfStabilityServer() { + sp<IBinder> remote = new BadStabilityTester; + internal::Stability::markVintf(remote.get()); // <- BAD, NO! DO NOT COPY + return new BpBinderStabilityTest(remote); + } +}; + +void checkNoStabilityServer(const sp<IBinderStabilityTest>& unkemptServer) { + EXPECT_TRUE(unkemptServer->sendBinder(new BBinder()).isOk()); + EXPECT_TRUE(unkemptServer->sendBinder(getCompilationUnitStability()).isOk()); + EXPECT_TRUE(unkemptServer->sendBinder(getVintfStability()).isOk()); + + sp<IBinder> out; + EXPECT_TRUE(unkemptServer->returnNoStabilityBinder(&out).isOk()); + EXPECT_NE(nullptr, out.get()); + + EXPECT_TRUE(unkemptServer->returnLocalStabilityBinder(&out).isOk()); + EXPECT_NE(nullptr, out.get()); + + EXPECT_TRUE(unkemptServer->returnVintfStabilityBinder(&out).isOk()); + EXPECT_NE(nullptr, out.get()); +} + +void checkLowStabilityServer(const sp<IBinderStabilityTest>& complServer) { + EXPECT_FALSE(complServer->sendBinder(new BBinder()).isOk()); + EXPECT_TRUE(complServer->sendBinder(getCompilationUnitStability()).isOk()); + EXPECT_TRUE(complServer->sendBinder(getVintfStability()).isOk()); + + sp<IBinder> out; + EXPECT_FALSE(complServer->returnNoStabilityBinder(&out).isOk()); + EXPECT_EQ(nullptr, out.get()); + + EXPECT_TRUE(complServer->returnLocalStabilityBinder(&out).isOk()); + EXPECT_NE(nullptr, out.get()); + + EXPECT_TRUE(complServer->returnVintfStabilityBinder(&out).isOk()); + EXPECT_NE(nullptr, out.get()); +} + +void checkHighStabilityServer(const sp<IBinderStabilityTest>& highStability) { + EXPECT_FALSE(highStability->sendBinder(new BBinder()).isOk()); + EXPECT_FALSE(highStability->sendBinder(getCompilationUnitStability()).isOk()); + EXPECT_TRUE(highStability->sendBinder(getVintfStability()).isOk()); + + sp<IBinder> out; + EXPECT_FALSE(highStability->returnNoStabilityBinder(&out).isOk()); + EXPECT_EQ(nullptr, out.get()); + + EXPECT_FALSE(highStability->returnLocalStabilityBinder(&out).isOk()); + EXPECT_EQ(nullptr, out.get()); + + EXPECT_TRUE(highStability->returnVintfStabilityBinder(&out).isOk()); + EXPECT_NE(nullptr, out.get()); +} + +TEST(BinderStability, LocalNoStabilityServer) { + // in practice, a low stability server is probably one that hasn't been rebuilt + // or was written by hand. + auto server = BadStabilityTester::getNoStabilityServer(); + ASSERT_NE(nullptr, IInterface::asBinder(server)->localBinder()); + checkNoStabilityServer(server); +} + +TEST(BinderStability, LocalLowStabilityServer) { + auto server = BadStabilityTester::getCompilationUnitStabilityServer(); + ASSERT_NE(nullptr, IInterface::asBinder(server)->localBinder()); + checkLowStabilityServer(server); +} + +TEST(BinderStability, LocalHighStabilityServer) { + auto server = BadStabilityTester::getVintfStabilityServer(); + ASSERT_NE(nullptr, IInterface::asBinder(server)->localBinder()); + checkHighStabilityServer(server); +} + +TEST(BinderStability, RemoteNoStabilityServer) { + sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kNoStabilityServer); + auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder); + + ASSERT_NE(nullptr, remoteServer.get()); + ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder()); + + checkNoStabilityServer(remoteServer); +} + +TEST(BinderStability, RemoteLowStabilityServer) { + sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kCompilationUnitServer); + auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder); + + ASSERT_NE(nullptr, remoteServer.get()); + ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder()); + + checkLowStabilityServer(remoteServer); +} + +TEST(BinderStability, RemoteVintfServer) { + sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kVintfServer); + auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder); + + ASSERT_NE(nullptr, remoteServer.get()); + ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder()); + + checkHighStabilityServer(remoteServer); +} + +class MarksStabilityInConstructor : public BBinder { +public: + static bool gDestructed; + + MarksStabilityInConstructor() { + internal::Stability::markCompilationUnit(this); + } + ~MarksStabilityInConstructor() { + gDestructed = true; + } +}; +bool MarksStabilityInConstructor::gDestructed = false; + +TEST(BinderStability, MarkingObjectNoDestructTest) { + ASSERT_FALSE(MarksStabilityInConstructor::gDestructed); + + // best practice is to put this directly in an sp, but for this test, we + // want to explicitly check what happens before that happens + MarksStabilityInConstructor* binder = new MarksStabilityInConstructor(); + ASSERT_FALSE(MarksStabilityInConstructor::gDestructed); + + sp<MarksStabilityInConstructor> binderSp = binder; + ASSERT_FALSE(MarksStabilityInConstructor::gDestructed); + + binderSp = nullptr; + ASSERT_TRUE(MarksStabilityInConstructor::gDestructed); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + + if (fork() == 0) { + // child process + prctl(PR_SET_PDEATHSIG, SIGHUP); + + sp<IBinder> noStability = new BadStabilityTester; + android::defaultServiceManager()->addService(kNoStabilityServer, noStability); + + sp<IBinder> compil = new BadStabilityTester; + internal::Stability::markCompilationUnit(compil.get()); + android::defaultServiceManager()->addService(kCompilationUnitServer, compil); + + sp<IBinder> vintf = new BadStabilityTester; + internal::Stability::markVintf(vintf.get()); + android::defaultServiceManager()->addService(kVintfServer, vintf); + + IPCThreadState::self()->joinThreadPool(true); + exit(1); // should not reach + } + + // This is not racey. Just giving these services some time to register before we call + // getService which sleeps for much longer... + usleep(10000); + + return RUN_ALL_TESTS(); +} |