You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
557 lines
16 KiB
557 lines
16 KiB
/*
|
|
* 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.
|
|
*/
|
|
|
|
// Convert objects from and to strings.
|
|
|
|
#include "parse_string.h"
|
|
|
|
#include <android-base/parseint.h>
|
|
|
|
#include "constants-private.h"
|
|
|
|
namespace android {
|
|
using base::ParseUint;
|
|
|
|
namespace vintf {
|
|
|
|
static const std::string kRequired("required");
|
|
static const std::string kOptional("optional");
|
|
static const std::string kConfigPrefix("CONFIG_");
|
|
|
|
std::vector<std::string> SplitString(const std::string &s, char c) {
|
|
std::vector<std::string> components;
|
|
|
|
size_t startPos = 0;
|
|
size_t matchPos;
|
|
while ((matchPos = s.find(c, startPos)) != std::string::npos) {
|
|
components.push_back(s.substr(startPos, matchPos - startPos));
|
|
startPos = matchPos + 1;
|
|
}
|
|
|
|
if (startPos <= s.length()) {
|
|
components.push_back(s.substr(startPos));
|
|
}
|
|
return components;
|
|
}
|
|
|
|
template <typename T>
|
|
std::ostream &operator<<(std::ostream &os, const std::vector<T> objs) {
|
|
bool first = true;
|
|
for (const T &v : objs) {
|
|
if (!first) {
|
|
os << ",";
|
|
}
|
|
os << v;
|
|
first = false;
|
|
}
|
|
return os;
|
|
}
|
|
|
|
template <typename T>
|
|
bool parse(const std::string &s, std::vector<T> *objs) {
|
|
std::vector<std::string> v = SplitString(s, ',');
|
|
objs->resize(v.size());
|
|
size_t idx = 0;
|
|
for (const auto &item : v) {
|
|
T ver;
|
|
if (!parse(item, &ver)) {
|
|
return false;
|
|
}
|
|
objs->at(idx++) = ver;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template<typename E, typename Array>
|
|
bool parseEnum(const std::string &s, E *e, const Array &strings) {
|
|
for (size_t i = 0; i < strings.size(); ++i) {
|
|
if (s == strings.at(i)) {
|
|
*e = static_cast<E>(i);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#define DEFINE_PARSE_STREAMIN_FOR_ENUM(ENUM) \
|
|
bool parse(const std::string &s, ENUM *hf) { \
|
|
return parseEnum(s, hf, g##ENUM##Strings); \
|
|
} \
|
|
std::ostream &operator<<(std::ostream &os, ENUM hf) { \
|
|
return os << g##ENUM##Strings.at(static_cast<size_t>(hf)); \
|
|
} \
|
|
|
|
DEFINE_PARSE_STREAMIN_FOR_ENUM(HalFormat)
|
|
DEFINE_PARSE_STREAMIN_FOR_ENUM(Transport)
|
|
DEFINE_PARSE_STREAMIN_FOR_ENUM(Arch)
|
|
DEFINE_PARSE_STREAMIN_FOR_ENUM(KernelConfigType)
|
|
DEFINE_PARSE_STREAMIN_FOR_ENUM(Tristate)
|
|
DEFINE_PARSE_STREAMIN_FOR_ENUM(SchemaType)
|
|
DEFINE_PARSE_STREAMIN_FOR_ENUM(XmlSchemaFormat)
|
|
|
|
std::ostream &operator<<(std::ostream &os, const KernelConfigTypedValue &kctv) {
|
|
switch (kctv.mType) {
|
|
case KernelConfigType::STRING:
|
|
return os << kctv.mStringValue;
|
|
case KernelConfigType::INTEGER:
|
|
return os << to_string(kctv.mIntegerValue);
|
|
case KernelConfigType::RANGE:
|
|
return os << to_string(kctv.mRangeValue.first) << "-"
|
|
<< to_string(kctv.mRangeValue.second);
|
|
case KernelConfigType::TRISTATE:
|
|
return os << to_string(kctv.mTristateValue);
|
|
}
|
|
}
|
|
|
|
bool parse(const std::string& s, Level* l) {
|
|
if (s.empty()) {
|
|
*l = Level::UNSPECIFIED;
|
|
return true;
|
|
}
|
|
if (s == "legacy") {
|
|
*l = Level::LEGACY;
|
|
return true;
|
|
}
|
|
size_t value;
|
|
if (!ParseUint(s, &value)) {
|
|
return false;
|
|
}
|
|
*l = static_cast<Level>(value);
|
|
return true;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os, Level l) {
|
|
if (l == Level::UNSPECIFIED) {
|
|
return os;
|
|
}
|
|
if (l == Level::LEGACY) {
|
|
return os << "legacy";
|
|
}
|
|
return os << static_cast<size_t>(l);
|
|
}
|
|
|
|
// Notice that strtoull is used even though KernelConfigIntValue is signed int64_t,
|
|
// because strtoull can accept negative values as well.
|
|
// Notice that according to man strtoul, strtoull can actually accept
|
|
// -2^64 + 1 to 2^64 - 1, with the 65th bit truncated.
|
|
// ParseInt / ParseUint are not used because they do not handle signed hex very well.
|
|
template <typename T>
|
|
bool parseKernelConfigIntHelper(const std::string &s, T *i) {
|
|
char *end;
|
|
errno = 0;
|
|
unsigned long long int ulli = strtoull(s.c_str(), &end, 0 /* base */);
|
|
// It is implementation defined that what value will be returned by strtoull
|
|
// in the error case, so we are checking errno directly here.
|
|
if (errno == 0 && s.c_str() != end && *end == '\0') {
|
|
*i = static_cast<T>(ulli);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool parseKernelConfigInt(const std::string &s, int64_t *i) {
|
|
return parseKernelConfigIntHelper(s, i);
|
|
}
|
|
|
|
bool parseKernelConfigInt(const std::string &s, uint64_t *i) {
|
|
return parseKernelConfigIntHelper(s, i);
|
|
}
|
|
|
|
bool parseRange(const std::string &s, KernelConfigRangeValue *range) {
|
|
auto pos = s.find('-');
|
|
if (pos == std::string::npos) {
|
|
return false;
|
|
}
|
|
return parseKernelConfigInt(s.substr(0, pos), &range->first)
|
|
&& parseKernelConfigInt(s.substr(pos + 1), &range->second);
|
|
}
|
|
|
|
bool parse(const std::string &s, KernelConfigKey *key) {
|
|
*key = s;
|
|
return true;
|
|
}
|
|
|
|
bool parseKernelConfigValue(const std::string &s, KernelConfigTypedValue *kctv) {
|
|
switch (kctv->mType) {
|
|
case KernelConfigType::STRING:
|
|
kctv->mStringValue = s;
|
|
return true;
|
|
case KernelConfigType::INTEGER:
|
|
return parseKernelConfigInt(s, &kctv->mIntegerValue);
|
|
case KernelConfigType::RANGE:
|
|
return parseRange(s, &kctv->mRangeValue);
|
|
case KernelConfigType::TRISTATE:
|
|
return parse(s, &kctv->mTristateValue);
|
|
}
|
|
}
|
|
|
|
bool parseKernelConfigTypedValue(const std::string& s, KernelConfigTypedValue* kctv) {
|
|
if (s.size() > 1 && s[0] == '"' && s.back() == '"') {
|
|
kctv->mType = KernelConfigType::STRING;
|
|
kctv->mStringValue = s.substr(1, s.size()-2);
|
|
return true;
|
|
}
|
|
if (parseKernelConfigInt(s, &kctv->mIntegerValue)) {
|
|
kctv->mType = KernelConfigType::INTEGER;
|
|
return true;
|
|
}
|
|
if (parse(s, &kctv->mTristateValue)) {
|
|
kctv->mType = KernelConfigType::TRISTATE;
|
|
return true;
|
|
}
|
|
// Do not test for KernelConfigType::RANGE.
|
|
return false;
|
|
}
|
|
|
|
bool parse(const std::string &s, Version *ver) {
|
|
std::vector<std::string> v = SplitString(s, '.');
|
|
if (v.size() != 2) {
|
|
return false;
|
|
}
|
|
size_t major, minor;
|
|
if (!ParseUint(v[0], &major)) {
|
|
return false;
|
|
}
|
|
if (!ParseUint(v[1], &minor)) {
|
|
return false;
|
|
}
|
|
*ver = Version(major, minor);
|
|
return true;
|
|
}
|
|
|
|
std::ostream &operator<<(std::ostream &os, const Version &ver) {
|
|
return os << ver.majorVer << "." << ver.minorVer;
|
|
}
|
|
|
|
// Helper for parsing a VersionRange object. versionParser defines how the first half
|
|
// (before the '-' character) of the string is parsed.
|
|
static bool parseVersionRange(
|
|
const std::string& s, VersionRange* vr,
|
|
const std::function<bool(const std::string&, Version*)>& versionParser) {
|
|
std::vector<std::string> v = SplitString(s, '-');
|
|
if (v.size() != 1 && v.size() != 2) {
|
|
return false;
|
|
}
|
|
Version minVer;
|
|
if (!versionParser(v[0], &minVer)) {
|
|
return false;
|
|
}
|
|
if (v.size() == 1) {
|
|
*vr = VersionRange(minVer.majorVer, minVer.minorVer);
|
|
} else {
|
|
size_t maxMinor;
|
|
if (!ParseUint(v[1], &maxMinor)) {
|
|
return false;
|
|
}
|
|
*vr = VersionRange(minVer.majorVer, minVer.minorVer, maxMinor);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool parse(const std::string& s, VersionRange* vr) {
|
|
bool (*versionParser)(const std::string&, Version*) = parse;
|
|
return parseVersionRange(s, vr, versionParser);
|
|
}
|
|
|
|
std::ostream &operator<<(std::ostream &os, const VersionRange &vr) {
|
|
if (vr.isSingleVersion()) {
|
|
return os << vr.minVer();
|
|
}
|
|
return os << vr.minVer() << "-" << vr.maxMinor;
|
|
}
|
|
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
bool parse(const std::string &s, VndkVersionRange *vr) {
|
|
std::vector<std::string> v = SplitString(s, '-');
|
|
if (v.size() != 1 && v.size() != 2) {
|
|
return false;
|
|
}
|
|
std::vector<std::string> minVector = SplitString(v[0], '.');
|
|
if (minVector.size() != 3) {
|
|
return false;
|
|
}
|
|
if (!ParseUint(minVector[0], &vr->sdk) ||
|
|
!ParseUint(minVector[1], &vr->vndk) ||
|
|
!ParseUint(minVector[2], &vr->patchMin)) {
|
|
return false;
|
|
}
|
|
if (v.size() == 1) {
|
|
vr->patchMax = vr->patchMin;
|
|
return true;
|
|
} else {
|
|
return ParseUint(v[1], &vr->patchMax);
|
|
}
|
|
}
|
|
|
|
std::ostream &operator<<(std::ostream &os, const VndkVersionRange &vr) {
|
|
os << vr.sdk << "." << vr.vndk << "." << vr.patchMin;
|
|
if (!vr.isSingleVersion()) {
|
|
os << "-" << vr.patchMax;
|
|
}
|
|
return os;
|
|
}
|
|
#pragma clang diagnostic pop
|
|
|
|
bool parse(const std::string &s, KernelVersion *kernelVersion) {
|
|
std::vector<std::string> v = SplitString(s, '.');
|
|
if (v.size() != 3) {
|
|
return false;
|
|
}
|
|
size_t version, major, minor;
|
|
if (!ParseUint(v[0], &version)) {
|
|
return false;
|
|
}
|
|
if (!ParseUint(v[1], &major)) {
|
|
return false;
|
|
}
|
|
if (!ParseUint(v[2], &minor)) {
|
|
return false;
|
|
}
|
|
*kernelVersion = KernelVersion(version, major, minor);
|
|
return true;
|
|
}
|
|
|
|
std::ostream &operator<<(std::ostream &os, const TransportArch &ta) {
|
|
return os << to_string(ta.transport) << to_string(ta.arch);
|
|
}
|
|
|
|
bool parse(const std::string &s, TransportArch *ta) {
|
|
bool transportSet = false;
|
|
bool archSet = false;
|
|
for (size_t i = 0; i < gTransportStrings.size(); ++i) {
|
|
if (s.find(gTransportStrings.at(i)) != std::string::npos) {
|
|
ta->transport = static_cast<Transport>(i);
|
|
transportSet = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!transportSet) {
|
|
return false;
|
|
}
|
|
for (size_t i = 0; i < gArchStrings.size(); ++i) {
|
|
if (s.find(gArchStrings.at(i)) != std::string::npos) {
|
|
ta->arch = static_cast<Arch>(i);
|
|
archSet = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!archSet) {
|
|
return false;
|
|
}
|
|
return ta->isValid();
|
|
}
|
|
|
|
std::ostream &operator<<(std::ostream &os, const KernelVersion &ver) {
|
|
return os << ver.version << "." << ver.majorRev << "." << ver.minorRev;
|
|
}
|
|
|
|
bool parse(const std::string &s, ManifestHal *hal) {
|
|
std::vector<std::string> v = SplitString(s, '/');
|
|
if (v.size() != 4) {
|
|
return false;
|
|
}
|
|
if (!parse(v[0], &hal->format)) {
|
|
return false;
|
|
}
|
|
hal->name = v[1];
|
|
if (!parse(v[2], &hal->transportArch)) {
|
|
return false;
|
|
}
|
|
if (!parse(v[3], &hal->versions)) {
|
|
return false;
|
|
}
|
|
return hal->isValid();
|
|
}
|
|
|
|
std::ostream &operator<<(std::ostream &os, const ManifestHal &hal) {
|
|
return os << hal.format << "/"
|
|
<< hal.name << "/"
|
|
<< hal.transportArch << "/"
|
|
<< hal.versions;
|
|
}
|
|
|
|
std::string expandInstances(const MatrixHal& req, const VersionRange& vr, bool brace) {
|
|
std::string s;
|
|
size_t count = 0;
|
|
req.forEachInstance(vr, [&](const auto& matrixInstance) {
|
|
if (count > 0) s += " AND ";
|
|
auto instance = matrixInstance.isRegex() ? matrixInstance.regexPattern()
|
|
: matrixInstance.exactInstance();
|
|
switch (req.format) {
|
|
case HalFormat::AIDL: {
|
|
s += toFQNameString(matrixInstance.interface(), instance) + " (@" +
|
|
aidlVersionRangeToString(vr) + ")";
|
|
} break;
|
|
case HalFormat::HIDL:
|
|
[[fallthrough]];
|
|
case HalFormat::NATIVE: {
|
|
s += toFQNameString(vr, matrixInstance.interface(), instance);
|
|
} break;
|
|
}
|
|
count++;
|
|
return true;
|
|
});
|
|
if (count == 0) {
|
|
s += "@" + to_string(vr);
|
|
}
|
|
if (count >= 2 && brace) {
|
|
s = "(" + s + ")";
|
|
}
|
|
return s;
|
|
}
|
|
|
|
std::vector<std::string> expandInstances(const MatrixHal& req) {
|
|
size_t count = req.instancesCount();
|
|
if (count == 0) {
|
|
return {};
|
|
}
|
|
if (count == 1) {
|
|
return {expandInstances(req, req.versionRanges.front(), false /* brace */)};
|
|
}
|
|
std::vector<std::string> ss;
|
|
for (const auto& vr : req.versionRanges) {
|
|
if (!ss.empty()) {
|
|
ss.back() += " OR";
|
|
}
|
|
ss.push_back(expandInstances(req, vr, true /* brace */));
|
|
}
|
|
return ss;
|
|
}
|
|
|
|
std::ostream &operator<<(std::ostream &os, KernelSepolicyVersion ksv){
|
|
return os << ksv.value;
|
|
}
|
|
|
|
bool parse(const std::string &s, KernelSepolicyVersion *ksv){
|
|
return ParseUint(s, &ksv->value);
|
|
}
|
|
|
|
std::string dump(const HalManifest &vm) {
|
|
std::ostringstream oss;
|
|
bool first = true;
|
|
for (const auto &hal : vm.getHals()) {
|
|
if (!first) {
|
|
oss << ":";
|
|
}
|
|
oss << hal;
|
|
first = false;
|
|
}
|
|
return oss.str();
|
|
}
|
|
|
|
std::string dump(const RuntimeInfo& ki, bool verbose) {
|
|
std::ostringstream oss;
|
|
|
|
oss << "kernel = " << ki.osName() << "/" << ki.nodeName() << "/" << ki.osRelease() << "/"
|
|
<< ki.osVersion() << "/" << ki.hardwareId() << ";" << ki.mBootAvbVersion << "/"
|
|
<< ki.mBootVbmetaAvbVersion << ";"
|
|
<< "kernelSepolicyVersion = " << ki.kernelSepolicyVersion() << ";";
|
|
|
|
if (verbose) {
|
|
oss << "\n\ncpu info:\n" << ki.cpuInfo();
|
|
}
|
|
|
|
oss << "\n#CONFIG's loaded = " << ki.kernelConfigs().size() << ";\n";
|
|
|
|
if (verbose) {
|
|
for (const auto& pair : ki.kernelConfigs()) {
|
|
oss << pair.first << "=" << pair.second << "\n";
|
|
}
|
|
}
|
|
|
|
return oss.str();
|
|
}
|
|
|
|
std::string toFQNameString(const std::string& package, const std::string& version,
|
|
const std::string& interface, const std::string& instance) {
|
|
std::stringstream ss;
|
|
ss << package << "@" << version;
|
|
if (!interface.empty()) {
|
|
ss << "::" << interface;
|
|
if (!instance.empty()) {
|
|
ss << "/" << instance;
|
|
}
|
|
}
|
|
return ss.str();
|
|
}
|
|
|
|
std::string toFQNameString(const std::string& package, const Version& version,
|
|
const std::string& interface, const std::string& instance) {
|
|
return toFQNameString(package, to_string(version), interface, instance);
|
|
}
|
|
|
|
std::string toFQNameString(const Version& version, const std::string& interface,
|
|
const std::string& instance) {
|
|
return toFQNameString("", version, interface, instance);
|
|
}
|
|
|
|
// android.hardware.foo@1.0-1::IFoo/default.
|
|
// Note that the format is extended to support a range of versions.
|
|
std::string toFQNameString(const std::string& package, const VersionRange& range,
|
|
const std::string& interface, const std::string& instance) {
|
|
return toFQNameString(package, to_string(range), interface, instance);
|
|
}
|
|
|
|
std::string toFQNameString(const VersionRange& range, const std::string& interface,
|
|
const std::string& instance) {
|
|
return toFQNameString("", range, interface, instance);
|
|
}
|
|
|
|
std::string toFQNameString(const std::string& interface, const std::string& instance) {
|
|
return interface + "/" + instance;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os, const FqInstance& fqInstance) {
|
|
return os << fqInstance.string();
|
|
}
|
|
|
|
bool parse(const std::string& s, FqInstance* fqInstance) {
|
|
return fqInstance->setTo(s);
|
|
}
|
|
|
|
std::string toAidlFqnameString(const std::string& package, const std::string& interface,
|
|
const std::string& instance) {
|
|
std::stringstream ss;
|
|
ss << package << "." << interface;
|
|
if (!instance.empty()) {
|
|
ss << "/" << instance;
|
|
}
|
|
return ss.str();
|
|
}
|
|
|
|
std::string aidlVersionToString(const Version& v) {
|
|
return to_string(v.minorVer);
|
|
}
|
|
bool parseAidlVersion(const std::string& s, Version* version) {
|
|
version->majorVer = details::kFakeAidlMajorVersion;
|
|
return android::base::ParseUint(s, &version->minorVer);
|
|
}
|
|
|
|
std::string aidlVersionRangeToString(const VersionRange& vr) {
|
|
if (vr.isSingleVersion()) {
|
|
return to_string(vr.minMinor);
|
|
}
|
|
return to_string(vr.minMinor) + "-" + to_string(vr.maxMinor);
|
|
}
|
|
|
|
bool parseAidlVersionRange(const std::string& s, VersionRange* vr) {
|
|
return parseVersionRange(s, vr, parseAidlVersion);
|
|
}
|
|
|
|
} // namespace vintf
|
|
} // namespace android
|