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 "VintfObject.h" 18 19#include "CompatibilityMatrix.h" 20#include "parse_xml.h" 21#include "utils.h" 22 23#include <functional> 24#include <memory> 25#include <mutex> 26 27namespace android { 28namespace vintf { 29 30template <typename T> 31struct LockedUniquePtr { 32 std::unique_ptr<T> object; 33 std::mutex mutex; 34}; 35 36static LockedUniquePtr<HalManifest> gDeviceManifest; 37static LockedUniquePtr<HalManifest> gFrameworkManifest; 38static LockedUniquePtr<CompatibilityMatrix> gDeviceMatrix; 39static LockedUniquePtr<CompatibilityMatrix> gFrameworkMatrix; 40static LockedUniquePtr<RuntimeInfo> gDeviceRuntimeInfo; 41 42template <typename T, typename F> 43static const T *Get( 44 LockedUniquePtr<T> *ptr, 45 bool skipCache, 46 const F &fetchAllInformation) { 47 std::unique_lock<std::mutex> _lock(ptr->mutex); 48 if (skipCache || ptr->object == nullptr) { 49 ptr->object = std::make_unique<T>(); 50 if (fetchAllInformation(ptr->object.get()) != OK) { 51 ptr->object = nullptr; // frees the old object 52 } 53 } 54 return ptr->object.get(); 55} 56 57// static 58const HalManifest *VintfObject::GetDeviceHalManifest(bool skipCache) { 59 return Get(&gDeviceManifest, skipCache, 60 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1, 61 "/vendor/manifest.xml")); 62} 63 64// static 65const HalManifest *VintfObject::GetFrameworkHalManifest(bool skipCache) { 66 return Get(&gFrameworkManifest, skipCache, 67 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1, 68 "/system/manifest.xml")); 69} 70 71 72// static 73const CompatibilityMatrix *VintfObject::GetDeviceCompatibilityMatrix(bool skipCache) { 74 return Get(&gDeviceMatrix, skipCache, 75 std::bind(&CompatibilityMatrix::fetchAllInformation, std::placeholders::_1, 76 "/vendor/compatibility_matrix.xml")); 77} 78 79// static 80const CompatibilityMatrix *VintfObject::GetFrameworkCompatibilityMatrix(bool skipCache) { 81 return Get(&gFrameworkMatrix, skipCache, 82 std::bind(&CompatibilityMatrix::fetchAllInformation, std::placeholders::_1, 83 "/system/compatibility_matrix.xml")); 84} 85 86// static 87const RuntimeInfo *VintfObject::GetRuntimeInfo(bool skipCache) { 88 return Get(&gDeviceRuntimeInfo, skipCache, 89 std::bind(&RuntimeInfo::fetchAllInformation, std::placeholders::_1)); 90} 91 92namespace details { 93 94enum class ParseStatus { 95 OK, 96 PARSE_ERROR, 97 DUPLICATED_FWK_ENTRY, 98 DUPLICATED_DEV_ENTRY, 99}; 100 101static std::string toString(ParseStatus status) { 102 switch(status) { 103 case ParseStatus::OK: return "OK"; 104 case ParseStatus::PARSE_ERROR: return "parse error"; 105 case ParseStatus::DUPLICATED_FWK_ENTRY: return "duplicated framework"; 106 case ParseStatus::DUPLICATED_DEV_ENTRY: return "duplicated device"; 107 } 108 return ""; 109} 110 111template<typename T> 112static ParseStatus tryParse(const std::string &xml, const XmlConverter<T> &parse, 113 std::unique_ptr<T> *fwk, std::unique_ptr<T> *dev) { 114 std::unique_ptr<T> ret = std::make_unique<T>(); 115 if (!parse(ret.get(), xml)) { 116 return ParseStatus::PARSE_ERROR; 117 } 118 if (ret->type() == SchemaType::FRAMEWORK) { 119 if (fwk->get() != nullptr) { 120 return ParseStatus::DUPLICATED_FWK_ENTRY; 121 } 122 *fwk = std::move(ret); 123 } else if (ret->type() == SchemaType::DEVICE) { 124 if (dev->get() != nullptr) { 125 return ParseStatus::DUPLICATED_DEV_ENTRY; 126 } 127 *dev = std::move(ret); 128 } 129 return ParseStatus::OK; 130} 131 132template<typename T, typename GetFunction> 133static status_t getMissing(const T *pkg, bool mount, 134 std::function<status_t(void)> mountFunction, 135 const T **updated, 136 GetFunction getFunction) { 137 if (pkg != nullptr) { 138 *updated = pkg; 139 } else { 140 if (mount) { 141 (void)mountFunction(); // ignore mount errors 142 } 143 *updated = getFunction(); 144 } 145 return OK; 146} 147 148#define ADD_MESSAGE(__error__) \ 149 if (error != nullptr) { \ 150 *error += (__error__); \ 151 } \ 152 153struct PackageInfo { 154 struct Pair { 155 std::unique_ptr<HalManifest> manifest; 156 std::unique_ptr<CompatibilityMatrix> matrix; 157 }; 158 Pair dev; 159 Pair fwk; 160}; 161 162struct UpdatedInfo { 163 struct Pair { 164 const HalManifest *manifest; 165 const CompatibilityMatrix *matrix; 166 }; 167 Pair dev; 168 Pair fwk; 169 const RuntimeInfo *runtimeInfo; 170}; 171 172// Checks given compatibility info against info on the device. If no 173// compatability info is given then the device info will be checked against 174// itself. 175int32_t checkCompatibility(const std::vector<std::string> &xmls, bool mount, 176 const PartitionMounter &mounter, std::string *error) { 177 178 status_t status; 179 ParseStatus parseStatus; 180 PackageInfo pkg; // All information from package. 181 UpdatedInfo updated; // All files and runtime info after the update. 182 183 // parse all information from package 184 for (const auto &xml : xmls) { 185 parseStatus = tryParse(xml, gHalManifestConverter, &pkg.fwk.manifest, &pkg.dev.manifest); 186 if (parseStatus == ParseStatus::OK) { 187 continue; // work on next one 188 } 189 if (parseStatus != ParseStatus::PARSE_ERROR) { 190 ADD_MESSAGE(toString(parseStatus) + " manifest"); 191 return ALREADY_EXISTS; 192 } 193 parseStatus = tryParse(xml, gCompatibilityMatrixConverter, &pkg.fwk.matrix, &pkg.dev.matrix); 194 if (parseStatus == ParseStatus::OK) { 195 continue; // work on next one 196 } 197 if (parseStatus != ParseStatus::PARSE_ERROR) { 198 ADD_MESSAGE(toString(parseStatus) + " matrix"); 199 return ALREADY_EXISTS; 200 } 201 ADD_MESSAGE(toString(parseStatus)); // parse error 202 return BAD_VALUE; 203 } 204 205 // get missing info from device 206 // use functions instead of std::bind because std::bind doesn't work well with mock objects 207 auto mountSystem = [&mounter] { return mounter.mountSystem(); }; 208 auto mountVendor = [&mounter] { return mounter.mountVendor(); }; 209 if ((status = getMissing( 210 pkg.fwk.manifest.get(), mount, mountSystem, &updated.fwk.manifest, 211 std::bind(VintfObject::GetFrameworkHalManifest, true /* skipCache */))) != OK) { 212 return status; 213 } 214 if ((status = getMissing( 215 pkg.dev.manifest.get(), mount, mountVendor, &updated.dev.manifest, 216 std::bind(VintfObject::GetDeviceHalManifest, true /* skipCache */))) != OK) { 217 return status; 218 } 219 if ((status = getMissing( 220 pkg.fwk.matrix.get(), mount, mountSystem, &updated.fwk.matrix, 221 std::bind(VintfObject::GetFrameworkCompatibilityMatrix, true /* skipCache */))) != 222 OK) { 223 return status; 224 } 225 if ((status = getMissing( 226 pkg.dev.matrix.get(), mount, mountVendor, &updated.dev.matrix, 227 std::bind(VintfObject::GetDeviceCompatibilityMatrix, true /* skipCache */))) != OK) { 228 return status; 229 } 230 231 if (mount) { 232 (void)mounter.umountSystem(); // ignore errors 233 (void)mounter.umountVendor(); // ignore errors 234 } 235 236 updated.runtimeInfo = VintfObject::GetRuntimeInfo(true /* skipCache */); 237 238 // null checks for files and runtime info after the update 239 // TODO(b/37321309) if a compat mat is missing, it is not matched and considered compatible. 240 if (updated.fwk.manifest == nullptr) { 241 ADD_MESSAGE("No framework manifest file from device or from update package"); 242 return NO_INIT; 243 } 244 if (updated.dev.manifest == nullptr) { 245 ADD_MESSAGE("No device manifest file from device or from update package"); 246 return NO_INIT; 247 } 248 if (updated.fwk.matrix == nullptr) { 249 ADD_MESSAGE("No framework matrix, skipping;"); 250 // TODO(b/37321309) consider missing matricies as errors. 251 } 252 if (updated.dev.matrix == nullptr) { 253 ADD_MESSAGE("No device matrix, skipping;"); 254 // TODO(b/37321309) consider missing matricies as errors. 255 } 256 if (updated.runtimeInfo == nullptr) { 257 ADD_MESSAGE("No runtime info from device"); 258 return NO_INIT; 259 } 260 261 // compatiblity check. 262 // TODO(b/37321309) outer if checks can be removed if we consider missing matrices as errors. 263 if (updated.dev.manifest && updated.fwk.matrix) { 264 if (!updated.dev.manifest->checkCompatibility(*updated.fwk.matrix, error)) { 265 if (error) 266 error->insert(0, "Device manifest and framework compatibility matrix " 267 "are incompatible: "); 268 return INCOMPATIBLE; 269 } 270 } 271 if (updated.fwk.manifest && updated.dev.matrix) { 272 if (!updated.fwk.manifest->checkCompatibility(*updated.dev.matrix, error)) { 273 if (error) 274 error->insert(0, "Framework manifest and device compatibility matrix " 275 "are incompatible: "); 276 return INCOMPATIBLE; 277 } 278 } 279 if (updated.runtimeInfo && updated.fwk.matrix) { 280 if (!updated.runtimeInfo->checkCompatibility(*updated.fwk.matrix, error)) { 281 if (error) 282 error->insert(0, "Runtime info and framework compatibility matrix " 283 "are incompatible: "); 284 return INCOMPATIBLE; 285 } 286 } 287 288 return COMPATIBLE; 289} 290 291} // namespace details 292 293// static 294int32_t VintfObject::CheckCompatibility( 295 const std::vector<std::string> &xmls, std::string *error) { 296 return details::checkCompatibility(xmls, false /* mount */, 297 *details::gPartitionMounter, 298 error); 299} 300 301 302} // namespace vintf 303} // namespace android 304