blob: 0f590b6e6940551a048c8e7281873a917c73b32d [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 Hong3daec812017-02-27 18:49:11 -080036template <typename T, typename F>
Yifan Hongfc73edf2017-08-29 11:39:07 -070037static std::shared_ptr<const T> Get(
38 LockedSharedPtr<T> *ptr,
Yifan Hong143cfe62017-04-13 20:18:01 -070039 bool skipCache,
Yifan Hong3daec812017-02-27 18:49:11 -080040 const F &fetchAllInformation) {
41 std::unique_lock<std::mutex> _lock(ptr->mutex);
Yifan Hong143cfe62017-04-13 20:18:01 -070042 if (skipCache || ptr->object == nullptr) {
Yifan Hong3daec812017-02-27 18:49:11 -080043 ptr->object = std::make_unique<T>();
44 if (fetchAllInformation(ptr->object.get()) != OK) {
45 ptr->object = nullptr; // frees the old object
46 }
47 }
Yifan Hongfc73edf2017-08-29 11:39:07 -070048 return ptr->object;
Yifan Hong3daec812017-02-27 18:49:11 -080049}
50
51// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070052std::shared_ptr<const HalManifest> VintfObject::GetDeviceHalManifest(bool skipCache) {
53 static LockedSharedPtr<HalManifest> gDeviceManifest;
Yifan Hong143cfe62017-04-13 20:18:01 -070054 return Get(&gDeviceManifest, skipCache,
Yifan Hong3daec812017-02-27 18:49:11 -080055 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1,
56 "/vendor/manifest.xml"));
57}
58
59// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070060std::shared_ptr<const HalManifest> VintfObject::GetFrameworkHalManifest(bool skipCache) {
61 static LockedSharedPtr<HalManifest> gFrameworkManifest;
Yifan Hong143cfe62017-04-13 20:18:01 -070062 return Get(&gFrameworkManifest, skipCache,
Yifan Hong3daec812017-02-27 18:49:11 -080063 std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1,
64 "/system/manifest.xml"));
65}
66
Yifan Hong2272bf82017-04-28 14:37:56 -070067
68// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070069std::shared_ptr<const CompatibilityMatrix> VintfObject::GetDeviceCompatibilityMatrix(bool skipCache) {
70 static LockedSharedPtr<CompatibilityMatrix> gDeviceMatrix;
Yifan Hong2272bf82017-04-28 14:37:56 -070071 return Get(&gDeviceMatrix, skipCache,
72 std::bind(&CompatibilityMatrix::fetchAllInformation, std::placeholders::_1,
73 "/vendor/compatibility_matrix.xml"));
74}
75
76// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070077std::shared_ptr<const CompatibilityMatrix> VintfObject::GetFrameworkCompatibilityMatrix(bool skipCache) {
78 static LockedSharedPtr<CompatibilityMatrix> gFrameworkMatrix;
Yifan Hong2272bf82017-04-28 14:37:56 -070079 return Get(&gFrameworkMatrix, skipCache,
80 std::bind(&CompatibilityMatrix::fetchAllInformation, std::placeholders::_1,
81 "/system/compatibility_matrix.xml"));
82}
83
Yifan Hong3daec812017-02-27 18:49:11 -080084// static
Yifan Hongfc73edf2017-08-29 11:39:07 -070085std::shared_ptr<const RuntimeInfo> VintfObject::GetRuntimeInfo(bool skipCache) {
86 static LockedSharedPtr<RuntimeInfo> gDeviceRuntimeInfo;
Yifan Hong143cfe62017-04-13 20:18:01 -070087 return Get(&gDeviceRuntimeInfo, skipCache,
Yifan Hong3daec812017-02-27 18:49:11 -080088 std::bind(&RuntimeInfo::fetchAllInformation, std::placeholders::_1));
89}
90
Yifan Hong143cfe62017-04-13 20:18:01 -070091namespace details {
92
Yifan Hong143cfe62017-04-13 20:18:01 -070093enum class ParseStatus {
94 OK,
95 PARSE_ERROR,
96 DUPLICATED_FWK_ENTRY,
97 DUPLICATED_DEV_ENTRY,
98};
99
Yifan Hong9532bd22017-04-14 15:30:52 -0700100static std::string toString(ParseStatus status) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700101 switch(status) {
102 case ParseStatus::OK: return "OK";
103 case ParseStatus::PARSE_ERROR: return "parse error";
104 case ParseStatus::DUPLICATED_FWK_ENTRY: return "duplicated framework";
105 case ParseStatus::DUPLICATED_DEV_ENTRY: return "duplicated device";
106 }
107 return "";
108}
109
110template<typename T>
Yifan Hong9532bd22017-04-14 15:30:52 -0700111static ParseStatus tryParse(const std::string &xml, const XmlConverter<T> &parse,
Yifan Hongfc73edf2017-08-29 11:39:07 -0700112 std::shared_ptr<T> *fwk, std::shared_ptr<T> *dev) {
113 std::shared_ptr<T> ret = std::make_shared<T>();
Yifan Hong143cfe62017-04-13 20:18:01 -0700114 if (!parse(ret.get(), xml)) {
115 return ParseStatus::PARSE_ERROR;
116 }
117 if (ret->type() == SchemaType::FRAMEWORK) {
118 if (fwk->get() != nullptr) {
119 return ParseStatus::DUPLICATED_FWK_ENTRY;
120 }
121 *fwk = std::move(ret);
122 } else if (ret->type() == SchemaType::DEVICE) {
123 if (dev->get() != nullptr) {
124 return ParseStatus::DUPLICATED_DEV_ENTRY;
125 }
126 *dev = std::move(ret);
127 }
128 return ParseStatus::OK;
129}
130
131template<typename T, typename GetFunction>
Yifan Hongfc73edf2017-08-29 11:39:07 -0700132static status_t getMissing(const std::shared_ptr<T>& pkg, bool mount,
Yifan Hong143cfe62017-04-13 20:18:01 -0700133 std::function<status_t(void)> mountFunction,
Yifan Hongfc73edf2017-08-29 11:39:07 -0700134 std::shared_ptr<const T>* updated,
Yifan Hong143cfe62017-04-13 20:18:01 -0700135 GetFunction getFunction) {
136 if (pkg != nullptr) {
137 *updated = pkg;
138 } else {
139 if (mount) {
140 (void)mountFunction(); // ignore mount errors
141 }
142 *updated = getFunction();
143 }
144 return OK;
145}
146
147#define ADD_MESSAGE(__error__) \
148 if (error != nullptr) { \
149 *error += (__error__); \
150 } \
151
152struct PackageInfo {
153 struct Pair {
Yifan Hongfc73edf2017-08-29 11:39:07 -0700154 std::shared_ptr<HalManifest> manifest;
155 std::shared_ptr<CompatibilityMatrix> matrix;
Yifan Hong143cfe62017-04-13 20:18:01 -0700156 };
157 Pair dev;
158 Pair fwk;
159};
160
161struct UpdatedInfo {
162 struct Pair {
Yifan Hongfc73edf2017-08-29 11:39:07 -0700163 std::shared_ptr<const HalManifest> manifest;
164 std::shared_ptr<const CompatibilityMatrix> matrix;
Yifan Hong143cfe62017-04-13 20:18:01 -0700165 };
166 Pair dev;
167 Pair fwk;
Yifan Hongfc73edf2017-08-29 11:39:07 -0700168 std::shared_ptr<const RuntimeInfo> runtimeInfo;
Yifan Hong143cfe62017-04-13 20:18:01 -0700169};
170
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700171// Checks given compatibility info against info on the device. If no
172// compatability info is given then the device info will be checked against
173// itself.
Yifan Hong143cfe62017-04-13 20:18:01 -0700174int32_t checkCompatibility(const std::vector<std::string> &xmls, bool mount,
Yifan Hong8640cd12017-05-17 12:02:28 -0700175 const PartitionMounter &mounter, std::string *error) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700176
177 status_t status;
178 ParseStatus parseStatus;
179 PackageInfo pkg; // All information from package.
180 UpdatedInfo updated; // All files and runtime info after the update.
181
Yifan Hong143cfe62017-04-13 20:18:01 -0700182 // parse all information from package
183 for (const auto &xml : xmls) {
184 parseStatus = tryParse(xml, gHalManifestConverter, &pkg.fwk.manifest, &pkg.dev.manifest);
185 if (parseStatus == ParseStatus::OK) {
186 continue; // work on next one
187 }
188 if (parseStatus != ParseStatus::PARSE_ERROR) {
189 ADD_MESSAGE(toString(parseStatus) + " manifest");
190 return ALREADY_EXISTS;
191 }
192 parseStatus = tryParse(xml, gCompatibilityMatrixConverter, &pkg.fwk.matrix, &pkg.dev.matrix);
193 if (parseStatus == ParseStatus::OK) {
194 continue; // work on next one
195 }
196 if (parseStatus != ParseStatus::PARSE_ERROR) {
197 ADD_MESSAGE(toString(parseStatus) + " matrix");
198 return ALREADY_EXISTS;
199 }
200 ADD_MESSAGE(toString(parseStatus)); // parse error
201 return BAD_VALUE;
202 }
203
204 // get missing info from device
Yifan Hong8640cd12017-05-17 12:02:28 -0700205 // use functions instead of std::bind because std::bind doesn't work well with mock objects
206 auto mountSystem = [&mounter] { return mounter.mountSystem(); };
207 auto mountVendor = [&mounter] { return mounter.mountVendor(); };
208 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700209 pkg.fwk.manifest, mount, mountSystem, &updated.fwk.manifest,
Yifan Hong8640cd12017-05-17 12:02:28 -0700210 std::bind(VintfObject::GetFrameworkHalManifest, true /* skipCache */))) != OK) {
Yifan Hong143cfe62017-04-13 20:18:01 -0700211 return status;
212 }
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700213 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700214 pkg.dev.manifest, mount, mountVendor, &updated.dev.manifest,
Yifan Hong8640cd12017-05-17 12:02:28 -0700215 std::bind(VintfObject::GetDeviceHalManifest, true /* skipCache */))) != OK) {
216 return status;
217 }
218 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700219 pkg.fwk.matrix, mount, mountSystem, &updated.fwk.matrix,
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700220 std::bind(VintfObject::GetFrameworkCompatibilityMatrix, true /* skipCache */))) !=
221 OK) {
222 return status;
223 }
224 if ((status = getMissing(
Yifan Hongfc73edf2017-08-29 11:39:07 -0700225 pkg.dev.matrix, mount, mountVendor, &updated.dev.matrix,
Michael Schwartz97dc0f92017-05-08 14:07:14 -0700226 std::bind(VintfObject::GetDeviceCompatibilityMatrix, true /* skipCache */))) != OK) {
227 return status;
228 }
Yifan Hong8640cd12017-05-17 12:02:28 -0700229
230 if (mount) {
231 (void)mounter.umountSystem(); // ignore errors
232 (void)mounter.umountVendor(); // ignore errors
233 }
234
235 updated.runtimeInfo = VintfObject::GetRuntimeInfo(true /* skipCache */);
Yifan Hong143cfe62017-04-13 20:18:01 -0700236
237 // null checks for files and runtime info after the update
238 // TODO(b/37321309) if a compat mat is missing, it is not matched and considered compatible.
239 if (updated.fwk.manifest == nullptr) {
240 ADD_MESSAGE("No framework manifest file from device or from update package");
241 return NO_INIT;
242 }
243 if (updated.dev.manifest == nullptr) {
244 ADD_MESSAGE("No device manifest file from device or from update package");
245 return NO_INIT;
246 }
247 if (updated.fwk.matrix == nullptr) {
248 ADD_MESSAGE("No framework matrix, skipping;");
249 // TODO(b/37321309) consider missing matricies as errors.
250 }
251 if (updated.dev.matrix == nullptr) {
252 ADD_MESSAGE("No device matrix, skipping;");
253 // TODO(b/37321309) consider missing matricies as errors.
254 }
255 if (updated.runtimeInfo == nullptr) {
256 ADD_MESSAGE("No runtime info from device");
257 return NO_INIT;
258 }
259
260 // compatiblity check.
261 // TODO(b/37321309) outer if checks can be removed if we consider missing matrices as errors.
262 if (updated.dev.manifest && updated.fwk.matrix) {
263 if (!updated.dev.manifest->checkCompatibility(*updated.fwk.matrix, error)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700264 if (error)
265 error->insert(0, "Device manifest and framework compatibility matrix "
266 "are incompatible: ");
Yifan Hong143cfe62017-04-13 20:18:01 -0700267 return INCOMPATIBLE;
268 }
269 }
270 if (updated.fwk.manifest && updated.dev.matrix) {
271 if (!updated.fwk.manifest->checkCompatibility(*updated.dev.matrix, error)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700272 if (error)
273 error->insert(0, "Framework manifest and device compatibility matrix "
274 "are incompatible: ");
Yifan Hong143cfe62017-04-13 20:18:01 -0700275 return INCOMPATIBLE;
276 }
277 }
278 if (updated.runtimeInfo && updated.fwk.matrix) {
279 if (!updated.runtimeInfo->checkCompatibility(*updated.fwk.matrix, error)) {
Yifan Hong0d4be122017-05-15 17:04:22 -0700280 if (error)
281 error->insert(0, "Runtime info and framework compatibility matrix "
282 "are incompatible: ");
Yifan Honge8b86842017-05-25 17:59:22 +0000283 return INCOMPATIBLE;
Yifan Hong143cfe62017-04-13 20:18:01 -0700284 }
285 }
286
287 return COMPATIBLE;
288}
289
290} // namespace details
291
Yifan Hongfbbf0472017-04-07 18:14:18 -0700292// static
293int32_t VintfObject::CheckCompatibility(
Yifan Hong9532bd22017-04-14 15:30:52 -0700294 const std::vector<std::string> &xmls, std::string *error) {
295 return details::checkCompatibility(xmls, false /* mount */,
Yifan Hong8640cd12017-05-17 12:02:28 -0700296 *details::gPartitionMounter,
Yifan Hong143cfe62017-04-13 20:18:01 -0700297 error);
Yifan Hongfbbf0472017-04-07 18:14:18 -0700298}
299
Yifan Hong3daec812017-02-27 18:49:11 -0800300
301} // namespace vintf
302} // namespace android