blob: efe62420403d1dc332c1e5eb5daf5a6426d0985b [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;
38};
39
Yifan Hong1fb004e2017-09-26 15:04:44 -070040struct LockedRuntimeInfoCache {
41 std::shared_ptr<RuntimeInfo> object;
42 std::mutex mutex;
43 RuntimeInfo::FetchFlags fetchedFlags = RuntimeInfo::FetchFlag::NONE;
44};
45
Yifan Hong3daec812017-02-27 18:49:11 -080046template <typename T, typename F>
Yifan Hongfc73edf2017-08-29 11:39:07 -070047static std::shared_ptr<const T> Get(
48 LockedSharedPtr<T> *ptr,
Yifan Hong143cfe62017-04-13 20:18:01 -070049 bool skipCache,
Yifan Hong3daec812017-02-27 18:49:11 -080050 const F &fetchAllInformation) {
51 std::unique_lock<std::mutex> _lock(ptr->mutex);
Yifan Hong143cfe62017-04-13 20:18:01 -070052 if (skipCache || ptr->object == nullptr) {
Yifan Hong3daec812017-02-27 18:49:11 -080053 ptr->object = std::make_unique<T>();
54 if (fetchAllInformation(ptr->object.get()) != OK) {
55 ptr->object = nullptr; // frees the old object
56 }
57 }
Yifan Hongfc73edf2017-08-29 11:39:07 -070058 return ptr->object;
Yifan Hong3daec812017-02-27 18:49:11 -080059}
60
61// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070062std::shared_ptr<const HalManifest> VintfObject::GetDeviceHalManifest(bool skipCache) {
Steven Moreland648a0012017-10-19 21:23:41 -070063 static LockedSharedPtr<HalManifest> gVendorManifest;
64 static LockedSharedPtr<HalManifest> gOdmManifest;
Bowgo Tsai39adc142017-11-03 12:46:26 +080065#ifdef LIBVINTF_TARGET
66 static LockedSharedPtr<HalManifest> gProductManifest;
67#endif
Steven Moreland648a0012017-10-19 21:23:41 -070068 static std::mutex gDeviceManifestMutex;
69
70 std::unique_lock<std::mutex> _lock(gDeviceManifestMutex);
71
Bowgo Tsai39adc142017-11-03 12:46:26 +080072#ifdef LIBVINTF_TARGET
73 std::string productModel = android::base::GetProperty("ro.product.model", "");
74 if (!productModel.empty()) {
75 auto product = Get(&gProductManifest, skipCache,
76 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1,
77 "/odm/manifest_" + productModel + ".xml"));
78 if (product != nullptr) {
79 return product;
80 }
81 }
82#endif
83
Steven Moreland648a0012017-10-19 21:23:41 -070084 auto odm = Get(
85 &gOdmManifest, skipCache,
86 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1, "/odm/manifest.xml"));
87 if (odm != nullptr) {
88 return odm;
89 }
90
91 return Get(&gVendorManifest, skipCache,
92 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1,
93 "/vendor/manifest.xml"));
Yifan Hong3daec812017-02-27 18:49:11 -080094}
95
96// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070097std::shared_ptr<const HalManifest> VintfObject::GetFrameworkHalManifest(bool skipCache) {
98 static LockedSharedPtr<HalManifest> gFrameworkManifest;
Yifan Hong143cfe62017-04-13 20:18:01 -070099 return Get(&gFrameworkManifest, skipCache,
Yifan Hong3daec812017-02-27 18:49:11 -0800100 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1,
101 "/system/manifest.xml"));
102}
103
Yifan Hong2272bf82017-04-28 14:37:56 -0700104
105// static
Yifan Hongfc73edf2017-08-29 11:39:07 -0700106std::shared_ptr<const CompatibilityMatrix> VintfObject::GetDeviceCompatibilityMatrix(bool skipCache) {
107 static LockedSharedPtr<CompatibilityMatrix> gDeviceMatrix;
Yifan Hong2272bf82017-04-28 14:37:56 -0700108 return Get(&gDeviceMatrix, skipCache,
109 std::bind(&CompatibilityMatrix::fetchAllInformation, std::placeholders::_1,
110 "/vendor/compatibility_matrix.xml"));
111}
112
113// static
Yifan Hongfc73edf2017-08-29 11:39:07 -0700114std::shared_ptr<const CompatibilityMatrix> VintfObject::GetFrameworkCompatibilityMatrix(bool skipCache) {
115 static LockedSharedPtr<CompatibilityMatrix> gFrameworkMatrix;
Yifan Hong2272bf82017-04-28 14:37:56 -0700116 return Get(&gFrameworkMatrix, skipCache,
117 std::bind(&CompatibilityMatrix::fetchAllInformation, std::placeholders::_1,
118 "/system/compatibility_matrix.xml"));
119}
120
Yifan Hong3daec812017-02-27 18:49:11 -0800121// static
Yifan Hong1fb004e2017-09-26 15:04:44 -0700122std::shared_ptr<const RuntimeInfo> VintfObject::GetRuntimeInfo(bool skipCache,
123 RuntimeInfo::FetchFlags flags) {
124 static LockedRuntimeInfoCache gDeviceRuntimeInfo;
125 std::unique_lock<std::mutex> _lock(gDeviceRuntimeInfo.mutex);
126
127 if (!skipCache) {
128 flags &= (~gDeviceRuntimeInfo.fetchedFlags);
129 }
130
131 if (gDeviceRuntimeInfo.object == nullptr) {
Yifan Hong29bb2d42017-09-27 13:28:00 -0700132 gDeviceRuntimeInfo.object = details::gRuntimeInfoFactory->make_shared();
Yifan Hong1fb004e2017-09-26 15:04:44 -0700133 }
134
135 status_t status = gDeviceRuntimeInfo.object->fetchAllInformation(flags);
136 if (status != OK) {
137 gDeviceRuntimeInfo.fetchedFlags &= (~flags); // mark the fields as "not fetched"
138 return nullptr;
139 }
140
141 gDeviceRuntimeInfo.fetchedFlags |= flags;
142 return gDeviceRuntimeInfo.object;
Yifan Hong3daec812017-02-27 18:49:11 -0800143}
144
Yifan Hong143cfe62017-04-13 20:18:01 -0700145namespace details {
146
Yifan Hong143cfe62017-04-13 20:18:01 -0700147enum class ParseStatus {
148 OK,
149 PARSE_ERROR,
150 DUPLICATED_FWK_ENTRY,
151 DUPLICATED_DEV_ENTRY,
152};
153
Yifan Hong9532bd22017-04-14 15:30:52 -0700154static std::string toString(ParseStatus status) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700155 switch(status) {
156 case ParseStatus::OK: return "OK";
157 case ParseStatus::PARSE_ERROR: return "parse error";
158 case ParseStatus::DUPLICATED_FWK_ENTRY: return "duplicated framework";
159 case ParseStatus::DUPLICATED_DEV_ENTRY: return "duplicated device";
160 }
161 return "";
162}
163
164template<typename T>
Yifan Hong9532bd22017-04-14 15:30:52 -0700165static ParseStatus tryParse(const std::string &xml, const XmlConverter<T> &parse,
Yifan Hongfc73edf2017-08-29 11:39:07 -0700166 std::shared_ptr<T> *fwk, std::shared_ptr<T> *dev) {
167 std::shared_ptr<T> ret = std::make_shared<T>();
Yifan Hong143cfe62017-04-13 20:18:01 -0700168 if (!parse(ret.get(), xml)) {
169 return ParseStatus::PARSE_ERROR;
170 }
171 if (ret->type() == SchemaType::FRAMEWORK) {
172 if (fwk->get() != nullptr) {
173 return ParseStatus::DUPLICATED_FWK_ENTRY;
174 }
175 *fwk = std::move(ret);
176 } else if (ret->type() == SchemaType::DEVICE) {
177 if (dev->get() != nullptr) {
178 return ParseStatus::DUPLICATED_DEV_ENTRY;
179 }
180 *dev = std::move(ret);
181 }
182 return ParseStatus::OK;
183}
184
185template<typename T, typename GetFunction>
Yifan Hongfc73edf2017-08-29 11:39:07 -0700186static status_t getMissing(const std::shared_ptr<T>& pkg, bool mount,
Yifan Hong143cfe62017-04-13 20:18:01 -0700187 std::function<status_t(void)> mountFunction,
Yifan Hongfc73edf2017-08-29 11:39:07 -0700188 std::shared_ptr<const T>* updated,
Yifan Hong143cfe62017-04-13 20:18:01 -0700189 GetFunction getFunction) {
190 if (pkg != nullptr) {
191 *updated = pkg;
192 } else {
193 if (mount) {
194 (void)mountFunction(); // ignore mount errors
195 }
196 *updated = getFunction();
197 }
198 return OK;
199}
200
201#define ADD_MESSAGE(__error__) \
202 if (error != nullptr) { \
203 *error += (__error__); \
204 } \
205
206struct PackageInfo {
207 struct Pair {
Yifan Hongfc73edf2017-08-29 11:39:07 -0700208 std::shared_ptr<HalManifest> manifest;
209 std::shared_ptr<CompatibilityMatrix> matrix;
Yifan Hong143cfe62017-04-13 20:18:01 -0700210 };
211 Pair dev;
212 Pair fwk;
213};
214
215struct UpdatedInfo {
216 struct Pair {
Yifan Hongfc73edf2017-08-29 11:39:07 -0700217 std::shared_ptr<const HalManifest> manifest;
218 std::shared_ptr<const CompatibilityMatrix> matrix;
Yifan Hong143cfe62017-04-13 20:18:01 -0700219 };
220 Pair dev;
221 Pair fwk;
Yifan Hongfc73edf2017-08-29 11:39:07 -0700222 std::shared_ptr<const RuntimeInfo> runtimeInfo;
Yifan Hong143cfe62017-04-13 20:18:01 -0700223};
224
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700225// Checks given compatibility info against info on the device. If no
226// compatability info is given then the device info will be checked against
227// itself.
Yifan Hongdb6423e2017-09-11 14:38:46 -0700228int32_t checkCompatibility(const std::vector<std::string>& xmls, bool mount,
229 const PartitionMounter& mounter, std::string* error,
230 DisabledChecks disabledChecks) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700231 status_t status;
232 ParseStatus parseStatus;
233 PackageInfo pkg; // All information from package.
234 UpdatedInfo updated; // All files and runtime info after the update.
235
Yifan Hong143cfe62017-04-13 20:18:01 -0700236 // parse all information from package
237 for (const auto &xml : xmls) {
238 parseStatus = tryParse(xml, gHalManifestConverter, &pkg.fwk.manifest, &pkg.dev.manifest);
239 if (parseStatus == ParseStatus::OK) {
240 continue; // work on next one
241 }
242 if (parseStatus != ParseStatus::PARSE_ERROR) {
243 ADD_MESSAGE(toString(parseStatus) + " manifest");
244 return ALREADY_EXISTS;
245 }
246 parseStatus = tryParse(xml, gCompatibilityMatrixConverter, &pkg.fwk.matrix, &pkg.dev.matrix);
247 if (parseStatus == ParseStatus::OK) {
248 continue; // work on next one
249 }
250 if (parseStatus != ParseStatus::PARSE_ERROR) {
251 ADD_MESSAGE(toString(parseStatus) + " matrix");
252 return ALREADY_EXISTS;
253 }
254 ADD_MESSAGE(toString(parseStatus)); // parse error
255 return BAD_VALUE;
256 }
257
258 // get missing info from device
Yifan Hong8640cd12017-05-17 12:02:28 -0700259 // use functions instead of std::bind because std::bind doesn't work well with mock objects
260 auto mountSystem = [&mounter] { return mounter.mountSystem(); };
261 auto mountVendor = [&mounter] { return mounter.mountVendor(); };
262 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700263 pkg.fwk.manifest, mount, mountSystem, &updated.fwk.manifest,
Yifan Hong8640cd12017-05-17 12:02:28 -0700264 std::bind(VintfObject::GetFrameworkHalManifest, true /* skipCache */))) != OK) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700265 return status;
266 }
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700267 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700268 pkg.dev.manifest, mount, mountVendor, &updated.dev.manifest,
Yifan Hong8640cd12017-05-17 12:02:28 -0700269 std::bind(VintfObject::GetDeviceHalManifest, true /* skipCache */))) != OK) {
270 return status;
271 }
272 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700273 pkg.fwk.matrix, mount, mountSystem, &updated.fwk.matrix,
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700274 std::bind(VintfObject::GetFrameworkCompatibilityMatrix, true /* skipCache */))) !=
275 OK) {
276 return status;
277 }
278 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700279 pkg.dev.matrix, mount, mountVendor, &updated.dev.matrix,
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700280 std::bind(VintfObject::GetDeviceCompatibilityMatrix, true /* skipCache */))) != OK) {
281 return status;
282 }
Yifan Hong8640cd12017-05-17 12:02:28 -0700283
284 if (mount) {
285 (void)mounter.umountSystem(); // ignore errors
286 (void)mounter.umountVendor(); // ignore errors
287 }
288
289 updated.runtimeInfo = VintfObject::GetRuntimeInfo(true /* skipCache */);
Yifan Hong143cfe62017-04-13 20:18:01 -0700290
291 // null checks for files and runtime info after the update
292 // TODO(b/37321309) if a compat mat is missing, it is not matched and considered compatible.
293 if (updated.fwk.manifest == nullptr) {
294 ADD_MESSAGE("No framework manifest file from device or from update package");
295 return NO_INIT;
296 }
297 if (updated.dev.manifest == nullptr) {
298 ADD_MESSAGE("No device manifest file from device or from update package");
299 return NO_INIT;
300 }
301 if (updated.fwk.matrix == nullptr) {
302 ADD_MESSAGE("No framework matrix, skipping;");
303 // TODO(b/37321309) consider missing matricies as errors.
304 }
305 if (updated.dev.matrix == nullptr) {
306 ADD_MESSAGE("No device matrix, skipping;");
307 // TODO(b/37321309) consider missing matricies as errors.
308 }
309 if (updated.runtimeInfo == nullptr) {
310 ADD_MESSAGE("No runtime info from device");
311 return NO_INIT;
312 }
313
314 // compatiblity check.
315 // TODO(b/37321309) outer if checks can be removed if we consider missing matrices as errors.
316 if (updated.dev.manifest && updated.fwk.matrix) {
317 if (!updated.dev.manifest->checkCompatibility(*updated.fwk.matrix, error)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700318 if (error)
319 error->insert(0, "Device manifest and framework compatibility matrix "
320 "are incompatible: ");
Yifan Hong143cfe62017-04-13 20:18:01 -0700321 return INCOMPATIBLE;
322 }
323 }
324 if (updated.fwk.manifest && updated.dev.matrix) {
325 if (!updated.fwk.manifest->checkCompatibility(*updated.dev.matrix, error)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700326 if (error)
327 error->insert(0, "Framework manifest and device compatibility matrix "
328 "are incompatible: ");
Yifan Hong143cfe62017-04-13 20:18:01 -0700329 return INCOMPATIBLE;
330 }
331 }
332 if (updated.runtimeInfo && updated.fwk.matrix) {
Yifan Hongdb6423e2017-09-11 14:38:46 -0700333 if (!updated.runtimeInfo->checkCompatibility(*updated.fwk.matrix, error, disabledChecks)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700334 if (error)
335 error->insert(0, "Runtime info and framework compatibility matrix "
336 "are incompatible: ");
Yifan Honge8b86842017-05-25 17:59:22 +0000337 return INCOMPATIBLE;
Yifan Hong143cfe62017-04-13 20:18:01 -0700338 }
339 }
340
341 return COMPATIBLE;
342}
343
344} // namespace details
345
Yifan Hongfbbf0472017-04-07 18:14:18 -0700346// static
Yifan Hongdb6423e2017-09-11 14:38:46 -0700347int32_t VintfObject::CheckCompatibility(const std::vector<std::string>& xmls, std::string* error,
348 DisabledChecks disabledChecks) {
349 return details::checkCompatibility(xmls, false /* mount */, *details::gPartitionMounter, error,
350 disabledChecks);
Yifan Hongfbbf0472017-04-07 18:14:18 -0700351}
352
Yifan Hong3daec812017-02-27 18:49:11 -0800353
354} // namespace vintf
355} // namespace android