/*
 * 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.
 */
#define LOG_TAG "Stability"

#include <binder/Stability.h>

#include <binder/BpBinder.h>
#include <binder/Binder.h>

namespace android {
namespace internal {

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");

    status_t result = setRepr(binder.get(), level, 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);
}

void Stability::markCompilationUnit(IBinder* binder) {
    status_t result = setRepr(binder, getLocalLevel(), REPR_LOG);
    LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
}

void Stability::markVintf(IBinder* binder) {
    status_t result = setRepr(binder, Level::VINTF, REPR_LOG);
    LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
}

std::string Stability::debugToString(const sp<IBinder>& binder) {
    return levelString(getRepr(binder.get()));
}

void Stability::markVndk(IBinder* binder) {
    status_t result = setRepr(binder, Level::VENDOR, REPR_LOG);
    LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
}

bool Stability::requiresVintfDeclaration(const sp<IBinder>& binder) {
    return check(getRepr(binder.get()), Level::VINTF);
}

void Stability::tryMarkCompilationUnit(IBinder* binder) {
    (void)setRepr(binder, getLocalLevel(), REPR_NONE);
}

// after deprecation of the VNDK, these should be aliases. At some point
// all references to __ANDROID_VNDK__ should be replaced by __ANDROID_VENDOR__
// but for right now, check that this condition holds because some
// places check __ANDROID_VNDK__ and some places check __ANDROID_VENDOR__
#if defined(__ANDROID_VNDK__) != defined(__ANDROID_VENDOR__)
#error "__ANDROID_VNDK__ and __ANDROID_VENDOR__ should be aliases"
#endif

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::setRepr(IBinder* binder, int32_t setting, uint32_t flags) {
    bool log = flags & REPR_LOG;
    bool allowDowngrade = flags & REPR_ALLOW_DOWNGRADE;

    int16_t current = getRepr(binder);

    // null binder is always written w/ 'UNDECLARED' stability
    if (binder == nullptr) {
        if (setting == UNDECLARED) {
            return OK;
        } else {
            if (log) {
                ALOGE("Null binder written with stability %s.", levelString(setting).c_str());
            }
            return BAD_TYPE;
        }
    }

    if (!isDeclaredLevel(setting)) {
        if (log) {
            ALOGE("Can only set known stability, not %d.", setting);
        }
        return BAD_TYPE;
    }
    Level levelSetting = static_cast<Level>(setting);

    if (current == setting) return OK;

    bool hasAlreadyBeenSet = current != Level::UNDECLARED;
    bool isAllowedDowngrade = allowDowngrade && check(current, levelSetting);
    if (hasAlreadyBeenSet && !isAllowedDowngrade) {
        if (log) {
            ALOGE("Interface being set with %s but it is already marked as %s",
                  levelString(setting).c_str(), levelString(current).c_str());
        }
        return BAD_TYPE;
    }

    if (isAllowedDowngrade) {
        ALOGI("Interface set with %s downgraded to %s stability", levelString(current).c_str(),
              levelString(setting).c_str());
    }

    BBinder* local = binder->localBinder();
    if (local != nullptr) {
        local->mStability = setting;
    } else {
        binder->remoteBinder()->mStability = setting;
    }

    return OK;
}

int16_t Stability::getRepr(IBinder* binder) {
    if (binder == nullptr) {
        return Level::UNDECLARED;
    }

    BBinder* local = binder->localBinder();
    if (local != nullptr) {
        return local->mStability;
    }

    return binder->remoteBinder()->mStability;
}

bool Stability::check(int16_t provided, Level required) {
    bool stable = (provided & required) == required;

    if (provided != UNDECLARED && !isDeclaredLevel(provided)) {
        ALOGE("Unknown stability when checking interface stability %d.", provided);

        stable = false;
    }

    return stable;
}

bool Stability::isDeclaredLevel(int32_t stability) {
    return stability == VENDOR || stability == SYSTEM || stability == VINTF;
}

std::string Stability::levelString(int32_t 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(level);
}

}  // namespace internal
}  // namespace stability
