1 /*
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"
18 #include <unordered_set>
19
20 #include "MapValueIterator.h"
21 #include "constants-private.h"
22 #include "parse_string.h"
23
24 namespace android {
25 namespace vintf {
26
isValid(std::string * error) const27 bool ManifestHal::isValid(std::string* error) const {
28 if (error) {
29 error->clear();
30 }
31
32 bool success = true;
33 std::map<size_t, Version> existing;
34 for (const auto &v : versions) {
35 auto&& [it, inserted] = existing.emplace(v.majorVer, v);
36 if (inserted) {
37 continue;
38 }
39 success = false;
40 if (error) {
41 *error += "Duplicated major version: " + to_string(v) + " vs. " + to_string(it->second);
42 }
43 }
44 std::string transportArchError;
45 if (!transportArch.isValid(&transportArchError)) {
46 success = false;
47 if (error) *error += transportArchError;
48 }
49 return success;
50 }
51
operator ==(const ManifestHal & other) const52 bool ManifestHal::operator==(const ManifestHal &other) const {
53 // ignore fileName().
54 if (format != other.format)
55 return false;
56 if (name != other.name)
57 return false;
58 if (versions != other.versions)
59 return false;
60 if (!(transportArch == other.transportArch)) return false;
61 if (interfaces != other.interfaces) return false;
62 if (isOverride() != other.isOverride()) return false;
63 if (mAdditionalInstances != other.mAdditionalInstances) return false;
64 return true;
65 }
66
forEachInstance(const std::function<bool (const ManifestInstance &)> & func) const67 bool ManifestHal::forEachInstance(const std::function<bool(const ManifestInstance&)>& func) const {
68 for (const auto& v : versions) {
69 for (const auto& intf : iterateValues(interfaces)) {
70 bool cont = intf.forEachInstance([&](const auto& interface, const auto& instance,
71 bool /* isRegex */) {
72 // TODO(b/73556059): Store ManifestInstance as well to avoid creating temps
73 FqInstance fqInstance;
74 if (fqInstance.setTo(getName(), v.majorVer, v.minorVer, interface, instance)) {
75 if (!func(ManifestInstance(std::move(fqInstance), TransportArch{transportArch},
76 format))) {
77 return false;
78 }
79 }
80 return true;
81 });
82 if (!cont) {
83 return false;
84 }
85 }
86 }
87
88 for (const auto& manifestInstance : mAdditionalInstances) {
89 if (!func(manifestInstance)) {
90 return false;
91 }
92 }
93
94 return true;
95 }
96
isDisabledHal() const97 bool ManifestHal::isDisabledHal() const {
98 if (!isOverride()) return false;
99 bool hasInstance = false;
100 forEachInstance([&hasInstance](const auto&) {
101 hasInstance = true;
102 return false; // has at least one instance, stop here.
103 });
104 return !hasInstance;
105 }
106
appendAllVersions(std::set<Version> * ret) const107 void ManifestHal::appendAllVersions(std::set<Version>* ret) const {
108 ret->insert(versions.begin(), versions.end());
109 forEachInstance([&](const auto& e) {
110 ret->insert(e.version());
111 return true;
112 });
113 }
114
verifyInstance(const FqInstance & fqInstance,std::string * error) const115 bool ManifestHal::verifyInstance(const FqInstance& fqInstance, std::string* error) const {
116 if (fqInstance.hasPackage() && fqInstance.getPackage() != this->getName()) {
117 if (error) {
118 *error = "Should not add \"" + fqInstance.string() + "\" to a HAL with name " +
119 this->getName();
120 }
121 return false;
122 }
123 if (!fqInstance.hasVersion()) {
124 if (error) *error = "Should specify version: \"" + fqInstance.string() + "\"";
125 return false;
126 }
127 if (!fqInstance.hasInterface()) {
128 if (error) *error = "Should specify interface: \"" + fqInstance.string() + "\"";
129 return false;
130 }
131 if (!fqInstance.hasInstance()) {
132 if (error) *error = "Should specify instance: \"" + fqInstance.string() + "\"";
133 return false;
134 }
135 return true;
136 }
137
insertInstances(const std::set<FqInstance> & fqInstances,std::string * error)138 bool ManifestHal::insertInstances(const std::set<FqInstance>& fqInstances, std::string* error) {
139 for (const FqInstance& e : fqInstances) {
140 if (!insertInstance(e, error)) {
141 return false;
142 }
143 }
144 return true;
145 }
146
insertInstance(const FqInstance & e,std::string * error)147 bool ManifestHal::insertInstance(const FqInstance& e, std::string* error) {
148 if (!verifyInstance(e, error)) {
149 return false;
150 }
151
152 size_t minorVer = e.getMinorVersion();
153 for (auto it = mAdditionalInstances.begin(); it != mAdditionalInstances.end();) {
154 if (it->version().majorVer == e.getMajorVersion() && it->interface() == e.getInterface() &&
155 it->instance() == e.getInstance()) {
156 minorVer = std::max(minorVer, it->version().minorVer);
157 it = mAdditionalInstances.erase(it);
158 } else {
159 ++it;
160 }
161 }
162
163 FqInstance toAdd;
164 if (!toAdd.setTo(this->getName(), e.getMajorVersion(), minorVer, e.getInterface(),
165 e.getInstance())) {
166 if (error) {
167 *error = "Cannot create FqInstance with package='" + this->getName() + "', version='" +
168 to_string(Version(e.getMajorVersion(), minorVer)) + "', interface='" +
169 e.getInterface() + "', instance='" + e.getInstance() + "'";
170 }
171 return false;
172 }
173
174 mAdditionalInstances.emplace(std::move(toAdd), this->transportArch, this->format);
175 return true;
176 }
177
178 } // namespace vintf
179 } // namespace android
180