summaryrefslogtreecommitdiff
path: root/libs/binder/Stability.cpp
diff options
context:
space:
mode:
author Steven Moreland <smoreland@google.com> 2019-07-16 18:06:55 -0700
committer Steven Moreland <smoreland@google.com> 2019-08-02 20:14:43 -0700
commitdea3cf9157146ceba20bfbeb60783b314c7d0c31 (patch)
tree4aa22c3877916e0d579c7da2cad3fae398b16aa2 /libs/binder/Stability.cpp
parent4fabf335993d07d94f1bd00966d63c1ba39cb531 (diff)
Binder: support storing interface stability
An internal CL adds stability annotations to interfaces. In order to make it easier to make changes against this on AOSP, the API only is merged here. This means, until Android Q is released, AOSP will have stability API annotations but not enforcement. Enforcement will only happen on internal branches. This is being done because of a mismatch between vndservicemanager (in the vendor.img blobs) and libbinder in the VNDK. (remaining comments are from the internal CL and aren't reflected in AOSP yet) 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 Merged-In: Ia637ee3652d55550e7fce78876458f391b1dd928
Diffstat (limited to 'libs/binder/Stability.cpp')
-rw-r--r--libs/binder/Stability.cpp117
1 files changed, 117 insertions, 0 deletions
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