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