blob: 9dea4d976ca399b4cfe1a59bf3e53880d9fb5896 [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
27namespace android {
28namespace vintf {
29
30template <typename T>
Yifan Hongfc73edf2017-08-29 11:39:07 -070031struct LockedSharedPtr {
32 std::shared_ptr<T> object;
Yifan Hong3daec812017-02-27 18:49:11 -080033 std::mutex mutex;
34};
35
Yifan Hong1fb004e2017-09-26 15:04:44 -070036struct LockedRuntimeInfoCache {
37 std::shared_ptr<RuntimeInfo> object;
38 std::mutex mutex;
39 RuntimeInfo::FetchFlags fetchedFlags = RuntimeInfo::FetchFlag::NONE;
40};
41
Yifan Hong3daec812017-02-27 18:49:11 -080042template <typename T, typename F>
Yifan Hongfc73edf2017-08-29 11:39:07 -070043static std::shared_ptr<const T> Get(
44 LockedSharedPtr<T> *ptr,
Yifan Hong143cfe62017-04-13 20:18:01 -070045 bool skipCache,
Yifan Hong3daec812017-02-27 18:49:11 -080046 const F &fetchAllInformation) {
47 std::unique_lock<std::mutex> _lock(ptr->mutex);
Yifan Hong143cfe62017-04-13 20:18:01 -070048 if (skipCache || ptr->object == nullptr) {
Yifan Hong3daec812017-02-27 18:49:11 -080049 ptr->object = std::make_unique<T>();
50 if (fetchAllInformation(ptr->object.get()) != OK) {
51 ptr->object = nullptr; // frees the old object
52 }
53 }
Yifan Hongfc73edf2017-08-29 11:39:07 -070054 return ptr->object;
Yifan Hong3daec812017-02-27 18:49:11 -080055}
56
57// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070058std::shared_ptr<const HalManifest> VintfObject::GetDeviceHalManifest(bool skipCache) {
Steven Moreland648a0012017-10-19 21:23:41 -070059 static LockedSharedPtr<HalManifest> gVendorManifest;
60 static LockedSharedPtr<HalManifest> gOdmManifest;
61 static std::mutex gDeviceManifestMutex;
62
63 std::unique_lock<std::mutex> _lock(gDeviceManifestMutex);
64
65 auto odm = Get(
66 &gOdmManifest, skipCache,
67 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1, "/odm/manifest.xml"));
68 if (odm != nullptr) {
69 return odm;
70 }
71
72 return Get(&gVendorManifest, skipCache,
73 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1,
74 "/vendor/manifest.xml"));
Yifan Hong3daec812017-02-27 18:49:11 -080075}
76
77// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070078std::shared_ptr<const HalManifest> VintfObject::GetFrameworkHalManifest(bool skipCache) {
79 static LockedSharedPtr<HalManifest> gFrameworkManifest;
Yifan Hong143cfe62017-04-13 20:18:01 -070080 return Get(&gFrameworkManifest, skipCache,
Yifan Hong3daec812017-02-27 18:49:11 -080081 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1,
82 "/system/manifest.xml"));
83}
84
Yifan Hong2272bf82017-04-28 14:37:56 -070085
86// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070087std::shared_ptr<const CompatibilityMatrix> VintfObject::GetDeviceCompatibilityMatrix(bool skipCache) {
88 static LockedSharedPtr<CompatibilityMatrix> gDeviceMatrix;
Yifan Hong2272bf82017-04-28 14:37:56 -070089 return Get(&gDeviceMatrix, skipCache,
90 std::bind(&CompatibilityMatrix::fetchAllInformation, std::placeholders::_1,
91 "/vendor/compatibility_matrix.xml"));
92}
93
94// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070095std::shared_ptr<const CompatibilityMatrix> VintfObject::GetFrameworkCompatibilityMatrix(bool skipCache) {
96 static LockedSharedPtr<CompatibilityMatrix> gFrameworkMatrix;
Yifan Hong2272bf82017-04-28 14:37:56 -070097 return Get(&gFrameworkMatrix, skipCache,
98 std::bind(&CompatibilityMatrix::fetchAllInformation, std::placeholders::_1,
99 "/system/compatibility_matrix.xml"));
100}
101
Yifan Hong3daec812017-02-27 18:49:11 -0800102// static
Yifan Hong1fb004e2017-09-26 15:04:44 -0700103std::shared_ptr<const RuntimeInfo> VintfObject::GetRuntimeInfo(bool skipCache,
104 RuntimeInfo::FetchFlags flags) {
105 static LockedRuntimeInfoCache gDeviceRuntimeInfo;
106 std::unique_lock<std::mutex> _lock(gDeviceRuntimeInfo.mutex);
107
108 if (!skipCache) {
109 flags &= (~gDeviceRuntimeInfo.fetchedFlags);
110 }
111
112 if (gDeviceRuntimeInfo.object == nullptr) {
Yifan Hong29bb2d42017-09-27 13:28:00 -0700113 gDeviceRuntimeInfo.object = details::gRuntimeInfoFactory->make_shared();
Yifan Hong1fb004e2017-09-26 15:04:44 -0700114 }
115
116 status_t status = gDeviceRuntimeInfo.object->fetchAllInformation(flags);
117 if (status != OK) {
118 gDeviceRuntimeInfo.fetchedFlags &= (~flags); // mark the fields as "not fetched"
119 return nullptr;
120 }
121
122 gDeviceRuntimeInfo.fetchedFlags |= flags;
123 return gDeviceRuntimeInfo.object;
Yifan Hong3daec812017-02-27 18:49:11 -0800124}
125
Yifan Hong143cfe62017-04-13 20:18:01 -0700126namespace details {
127
Yifan Hong143cfe62017-04-13 20:18:01 -0700128enum class ParseStatus {
129 OK,
130 PARSE_ERROR,
131 DUPLICATED_FWK_ENTRY,
132 DUPLICATED_DEV_ENTRY,
133};
134
Yifan Hong9532bd22017-04-14 15:30:52 -0700135static std::string toString(ParseStatus status) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700136 switch(status) {
137 case ParseStatus::OK: return "OK";
138 case ParseStatus::PARSE_ERROR: return "parse error";
139 case ParseStatus::DUPLICATED_FWK_ENTRY: return "duplicated framework";
140 case ParseStatus::DUPLICATED_DEV_ENTRY: return "duplicated device";
141 }
142 return "";
143}
144
145template<typename T>
Yifan Hong9532bd22017-04-14 15:30:52 -0700146static ParseStatus tryParse(const std::string &xml, const XmlConverter<T> &parse,
Yifan Hongfc73edf2017-08-29 11:39:07 -0700147 std::shared_ptr<T> *fwk, std::shared_ptr<T> *dev) {
148 std::shared_ptr<T> ret = std::make_shared<T>();
Yifan Hong143cfe62017-04-13 20:18:01 -0700149 if (!parse(ret.get(), xml)) {
150 return ParseStatus::PARSE_ERROR;
151 }
152 if (ret->type() == SchemaType::FRAMEWORK) {
153 if (fwk->get() != nullptr) {
154 return ParseStatus::DUPLICATED_FWK_ENTRY;
155 }
156 *fwk = std::move(ret);
157 } else if (ret->type() == SchemaType::DEVICE) {
158 if (dev->get() != nullptr) {
159 return ParseStatus::DUPLICATED_DEV_ENTRY;
160 }
161 *dev = std::move(ret);
162 }
163 return ParseStatus::OK;
164}
165
166template<typename T, typename GetFunction>
Yifan Hongfc73edf2017-08-29 11:39:07 -0700167static status_t getMissing(const std::shared_ptr<T>& pkg, bool mount,
Yifan Hong143cfe62017-04-13 20:18:01 -0700168 std::function<status_t(void)> mountFunction,
Yifan Hongfc73edf2017-08-29 11:39:07 -0700169 std::shared_ptr<const T>* updated,
Yifan Hong143cfe62017-04-13 20:18:01 -0700170 GetFunction getFunction) {
171 if (pkg != nullptr) {
172 *updated = pkg;
173 } else {
174 if (mount) {
175 (void)mountFunction(); // ignore mount errors
176 }
177 *updated = getFunction();
178 }
179 return OK;
180}
181
182#define ADD_MESSAGE(__error__) \
183 if (error != nullptr) { \
184 *error += (__error__); \
185 } \
186
187struct PackageInfo {
188 struct Pair {
Yifan Hongfc73edf2017-08-29 11:39:07 -0700189 std::shared_ptr<HalManifest> manifest;
190 std::shared_ptr<CompatibilityMatrix> matrix;
Yifan Hong143cfe62017-04-13 20:18:01 -0700191 };
192 Pair dev;
193 Pair fwk;
194};
195
196struct UpdatedInfo {
197 struct Pair {
Yifan Hongfc73edf2017-08-29 11:39:07 -0700198 std::shared_ptr<const HalManifest> manifest;
199 std::shared_ptr<const CompatibilityMatrix> matrix;
Yifan Hong143cfe62017-04-13 20:18:01 -0700200 };
201 Pair dev;
202 Pair fwk;
Yifan Hongfc73edf2017-08-29 11:39:07 -0700203 std::shared_ptr<const RuntimeInfo> runtimeInfo;
Yifan Hong143cfe62017-04-13 20:18:01 -0700204};
205
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700206// Checks given compatibility info against info on the device. If no
207// compatability info is given then the device info will be checked against
208// itself.
Yifan Hongdb6423e2017-09-11 14:38:46 -0700209int32_t checkCompatibility(const std::vector<std::string>& xmls, bool mount,
210 const PartitionMounter& mounter, std::string* error,
211 DisabledChecks disabledChecks) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700212 status_t status;
213 ParseStatus parseStatus;
214 PackageInfo pkg; // All information from package.
215 UpdatedInfo updated; // All files and runtime info after the update.
216
Yifan Hong143cfe62017-04-13 20:18:01 -0700217 // parse all information from package
218 for (const auto &xml : xmls) {
219 parseStatus = tryParse(xml, gHalManifestConverter, &pkg.fwk.manifest, &pkg.dev.manifest);
220 if (parseStatus == ParseStatus::OK) {
221 continue; // work on next one
222 }
223 if (parseStatus != ParseStatus::PARSE_ERROR) {
224 ADD_MESSAGE(toString(parseStatus) + " manifest");
225 return ALREADY_EXISTS;
226 }
227 parseStatus = tryParse(xml, gCompatibilityMatrixConverter, &pkg.fwk.matrix, &pkg.dev.matrix);
228 if (parseStatus == ParseStatus::OK) {
229 continue; // work on next one
230 }
231 if (parseStatus != ParseStatus::PARSE_ERROR) {
232 ADD_MESSAGE(toString(parseStatus) + " matrix");
233 return ALREADY_EXISTS;
234 }
235 ADD_MESSAGE(toString(parseStatus)); // parse error
236 return BAD_VALUE;
237 }
238
239 // get missing info from device
Yifan Hong8640cd12017-05-17 12:02:28 -0700240 // use functions instead of std::bind because std::bind doesn't work well with mock objects
241 auto mountSystem = [&mounter] { return mounter.mountSystem(); };
242 auto mountVendor = [&mounter] { return mounter.mountVendor(); };
243 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700244 pkg.fwk.manifest, mount, mountSystem, &updated.fwk.manifest,
Yifan Hong8640cd12017-05-17 12:02:28 -0700245 std::bind(VintfObject::GetFrameworkHalManifest, true /* skipCache */))) != OK) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700246 return status;
247 }
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700248 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700249 pkg.dev.manifest, mount, mountVendor, &updated.dev.manifest,
Yifan Hong8640cd12017-05-17 12:02:28 -0700250 std::bind(VintfObject::GetDeviceHalManifest, true /* skipCache */))) != OK) {
251 return status;
252 }
253 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700254 pkg.fwk.matrix, mount, mountSystem, &updated.fwk.matrix,
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700255 std::bind(VintfObject::GetFrameworkCompatibilityMatrix, true /* skipCache */))) !=
256 OK) {
257 return status;
258 }
259 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700260 pkg.dev.matrix, mount, mountVendor, &updated.dev.matrix,
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700261 std::bind(VintfObject::GetDeviceCompatibilityMatrix, true /* skipCache */))) != OK) {
262 return status;
263 }
Yifan Hong8640cd12017-05-17 12:02:28 -0700264
265 if (mount) {
266 (void)mounter.umountSystem(); // ignore errors
267 (void)mounter.umountVendor(); // ignore errors
268 }
269
270 updated.runtimeInfo = VintfObject::GetRuntimeInfo(true /* skipCache */);
Yifan Hong143cfe62017-04-13 20:18:01 -0700271
272 // null checks for files and runtime info after the update
273 // TODO(b/37321309) if a compat mat is missing, it is not matched and considered compatible.
274 if (updated.fwk.manifest == nullptr) {
275 ADD_MESSAGE("No framework manifest file from device or from update package");
276 return NO_INIT;
277 }
278 if (updated.dev.manifest == nullptr) {
279 ADD_MESSAGE("No device manifest file from device or from update package");
280 return NO_INIT;
281 }
282 if (updated.fwk.matrix == nullptr) {
283 ADD_MESSAGE("No framework matrix, skipping;");
284 // TODO(b/37321309) consider missing matricies as errors.
285 }
286 if (updated.dev.matrix == nullptr) {
287 ADD_MESSAGE("No device matrix, skipping;");
288 // TODO(b/37321309) consider missing matricies as errors.
289 }
290 if (updated.runtimeInfo == nullptr) {
291 ADD_MESSAGE("No runtime info from device");
292 return NO_INIT;
293 }
294
295 // compatiblity check.
296 // TODO(b/37321309) outer if checks can be removed if we consider missing matrices as errors.
297 if (updated.dev.manifest && updated.fwk.matrix) {
298 if (!updated.dev.manifest->checkCompatibility(*updated.fwk.matrix, error)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700299 if (error)
300 error->insert(0, "Device manifest and framework compatibility matrix "
301 "are incompatible: ");
Yifan Hong143cfe62017-04-13 20:18:01 -0700302 return INCOMPATIBLE;
303 }
304 }
305 if (updated.fwk.manifest && updated.dev.matrix) {
306 if (!updated.fwk.manifest->checkCompatibility(*updated.dev.matrix, error)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700307 if (error)
308 error->insert(0, "Framework manifest and device compatibility matrix "
309 "are incompatible: ");
Yifan Hong143cfe62017-04-13 20:18:01 -0700310 return INCOMPATIBLE;
311 }
312 }
313 if (updated.runtimeInfo && updated.fwk.matrix) {
Yifan Hongdb6423e2017-09-11 14:38:46 -0700314 if (!updated.runtimeInfo->checkCompatibility(*updated.fwk.matrix, error, disabledChecks)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700315 if (error)
316 error->insert(0, "Runtime info and framework compatibility matrix "
317 "are incompatible: ");
Yifan Honge8b86842017-05-25 17:59:22 +0000318 return INCOMPATIBLE;
Yifan Hong143cfe62017-04-13 20:18:01 -0700319 }
320 }
321
322 return COMPATIBLE;
323}
324
325} // namespace details
326
Yifan Hongfbbf0472017-04-07 18:14:18 -0700327// static
Yifan Hongdb6423e2017-09-11 14:38:46 -0700328int32_t VintfObject::CheckCompatibility(const std::vector<std::string>& xmls, std::string* error,
329 DisabledChecks disabledChecks) {
330 return details::checkCompatibility(xmls, false /* mount */, *details::gPartitionMounter, error,
331 disabledChecks);
Yifan Hongfbbf0472017-04-07 18:14:18 -0700332}
333
Yifan Hong3daec812017-02-27 18:49:11 -0800334
335} // namespace vintf
336} // namespace android