blob: bfceae898718c0c1ff246b64b7e99a9787760383 [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 Hong3daec812017-02-27 18:49:11 -080031namespace android {
32namespace vintf {
33
34template <typename T>
Yifan Hongfc73edf2017-08-29 11:39:07 -070035struct LockedSharedPtr {
36 std::shared_ptr<T> object;
Yifan Hong3daec812017-02-27 18:49:11 -080037 std::mutex mutex;
Yifan Hong7219ba12018-01-08 16:23:49 -080038 bool fetchedOnce = false;
Yifan Hong3daec812017-02-27 18:49:11 -080039};
40
Yifan Hong1fb004e2017-09-26 15:04:44 -070041struct LockedRuntimeInfoCache {
42 std::shared_ptr<RuntimeInfo> object;
43 std::mutex mutex;
44 RuntimeInfo::FetchFlags fetchedFlags = RuntimeInfo::FetchFlag::NONE;
45};
46
Yifan Hong3daec812017-02-27 18:49:11 -080047template <typename T, typename F>
Yifan Hongfc73edf2017-08-29 11:39:07 -070048static std::shared_ptr<const T> Get(
49 LockedSharedPtr<T> *ptr,
Yifan Hong143cfe62017-04-13 20:18:01 -070050 bool skipCache,
Yifan Hong3daec812017-02-27 18:49:11 -080051 const F &fetchAllInformation) {
52 std::unique_lock<std::mutex> _lock(ptr->mutex);
Yifan Hong7219ba12018-01-08 16:23:49 -080053 if (skipCache || !ptr->fetchedOnce) {
Yifan Hong3daec812017-02-27 18:49:11 -080054 ptr->object = std::make_unique<T>();
55 if (fetchAllInformation(ptr->object.get()) != OK) {
56 ptr->object = nullptr; // frees the old object
57 }
Yifan Hong7219ba12018-01-08 16:23:49 -080058 ptr->fetchedOnce = true;
Yifan Hong3daec812017-02-27 18:49:11 -080059 }
Yifan Hongfc73edf2017-08-29 11:39:07 -070060 return ptr->object;
Yifan Hong3daec812017-02-27 18:49:11 -080061}
62
63// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070064std::shared_ptr<const HalManifest> VintfObject::GetDeviceHalManifest(bool skipCache) {
Steven Moreland648a0012017-10-19 21:23:41 -070065 static LockedSharedPtr<HalManifest> gVendorManifest;
66 static LockedSharedPtr<HalManifest> gOdmManifest;
Bowgo Tsai39adc142017-11-03 12:46:26 +080067#ifdef LIBVINTF_TARGET
68 static LockedSharedPtr<HalManifest> gProductManifest;
69#endif
Steven Moreland648a0012017-10-19 21:23:41 -070070 static std::mutex gDeviceManifestMutex;
71
72 std::unique_lock<std::mutex> _lock(gDeviceManifestMutex);
73
Bowgo Tsai39adc142017-11-03 12:46:26 +080074#ifdef LIBVINTF_TARGET
75 std::string productModel = android::base::GetProperty("ro.product.model", "");
76 if (!productModel.empty()) {
77 auto product = Get(&gProductManifest, skipCache,
78 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1,
79 "/odm/manifest_" + productModel + ".xml"));
80 if (product != nullptr) {
81 return product;
82 }
83 }
84#endif
85
Steven Moreland648a0012017-10-19 21:23:41 -070086 auto odm = Get(
87 &gOdmManifest, skipCache,
88 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1, "/odm/manifest.xml"));
89 if (odm != nullptr) {
90 return odm;
91 }
92
93 return Get(&gVendorManifest, skipCache,
94 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1,
95 "/vendor/manifest.xml"));
Yifan Hong3daec812017-02-27 18:49:11 -080096}
97
98// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070099std::shared_ptr<const HalManifest> VintfObject::GetFrameworkHalManifest(bool skipCache) {
100 static LockedSharedPtr<HalManifest> gFrameworkManifest;
Yifan Hong143cfe62017-04-13 20:18:01 -0700101 return Get(&gFrameworkManifest, skipCache,
Yifan Hong3daec812017-02-27 18:49:11 -0800102 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1,
103 "/system/manifest.xml"));
104}
105
Yifan Hong2272bf82017-04-28 14:37:56 -0700106
107// static
Yifan Hongfc73edf2017-08-29 11:39:07 -0700108std::shared_ptr<const CompatibilityMatrix> VintfObject::GetDeviceCompatibilityMatrix(bool skipCache) {
109 static LockedSharedPtr<CompatibilityMatrix> gDeviceMatrix;
Yifan Hong2272bf82017-04-28 14:37:56 -0700110 return Get(&gDeviceMatrix, skipCache,
111 std::bind(&CompatibilityMatrix::fetchAllInformation, std::placeholders::_1,
112 "/vendor/compatibility_matrix.xml"));
113}
114
115// static
Yifan Hongfc73edf2017-08-29 11:39:07 -0700116std::shared_ptr<const CompatibilityMatrix> VintfObject::GetFrameworkCompatibilityMatrix(bool skipCache) {
117 static LockedSharedPtr<CompatibilityMatrix> gFrameworkMatrix;
Yifan Hong2272bf82017-04-28 14:37:56 -0700118 return Get(&gFrameworkMatrix, skipCache,
119 std::bind(&CompatibilityMatrix::fetchAllInformation, std::placeholders::_1,
120 "/system/compatibility_matrix.xml"));
121}
122
Yifan Hong3daec812017-02-27 18:49:11 -0800123// static
Yifan Hong1fb004e2017-09-26 15:04:44 -0700124std::shared_ptr<const RuntimeInfo> VintfObject::GetRuntimeInfo(bool skipCache,
125 RuntimeInfo::FetchFlags flags) {
126 static LockedRuntimeInfoCache gDeviceRuntimeInfo;
127 std::unique_lock<std::mutex> _lock(gDeviceRuntimeInfo.mutex);
128
129 if (!skipCache) {
130 flags &= (~gDeviceRuntimeInfo.fetchedFlags);
131 }
132
133 if (gDeviceRuntimeInfo.object == nullptr) {
Yifan Hong29bb2d42017-09-27 13:28:00 -0700134 gDeviceRuntimeInfo.object = details::gRuntimeInfoFactory->make_shared();
Yifan Hong1fb004e2017-09-26 15:04:44 -0700135 }
136
137 status_t status = gDeviceRuntimeInfo.object->fetchAllInformation(flags);
138 if (status != OK) {
139 gDeviceRuntimeInfo.fetchedFlags &= (~flags); // mark the fields as "not fetched"
140 return nullptr;
141 }
142
143 gDeviceRuntimeInfo.fetchedFlags |= flags;
144 return gDeviceRuntimeInfo.object;
Yifan Hong3daec812017-02-27 18:49:11 -0800145}
146
Yifan Hong143cfe62017-04-13 20:18:01 -0700147namespace details {
148
Yifan Hong143cfe62017-04-13 20:18:01 -0700149enum class ParseStatus {
150 OK,
151 PARSE_ERROR,
152 DUPLICATED_FWK_ENTRY,
153 DUPLICATED_DEV_ENTRY,
154};
155
Yifan Hong9532bd22017-04-14 15:30:52 -0700156static std::string toString(ParseStatus status) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700157 switch(status) {
158 case ParseStatus::OK: return "OK";
159 case ParseStatus::PARSE_ERROR: return "parse error";
160 case ParseStatus::DUPLICATED_FWK_ENTRY: return "duplicated framework";
161 case ParseStatus::DUPLICATED_DEV_ENTRY: return "duplicated device";
162 }
163 return "";
164}
165
166template<typename T>
Yifan Hong9532bd22017-04-14 15:30:52 -0700167static ParseStatus tryParse(const std::string &xml, const XmlConverter<T> &parse,
Yifan Hongfc73edf2017-08-29 11:39:07 -0700168 std::shared_ptr<T> *fwk, std::shared_ptr<T> *dev) {
169 std::shared_ptr<T> ret = std::make_shared<T>();
Yifan Hong143cfe62017-04-13 20:18:01 -0700170 if (!parse(ret.get(), xml)) {
171 return ParseStatus::PARSE_ERROR;
172 }
173 if (ret->type() == SchemaType::FRAMEWORK) {
174 if (fwk->get() != nullptr) {
175 return ParseStatus::DUPLICATED_FWK_ENTRY;
176 }
177 *fwk = std::move(ret);
178 } else if (ret->type() == SchemaType::DEVICE) {
179 if (dev->get() != nullptr) {
180 return ParseStatus::DUPLICATED_DEV_ENTRY;
181 }
182 *dev = std::move(ret);
183 }
184 return ParseStatus::OK;
185}
186
187template<typename T, typename GetFunction>
Yifan Hongfc73edf2017-08-29 11:39:07 -0700188static status_t getMissing(const std::shared_ptr<T>& pkg, bool mount,
Yifan Hong143cfe62017-04-13 20:18:01 -0700189 std::function<status_t(void)> mountFunction,
Yifan Hongfc73edf2017-08-29 11:39:07 -0700190 std::shared_ptr<const T>* updated,
Yifan Hong143cfe62017-04-13 20:18:01 -0700191 GetFunction getFunction) {
192 if (pkg != nullptr) {
193 *updated = pkg;
194 } else {
195 if (mount) {
196 (void)mountFunction(); // ignore mount errors
197 }
198 *updated = getFunction();
199 }
200 return OK;
201}
202
203#define ADD_MESSAGE(__error__) \
204 if (error != nullptr) { \
205 *error += (__error__); \
206 } \
207
208struct PackageInfo {
209 struct Pair {
Yifan Hongfc73edf2017-08-29 11:39:07 -0700210 std::shared_ptr<HalManifest> manifest;
211 std::shared_ptr<CompatibilityMatrix> matrix;
Yifan Hong143cfe62017-04-13 20:18:01 -0700212 };
213 Pair dev;
214 Pair fwk;
215};
216
217struct UpdatedInfo {
218 struct Pair {
Yifan Hongfc73edf2017-08-29 11:39:07 -0700219 std::shared_ptr<const HalManifest> manifest;
220 std::shared_ptr<const CompatibilityMatrix> matrix;
Yifan Hong143cfe62017-04-13 20:18:01 -0700221 };
222 Pair dev;
223 Pair fwk;
Yifan Hongfc73edf2017-08-29 11:39:07 -0700224 std::shared_ptr<const RuntimeInfo> runtimeInfo;
Yifan Hong143cfe62017-04-13 20:18:01 -0700225};
226
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700227// Checks given compatibility info against info on the device. If no
228// compatability info is given then the device info will be checked against
229// itself.
Yifan Hongdb6423e2017-09-11 14:38:46 -0700230int32_t checkCompatibility(const std::vector<std::string>& xmls, bool mount,
231 const PartitionMounter& mounter, std::string* error,
232 DisabledChecks disabledChecks) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700233 status_t status;
234 ParseStatus parseStatus;
235 PackageInfo pkg; // All information from package.
236 UpdatedInfo updated; // All files and runtime info after the update.
237
Yifan Hong143cfe62017-04-13 20:18:01 -0700238 // parse all information from package
239 for (const auto &xml : xmls) {
240 parseStatus = tryParse(xml, gHalManifestConverter, &pkg.fwk.manifest, &pkg.dev.manifest);
241 if (parseStatus == ParseStatus::OK) {
242 continue; // work on next one
243 }
244 if (parseStatus != ParseStatus::PARSE_ERROR) {
245 ADD_MESSAGE(toString(parseStatus) + " manifest");
246 return ALREADY_EXISTS;
247 }
248 parseStatus = tryParse(xml, gCompatibilityMatrixConverter, &pkg.fwk.matrix, &pkg.dev.matrix);
249 if (parseStatus == ParseStatus::OK) {
250 continue; // work on next one
251 }
252 if (parseStatus != ParseStatus::PARSE_ERROR) {
253 ADD_MESSAGE(toString(parseStatus) + " matrix");
254 return ALREADY_EXISTS;
255 }
256 ADD_MESSAGE(toString(parseStatus)); // parse error
257 return BAD_VALUE;
258 }
259
260 // get missing info from device
Yifan Hong8640cd12017-05-17 12:02:28 -0700261 // use functions instead of std::bind because std::bind doesn't work well with mock objects
262 auto mountSystem = [&mounter] { return mounter.mountSystem(); };
263 auto mountVendor = [&mounter] { return mounter.mountVendor(); };
264 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700265 pkg.fwk.manifest, mount, mountSystem, &updated.fwk.manifest,
Yifan Hong8640cd12017-05-17 12:02:28 -0700266 std::bind(VintfObject::GetFrameworkHalManifest, true /* skipCache */))) != OK) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700267 return status;
268 }
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700269 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700270 pkg.dev.manifest, mount, mountVendor, &updated.dev.manifest,
Yifan Hong8640cd12017-05-17 12:02:28 -0700271 std::bind(VintfObject::GetDeviceHalManifest, true /* skipCache */))) != OK) {
272 return status;
273 }
274 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700275 pkg.fwk.matrix, mount, mountSystem, &updated.fwk.matrix,
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700276 std::bind(VintfObject::GetFrameworkCompatibilityMatrix, true /* skipCache */))) !=
277 OK) {
278 return status;
279 }
280 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700281 pkg.dev.matrix, mount, mountVendor, &updated.dev.matrix,
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700282 std::bind(VintfObject::GetDeviceCompatibilityMatrix, true /* skipCache */))) != OK) {
283 return status;
284 }
Yifan Hong8640cd12017-05-17 12:02:28 -0700285
286 if (mount) {
287 (void)mounter.umountSystem(); // ignore errors
288 (void)mounter.umountVendor(); // ignore errors
289 }
290
291 updated.runtimeInfo = VintfObject::GetRuntimeInfo(true /* skipCache */);
Yifan Hong143cfe62017-04-13 20:18:01 -0700292
293 // null checks for files and runtime info after the update
294 // TODO(b/37321309) if a compat mat is missing, it is not matched and considered compatible.
295 if (updated.fwk.manifest == nullptr) {
296 ADD_MESSAGE("No framework manifest file from device or from update package");
297 return NO_INIT;
298 }
299 if (updated.dev.manifest == nullptr) {
300 ADD_MESSAGE("No device manifest file from device or from update package");
301 return NO_INIT;
302 }
303 if (updated.fwk.matrix == nullptr) {
304 ADD_MESSAGE("No framework matrix, skipping;");
305 // TODO(b/37321309) consider missing matricies as errors.
306 }
307 if (updated.dev.matrix == nullptr) {
308 ADD_MESSAGE("No device matrix, skipping;");
309 // TODO(b/37321309) consider missing matricies as errors.
310 }
311 if (updated.runtimeInfo == nullptr) {
312 ADD_MESSAGE("No runtime info from device");
313 return NO_INIT;
314 }
315
316 // compatiblity check.
317 // TODO(b/37321309) outer if checks can be removed if we consider missing matrices as errors.
318 if (updated.dev.manifest && updated.fwk.matrix) {
319 if (!updated.dev.manifest->checkCompatibility(*updated.fwk.matrix, error)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700320 if (error)
321 error->insert(0, "Device manifest and framework compatibility matrix "
322 "are incompatible: ");
Yifan Hong143cfe62017-04-13 20:18:01 -0700323 return INCOMPATIBLE;
324 }
325 }
326 if (updated.fwk.manifest && updated.dev.matrix) {
327 if (!updated.fwk.manifest->checkCompatibility(*updated.dev.matrix, error)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700328 if (error)
329 error->insert(0, "Framework manifest and device compatibility matrix "
330 "are incompatible: ");
Yifan Hong143cfe62017-04-13 20:18:01 -0700331 return INCOMPATIBLE;
332 }
333 }
334 if (updated.runtimeInfo && updated.fwk.matrix) {
Yifan Hongdb6423e2017-09-11 14:38:46 -0700335 if (!updated.runtimeInfo->checkCompatibility(*updated.fwk.matrix, error, disabledChecks)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700336 if (error)
337 error->insert(0, "Runtime info and framework compatibility matrix "
338 "are incompatible: ");
Yifan Honge8b86842017-05-25 17:59:22 +0000339 return INCOMPATIBLE;
Yifan Hong143cfe62017-04-13 20:18:01 -0700340 }
341 }
342
343 return COMPATIBLE;
344}
345
346} // namespace details
347
Yifan Hongfbbf0472017-04-07 18:14:18 -0700348// static
Yifan Hongdb6423e2017-09-11 14:38:46 -0700349int32_t VintfObject::CheckCompatibility(const std::vector<std::string>& xmls, std::string* error,
350 DisabledChecks disabledChecks) {
351 return details::checkCompatibility(xmls, false /* mount */, *details::gPartitionMounter, error,
352 disabledChecks);
Yifan Hongfbbf0472017-04-07 18:14:18 -0700353}
354
Yifan Hong3daec812017-02-27 18:49:11 -0800355
356} // namespace vintf
357} // namespace android