diff options
Diffstat (limited to 'libs/binder/Stability.cpp')
-rw-r--r-- | libs/binder/Stability.cpp | 151 |
1 files changed, 121 insertions, 30 deletions
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp index e1565fac43..f12ef4e35b 100644 --- a/libs/binder/Stability.cpp +++ b/libs/binder/Stability.cpp @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#define LOG_TAG "Stability" + #include <binder/Stability.h> #include <binder/BpBinder.h> @@ -21,92 +23,181 @@ namespace android { namespace internal { +// the libbinder parcel format is currently unstable + +// oldest version which is supported +constexpr uint8_t kBinderWireFormatOldest = 1; +// current version +constexpr uint8_t kBinderWireFormatVersion = 1; + +Stability::Category Stability::Category::currentFromLevel(Level level) { + return { + .version = kBinderWireFormatVersion, + .reserved = {0}, + .level = level, + }; +} + +void Stability::forceDowngradeToStability(const sp<IBinder>& binder, Level level) { + // Downgrading a remote binder would require also copying the version from + // the binder sent here. In practice though, we don't need to downgrade the + // stability of a remote binder, since this would as an effect only restrict + // what we can do to it. + LOG_ALWAYS_FATAL_IF(!binder || !binder->localBinder(), "Can only downgrade local binder"); + + auto stability = Category::currentFromLevel(level); + status_t result = setRepr(binder.get(), stability.repr(), REPR_LOG | REPR_ALLOW_DOWNGRADE); + LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object."); +} + +void Stability::forceDowngradeToLocalStability(const sp<IBinder>& binder) { + forceDowngradeToStability(binder, getLocalLevel()); +} + +void Stability::forceDowngradeToSystemStability(const sp<IBinder>& binder) { + forceDowngradeToStability(binder, Level::SYSTEM); +} + +void Stability::forceDowngradeToVendorStability(const sp<IBinder>& binder) { + forceDowngradeToStability(binder, Level::VENDOR); +} + +std::string Stability::Category::debugString() { + return levelString(level) + " wire protocol version " + + std::to_string(version); +} + void Stability::markCompilationUnit(IBinder* binder) { - status_t result = set(binder, kLocalStability, true /*log*/); + auto stability = Category::currentFromLevel(getLocalLevel()); + status_t result = setRepr(binder, stability.repr(), REPR_LOG); LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object."); } void Stability::markVintf(IBinder* binder) { - status_t result = set(binder, Level::VINTF, true /*log*/); + auto stability = Category::currentFromLevel(Level::VINTF); + status_t result = setRepr(binder, stability.repr(), REPR_LOG); LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object."); } void Stability::debugLogStability(const std::string& tag, const sp<IBinder>& binder) { - ALOGE("%s: stability is %s", tag.c_str(), stabilityString(get(binder.get())).c_str()); + auto stability = getCategory(binder.get()); + ALOGE("%s: stability is %s", tag.c_str(), stability.debugString().c_str()); } void Stability::markVndk(IBinder* binder) { - status_t result = set(binder, Level::VENDOR, true /*log*/); + auto stability = Category::currentFromLevel(Level::VENDOR); + status_t result = setRepr(binder, stability.repr(), REPR_LOG); LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object."); } bool Stability::requiresVintfDeclaration(const sp<IBinder>& binder) { - return check(get(binder.get()), Level::VINTF); + return check(getCategory(binder.get()), Level::VINTF); } void Stability::tryMarkCompilationUnit(IBinder* binder) { - (void) set(binder, kLocalStability, false /*log*/); + auto stability = Category::currentFromLevel(getLocalLevel()); + (void) setRepr(binder, stability.repr(), REPR_NONE); +} + +Stability::Level Stability::getLocalLevel() { +#ifdef __ANDROID_APEX__ +#error APEX can't use libbinder (must use libbinder_ndk) +#endif + +#ifdef __ANDROID_VNDK__ + return Level::VENDOR; +#else + // TODO(b/139325195): split up stability levels for system/APEX. + return Level::SYSTEM; +#endif } -status_t Stability::set(IBinder* binder, int32_t stability, bool log) { - Level currentStability = get(binder); +status_t Stability::setRepr(IBinder* binder, int32_t representation, uint32_t flags) { + bool log = flags & REPR_LOG; + bool allowDowngrade = flags & REPR_ALLOW_DOWNGRADE; + + auto current = getCategory(binder); + auto setting = Category::fromRepr(representation); + + // If we have ahold of a binder with a newer declared version, then it + // should support older versions, and we will simply write our parcels with + // the current wire parcel format. + if (setting.version < kBinderWireFormatOldest) { + // always log, because this shouldn't happen + ALOGE("Cannot accept binder with older binder wire protocol version " + "%u. Versions less than %u are unsupported.", setting.version, + kBinderWireFormatOldest); + return BAD_TYPE; + } // null binder is always written w/ 'UNDECLARED' stability if (binder == nullptr) { - if (stability == UNDECLARED) { + if (setting.level == UNDECLARED) { return OK; } else { if (log) { ALOGE("Null binder written with stability %s.", - stabilityString(stability).c_str()); + levelString(setting.level).c_str()); } return BAD_TYPE; } } - if (!isDeclaredStability(stability)) { + if (!isDeclaredLevel(setting.level)) { if (log) { - ALOGE("Can only set known stability, not %d.", stability); + ALOGE("Can only set known stability, not %u.", setting.level); } return BAD_TYPE; } - if (currentStability != Level::UNDECLARED && currentStability != stability) { + if (current == setting) return OK; + + bool hasAlreadyBeenSet = current.repr() != 0; + bool isAllowedDowngrade = allowDowngrade && check(current, setting.level); + if (hasAlreadyBeenSet && !isAllowedDowngrade) { if (log) { - ALOGE("Interface being set with %s but it is already marked as %s.", - stabilityString(stability).c_str(), stabilityString(currentStability).c_str()); + ALOGE("Interface being set with %s but it is already marked as %s", + setting.debugString().c_str(), + current.debugString().c_str()); } return BAD_TYPE; } - if (currentStability == stability) return OK; + if (isAllowedDowngrade) { + ALOGI("Interface set with %s downgraded to %s stability", + current.debugString().c_str(), + setting.debugString().c_str()); + } BBinder* local = binder->localBinder(); if (local != nullptr) { - local->mStability = static_cast<int32_t>(stability); + local->mStability = setting.repr(); } else { - binder->remoteBinder()->mStability = static_cast<int32_t>(stability); + binder->remoteBinder()->mStability = setting.repr(); } return OK; } -Stability::Level Stability::get(IBinder* binder) { - if (binder == nullptr) return UNDECLARED; +Stability::Category Stability::getCategory(IBinder* binder) { + if (binder == nullptr) { + return Category::currentFromLevel(Level::UNDECLARED); + } BBinder* local = binder->localBinder(); if (local != nullptr) { - return static_cast<Stability::Level>(local->mStability); + return Category::fromRepr(local->mStability); } - return static_cast<Stability::Level>(binder->remoteBinder()->mStability); + return Category::fromRepr(binder->remoteBinder()->mStability); } -bool Stability::check(int32_t provided, Level required) { - bool stable = (provided & required) == required; +bool Stability::check(Category provided, Level required) { + bool stable = (provided.level & required) == required; - if (!isDeclaredStability(provided) && provided != UNDECLARED) { - ALOGE("Unknown stability when checking interface stability %d.", provided); + if (provided.level != UNDECLARED && !isDeclaredLevel(provided.level)) { + ALOGE("Unknown stability when checking interface stability %d.", + provided.level); stable = false; } @@ -114,18 +205,18 @@ bool Stability::check(int32_t provided, Level required) { return stable; } -bool Stability::isDeclaredStability(int32_t stability) { +bool Stability::isDeclaredLevel(Level stability) { return stability == VENDOR || stability == SYSTEM || stability == VINTF; } -std::string Stability::stabilityString(int32_t stability) { - switch (stability) { +std::string Stability::levelString(Level level) { + switch (level) { 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); + return "unknown stability " + std::to_string(level); } } // namespace internal |