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

Commit dea3cf91 authored by Steven Moreland's avatar Steven Moreland
Browse files

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
parent 4fabf335
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ cc_library_shared {
        "ProcessInfoService.cpp",
        "ProcessState.cpp",
        "Static.cpp",
        "Stability.cpp",
        "Status.cpp",
        "TextOutput.cpp",
        "IpPrefix.cpp",
+3 −0
Original line number Diff line number Diff line
@@ -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;
+5 −0
Original line number Diff line number Diff line
@@ -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;
    }

+48 −26
Original line number Diff line number Diff line
@@ -164,14 +164,37 @@ 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)
{
    return out->writeObject(flat, false);
    status_t status = writeObject(flat, false);
    if (status != OK) return status;

    // Cannot change wire protocol w/o SM update
    // return writeInt32(internal::Stability::get(binder.get()));
    return OK;
}

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;
    // Cannot change wire protocol w/o SM update
    // 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 +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) {
@@ -965,7 +986,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)
@@ -1903,7 +1924,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
@@ -2592,9 +2613,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;

+117 −0
Original line number Diff line number Diff line
/*
 * 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
Loading