blob: a49fc247bf2a3c0ee811c105dcd665ee93913513 [file] [log] [blame]
Yifan Hong3daec812017-02-27 18:49:11 -08001/*
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
Yifan Hong143cfe62017-04-13 20:18:01 -070019#include "CompatibilityMatrix.h"
20#include "parse_xml.h"
Yifan Hong8640cd12017-05-17 12:02:28 -070021#include "utils.h"
Yifan Hong143cfe62017-04-13 20:18:01 -070022
Yifan Hong3daec812017-02-27 18:49:11 -080023#include <functional>
24#include <memory>
25#include <mutex>
26
Bowgo Tsai39adc142017-11-03 12:46:26 +080027#ifdef LIBVINTF_TARGET
28#include <android-base/properties.h>
29#endif
30
Yifan Hong60217032018-01-08 16:19:42 -080031#include <android-base/logging.h>
32
33using std::placeholders::_1;
34using std::placeholders::_2;
35
Yifan Hong3daec812017-02-27 18:49:11 -080036namespace android {
37namespace vintf {
38
39template <typename T>
Yifan Hongfc73edf2017-08-29 11:39:07 -070040struct LockedSharedPtr {
41 std::shared_ptr<T> object;
Yifan Hong3daec812017-02-27 18:49:11 -080042 std::mutex mutex;
Yifan Hong7219ba12018-01-08 16:23:49 -080043 bool fetchedOnce = false;
Yifan Hong3daec812017-02-27 18:49:11 -080044};
45
Yifan Hong1fb004e2017-09-26 15:04:44 -070046struct LockedRuntimeInfoCache {
47 std::shared_ptr<RuntimeInfo> object;
48 std::mutex mutex;
49 RuntimeInfo::FetchFlags fetchedFlags = RuntimeInfo::FetchFlag::NONE;
50};
51
Yifan Hong3daec812017-02-27 18:49:11 -080052template <typename T, typename F>
Yifan Hongfc73edf2017-08-29 11:39:07 -070053static std::shared_ptr<const T> Get(
54 LockedSharedPtr<T> *ptr,
Yifan Hong143cfe62017-04-13 20:18:01 -070055 bool skipCache,
Yifan Hong3daec812017-02-27 18:49:11 -080056 const F &fetchAllInformation) {
57 std::unique_lock<std::mutex> _lock(ptr->mutex);
Yifan Hong7219ba12018-01-08 16:23:49 -080058 if (skipCache || !ptr->fetchedOnce) {
Yifan Hong3daec812017-02-27 18:49:11 -080059 ptr->object = std::make_unique<T>();
Yifan Hong60217032018-01-08 16:19:42 -080060 std::string error;
61 if (fetchAllInformation(ptr->object.get(), &error) != OK) {
62 LOG(WARNING) << error;
Yifan Hong3daec812017-02-27 18:49:11 -080063 ptr->object = nullptr; // frees the old object
64 }
Yifan Hong7219ba12018-01-08 16:23:49 -080065 ptr->fetchedOnce = true;
Yifan Hong3daec812017-02-27 18:49:11 -080066 }
Yifan Hongfc73edf2017-08-29 11:39:07 -070067 return ptr->object;
Yifan Hong3daec812017-02-27 18:49:11 -080068}
69
70// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070071std::shared_ptr<const HalManifest> VintfObject::GetDeviceHalManifest(bool skipCache) {
Steven Moreland648a0012017-10-19 21:23:41 -070072 static LockedSharedPtr<HalManifest> gVendorManifest;
73 static LockedSharedPtr<HalManifest> gOdmManifest;
Bowgo Tsai39adc142017-11-03 12:46:26 +080074#ifdef LIBVINTF_TARGET
75 static LockedSharedPtr<HalManifest> gProductManifest;
76#endif
Steven Moreland648a0012017-10-19 21:23:41 -070077 static std::mutex gDeviceManifestMutex;
78
79 std::unique_lock<std::mutex> _lock(gDeviceManifestMutex);
80
Bowgo Tsai39adc142017-11-03 12:46:26 +080081#ifdef LIBVINTF_TARGET
82 std::string productModel = android::base::GetProperty("ro.product.model", "");
83 if (!productModel.empty()) {
84 auto product = Get(&gProductManifest, skipCache,
Yifan Hong60217032018-01-08 16:19:42 -080085 std::bind(&HalManifest::fetchAllInformation, _1,
86 "/odm/manifest_" + productModel + ".xml", _2));
Bowgo Tsai39adc142017-11-03 12:46:26 +080087 if (product != nullptr) {
88 return product;
89 }
90 }
91#endif
92
Yifan Hong60217032018-01-08 16:19:42 -080093 auto odm = Get(&gOdmManifest, skipCache,
94 std::bind(&HalManifest::fetchAllInformation, _1, "/odm/manifest.xml", _2));
Steven Moreland648a0012017-10-19 21:23:41 -070095 if (odm != nullptr) {
96 return odm;
97 }
98
99 return Get(&gVendorManifest, skipCache,
Yifan Hong60217032018-01-08 16:19:42 -0800100 std::bind(&HalManifest::fetchAllInformation, _1, "/vendor/manifest.xml", _2));
Yifan Hong3daec812017-02-27 18:49:11 -0800101}
102
103// static
Yifan Hongfc73edf2017-08-29 11:39:07 -0700104std::shared_ptr<const HalManifest> VintfObject::GetFrameworkHalManifest(bool skipCache) {
105 static LockedSharedPtr<HalManifest> gFrameworkManifest;
Yifan Hong143cfe62017-04-13 20:18:01 -0700106 return Get(&gFrameworkManifest, skipCache,
Yifan Hong60217032018-01-08 16:19:42 -0800107 std::bind(&HalManifest::fetchAllInformation, _1, "/system/manifest.xml", _2));
Yifan Hong3daec812017-02-27 18:49:11 -0800108}
109
Yifan Hong2272bf82017-04-28 14:37:56 -0700110
111// static
Yifan Hongfc73edf2017-08-29 11:39:07 -0700112std::shared_ptr<const CompatibilityMatrix> VintfObject::GetDeviceCompatibilityMatrix(bool skipCache) {
113 static LockedSharedPtr<CompatibilityMatrix> gDeviceMatrix;
Yifan Hong2272bf82017-04-28 14:37:56 -0700114 return Get(&gDeviceMatrix, skipCache,
Yifan Hong60217032018-01-08 16:19:42 -0800115 std::bind(&CompatibilityMatrix::fetchAllInformation, _1,
116 "/vendor/compatibility_matrix.xml", _2));
Yifan Hong2272bf82017-04-28 14:37:56 -0700117}
118
119// static
Yifan Hongfc73edf2017-08-29 11:39:07 -0700120std::shared_ptr<const CompatibilityMatrix> VintfObject::GetFrameworkCompatibilityMatrix(bool skipCache) {
121 static LockedSharedPtr<CompatibilityMatrix> gFrameworkMatrix;
Yifan Hong2272bf82017-04-28 14:37:56 -0700122 return Get(&gFrameworkMatrix, skipCache,
Yifan Hong60217032018-01-08 16:19:42 -0800123 std::bind(&CompatibilityMatrix::fetchAllInformation, _1,
124 "/system/compatibility_matrix.xml", _2));
Yifan Hong2272bf82017-04-28 14:37:56 -0700125}
126
Yifan Hong3daec812017-02-27 18:49:11 -0800127// static
Yifan Hong1fb004e2017-09-26 15:04:44 -0700128std::shared_ptr<const RuntimeInfo> VintfObject::GetRuntimeInfo(bool skipCache,
129 RuntimeInfo::FetchFlags flags) {
130 static LockedRuntimeInfoCache gDeviceRuntimeInfo;
131 std::unique_lock<std::mutex> _lock(gDeviceRuntimeInfo.mutex);
132
133 if (!skipCache) {
134 flags &= (~gDeviceRuntimeInfo.fetchedFlags);
135 }
136
137 if (gDeviceRuntimeInfo.object == nullptr) {
Yifan Hong29bb2d42017-09-27 13:28:00 -0700138 gDeviceRuntimeInfo.object = details::gRuntimeInfoFactory->make_shared();
Yifan Hong1fb004e2017-09-26 15:04:44 -0700139 }
140
141 status_t status = gDeviceRuntimeInfo.object->fetchAllInformation(flags);
142 if (status != OK) {
143 gDeviceRuntimeInfo.fetchedFlags &= (~flags); // mark the fields as "not fetched"
144 return nullptr;
145 }
146
147 gDeviceRuntimeInfo.fetchedFlags |= flags;
148 return gDeviceRuntimeInfo.object;
Yifan Hong3daec812017-02-27 18:49:11 -0800149}
150
Yifan Hong143cfe62017-04-13 20:18:01 -0700151namespace details {
152
Yifan Hong143cfe62017-04-13 20:18:01 -0700153enum class ParseStatus {
154 OK,
155 PARSE_ERROR,
156 DUPLICATED_FWK_ENTRY,
157 DUPLICATED_DEV_ENTRY,
158};
159
Yifan Hong9532bd22017-04-14 15:30:52 -0700160static std::string toString(ParseStatus status) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700161 switch(status) {
162 case ParseStatus::OK: return "OK";
163 case ParseStatus::PARSE_ERROR: return "parse error";
164 case ParseStatus::DUPLICATED_FWK_ENTRY: return "duplicated framework";
165 case ParseStatus::DUPLICATED_DEV_ENTRY: return "duplicated device";
166 }
167 return "";
168}
169
170template<typename T>
Yifan Hong9532bd22017-04-14 15:30:52 -0700171static ParseStatus tryParse(const std::string &xml, const XmlConverter<T> &parse,
Yifan Hongfc73edf2017-08-29 11:39:07 -0700172 std::shared_ptr<T> *fwk, std::shared_ptr<T> *dev) {
173 std::shared_ptr<T> ret = std::make_shared<T>();
Yifan Hong143cfe62017-04-13 20:18:01 -0700174 if (!parse(ret.get(), xml)) {
175 return ParseStatus::PARSE_ERROR;
176 }
177 if (ret->type() == SchemaType::FRAMEWORK) {
178 if (fwk->get() != nullptr) {
179 return ParseStatus::DUPLICATED_FWK_ENTRY;
180 }
181 *fwk = std::move(ret);
182 } else if (ret->type() == SchemaType::DEVICE) {
183 if (dev->get() != nullptr) {
184 return ParseStatus::DUPLICATED_DEV_ENTRY;
185 }
186 *dev = std::move(ret);
187 }
188 return ParseStatus::OK;
189}
190
191template<typename T, typename GetFunction>
Yifan Hongfc73edf2017-08-29 11:39:07 -0700192static status_t getMissing(const std::shared_ptr<T>& pkg, bool mount,
Yifan Hong143cfe62017-04-13 20:18:01 -0700193 std::function<status_t(void)> mountFunction,
Yifan Hongfc73edf2017-08-29 11:39:07 -0700194 std::shared_ptr<const T>* updated,
Yifan Hong143cfe62017-04-13 20:18:01 -0700195 GetFunction getFunction) {
196 if (pkg != nullptr) {
197 *updated = pkg;
198 } else {
199 if (mount) {
200 (void)mountFunction(); // ignore mount errors
201 }
202 *updated = getFunction();
203 }
204 return OK;
205}
206
207#define ADD_MESSAGE(__error__) \
208 if (error != nullptr) { \
209 *error += (__error__); \
210 } \
211
212struct PackageInfo {
213 struct Pair {
Yifan Hongfc73edf2017-08-29 11:39:07 -0700214 std::shared_ptr<HalManifest> manifest;
215 std::shared_ptr<CompatibilityMatrix> matrix;
Yifan Hong143cfe62017-04-13 20:18:01 -0700216 };
217 Pair dev;
218 Pair fwk;
219};
220
221struct UpdatedInfo {
222 struct Pair {
Yifan Hongfc73edf2017-08-29 11:39:07 -0700223 std::shared_ptr<const HalManifest> manifest;
224 std::shared_ptr<const CompatibilityMatrix> matrix;
Yifan Hong143cfe62017-04-13 20:18:01 -0700225 };
226 Pair dev;
227 Pair fwk;
Yifan Hongfc73edf2017-08-29 11:39:07 -0700228 std::shared_ptr<const RuntimeInfo> runtimeInfo;
Yifan Hong143cfe62017-04-13 20:18:01 -0700229};
230
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700231// Checks given compatibility info against info on the device. If no
232// compatability info is given then the device info will be checked against
233// itself.
Yifan Hongdb6423e2017-09-11 14:38:46 -0700234int32_t checkCompatibility(const std::vector<std::string>& xmls, bool mount,
235 const PartitionMounter& mounter, std::string* error,
236 DisabledChecks disabledChecks) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700237 status_t status;
238 ParseStatus parseStatus;
239 PackageInfo pkg; // All information from package.
240 UpdatedInfo updated; // All files and runtime info after the update.
241
Yifan Hong143cfe62017-04-13 20:18:01 -0700242 // parse all information from package
243 for (const auto &xml : xmls) {
244 parseStatus = tryParse(xml, gHalManifestConverter, &pkg.fwk.manifest, &pkg.dev.manifest);
245 if (parseStatus == ParseStatus::OK) {
246 continue; // work on next one
247 }
248 if (parseStatus != ParseStatus::PARSE_ERROR) {
249 ADD_MESSAGE(toString(parseStatus) + " manifest");
250 return ALREADY_EXISTS;
251 }
252 parseStatus = tryParse(xml, gCompatibilityMatrixConverter, &pkg.fwk.matrix, &pkg.dev.matrix);
253 if (parseStatus == ParseStatus::OK) {
254 continue; // work on next one
255 }
256 if (parseStatus != ParseStatus::PARSE_ERROR) {
257 ADD_MESSAGE(toString(parseStatus) + " matrix");
258 return ALREADY_EXISTS;
259 }
260 ADD_MESSAGE(toString(parseStatus)); // parse error
261 return BAD_VALUE;
262 }
263
264 // get missing info from device
Yifan Hong8640cd12017-05-17 12:02:28 -0700265 // use functions instead of std::bind because std::bind doesn't work well with mock objects
266 auto mountSystem = [&mounter] { return mounter.mountSystem(); };
267 auto mountVendor = [&mounter] { return mounter.mountVendor(); };
268 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700269 pkg.fwk.manifest, mount, mountSystem, &updated.fwk.manifest,
Yifan Hong8640cd12017-05-17 12:02:28 -0700270 std::bind(VintfObject::GetFrameworkHalManifest, true /* skipCache */))) != OK) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700271 return status;
272 }
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700273 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700274 pkg.dev.manifest, mount, mountVendor, &updated.dev.manifest,
Yifan Hong8640cd12017-05-17 12:02:28 -0700275 std::bind(VintfObject::GetDeviceHalManifest, true /* skipCache */))) != OK) {
276 return status;
277 }
278 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700279 pkg.fwk.matrix, mount, mountSystem, &updated.fwk.matrix,
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700280 std::bind(VintfObject::GetFrameworkCompatibilityMatrix, true /* skipCache */))) !=
281 OK) {
282 return status;
283 }
284 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700285 pkg.dev.matrix, mount, mountVendor, &updated.dev.matrix,
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700286 std::bind(VintfObject::GetDeviceCompatibilityMatrix, true /* skipCache */))) != OK) {
287 return status;
288 }
Yifan Hong8640cd12017-05-17 12:02:28 -0700289
290 if (mount) {
291 (void)mounter.umountSystem(); // ignore errors
292 (void)mounter.umountVendor(); // ignore errors
293 }
294
295 updated.runtimeInfo = VintfObject::GetRuntimeInfo(true /* skipCache */);
Yifan Hong143cfe62017-04-13 20:18:01 -0700296
297 // null checks for files and runtime info after the update
298 // TODO(b/37321309) if a compat mat is missing, it is not matched and considered compatible.
299 if (updated.fwk.manifest == nullptr) {
300 ADD_MESSAGE("No framework manifest file from device or from update package");
301 return NO_INIT;
302 }
303 if (updated.dev.manifest == nullptr) {
304 ADD_MESSAGE("No device manifest file from device or from update package");
305 return NO_INIT;
306 }
307 if (updated.fwk.matrix == nullptr) {
308 ADD_MESSAGE("No framework matrix, skipping;");
309 // TODO(b/37321309) consider missing matricies as errors.
310 }
311 if (updated.dev.matrix == nullptr) {
312 ADD_MESSAGE("No device matrix, skipping;");
313 // TODO(b/37321309) consider missing matricies as errors.
314 }
315 if (updated.runtimeInfo == nullptr) {
316 ADD_MESSAGE("No runtime info from device");
317 return NO_INIT;
318 }
319
320 // compatiblity check.
321 // TODO(b/37321309) outer if checks can be removed if we consider missing matrices as errors.
322 if (updated.dev.manifest && updated.fwk.matrix) {
323 if (!updated.dev.manifest->checkCompatibility(*updated.fwk.matrix, error)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700324 if (error)
325 error->insert(0, "Device manifest and framework compatibility matrix "
326 "are incompatible: ");
Yifan Hong143cfe62017-04-13 20:18:01 -0700327 return INCOMPATIBLE;
328 }
329 }
330 if (updated.fwk.manifest && updated.dev.matrix) {
331 if (!updated.fwk.manifest->checkCompatibility(*updated.dev.matrix, error)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700332 if (error)
333 error->insert(0, "Framework manifest and device compatibility matrix "
334 "are incompatible: ");
Yifan Hong143cfe62017-04-13 20:18:01 -0700335 return INCOMPATIBLE;
336 }
337 }
338 if (updated.runtimeInfo && updated.fwk.matrix) {
Yifan Hongdb6423e2017-09-11 14:38:46 -0700339 if (!updated.runtimeInfo->checkCompatibility(*updated.fwk.matrix, error, disabledChecks)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700340 if (error)
341 error->insert(0, "Runtime info and framework compatibility matrix "
342 "are incompatible: ");
Yifan Honge8b86842017-05-25 17:59:22 +0000343 return INCOMPATIBLE;
Yifan Hong143cfe62017-04-13 20:18:01 -0700344 }
345 }
346
347 return COMPATIBLE;
348}
349
350} // namespace details
351
Yifan Hongfbbf0472017-04-07 18:14:18 -0700352// static
Yifan Hongdb6423e2017-09-11 14:38:46 -0700353int32_t VintfObject::CheckCompatibility(const std::vector<std::string>& xmls, std::string* error,
354 DisabledChecks disabledChecks) {
355 return details::checkCompatibility(xmls, false /* mount */, *details::gPartitionMounter, error,
356 disabledChecks);
Yifan Hongfbbf0472017-04-07 18:14:18 -0700357}
358
Yifan Hong3daec812017-02-27 18:49:11 -0800359
360} // namespace vintf
361} // namespace android