blob: 5cee28acff238c231ef06c79c76dad6c41cbc92b [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#include "ManifestHal.h"
Yifan Hong21e3b6e2021-01-19 12:34:37 -080018
Yifan Hong676447a2016-11-15 12:57:23 -080019#include <unordered_set>
20
Yifan Hong2a90ffe2018-03-05 17:45:34 -080021#include "MapValueIterator.h"
Yifan Hong934de622019-08-30 15:28:59 -070022#include "constants-private.h"
Yifan Hong2b1efaa2018-03-13 12:36:38 -070023#include "parse_string.h"
Yifan Hong21e3b6e2021-01-19 12:34:37 -080024#include "utils.h"
Yifan Hong2a90ffe2018-03-05 17:45:34 -080025
Yifan Hong676447a2016-11-15 12:57:23 -080026namespace android {
27namespace vintf {
28
Yifan Hong21e3b6e2021-01-19 12:34:37 -080029using details::canConvertToFqInstance;
30
Yifan Hong9f9a3192020-04-13 16:39:45 -070031bool ManifestHal::isValid(std::string* error) const {
32 if (error) {
33 error->clear();
Yifan Hong676447a2016-11-15 12:57:23 -080034 }
Yifan Hong9f9a3192020-04-13 16:39:45 -070035
36 bool success = true;
37 std::map<size_t, Version> existing;
38 for (const auto &v : versions) {
39 auto&& [it, inserted] = existing.emplace(v.majorVer, v);
40 if (inserted) {
41 continue;
42 }
43 success = false;
44 if (error) {
Yifan Hong21e3b6e2021-01-19 12:34:37 -080045 *error += "Duplicated major version: " + to_string(v) + " vs. " +
46 to_string(it->second) + ".\n";
Yifan Hong9f9a3192020-04-13 16:39:45 -070047 }
48 }
Yifan Hong21e3b6e2021-01-19 12:34:37 -080049
50 // Check legacy instances (i.e. <version> + <interface> + <instance>) can be
51 // converted into FqInstance because forEachInstance relies on FqInstance.
52 for (const auto& v : versions) {
53 for (const auto& intf : iterateValues(interfaces)) {
54 intf.forEachInstance(
55 [&](const auto& interface, const auto& instance, bool /* isRegex */) {
56 if (!canConvertToFqInstance(getName(), v, interface, instance, format, error)) {
57 success = false;
58 }
59 return true; // continue
60 });
61 }
62 }
63
Yifan Hong9f9a3192020-04-13 16:39:45 -070064 std::string transportArchError;
65 if (!transportArch.isValid(&transportArchError)) {
66 success = false;
Yifan Hong21e3b6e2021-01-19 12:34:37 -080067 if (error) *error += transportArchError + "\n";
Yifan Hong9f9a3192020-04-13 16:39:45 -070068 }
69 return success;
Yifan Hong676447a2016-11-15 12:57:23 -080070}
71
Yifan Hong676447a2016-11-15 12:57:23 -080072bool ManifestHal::operator==(const ManifestHal &other) const {
Yifan Hongba6cb5b2020-04-13 14:30:49 -070073 // ignore fileName().
Yifan Hong676447a2016-11-15 12:57:23 -080074 if (format != other.format)
75 return false;
76 if (name != other.name)
77 return false;
78 if (versions != other.versions)
79 return false;
Yifan Hong3dd2a312018-03-13 13:48:25 -070080 if (!(transportArch == other.transportArch)) return false;
81 if (interfaces != other.interfaces) return false;
82 if (isOverride() != other.isOverride()) return false;
Jooyung Han75c3d512021-03-23 12:33:12 +090083 if (updatableViaApex() != other.updatableViaApex()) return false;
Yifan Hong2b1efaa2018-03-13 12:36:38 -070084 if (mAdditionalInstances != other.mAdditionalInstances) return false;
Yifan Hong676447a2016-11-15 12:57:23 -080085 return true;
86}
87
Yifan Hong2a90ffe2018-03-05 17:45:34 -080088bool ManifestHal::forEachInstance(const std::function<bool(const ManifestInstance&)>& func) const {
Yifan Hong2a90ffe2018-03-05 17:45:34 -080089 for (const auto& v : versions) {
90 for (const auto& intf : iterateValues(interfaces)) {
Yifan Hong7e9e04d2018-03-20 13:06:00 -070091 bool cont = intf.forEachInstance([&](const auto& interface, const auto& instance,
92 bool /* isRegex */) {
Yifan Hong2a90ffe2018-03-05 17:45:34 -080093 // TODO(b/73556059): Store ManifestInstance as well to avoid creating temps
94 FqInstance fqInstance;
Yifan Hong7e9e04d2018-03-20 13:06:00 -070095 if (fqInstance.setTo(getName(), v.majorVer, v.minorVer, interface, instance)) {
Yifan Hongf079a3d2018-03-19 17:26:53 -070096 if (!func(ManifestInstance(std::move(fqInstance), TransportArch{transportArch},
Jooyung Han75c3d512021-03-23 12:33:12 +090097 format, updatableViaApex()))) {
Yifan Hong2a90ffe2018-03-05 17:45:34 -080098 return false;
99 }
100 }
Yifan Hong7e9e04d2018-03-20 13:06:00 -0700101 return true;
102 });
103 if (!cont) {
104 return false;
Yifan Hong2a90ffe2018-03-05 17:45:34 -0800105 }
106 }
107 }
Yifan Hong2b1efaa2018-03-13 12:36:38 -0700108
109 for (const auto& manifestInstance : mAdditionalInstances) {
Yifan Hongaf5b43d2020-12-17 18:22:27 -0800110 // For AIDL HALs, <version> tag is mangled with <fqname>. Note that if there's no
111 // <version> tag, libvintf will create one by default, so each <fqname> is executed
112 // at least once.
113 if (format == HalFormat::AIDL) {
114 for (const auto& v : versions) {
115 if (!func(manifestInstance.withVersion(v))) {
116 return false;
117 }
118 }
119 } else {
120 if (!func(manifestInstance)) {
121 return false;
122 }
Yifan Hong2b1efaa2018-03-13 12:36:38 -0700123 }
124 }
125
Yifan Hong2a90ffe2018-03-05 17:45:34 -0800126 return true;
127}
128
Yifan Hong470144f2018-03-13 18:22:34 -0700129bool ManifestHal::isDisabledHal() const {
130 if (!isOverride()) return false;
131 bool hasInstance = false;
132 forEachInstance([&hasInstance](const auto&) {
133 hasInstance = true;
134 return false; // has at least one instance, stop here.
135 });
136 return !hasInstance;
137}
138
Yifan Hong075b3632018-03-14 16:03:11 -0700139void ManifestHal::appendAllVersions(std::set<Version>* ret) const {
140 ret->insert(versions.begin(), versions.end());
141 forEachInstance([&](const auto& e) {
142 ret->insert(e.version());
143 return true;
144 });
145}
146
Yifan Hong55410692018-05-01 19:08:51 -0700147bool ManifestHal::verifyInstance(const FqInstance& fqInstance, std::string* error) const {
148 if (fqInstance.hasPackage() && fqInstance.getPackage() != this->getName()) {
149 if (error) {
150 *error = "Should not add \"" + fqInstance.string() + "\" to a HAL with name " +
151 this->getName();
Yifan Hong2b1efaa2018-03-13 12:36:38 -0700152 }
Yifan Hong55410692018-05-01 19:08:51 -0700153 return false;
154 }
155 if (!fqInstance.hasVersion()) {
156 if (error) *error = "Should specify version: \"" + fqInstance.string() + "\"";
157 return false;
158 }
159 if (!fqInstance.hasInterface()) {
160 if (error) *error = "Should specify interface: \"" + fqInstance.string() + "\"";
161 return false;
162 }
163 if (!fqInstance.hasInstance()) {
164 if (error) *error = "Should specify instance: \"" + fqInstance.string() + "\"";
165 return false;
166 }
167 return true;
168}
169
170bool ManifestHal::insertInstances(const std::set<FqInstance>& fqInstances, std::string* error) {
171 for (const FqInstance& e : fqInstances) {
172 if (!insertInstance(e, error)) {
Yifan Hong2b1efaa2018-03-13 12:36:38 -0700173 return false;
174 }
175 }
176 return true;
177}
178
Yifan Hong55410692018-05-01 19:08:51 -0700179bool ManifestHal::insertInstance(const FqInstance& e, std::string* error) {
180 if (!verifyInstance(e, error)) {
Yifan Hong2b1efaa2018-03-13 12:36:38 -0700181 return false;
182 }
183
Yifan Hong55410692018-05-01 19:08:51 -0700184 size_t minorVer = e.getMinorVersion();
185 for (auto it = mAdditionalInstances.begin(); it != mAdditionalInstances.end();) {
186 if (it->version().majorVer == e.getMajorVersion() && it->interface() == e.getInterface() &&
187 it->instance() == e.getInstance()) {
188 minorVer = std::max(minorVer, it->version().minorVer);
189 it = mAdditionalInstances.erase(it);
190 } else {
191 ++it;
Yifan Hong2b1efaa2018-03-13 12:36:38 -0700192 }
Yifan Hong2b1efaa2018-03-13 12:36:38 -0700193 }
194
Yifan Hong55410692018-05-01 19:08:51 -0700195 FqInstance toAdd;
196 if (!toAdd.setTo(this->getName(), e.getMajorVersion(), minorVer, e.getInterface(),
197 e.getInstance())) {
198 if (error) {
199 *error = "Cannot create FqInstance with package='" + this->getName() + "', version='" +
200 to_string(Version(e.getMajorVersion(), minorVer)) + "', interface='" +
201 e.getInterface() + "', instance='" + e.getInstance() + "'";
202 }
203 return false;
204 }
205
Jooyung Han75c3d512021-03-23 12:33:12 +0900206 mAdditionalInstances.emplace(std::move(toAdd), this->transportArch, this->format,
207 this->updatableViaApex());
Yifan Hong2b1efaa2018-03-13 12:36:38 -0700208 return true;
209}
210
Yifan Hong676447a2016-11-15 12:57:23 -0800211} // namespace vintf
212} // namespace android