Binder: support storing interface stability
This adds runtime information for what the stability class of a binder
is in preparation for allowing binders system<->vendor. However, this
shouldn't necessarily be restricted to this case. For instance, it may
also be used to separate APEX interface stability levels. The idea is
that for code serving an interface of a given stability, only intefaces
of greater stability can be sent to it. This is slightly less
restrictive than existing binder domains. For instance, this could
potentially support having a single interface 'vintf' interface which is
shared by both system and vendor (this removing the need for infra like
ITokenManager).
The API that is exposed only allows marking a binder as a specific
stability class (see Stability.h). For instance, 'markVintf' marks an
API as being exposed system<->vendor. Although, infrastructure in
servicemanager, aidl, sepolicy, and VTS still need to support this in
order to be useful.
The actual implementation of these stability classes (bitmasks) is not
exposed and may be changed arbitrarily. Currently these bitmasks are
32-bit integers. These are sent to other processes because the type
system in AIDL cannot encode the stability requirements here without
either dropping IBinder or differentating IBinder by stability level
(which we don't want). So, where possible, AIDL will differentiate
stability level at compile time, but when IBinder is used, for
handwritten interfaces, and as a backup in case any other piece of the
infrastructure fails, the stability is also checked at runtime.
Bug: 136027762
Test: atest binderStabilityTest
Change-Id: Ia637ee3652d55550e7fce78876458f391b1dd928
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b230943..c6ce576 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -70,6 +70,7 @@
"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 bdf0f8e..268c85e 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -124,6 +124,7 @@
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 @@
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 5ceb218..57440d5 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -216,6 +216,11 @@
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 5537430..0b9849a 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -164,14 +164,34 @@
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)
{
- return out->writeObject(flat, false);
+ status_t status = writeObject(flat, false);
+ if (status != OK) return status;
+
+ return writeInt32(internal::Stability::get(binder.get()));
}
-static status_t flatten_binder(const sp<ProcessState>& /*proc*/,
- const sp<IBinder>& binder, Parcel* out)
+status_t Parcel::finishUnflattenBinder(
+ const sp<IBinder>& binder, sp<IBinder>* out) const
+{
+ 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;
+}
+
+status_t Parcel::flattenBinder(const sp<IBinder>& binder)
{
flat_binder_object obj;
@@ -209,30 +229,24 @@
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 +351,10 @@
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 +1050,7 @@
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 +1996,7 @@
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 +2700,10 @@
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 0000000..d6d312a
--- /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 01e57d3..136bdb0 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 f5eee87..4e5f1aa 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 @@
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 @@
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 @@
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 0000000..77f0667
--- /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 : int32_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 44a691d..05db81e 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -137,3 +137,18 @@
],
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 0000000..7540ec9
--- /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 0000000..2b27a81
--- /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();
+}