blob: e87dd050e9bf2d24ad1229873fa5db1c4c3ec728 [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) {
59 static LockedSharedPtr<HalManifest> gDeviceManifest;
Yifan Hong143cfe62017-04-13 20:18:01 -070060 return Get(&gDeviceManifest, skipCache,
Yifan Hong3daec812017-02-27 18:49:11 -080061 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1,
62 "/vendor/manifest.xml"));
63}
64
65// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070066std::shared_ptr<const HalManifest> VintfObject::GetFrameworkHalManifest(bool skipCache) {
67 static LockedSharedPtr<HalManifest> gFrameworkManifest;
Yifan Hong143cfe62017-04-13 20:18:01 -070068 return Get(&gFrameworkManifest, skipCache,
Yifan Hong3daec812017-02-27 18:49:11 -080069 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1,
70 "/system/manifest.xml"));
71}
72
Yifan Hong2272bf82017-04-28 14:37:56 -070073
74// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070075std::shared_ptr<const CompatibilityMatrix> VintfObject::GetDeviceCompatibilityMatrix(bool skipCache) {
76 static LockedSharedPtr<CompatibilityMatrix> gDeviceMatrix;
Yifan Hong2272bf82017-04-28 14:37:56 -070077 return Get(&gDeviceMatrix, skipCache,
78 std::bind(&CompatibilityMatrix::fetchAllInformation, std::placeholders::_1,
79 "/vendor/compatibility_matrix.xml"));
80}
81
82// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070083std::shared_ptr<const CompatibilityMatrix> VintfObject::GetFrameworkCompatibilityMatrix(bool skipCache) {
84 static LockedSharedPtr<CompatibilityMatrix> gFrameworkMatrix;
Yifan Hong2272bf82017-04-28 14:37:56 -070085 return Get(&gFrameworkMatrix, skipCache,
86 std::bind(&CompatibilityMatrix::fetchAllInformation, std::placeholders::_1,
87 "/system/compatibility_matrix.xml"));
88}
89
Yifan Hong3daec812017-02-27 18:49:11 -080090// static
Yifan Hong1fb004e2017-09-26 15:04:44 -070091std::shared_ptr<const RuntimeInfo> VintfObject::GetRuntimeInfo(bool skipCache,
92 RuntimeInfo::FetchFlags flags) {
93 static LockedRuntimeInfoCache gDeviceRuntimeInfo;
94 std::unique_lock<std::mutex> _lock(gDeviceRuntimeInfo.mutex);
95
96 if (!skipCache) {
97 flags &= (~gDeviceRuntimeInfo.fetchedFlags);
98 }
99
100 if (gDeviceRuntimeInfo.object == nullptr) {
101 gDeviceRuntimeInfo.object = std::make_shared<RuntimeInfo>();
102 }
103
104 status_t status = gDeviceRuntimeInfo.object->fetchAllInformation(flags);
105 if (status != OK) {
106 gDeviceRuntimeInfo.fetchedFlags &= (~flags); // mark the fields as "not fetched"
107 return nullptr;
108 }
109
110 gDeviceRuntimeInfo.fetchedFlags |= flags;
111 return gDeviceRuntimeInfo.object;
Yifan Hong3daec812017-02-27 18:49:11 -0800112}
113
Yifan Hong143cfe62017-04-13 20:18:01 -0700114namespace details {
115
Yifan Hong143cfe62017-04-13 20:18:01 -0700116enum class ParseStatus {
117 OK,
118 PARSE_ERROR,
119 DUPLICATED_FWK_ENTRY,
120 DUPLICATED_DEV_ENTRY,
121};
122
Yifan Hong9532bd22017-04-14 15:30:52 -0700123static std::string toString(ParseStatus status) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700124 switch(status) {
125 case ParseStatus::OK: return "OK";
126 case ParseStatus::PARSE_ERROR: return "parse error";
127 case ParseStatus::DUPLICATED_FWK_ENTRY: return "duplicated framework";
128 case ParseStatus::DUPLICATED_DEV_ENTRY: return "duplicated device";
129 }
130 return "";
131}
132
133template<typename T>
Yifan Hong9532bd22017-04-14 15:30:52 -0700134static ParseStatus tryParse(const std::string &xml, const XmlConverter<T> &parse,
Yifan Hongfc73edf2017-08-29 11:39:07 -0700135 std::shared_ptr<T> *fwk, std::shared_ptr<T> *dev) {
136 std::shared_ptr<T> ret = std::make_shared<T>();
Yifan Hong143cfe62017-04-13 20:18:01 -0700137 if (!parse(ret.get(), xml)) {
138 return ParseStatus::PARSE_ERROR;
139 }
140 if (ret->type() == SchemaType::FRAMEWORK) {
141 if (fwk->get() != nullptr) {
142 return ParseStatus::DUPLICATED_FWK_ENTRY;
143 }
144 *fwk = std::move(ret);
145 } else if (ret->type() == SchemaType::DEVICE) {
146 if (dev->get() != nullptr) {
147 return ParseStatus::DUPLICATED_DEV_ENTRY;
148 }
149 *dev = std::move(ret);
150 }
151 return ParseStatus::OK;
152}
153
154template<typename T, typename GetFunction>
Yifan Hongfc73edf2017-08-29 11:39:07 -0700155static status_t getMissing(const std::shared_ptr<T>& pkg, bool mount,
Yifan Hong143cfe62017-04-13 20:18:01 -0700156 std::function<status_t(void)> mountFunction,
Yifan Hongfc73edf2017-08-29 11:39:07 -0700157 std::shared_ptr<const T>* updated,
Yifan Hong143cfe62017-04-13 20:18:01 -0700158 GetFunction getFunction) {
159 if (pkg != nullptr) {
160 *updated = pkg;
161 } else {
162 if (mount) {
163 (void)mountFunction(); // ignore mount errors
164 }
165 *updated = getFunction();
166 }
167 return OK;
168}
169
170#define ADD_MESSAGE(__error__) \
171 if (error != nullptr) { \
172 *error += (__error__); \
173 } \
174
175struct PackageInfo {
176 struct Pair {
Yifan Hongfc73edf2017-08-29 11:39:07 -0700177 std::shared_ptr<HalManifest> manifest;
178 std::shared_ptr<CompatibilityMatrix> matrix;
Yifan Hong143cfe62017-04-13 20:18:01 -0700179 };
180 Pair dev;
181 Pair fwk;
182};
183
184struct UpdatedInfo {
185 struct Pair {
Yifan Hongfc73edf2017-08-29 11:39:07 -0700186 std::shared_ptr<const HalManifest> manifest;
187 std::shared_ptr<const CompatibilityMatrix> matrix;
Yifan Hong143cfe62017-04-13 20:18:01 -0700188 };
189 Pair dev;
190 Pair fwk;
Yifan Hongfc73edf2017-08-29 11:39:07 -0700191 std::shared_ptr<const RuntimeInfo> runtimeInfo;
Yifan Hong143cfe62017-04-13 20:18:01 -0700192};
193
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700194// Checks given compatibility info against info on the device. If no
195// compatability info is given then the device info will be checked against
196// itself.
Yifan Hongdb6423e2017-09-11 14:38:46 -0700197int32_t checkCompatibility(const std::vector<std::string>& xmls, bool mount,
198 const PartitionMounter& mounter, std::string* error,
199 DisabledChecks disabledChecks) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700200 status_t status;
201 ParseStatus parseStatus;
202 PackageInfo pkg; // All information from package.
203 UpdatedInfo updated; // All files and runtime info after the update.
204
Yifan Hong143cfe62017-04-13 20:18:01 -0700205 // parse all information from package
206 for (const auto &xml : xmls) {
207 parseStatus = tryParse(xml, gHalManifestConverter, &pkg.fwk.manifest, &pkg.dev.manifest);
208 if (parseStatus == ParseStatus::OK) {
209 continue; // work on next one
210 }
211 if (parseStatus != ParseStatus::PARSE_ERROR) {
212 ADD_MESSAGE(toString(parseStatus) + " manifest");
213 return ALREADY_EXISTS;
214 }
215 parseStatus = tryParse(xml, gCompatibilityMatrixConverter, &pkg.fwk.matrix, &pkg.dev.matrix);
216 if (parseStatus == ParseStatus::OK) {
217 continue; // work on next one
218 }
219 if (parseStatus != ParseStatus::PARSE_ERROR) {
220 ADD_MESSAGE(toString(parseStatus) + " matrix");
221 return ALREADY_EXISTS;
222 }
223 ADD_MESSAGE(toString(parseStatus)); // parse error
224 return BAD_VALUE;
225 }
226
227 // get missing info from device
Yifan Hong8640cd12017-05-17 12:02:28 -0700228 // use functions instead of std::bind because std::bind doesn't work well with mock objects
229 auto mountSystem = [&mounter] { return mounter.mountSystem(); };
230 auto mountVendor = [&mounter] { return mounter.mountVendor(); };
231 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700232 pkg.fwk.manifest, mount, mountSystem, &updated.fwk.manifest,
Yifan Hong8640cd12017-05-17 12:02:28 -0700233 std::bind(VintfObject::GetFrameworkHalManifest, true /* skipCache */))) != OK) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700234 return status;
235 }
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700236 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700237 pkg.dev.manifest, mount, mountVendor, &updated.dev.manifest,
Yifan Hong8640cd12017-05-17 12:02:28 -0700238 std::bind(VintfObject::GetDeviceHalManifest, true /* skipCache */))) != OK) {
239 return status;
240 }
241 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700242 pkg.fwk.matrix, mount, mountSystem, &updated.fwk.matrix,
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700243 std::bind(VintfObject::GetFrameworkCompatibilityMatrix, true /* skipCache */))) !=
244 OK) {
245 return status;
246 }
247 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700248 pkg.dev.matrix, mount, mountVendor, &updated.dev.matrix,
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700249 std::bind(VintfObject::GetDeviceCompatibilityMatrix, true /* skipCache */))) != OK) {
250 return status;
251 }
Yifan Hong8640cd12017-05-17 12:02:28 -0700252
253 if (mount) {
254 (void)mounter.umountSystem(); // ignore errors
255 (void)mounter.umountVendor(); // ignore errors
256 }
257
258 updated.runtimeInfo = VintfObject::GetRuntimeInfo(true /* skipCache */);
Yifan Hong143cfe62017-04-13 20:18:01 -0700259
260 // null checks for files and runtime info after the update
261 // TODO(b/37321309) if a compat mat is missing, it is not matched and considered compatible.
262 if (updated.fwk.manifest == nullptr) {
263 ADD_MESSAGE("No framework manifest file from device or from update package");
264 return NO_INIT;
265 }
266 if (updated.dev.manifest == nullptr) {
267 ADD_MESSAGE("No device manifest file from device or from update package");
268 return NO_INIT;
269 }
270 if (updated.fwk.matrix == nullptr) {
271 ADD_MESSAGE("No framework matrix, skipping;");
272 // TODO(b/37321309) consider missing matricies as errors.
273 }
274 if (updated.dev.matrix == nullptr) {
275 ADD_MESSAGE("No device matrix, skipping;");
276 // TODO(b/37321309) consider missing matricies as errors.
277 }
278 if (updated.runtimeInfo == nullptr) {
279 ADD_MESSAGE("No runtime info from device");
280 return NO_INIT;
281 }
282
283 // compatiblity check.
284 // TODO(b/37321309) outer if checks can be removed if we consider missing matrices as errors.
285 if (updated.dev.manifest && updated.fwk.matrix) {
286 if (!updated.dev.manifest->checkCompatibility(*updated.fwk.matrix, error)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700287 if (error)
288 error->insert(0, "Device manifest and framework compatibility matrix "
289 "are incompatible: ");
Yifan Hong143cfe62017-04-13 20:18:01 -0700290 return INCOMPATIBLE;
291 }
292 }
293 if (updated.fwk.manifest && updated.dev.matrix) {
294 if (!updated.fwk.manifest->checkCompatibility(*updated.dev.matrix, error)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700295 if (error)
296 error->insert(0, "Framework manifest and device compatibility matrix "
297 "are incompatible: ");
Yifan Hong143cfe62017-04-13 20:18:01 -0700298 return INCOMPATIBLE;
299 }
300 }
301 if (updated.runtimeInfo && updated.fwk.matrix) {
Yifan Hongdb6423e2017-09-11 14:38:46 -0700302 if (!updated.runtimeInfo->checkCompatibility(*updated.fwk.matrix, error, disabledChecks)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700303 if (error)
304 error->insert(0, "Runtime info and framework compatibility matrix "
305 "are incompatible: ");
Yifan Honge8b86842017-05-25 17:59:22 +0000306 return INCOMPATIBLE;
Yifan Hong143cfe62017-04-13 20:18:01 -0700307 }
308 }
309
310 return COMPATIBLE;
311}
312
313} // namespace details
314
Yifan Hongfbbf0472017-04-07 18:14:18 -0700315// static
Yifan Hongdb6423e2017-09-11 14:38:46 -0700316int32_t VintfObject::CheckCompatibility(const std::vector<std::string>& xmls, std::string* error,
317 DisabledChecks disabledChecks) {
318 return details::checkCompatibility(xmls, false /* mount */, *details::gPartitionMounter, error,
319 disabledChecks);
Yifan Hongfbbf0472017-04-07 18:14:18 -0700320}
321
Yifan Hong3daec812017-02-27 18:49:11 -0800322
323} // namespace vintf
324} // namespace android