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 19 #include <unordered_set> 20 21 #include "MapValueIterator.h" 22 #include "constants-private.h" 23 #include "parse_string.h" 24 #include "utils.h" 25 26 namespace android { 27 namespace vintf { 28 29 using details::canConvertToFqInstance; 30 31 bool ManifestHal::isValid(std::string* error) const { 32 if (error) { 33 error->clear(); 34 } 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) { 45 *error += "Duplicated major version: " + to_string(v) + " vs. " + 46 to_string(it->second) + ".\n"; 47 } 48 } 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 64 std::string transportArchError; 65 if (!transportArch.isValid(&transportArchError)) { 66 success = false; 67 if (error) *error += transportArchError + "\n"; 68 } 69 return success; 70 } 71 72 bool ManifestHal::operator==(const ManifestHal &other) const { 73 // ignore fileName(). 74 if (format != other.format) 75 return false; 76 if (name != other.name) 77 return false; 78 if (versions != other.versions) 79 return false; 80 if (!(transportArch == other.transportArch)) return false; 81 if (interfaces != other.interfaces) return false; 82 if (isOverride() != other.isOverride()) return false; 83 if (updatableViaApex() != other.updatableViaApex()) return false; 84 if (mAdditionalInstances != other.mAdditionalInstances) return false; 85 return true; 86 } 87 88 bool ManifestHal::forEachInstance(const std::function<bool(const ManifestInstance&)>& func) const { 89 for (const auto& v : versions) { 90 for (const auto& intf : iterateValues(interfaces)) { 91 bool cont = intf.forEachInstance([&](const auto& interface, const auto& instance, 92 bool /* isRegex */) { 93 // TODO(b/73556059): Store ManifestInstance as well to avoid creating temps 94 FqInstance fqInstance; 95 if (fqInstance.setTo(getName(), v.majorVer, v.minorVer, interface, instance)) { 96 if (!func(ManifestInstance(std::move(fqInstance), TransportArch{transportArch}, 97 format, updatableViaApex()))) { 98 return false; 99 } 100 } 101 return true; 102 }); 103 if (!cont) { 104 return false; 105 } 106 } 107 } 108 109 for (const auto& manifestInstance : mAdditionalInstances) { 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 } 123 } 124 } 125 126 return true; 127 } 128 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 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 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(); 152 } 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)) { 173 return false; 174 } 175 } 176 return true; 177 } 178 179 bool ManifestHal::insertInstance(const FqInstance& e, std::string* error) { 180 if (!verifyInstance(e, error)) { 181 return false; 182 } 183 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; 192 } 193 } 194 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 206 mAdditionalInstances.emplace(std::move(toAdd), this->transportArch, this->format, 207 this->updatableViaApex()); 208 return true; 209 } 210 211 } // namespace vintf 212 } // namespace android 213