blob: b99ba61dfe019ee88e3baa2d44720c857030f833 [file] [log] [blame]
Yifan Hong676447a2016-11-15 12:57:23 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// Convert objects from and to strings.
18
19#include "parse_string.h"
20#include <android-base/parseint.h>
21
22namespace android {
23using base::ParseUint;
24
25namespace vintf {
26
27static const std::string kRequired("required");
28static const std::string kOptional("optional");
29static const std::string kConfigPrefix("CONFIG_");
30
31std::vector<std::string> SplitString(const std::string &s, char c) {
32 std::vector<std::string> components;
33
34 size_t startPos = 0;
35 size_t matchPos;
36 while ((matchPos = s.find(c, startPos)) != std::string::npos) {
37 components.push_back(s.substr(startPos, matchPos - startPos));
38 startPos = matchPos + 1;
39 }
40
41 if (startPos <= s.length()) {
42 components.push_back(s.substr(startPos));
43 }
44 return components;
45}
46
47template <typename T>
48std::ostream &operator<<(std::ostream &os, const std::vector<T> objs) {
49 bool first = true;
50 for (const T &v : objs) {
51 if (!first) {
52 os << ",";
53 }
54 os << v;
55 first = false;
56 }
57 return os;
58}
59
60template <typename T>
61bool parse(const std::string &s, std::vector<T> *objs) {
62 std::vector<std::string> v = SplitString(s, ',');
63 objs->resize(v.size());
64 size_t idx = 0;
65 for (const auto &item : v) {
66 T ver;
67 if (!parse(item, &ver)) {
68 return false;
69 }
70 objs->at(idx++) = ver;
71 }
72 return true;
73}
74
75template<typename E, typename Array>
76bool parseEnum(const std::string &s, E *e, const Array &strings) {
77 for (size_t i = 0; i < strings.size(); ++i) {
78 if (s == strings.at(i)) {
79 *e = static_cast<E>(i);
80 return true;
81 }
82 }
83 return false;
84}
85
Yifan Hongc54d32c2017-03-07 19:12:26 -080086#define DEFINE_PARSE_STREAMIN_FOR_ENUM(ENUM) \
87 bool parse(const std::string &s, ENUM *hf) { \
88 return parseEnum(s, hf, g##ENUM##Strings); \
89 } \
90 std::ostream &operator<<(std::ostream &os, ENUM hf) { \
91 return os << g##ENUM##Strings.at(static_cast<size_t>(hf)); \
92 } \
Yifan Hong676447a2016-11-15 12:57:23 -080093
Yifan Hongc54d32c2017-03-07 19:12:26 -080094DEFINE_PARSE_STREAMIN_FOR_ENUM(HalFormat);
Yifan Hongc54d32c2017-03-07 19:12:26 -080095DEFINE_PARSE_STREAMIN_FOR_ENUM(Transport);
96DEFINE_PARSE_STREAMIN_FOR_ENUM(Arch);
97DEFINE_PARSE_STREAMIN_FOR_ENUM(KernelConfigType);
98DEFINE_PARSE_STREAMIN_FOR_ENUM(Tristate);
Yifan Hong7c7d7062017-04-04 16:26:51 -070099DEFINE_PARSE_STREAMIN_FOR_ENUM(SchemaType);
Yifan Hongd4857902017-06-13 14:13:56 -0700100DEFINE_PARSE_STREAMIN_FOR_ENUM(XmlSchemaFormat);
Yifan Hong3f5489a2017-02-08 11:14:21 -0800101
102std::ostream &operator<<(std::ostream &os, const KernelConfigTypedValue &kctv) {
103 switch (kctv.mType) {
104 case KernelConfigType::STRING:
105 return os << kctv.mStringValue;
106 case KernelConfigType::INTEGER:
107 return os << to_string(kctv.mIntegerValue);
108 case KernelConfigType::RANGE:
109 return os << to_string(kctv.mRangeValue.first) << "-"
110 << to_string(kctv.mRangeValue.second);
111 case KernelConfigType::TRISTATE:
112 return os << to_string(kctv.mTristateValue);
113 }
114}
115
Yifan Hong2027a492017-12-11 15:21:19 -0800116bool parse(const std::string& s, Level* l) {
117 if (s.empty()) {
118 *l = Level::UNSPECIFIED;
119 return true;
120 }
121 if (s == "legacy") {
122 *l = Level::LEGACY;
123 return true;
124 }
125 size_t value;
126 if (!ParseUint(s, &value)) {
127 return false;
128 }
129 *l = static_cast<Level>(value);
130 return true;
131}
132
133std::ostream& operator<<(std::ostream& os, Level l) {
134 if (l == Level::UNSPECIFIED) {
135 return os;
136 }
137 if (l == Level::LEGACY) {
138 return os << "legacy";
139 }
140 return os << static_cast<size_t>(l);
141}
142
Yifan Hong3f5489a2017-02-08 11:14:21 -0800143// Notice that strtoull is used even though KernelConfigIntValue is signed int64_t,
144// because strtoull can accept negative values as well.
145// Notice that according to man strtoul, strtoull can actually accept
146// -2^64 + 1 to 2^64 - 1, with the 65th bit truncated.
147// ParseInt / ParseUint are not used because they do not handle signed hex very well.
148template <typename T>
149bool parseKernelConfigIntHelper(const std::string &s, T *i) {
150 char *end;
151 errno = 0;
152 unsigned long long int ulli = strtoull(s.c_str(), &end, 0 /* base */);
153 // It is implementation defined that what value will be returned by strtoull
154 // in the error case, so we are checking errno directly here.
155 if (errno == 0 && s.c_str() != end && *end == '\0') {
156 *i = static_cast<T>(ulli);
157 return true;
158 }
159 return false;
160}
161
162bool parseKernelConfigInt(const std::string &s, int64_t *i) {
163 return parseKernelConfigIntHelper(s, i);
164}
165
166bool parseKernelConfigInt(const std::string &s, uint64_t *i) {
167 return parseKernelConfigIntHelper(s, i);
168}
169
170bool parseRange(const std::string &s, KernelConfigRangeValue *range) {
171 auto pos = s.find('-');
172 if (pos == std::string::npos) {
173 return false;
174 }
175 return parseKernelConfigInt(s.substr(0, pos), &range->first)
176 && parseKernelConfigInt(s.substr(pos + 1), &range->second);
177}
178
179bool parse(const std::string &s, KernelConfigKey *key) {
180 *key = s;
181 return true;
182}
183
184bool parseKernelConfigValue(const std::string &s, KernelConfigTypedValue *kctv) {
185 switch (kctv->mType) {
186 case KernelConfigType::STRING:
187 kctv->mStringValue = s;
188 return true;
189 case KernelConfigType::INTEGER:
190 return parseKernelConfigInt(s, &kctv->mIntegerValue);
191 case KernelConfigType::RANGE:
192 return parseRange(s, &kctv->mRangeValue);
193 case KernelConfigType::TRISTATE:
194 return parse(s, &kctv->mTristateValue);
195 }
Yifan Hong676447a2016-11-15 12:57:23 -0800196}
197
Yifan Hong8fac3f32017-07-06 14:06:54 -0700198bool parseKernelConfigTypedValue(const std::string& s, KernelConfigTypedValue* kctv) {
199 if (parseKernelConfigInt(s, &kctv->mIntegerValue)) {
200 kctv->mType = KernelConfigType::INTEGER;
201 return true;
202 }
203 if (parse(s, &kctv->mTristateValue)) {
204 kctv->mType = KernelConfigType::TRISTATE;
205 return true;
206 }
207 // Do not test for KernelConfigType::RANGE.
208 kctv->mType = KernelConfigType::STRING;
209 kctv->mStringValue = s;
210 return true;
211}
212
Yifan Hong676447a2016-11-15 12:57:23 -0800213bool parse(const std::string &s, Version *ver) {
214 std::vector<std::string> v = SplitString(s, '.');
215 if (v.size() != 2) {
216 return false;
217 }
218 size_t major, minor;
219 if (!ParseUint(v[0], &major)) {
220 return false;
221 }
222 if (!ParseUint(v[1], &minor)) {
223 return false;
224 }
225 *ver = Version(major, minor);
226 return true;
227}
228
229std::ostream &operator<<(std::ostream &os, const Version &ver) {
230 return os << ver.majorVer << "." << ver.minorVer;
231}
232
233bool parse(const std::string &s, VersionRange *vr) {
234 std::vector<std::string> v = SplitString(s, '-');
235 if (v.size() != 1 && v.size() != 2) {
236 return false;
237 }
238 Version minVer;
239 if (!parse(v[0], &minVer)) {
240 return false;
241 }
242 if (v.size() == 1) {
243 *vr = VersionRange(minVer.majorVer, minVer.minorVer);
244 } else {
245 size_t maxMinor;
246 if (!ParseUint(v[1], &maxMinor)) {
247 return false;
248 }
249 *vr = VersionRange(minVer.majorVer, minVer.minorVer, maxMinor);
250 }
251 return true;
252}
253
254std::ostream &operator<<(std::ostream &os, const VersionRange &vr) {
255 if (vr.isSingleVersion()) {
256 return os << vr.minVer();
257 }
258 return os << vr.minVer() << "-" << vr.maxMinor;
259}
260
Yifan Hong0f529fa2018-01-10 14:51:59 -0800261#pragma clang diagnostic push
262#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Yifan Honga04e1472017-04-05 13:15:34 -0700263bool parse(const std::string &s, VndkVersionRange *vr) {
264 std::vector<std::string> v = SplitString(s, '-');
265 if (v.size() != 1 && v.size() != 2) {
266 return false;
267 }
268 std::vector<std::string> minVector = SplitString(v[0], '.');
269 if (minVector.size() != 3) {
270 return false;
271 }
272 if (!ParseUint(minVector[0], &vr->sdk) ||
273 !ParseUint(minVector[1], &vr->vndk) ||
274 !ParseUint(minVector[2], &vr->patchMin)) {
275 return false;
276 }
277 if (v.size() == 1) {
278 vr->patchMax = vr->patchMin;
279 return true;
280 } else {
281 return ParseUint(v[1], &vr->patchMax);
282 }
283}
284
285std::ostream &operator<<(std::ostream &os, const VndkVersionRange &vr) {
286 os << vr.sdk << "." << vr.vndk << "." << vr.patchMin;
287 if (!vr.isSingleVersion()) {
288 os << "-" << vr.patchMax;
289 }
290 return os;
291}
Yifan Hong0f529fa2018-01-10 14:51:59 -0800292#pragma clang diagnostic pop
Yifan Honga04e1472017-04-05 13:15:34 -0700293
Yifan Hong3f5489a2017-02-08 11:14:21 -0800294bool parse(const std::string &s, KernelVersion *kernelVersion) {
295 std::vector<std::string> v = SplitString(s, '.');
296 if (v.size() != 3) {
297 return false;
298 }
299 size_t version, major, minor;
300 if (!ParseUint(v[0], &version)) {
301 return false;
302 }
303 if (!ParseUint(v[1], &major)) {
304 return false;
305 }
306 if (!ParseUint(v[2], &minor)) {
307 return false;
308 }
309 *kernelVersion = KernelVersion(version, major, minor);
310 return true;
311}
312
Yifan Hongc54d32c2017-03-07 19:12:26 -0800313std::ostream &operator<<(std::ostream &os, const TransportArch &ta) {
314 return os << to_string(ta.transport) << to_string(ta.arch);
315}
316
317bool parse(const std::string &s, TransportArch *ta) {
318 bool transportSet = false;
319 bool archSet = false;
320 for (size_t i = 0; i < gTransportStrings.size(); ++i) {
321 if (s.find(gTransportStrings.at(i)) != std::string::npos) {
322 ta->transport = static_cast<Transport>(i);
323 transportSet = true;
324 break;
325 }
326 }
327 if (!transportSet) {
328 return false;
329 }
330 for (size_t i = 0; i < gArchStrings.size(); ++i) {
331 if (s.find(gArchStrings.at(i)) != std::string::npos) {
332 ta->arch = static_cast<Arch>(i);
333 archSet = true;
334 break;
335 }
336 }
337 if (!archSet) {
338 return false;
339 }
340 return ta->isValid();
341}
342
Yifan Hong3f5489a2017-02-08 11:14:21 -0800343std::ostream &operator<<(std::ostream &os, const KernelVersion &ver) {
344 return os << ver.version << "." << ver.majorRev << "." << ver.minorRev;
345}
346
Yifan Hong676447a2016-11-15 12:57:23 -0800347bool parse(const std::string &s, ManifestHal *hal) {
348 std::vector<std::string> v = SplitString(s, '/');
Yifan Hong974ad9c2017-04-04 15:37:39 -0700349 if (v.size() != 4) {
Yifan Hong676447a2016-11-15 12:57:23 -0800350 return false;
351 }
352 if (!parse(v[0], &hal->format)) {
353 return false;
354 }
355 hal->name = v[1];
Yifan Hongc54d32c2017-03-07 19:12:26 -0800356 if (!parse(v[2], &hal->transportArch)) {
Yifan Hong676447a2016-11-15 12:57:23 -0800357 return false;
358 }
Yifan Hong974ad9c2017-04-04 15:37:39 -0700359 if (!parse(v[3], &hal->versions)) {
Yifan Hong676447a2016-11-15 12:57:23 -0800360 return false;
361 }
Yifan Hong5a06ef72017-01-24 19:54:24 -0800362 return hal->isValid();
Yifan Hong676447a2016-11-15 12:57:23 -0800363}
364
365std::ostream &operator<<(std::ostream &os, const ManifestHal &hal) {
366 return os << hal.format << "/"
367 << hal.name << "/"
Yifan Hongc54d32c2017-03-07 19:12:26 -0800368 << hal.transportArch << "/"
Yifan Hong676447a2016-11-15 12:57:23 -0800369 << hal.versions;
370}
371
372bool parse(const std::string &s, MatrixHal *req) {
373 std::vector<std::string> v = SplitString(s, '/');
374 if (v.size() != 4) {
375 return false;
376 }
377 if (!parse(v[0], &req->format)) {
378 return false;
379 }
380 req->name = v[1];
381 if (!parse(v[2], &req->versionRanges)) {
382 return false;
383 }
384 if (v[3] != kRequired || v[3] != kOptional) {
385 return false;
386 }
387 req->optional = (v[3] == kOptional);
388 return true;
389}
390
391std::ostream &operator<<(std::ostream &os, const MatrixHal &req) {
392 return os << req.format << "/"
393 << req.name << "/"
394 << req.versionRanges << "/"
395 << (req.optional ? kOptional : kRequired);
396}
397
Yifan Hong6e82b112018-03-20 13:06:00 -0700398std::string expandInstances(const MatrixHal& req, const VersionRange& vr, bool brace) {
Yifan Hongde3aec22018-02-12 15:39:47 -0800399 std::string s;
Yifan Hong8d8264e2018-03-14 16:03:11 -0700400 size_t count = 0;
Yifan Hong6e82b112018-03-20 13:06:00 -0700401 req.forEachInstance(vr, [&](const auto& matrixInstance) {
402 if (count > 0) s += " AND ";
403 s += toFQNameString(vr, matrixInstance.interface(),
404 matrixInstance.isRegex() ? matrixInstance.regexPattern()
405 : matrixInstance.exactInstance());
406 count++;
407 return true;
408 });
Yifan Hong8d8264e2018-03-14 16:03:11 -0700409 if (count == 0) {
410 s += "@" + to_string(vr);
411 }
412 if (count >= 2 && brace) {
413 s = "(" + s + ")";
414 }
Yifan Hongde3aec22018-02-12 15:39:47 -0800415 return s;
416}
417
418std::vector<std::string> expandInstances(const MatrixHal& req) {
Yifan Hong6e82b112018-03-20 13:06:00 -0700419 size_t count = req.instancesCount();
420 if (count == 0) {
Yifan Hongde3aec22018-02-12 15:39:47 -0800421 return {};
422 }
Yifan Hong6e82b112018-03-20 13:06:00 -0700423 if (count == 1) {
Yifan Hong8d8264e2018-03-14 16:03:11 -0700424 return {expandInstances(req, req.versionRanges.front(), false /* brace */)};
Yifan Hongde3aec22018-02-12 15:39:47 -0800425 }
426 std::vector<std::string> ss;
427 for (const auto& vr : req.versionRanges) {
428 if (!ss.empty()) {
429 ss.back() += " OR";
430 }
Yifan Hong8d8264e2018-03-14 16:03:11 -0700431 ss.push_back(expandInstances(req, vr, true /* brace */));
Yifan Hongde3aec22018-02-12 15:39:47 -0800432 }
433 return ss;
434}
Yifan Hong558380a2017-02-09 15:37:32 -0800435
436std::ostream &operator<<(std::ostream &os, KernelSepolicyVersion ksv){
437 return os << ksv.value;
438}
439
440bool parse(const std::string &s, KernelSepolicyVersion *ksv){
441 return ParseUint(s, &ksv->value);
442}
443
Yifan Hongd2b7e642017-02-17 10:15:32 -0800444std::string dump(const HalManifest &vm) {
Yifan Hong676447a2016-11-15 12:57:23 -0800445 std::ostringstream oss;
446 bool first = true;
Yifan Hongef6d4d32017-01-23 14:12:28 -0800447 for (const auto &hal : vm.getHals()) {
Yifan Hong676447a2016-11-15 12:57:23 -0800448 if (!first) {
449 oss << ":";
450 }
451 oss << hal;
452 first = false;
453 }
454 return oss.str();
455}
456
Yifan Honge3a92342018-01-25 17:00:16 -0800457std::string dump(const RuntimeInfo& ki, bool verbose) {
Yifan Hongccf967b2017-01-18 11:04:19 -0800458 std::ostringstream oss;
459
Yifan Honge3a92342018-01-25 17:00:16 -0800460 oss << "kernel = " << ki.osName() << "/" << ki.nodeName() << "/" << ki.osRelease() << "/"
461 << ki.osVersion() << "/" << ki.hardwareId() << ";" << ki.mBootAvbVersion << "/"
Yifan Hong881a9e452017-04-27 19:31:13 -0700462 << ki.mBootVbmetaAvbVersion << ";"
Yifan Honge3a92342018-01-25 17:00:16 -0800463 << "kernelSepolicyVersion = " << ki.kernelSepolicyVersion() << ";";
464
465 if (verbose) {
466 oss << "\n\ncpu info:\n" << ki.cpuInfo();
467 }
468
469 oss << "\n#CONFIG's loaded = " << ki.mKernelConfigs.size() << ";\n";
470
471 if (verbose) {
472 for (const auto& pair : ki.mKernelConfigs) {
473 oss << pair.first << "=" << pair.second << "\n";
474 }
Yifan Hongccf967b2017-01-18 11:04:19 -0800475 }
476
477 return oss.str();
478}
479
Yifan Hongb6c7f492018-02-27 14:07:57 -0800480std::string toFQNameString(const std::string& package, const std::string& version,
481 const std::string& interface, const std::string& instance) {
482 std::stringstream ss;
483 ss << package << "@" << version;
484 if (!interface.empty()) {
485 ss << "::" << interface;
486 if (!instance.empty()) {
487 ss << "/" << instance;
488 }
489 }
490 return ss.str();
491}
492
493std::string toFQNameString(const std::string& package, const Version& version,
494 const std::string& interface, const std::string& instance) {
495 return toFQNameString(package, to_string(version), interface, instance);
496}
497
498std::string toFQNameString(const Version& version, const std::string& interface,
499 const std::string& instance) {
500 return toFQNameString("", version, interface, instance);
501}
502
503// android.hardware.foo@1.0-1::IFoo/default.
504// Note that the format is extended to support a range of versions.
505std::string toFQNameString(const std::string& package, const VersionRange& range,
506 const std::string& interface, const std::string& instance) {
507 return toFQNameString(package, to_string(range), interface, instance);
508}
509
510std::string toFQNameString(const VersionRange& range, const std::string& interface,
511 const std::string& instance) {
512 return toFQNameString("", range, interface, instance);
513}
514
Yifan Honga1fae892018-03-13 12:36:38 -0700515std::ostream& operator<<(std::ostream& os, const FqInstance& fqInstance) {
516 return os << fqInstance.string();
517}
518
519bool parse(const std::string& s, FqInstance* fqInstance) {
520 return fqInstance->setTo(s);
521}
522
Yifan Hong676447a2016-11-15 12:57:23 -0800523} // namespace vintf
524} // namespace android