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