| /* |
| * Copyright (C) 2017 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 "libvintf" |
| |
| #include "RuntimeInfo.h" |
| |
| #include <android-base/logging.h> |
| #include <kver/kernel_release.h> |
| |
| #include "CompatibilityMatrix.h" |
| #include "parse_string.h" |
| |
| namespace android { |
| namespace vintf { |
| |
| const std::string &RuntimeInfo::osName() const { |
| return mOsName; |
| } |
| |
| const std::string &RuntimeInfo::nodeName() const { |
| return mNodeName; |
| } |
| |
| const std::string &RuntimeInfo::osRelease() const { |
| return mOsRelease; |
| } |
| |
| const std::string &RuntimeInfo::osVersion() const { |
| return mOsVersion; |
| } |
| |
| const std::string &RuntimeInfo::hardwareId() const { |
| return mHardwareId; |
| } |
| |
| const KernelVersion &RuntimeInfo::kernelVersion() const { |
| return mKernel.version(); |
| } |
| |
| const std::map<std::string, std::string> &RuntimeInfo::kernelConfigs() const { |
| return mKernel.configs(); |
| } |
| |
| size_t RuntimeInfo::kernelSepolicyVersion() const { |
| return mKernelSepolicyVersion; |
| } |
| |
| const std::string &RuntimeInfo::cpuInfo() const { |
| return mCpuInfo; |
| } |
| |
| const Version &RuntimeInfo::bootVbmetaAvbVersion() const { |
| return mBootVbmetaAvbVersion; |
| } |
| |
| const Version &RuntimeInfo::bootAvbVersion() const { |
| return mBootAvbVersion; |
| } |
| |
| bool RuntimeInfo::isMainlineKernel() const { |
| return mIsMainline; |
| } |
| |
| bool RuntimeInfo::checkCompatibility(const CompatibilityMatrix& mat, std::string* error, |
| CheckFlags::Type flags) const { |
| if (mat.mType != SchemaType::FRAMEWORK) { |
| if (error != nullptr) { |
| *error = "Should not check runtime info against " + to_string(mat.mType) |
| + " compatibility matrix."; |
| } |
| return false; |
| } |
| if (kernelSepolicyVersion() < mat.framework.mSepolicy.kernelSepolicyVersion()) { |
| if (error != nullptr) { |
| *error = |
| "kernelSepolicyVersion = " + to_string(kernelSepolicyVersion()) + |
| " but required >= " + to_string(mat.framework.mSepolicy.kernelSepolicyVersion()); |
| } |
| return false; |
| } |
| |
| // mat.mSepolicy.sepolicyVersion() is checked against static |
| // HalManifest.device.mSepolicyVersion in HalManifest::checkCompatibility. |
| |
| if (flags.isKernelEnabled()) { |
| if (!isMainlineKernel() && |
| mKernel.getMatchedKernelRequirements(mat.framework.mKernels, kernelLevel(), error) |
| .empty()) { |
| return false; |
| } |
| } |
| |
| if (flags.isAvbEnabled()) { |
| const Version& matAvb = mat.framework.mAvbMetaVersion; |
| if (mBootAvbVersion.majorVer != matAvb.majorVer || |
| mBootAvbVersion.minorVer < matAvb.minorVer) { |
| if (error != nullptr) { |
| std::stringstream ss; |
| ss << "AVB version " << mBootAvbVersion << " does not match framework matrix " |
| << matAvb; |
| *error = ss.str(); |
| } |
| return false; |
| } |
| if (mBootVbmetaAvbVersion.majorVer != matAvb.majorVer || |
| mBootVbmetaAvbVersion.minorVer < matAvb.minorVer) { |
| if (error != nullptr) { |
| std::stringstream ss; |
| ss << "Vbmeta version " << mBootVbmetaAvbVersion |
| << " does not match framework matrix " << matAvb; |
| *error = ss.str(); |
| } |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| void RuntimeInfo::setKernelLevel(Level level) { |
| mKernel.mLevel = level; |
| } |
| |
| Level RuntimeInfo::kernelLevel() const { |
| return mKernel.mLevel; |
| } |
| |
| status_t RuntimeInfo::parseGkiKernelRelease(RuntimeInfo::FetchFlags flags, |
| const std::string& kernelReleaseString, |
| KernelVersion* outVersion, Level* outLevel) { |
| auto kernelRelease = |
| android::kver::KernelRelease::Parse(kernelReleaseString, true /* allow suffix */); |
| if (kernelRelease == std::nullopt) { |
| return UNKNOWN_ERROR; |
| } |
| |
| if (flags & RuntimeInfo::FetchFlag::CPU_VERSION) { |
| if (kernelRelease->version() > std::numeric_limits<size_t>::max() || |
| kernelRelease->patch_level() > std::numeric_limits<size_t>::max() || |
| kernelRelease->sub_level() > std::numeric_limits<size_t>::max()) { |
| LOG(ERROR) << "Overflow : " << kernelRelease->string(); |
| return UNKNOWN_ERROR; |
| } |
| *outVersion = {static_cast<size_t>(kernelRelease->version()), |
| static_cast<size_t>(kernelRelease->patch_level()), |
| static_cast<size_t>(kernelRelease->sub_level())}; |
| } |
| |
| if (flags & RuntimeInfo::FetchFlag::KERNEL_FCM) { |
| Level kernelLevel = gkiAndroidReleaseToLevel(kernelRelease->android_release()); |
| if (kernelLevel == Level::UNSPECIFIED) { |
| LOG(ERROR) << "Cannot infer level corresponding to Android " |
| << kernelRelease->android_release() |
| << "; update libvintf to recognize this value."; |
| return UNKNOWN_ERROR; |
| } |
| // VintfObject may previously set mRuntimeInfo->mKernel.mLevel to the kernel level |
| // from device manifest. Check consistency. |
| if (*outLevel != Level::UNSPECIFIED && *outLevel != kernelLevel) { |
| LOG(ERROR) << "Kernel level in device manifest (" << *outLevel |
| << ") does not match kernel level in kernel release (" << kernelLevel |
| << " for Android " << kernelRelease->android_release() << ")"; |
| return UNKNOWN_ERROR; |
| } |
| *outLevel = kernelLevel; |
| } |
| return OK; |
| } |
| |
| Level RuntimeInfo::gkiAndroidReleaseToLevel(uint64_t androidRelease) { |
| constexpr size_t ANDROID_S = 12; |
| |
| // Values prior to Android 12 is ignored because GKI kernel release format starts |
| // at Android 12. |
| if (androidRelease < ANDROID_S) return Level::UNSPECIFIED; |
| |
| Level ret = static_cast<Level>(androidRelease - ANDROID_S + static_cast<size_t>(Level::S)); |
| CHECK(ret < Level::LAST_PLUS_ONE) |
| << "Convert Android " << androidRelease << " to level '" << ret |
| << "' goes out of bounds. Fix by adding a new Level enum."; |
| return ret; |
| } |
| |
| } // namespace vintf |
| } // namespace android |