Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3637e29a authored by Steven Moreland's avatar Steven Moreland Committed by Automerger Merge Worker
Browse files

Merge "libbinder: binders hold wire protocol version" am: 9c8f3f0d

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1498158

Change-Id: I2d447bb9e14c210b253c8f29557a304d547fc3ae
parents e22858a2 9c8f3f0d
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -223,13 +223,14 @@ status_t BpBinder::transact(
        if (code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION) {
            using android::internal::Stability;

            auto stability = Stability::get(this);
            auto required = privateVendor ? Stability::VENDOR : Stability::getLocalStability();
            auto category = Stability::getCategory(this);
            Stability::Level required = privateVendor ? Stability::VENDOR
                : Stability::getLocalLevel();

            if (CC_UNLIKELY(!Stability::check(stability, required))) {
            if (CC_UNLIKELY(!Stability::check(category, required))) {
                ALOGE("Cannot do a user transaction on a %s binder in a %s context.",
                    Stability::stabilityString(stability).c_str(),
                    Stability::stabilityString(required).c_str());
                    category.debugString().c_str(),
                    Stability::levelString(required).c_str());
                return BAD_TYPE;
            }
        }
+3 −2
Original line number Diff line number Diff line
@@ -171,7 +171,8 @@ status_t Parcel::finishFlattenBinder(
    if (status != OK) return status;

    internal::Stability::tryMarkCompilationUnit(binder.get());
    return writeInt32(internal::Stability::get(binder.get()));
    auto category = internal::Stability::getCategory(binder.get());
    return writeInt32(category.repr());
}

status_t Parcel::finishUnflattenBinder(
@@ -181,7 +182,7 @@ status_t Parcel::finishUnflattenBinder(
    status_t status = readInt32(&stability);
    if (status != OK) return status;

    status = internal::Stability::set(binder.get(), stability, true /*log*/);
    status = internal::Stability::setRepr(binder.get(), stability, true /*log*/);
    if (status != OK) return status;

    *out = binder;
+74 −31
Original line number Diff line number Diff line
@@ -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,34 +23,59 @@
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,
    };
}

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, getLocalStability(), true /*log*/);
    auto stability = Category::currentFromLevel(getLocalLevel());
    status_t result = setRepr(binder, stability.repr(), true /*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(), true /*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(), true /*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, getLocalStability(), false /*log*/);
    auto stability = Category::currentFromLevel(getLocalLevel());
    (void) setRepr(binder, stability.repr(), false /*log*/);
}

Stability::Level Stability::getLocalStability() {
Stability::Level Stability::getLocalLevel() {
#ifdef __ANDROID_VNDK__
    #ifdef __ANDROID_APEX__
        // TODO(b/142684679) avoid use_vendor on system APEXes
@@ -67,65 +94,81 @@ Stability::Level Stability::getLocalStability() {
#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, bool log) {
    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.repr() != 0 && current != setting) {
        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 (current == setting) return OK;

    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;
    }
@@ -133,18 +176,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
+65 −7
Original line number Diff line number Diff line
@@ -26,6 +26,29 @@ class ProcessState;

namespace internal {

// Stability encodes how a binder changes over time. There are two levels of
// stability:
// 1). the interface stability - this is how a particular set of API calls (a
//   particular ordering of things like writeInt32/readInt32) are changed over
//   time. If one release, we have 'writeInt32' and the next release, we have
//   'writeInt64', then this interface doesn't have a very stable
//   Stability::Level. Usually this ordering is controlled by a .aidl file.
// 2). the wire format stability - this is how these API calls map to actual
//   bytes that are written to the wire (literally, this is how they are written
//   to the kernel inside of IBinder::transact, but it may be expanded to other
//   wires in the future). For instance, writeInt32 in binder translates to
//   writing a 4-byte little-endian integer in two's complement. You can imagine
//   in the future, we change writeInt32/readInt32 to instead write 8-bytes with
//   that integer and some check bits. In this case, the wire format changes,
//   but as long as a client libbinder knows to keep on writing a 4-byte value
//   to old servers, and new servers know how to interpret the 8-byte result,
//   they can still communicate.
//
// Every binder object has a stability level associated with it, and when
// communicating with a binder, we make sure that the command we sent is one
// that it knows how to process. The summary of stability of a binder is
// represented by a Stability::Category object.

// 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 {
@@ -73,7 +96,7 @@ private:

    static void tryMarkCompilationUnit(IBinder* binder);

    enum Level : int32_t {
    enum Level : uint8_t {
        UNDECLARED = 0,

        VENDOR = 0b000011,
@@ -81,19 +104,54 @@ private:
        VINTF = 0b111111,
    };

    // This is the format of stability passed on the wire.
    struct Category {
        static inline Category fromRepr(int32_t representation) {
            return *reinterpret_cast<Category*>(&representation);
        }
        int32_t repr() const {
            return *reinterpret_cast<const int32_t*>(this);
        }
        static inline Category currentFromLevel(Level level);

        bool operator== (const Category& o) const {
            return repr() == o.repr();
        }
        bool operator!= (const Category& o) const {
            return !(*this == o);
        }

        std::string debugString();

        // This is the version of the wire protocol associated with the host
        // process of a particular binder. As the wire protocol changes, if
        // sending a transaction to a binder with an old version, the Parcel
        // class must write parcels according to the version documented here.
        uint8_t version;

        uint8_t reserved[2];

        // bitmask of Stability::Level
        Level level;
    };
    static_assert(sizeof(Category) == sizeof(int32_t));

    // returns the stability according to how this was built
    static Level getLocalStability();
    static Level getLocalLevel();

    // applies stability to binder if stability level is known
    __attribute__((warn_unused_result))
    static status_t set(IBinder* binder, int32_t stability, bool log);
    static status_t setRepr(IBinder* binder, int32_t representation, bool log);

    static Level get(IBinder* binder);
    // get stability information as encoded on the wire
    static Category getCategory(IBinder* binder);

    static bool check(int32_t provided, Level required);
    // whether a transaction on binder is allowed, if the transaction
    // is done from a context with a specific stability level
    static bool check(Category provided, Level required);

    static bool isDeclaredStability(int32_t stability);
    static std::string stabilityString(int32_t stability);
    static bool isDeclaredLevel(Level level);
    static std::string levelString(Level level);

    Stability();
};