Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 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" |
Yifan Hong | 21e3b6e | 2021-01-19 12:34:37 -0800 | [diff] [blame] | 18 | |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 19 | #include <unordered_set> |
| 20 | |
Yifan Hong | 2a90ffe | 2018-03-05 17:45:34 -0800 | [diff] [blame] | 21 | #include "MapValueIterator.h" |
Yifan Hong | 934de62 | 2019-08-30 15:28:59 -0700 | [diff] [blame] | 22 | #include "constants-private.h" |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 23 | #include "parse_string.h" |
Yifan Hong | 21e3b6e | 2021-01-19 12:34:37 -0800 | [diff] [blame] | 24 | #include "utils.h" |
Yifan Hong | 2a90ffe | 2018-03-05 17:45:34 -0800 | [diff] [blame] | 25 | |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 26 | namespace android { |
| 27 | namespace vintf { |
| 28 | |
Yifan Hong | 21e3b6e | 2021-01-19 12:34:37 -0800 | [diff] [blame] | 29 | using details::canConvertToFqInstance; |
| 30 | |
Yifan Hong | 9f9a319 | 2020-04-13 16:39:45 -0700 | [diff] [blame] | 31 | bool ManifestHal::isValid(std::string* error) const { |
| 32 | if (error) { |
| 33 | error->clear(); |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 34 | } |
Yifan Hong | 9f9a319 | 2020-04-13 16:39:45 -0700 | [diff] [blame] | 35 | |
| 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 Hong | 21e3b6e | 2021-01-19 12:34:37 -0800 | [diff] [blame] | 45 | *error += "Duplicated major version: " + to_string(v) + " vs. " + |
| 46 | to_string(it->second) + ".\n"; |
Yifan Hong | 9f9a319 | 2020-04-13 16:39:45 -0700 | [diff] [blame] | 47 | } |
| 48 | } |
Yifan Hong | 21e3b6e | 2021-01-19 12:34:37 -0800 | [diff] [blame] | 49 | |
| 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 Hong | 9f9a319 | 2020-04-13 16:39:45 -0700 | [diff] [blame] | 64 | std::string transportArchError; |
| 65 | if (!transportArch.isValid(&transportArchError)) { |
| 66 | success = false; |
Yifan Hong | 21e3b6e | 2021-01-19 12:34:37 -0800 | [diff] [blame] | 67 | if (error) *error += transportArchError + "\n"; |
Yifan Hong | 9f9a319 | 2020-04-13 16:39:45 -0700 | [diff] [blame] | 68 | } |
| 69 | return success; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 70 | } |
| 71 | |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 72 | bool ManifestHal::operator==(const ManifestHal &other) const { |
Yifan Hong | ba6cb5b | 2020-04-13 14:30:49 -0700 | [diff] [blame] | 73 | // ignore fileName(). |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 74 | if (format != other.format) |
| 75 | return false; |
| 76 | if (name != other.name) |
| 77 | return false; |
| 78 | if (versions != other.versions) |
| 79 | return false; |
Yifan Hong | 3dd2a31 | 2018-03-13 13:48:25 -0700 | [diff] [blame] | 80 | if (!(transportArch == other.transportArch)) return false; |
| 81 | if (interfaces != other.interfaces) return false; |
| 82 | if (isOverride() != other.isOverride()) return false; |
Jooyung Han | 75c3d51 | 2021-03-23 12:33:12 +0900 | [diff] [blame] | 83 | if (updatableViaApex() != other.updatableViaApex()) return false; |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 84 | if (mAdditionalInstances != other.mAdditionalInstances) return false; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 85 | return true; |
| 86 | } |
| 87 | |
Yifan Hong | 2a90ffe | 2018-03-05 17:45:34 -0800 | [diff] [blame] | 88 | bool ManifestHal::forEachInstance(const std::function<bool(const ManifestInstance&)>& func) const { |
Yifan Hong | 2a90ffe | 2018-03-05 17:45:34 -0800 | [diff] [blame] | 89 | for (const auto& v : versions) { |
| 90 | for (const auto& intf : iterateValues(interfaces)) { |
Yifan Hong | 7e9e04d | 2018-03-20 13:06:00 -0700 | [diff] [blame] | 91 | bool cont = intf.forEachInstance([&](const auto& interface, const auto& instance, |
| 92 | bool /* isRegex */) { |
Yifan Hong | 2a90ffe | 2018-03-05 17:45:34 -0800 | [diff] [blame] | 93 | // TODO(b/73556059): Store ManifestInstance as well to avoid creating temps |
| 94 | FqInstance fqInstance; |
Yifan Hong | 7e9e04d | 2018-03-20 13:06:00 -0700 | [diff] [blame] | 95 | if (fqInstance.setTo(getName(), v.majorVer, v.minorVer, interface, instance)) { |
Yifan Hong | f079a3d | 2018-03-19 17:26:53 -0700 | [diff] [blame] | 96 | if (!func(ManifestInstance(std::move(fqInstance), TransportArch{transportArch}, |
Jooyung Han | 75c3d51 | 2021-03-23 12:33:12 +0900 | [diff] [blame] | 97 | format, updatableViaApex()))) { |
Yifan Hong | 2a90ffe | 2018-03-05 17:45:34 -0800 | [diff] [blame] | 98 | return false; |
| 99 | } |
| 100 | } |
Yifan Hong | 7e9e04d | 2018-03-20 13:06:00 -0700 | [diff] [blame] | 101 | return true; |
| 102 | }); |
| 103 | if (!cont) { |
| 104 | return false; |
Yifan Hong | 2a90ffe | 2018-03-05 17:45:34 -0800 | [diff] [blame] | 105 | } |
| 106 | } |
| 107 | } |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 108 | |
| 109 | for (const auto& manifestInstance : mAdditionalInstances) { |
Yifan Hong | af5b43d | 2020-12-17 18:22:27 -0800 | [diff] [blame] | 110 | // 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 Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 123 | } |
| 124 | } |
| 125 | |
Yifan Hong | 2a90ffe | 2018-03-05 17:45:34 -0800 | [diff] [blame] | 126 | return true; |
| 127 | } |
| 128 | |
Yifan Hong | 470144f | 2018-03-13 18:22:34 -0700 | [diff] [blame] | 129 | bool 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 Hong | 075b363 | 2018-03-14 16:03:11 -0700 | [diff] [blame] | 139 | void 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 Hong | 5541069 | 2018-05-01 19:08:51 -0700 | [diff] [blame] | 147 | bool 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 Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 152 | } |
Yifan Hong | 5541069 | 2018-05-01 19:08:51 -0700 | [diff] [blame] | 153 | 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 | |
| 170 | bool ManifestHal::insertInstances(const std::set<FqInstance>& fqInstances, std::string* error) { |
| 171 | for (const FqInstance& e : fqInstances) { |
| 172 | if (!insertInstance(e, error)) { |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 173 | return false; |
| 174 | } |
| 175 | } |
| 176 | return true; |
| 177 | } |
| 178 | |
Yifan Hong | 5541069 | 2018-05-01 19:08:51 -0700 | [diff] [blame] | 179 | bool ManifestHal::insertInstance(const FqInstance& e, std::string* error) { |
| 180 | if (!verifyInstance(e, error)) { |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 181 | return false; |
| 182 | } |
| 183 | |
Yifan Hong | 5541069 | 2018-05-01 19:08:51 -0700 | [diff] [blame] | 184 | 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 Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 192 | } |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 193 | } |
| 194 | |
Yifan Hong | 5541069 | 2018-05-01 19:08:51 -0700 | [diff] [blame] | 195 | 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 Han | 75c3d51 | 2021-03-23 12:33:12 +0900 | [diff] [blame] | 206 | mAdditionalInstances.emplace(std::move(toAdd), this->transportArch, this->format, |
| 207 | this->updatableViaApex()); |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 208 | return true; |
| 209 | } |
| 210 | |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 211 | } // namespace vintf |
| 212 | } // namespace android |