diff options
author | Yifan Hong | 2018-01-16 15:11:23 -0600 |
---|---|---|
committer | android-build-merger | 2018-01-16 15:11:23 -0600 |
commit | 9d2c77276bb4f77273f287efd7f4082384127ffc (patch) | |
tree | 12a9e88176075bc44cdc2fe98a1b396136de0131 | |
parent | b7008f8d49920594ce28dbeb36057394816d1c59 (diff) | |
parent | 85b1bde302c7dfc42c8a9b8dbb5db26c88c1f362 (diff) | |
download | platform-system-libvintf-9d2c77276bb4f77273f287efd7f4082384127ffc.tar.gz platform-system-libvintf-9d2c77276bb4f77273f287efd7f4082384127ffc.tar.xz platform-system-libvintf-9d2c77276bb4f77273f287efd7f4082384127ffc.zip |
VintfObject::GetFwkMatrix combine matrices at runtime am: d52bf3e64c am: f1166a6a17
am: 85b1bde302
Change-Id: If17c173ce5d31ca63e6f22b42a57dbd682b749fe
-rw-r--r-- | VintfObject.cpp | 123 | ||||
-rw-r--r-- | include/vintf/CompatibilityMatrix.h | 1 | ||||
-rw-r--r-- | include/vintf/VintfObject.h | 8 | ||||
-rw-r--r-- | test/Android.bp | 2 | ||||
-rw-r--r-- | test/utils-fake.h | 5 | ||||
-rw-r--r-- | test/vintf_object_tests.cpp | 38 | ||||
-rw-r--r-- | utils.h | 21 |
7 files changed, 198 insertions, 0 deletions
diff --git a/VintfObject.cpp b/VintfObject.cpp index 8dd08ef..24694cd 100644 --- a/VintfObject.cpp +++ b/VintfObject.cpp | |||
@@ -20,6 +20,8 @@ | |||
20 | #include "parse_xml.h" | 20 | #include "parse_xml.h" |
21 | #include "utils.h" | 21 | #include "utils.h" |
22 | 22 | ||
23 | #include <dirent.h> | ||
24 | |||
23 | #include <functional> | 25 | #include <functional> |
24 | #include <memory> | 26 | #include <memory> |
25 | #include <mutex> | 27 | #include <mutex> |
@@ -30,6 +32,8 @@ | |||
30 | 32 | ||
31 | #include <android-base/logging.h> | 33 | #include <android-base/logging.h> |
32 | 34 | ||
35 | #define FRAMEWORK_MATRIX_DIR "/system/etc/vintf/" | ||
36 | |||
33 | using std::placeholders::_1; | 37 | using std::placeholders::_1; |
34 | using std::placeholders::_2; | 38 | using std::placeholders::_2; |
35 | 39 | ||
@@ -119,11 +123,130 @@ std::shared_ptr<const CompatibilityMatrix> VintfObject::GetDeviceCompatibilityMa | |||
119 | // static | 123 | // static |
120 | std::shared_ptr<const CompatibilityMatrix> VintfObject::GetFrameworkCompatibilityMatrix(bool skipCache) { | 124 | std::shared_ptr<const CompatibilityMatrix> VintfObject::GetFrameworkCompatibilityMatrix(bool skipCache) { |
121 | static LockedSharedPtr<CompatibilityMatrix> gFrameworkMatrix; | 125 | static LockedSharedPtr<CompatibilityMatrix> gFrameworkMatrix; |
126 | static LockedSharedPtr<CompatibilityMatrix> gCombinedFrameworkMatrix; | ||
127 | static std::mutex gFrameworkCompatibilityMatrixMutex; | ||
128 | |||
129 | // To avoid deadlock, get device manifest before any locks. | ||
130 | auto deviceManifest = GetDeviceHalManifest(); | ||
131 | |||
132 | std::unique_lock<std::mutex> _lock(gFrameworkCompatibilityMatrixMutex); | ||
133 | |||
134 | auto combined = | ||
135 | Get(&gCombinedFrameworkMatrix, skipCache, | ||
136 | std::bind(&VintfObject::GetCombinedFrameworkMatrix, deviceManifest, _1, _2)); | ||
137 | if (combined != nullptr) { | ||
138 | return combined; | ||
139 | } | ||
140 | |||
122 | return Get(&gFrameworkMatrix, skipCache, | 141 | return Get(&gFrameworkMatrix, skipCache, |
123 | std::bind(&CompatibilityMatrix::fetchAllInformation, _1, | 142 | std::bind(&CompatibilityMatrix::fetchAllInformation, _1, |
124 | "/system/compatibility_matrix.xml", _2)); | 143 | "/system/compatibility_matrix.xml", _2)); |
125 | } | 144 | } |
126 | 145 | ||
146 | status_t VintfObject::GetCombinedFrameworkMatrix( | ||
147 | const std::shared_ptr<const HalManifest>& deviceManifest, CompatibilityMatrix* out, | ||
148 | std::string* error) { | ||
149 | auto matrixFragments = GetAllFrameworkMatrixLevels(error); | ||
150 | if (matrixFragments.empty()) { | ||
151 | return NAME_NOT_FOUND; | ||
152 | } | ||
153 | |||
154 | Level deviceLevel = Level::UNSPECIFIED; | ||
155 | |||
156 | if (deviceManifest != nullptr) { | ||
157 | deviceLevel = deviceManifest->level(); | ||
158 | } | ||
159 | |||
160 | // TODO(b/70628538): Do not infer from Shipping API level. | ||
161 | #ifdef LIBVINTF_TARGET | ||
162 | if (deviceLevel == Level::UNSPECIFIED) { | ||
163 | auto shippingApi = | ||
164 | android::base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0u); | ||
165 | if (shippingApi != 0u) { | ||
166 | deviceLevel = details::convertFromApiLevel(shippingApi); | ||
167 | } | ||
168 | } | ||
169 | #endif | ||
170 | |||
171 | if (deviceLevel == Level::UNSPECIFIED) { | ||
172 | // Cannot infer FCM version. Combine all matrices by assuming | ||
173 | // Shipping FCM Version == min(all supported FCM Versions in the framework) | ||
174 | for (auto&& pair : matrixFragments) { | ||
175 | Level fragmentLevel = pair.object.level(); | ||
176 | if (fragmentLevel != Level::UNSPECIFIED && deviceLevel > fragmentLevel) { | ||
177 | deviceLevel = fragmentLevel; | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | |||
182 | if (deviceLevel == Level::UNSPECIFIED) { | ||
183 | // None of the fragments specify any FCM version. Should never happen except | ||
184 | // for inconsistent builds. | ||
185 | if (error) { | ||
186 | *error = "No framework compatibility matrix files under " FRAMEWORK_MATRIX_DIR | ||
187 | " declare FCM version."; | ||
188 | } | ||
189 | return NAME_NOT_FOUND; | ||
190 | } | ||
191 | |||
192 | CompatibilityMatrix* combined = | ||
193 | CompatibilityMatrix::combine(deviceLevel, &matrixFragments, error); | ||
194 | if (combined == nullptr) { | ||
195 | return BAD_VALUE; | ||
196 | } | ||
197 | *out = std::move(*combined); | ||
198 | return OK; | ||
199 | } | ||
200 | |||
201 | std::vector<Named<CompatibilityMatrix>> VintfObject::GetAllFrameworkMatrixLevels( | ||
202 | std::string* error) { | ||
203 | std::vector<std::string> fileNames; | ||
204 | std::vector<Named<CompatibilityMatrix>> results; | ||
205 | |||
206 | if (details::gFetcher->listFiles(FRAMEWORK_MATRIX_DIR, &fileNames, error) != OK) { | ||
207 | return {}; | ||
208 | } | ||
209 | for (const std::string& fileName : fileNames) { | ||
210 | std::string path = FRAMEWORK_MATRIX_DIR + fileName; | ||
211 | |||
212 | std::string content; | ||
213 | std::string fetchError; | ||
214 | status_t status = details::gFetcher->fetch(path, content, &fetchError); | ||
215 | if (status != OK) { | ||
216 | if (error) { | ||
217 | *error += "Ignore file " + path + ": " + fetchError + "\n"; | ||
218 | } | ||
219 | continue; | ||
220 | } | ||
221 | |||
222 | auto it = results.emplace(results.end()); | ||
223 | if (!gCompatibilityMatrixConverter(&it->object, content)) { | ||
224 | if (error) { | ||
225 | // TODO(b/71874788): do not use lastError() because it is not thread-safe. | ||
226 | *error += | ||
227 | "Ignore file " + path + ": " + gCompatibilityMatrixConverter.lastError() + "\n"; | ||
228 | } | ||
229 | results.erase(it); | ||
230 | continue; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | if (results.empty()) { | ||
235 | if (error) { | ||
236 | *error = "No framework matrices under " FRAMEWORK_MATRIX_DIR | ||
237 | " can be fetched or parsed.\n" + | ||
238 | *error; | ||
239 | } | ||
240 | } else { | ||
241 | if (error && !error->empty()) { | ||
242 | LOG(WARNING) << *error; | ||
243 | *error = ""; | ||
244 | } | ||
245 | } | ||
246 | |||
247 | return results; | ||
248 | } | ||
249 | |||
127 | // static | 250 | // static |
128 | std::shared_ptr<const RuntimeInfo> VintfObject::GetRuntimeInfo(bool skipCache, | 251 | std::shared_ptr<const RuntimeInfo> VintfObject::GetRuntimeInfo(bool skipCache, |
129 | RuntimeInfo::FetchFlags flags) { | 252 | RuntimeInfo::FetchFlags flags) { |
diff --git a/include/vintf/CompatibilityMatrix.h b/include/vintf/CompatibilityMatrix.h index e3432a0..b7a5541 100644 --- a/include/vintf/CompatibilityMatrix.h +++ b/include/vintf/CompatibilityMatrix.h | |||
@@ -82,6 +82,7 @@ struct CompatibilityMatrix : public HalGroup<MatrixHal>, public XmlFileGroup<Mat | |||
82 | // - If level() == deviceLevel, all HAL versions and XML files are added as is | 82 | // - If level() == deviceLevel, all HAL versions and XML files are added as is |
83 | // (optionality is kept) | 83 | // (optionality is kept) |
84 | // - If level() > deviceLevel, all HAL versions and XML files are added as optional. | 84 | // - If level() > deviceLevel, all HAL versions and XML files are added as optional. |
85 | // Return a pointer into one of the elements in "matrices". | ||
85 | static CompatibilityMatrix* combine(Level deviceLevel, | 86 | static CompatibilityMatrix* combine(Level deviceLevel, |
86 | std::vector<Named<CompatibilityMatrix>>* matrices, | 87 | std::vector<Named<CompatibilityMatrix>>* matrices, |
87 | std::string* error); | 88 | std::string* error); |
diff --git a/include/vintf/VintfObject.h b/include/vintf/VintfObject.h index 5593da5..80df9ea 100644 --- a/include/vintf/VintfObject.h +++ b/include/vintf/VintfObject.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "CompatibilityMatrix.h" | 22 | #include "CompatibilityMatrix.h" |
23 | #include "DisabledChecks.h" | 23 | #include "DisabledChecks.h" |
24 | #include "HalManifest.h" | 24 | #include "HalManifest.h" |
25 | #include "Named.h" | ||
25 | #include "RuntimeInfo.h" | 26 | #include "RuntimeInfo.h" |
26 | 27 | ||
27 | namespace android { | 28 | namespace android { |
@@ -110,6 +111,13 @@ public: | |||
110 | static int32_t CheckCompatibility(const std::vector<std::string>& packageInfo, | 111 | static int32_t CheckCompatibility(const std::vector<std::string>& packageInfo, |
111 | std::string* error = nullptr, | 112 | std::string* error = nullptr, |
112 | DisabledChecks disabledChecks = ENABLE_ALL_CHECKS); | 113 | DisabledChecks disabledChecks = ENABLE_ALL_CHECKS); |
114 | |||
115 | private: | ||
116 | static status_t GetCombinedFrameworkMatrix( | ||
117 | const std::shared_ptr<const HalManifest>& deviceManifest, CompatibilityMatrix* out, | ||
118 | std::string* error = nullptr); | ||
119 | static std::vector<Named<CompatibilityMatrix>> GetAllFrameworkMatrixLevels( | ||
120 | std::string* error = nullptr); | ||
113 | }; | 121 | }; |
114 | 122 | ||
115 | enum : int32_t { | 123 | enum : int32_t { |
diff --git a/test/Android.bp b/test/Android.bp index 607d452..540298a 100644 --- a/test/Android.bp +++ b/test/Android.bp | |||
@@ -68,6 +68,8 @@ cc_test { | |||
68 | cflags: [ | 68 | cflags: [ |
69 | "-O0", | 69 | "-O0", |
70 | "-g", | 70 | "-g", |
71 | // Unexpected logging of string pointer warning from gmock | ||
72 | "-Wno-user-defined-warnings" | ||
71 | ], | 73 | ], |
72 | target: { | 74 | target: { |
73 | android: { | 75 | android: { |
diff --git a/test/utils-fake.h b/test/utils-fake.h index 7d7caf2..e2b2706 100644 --- a/test/utils-fake.h +++ b/test/utils-fake.h | |||
@@ -34,9 +34,14 @@ class MockFileFetcher : public FileFetcher { | |||
34 | ON_CALL(*this, fetch(_, _)).WillByDefault(Invoke([this](const auto& path, auto& fetched) { | 34 | ON_CALL(*this, fetch(_, _)).WillByDefault(Invoke([this](const auto& path, auto& fetched) { |
35 | return real_.fetchInternal(path, fetched, nullptr); | 35 | return real_.fetchInternal(path, fetched, nullptr); |
36 | })); | 36 | })); |
37 | ON_CALL(*this, listFiles(_, _, _)) | ||
38 | .WillByDefault( | ||
39 | Invoke([this](const std::string& path, std::vector<std::string>* out, | ||
40 | std::string* error) { return real_.listFiles(path, out, error); })); | ||
37 | } | 41 | } |
38 | 42 | ||
39 | MOCK_METHOD2(fetch, status_t(const std::string& path, std::string& fetched)); | 43 | MOCK_METHOD2(fetch, status_t(const std::string& path, std::string& fetched)); |
44 | MOCK_METHOD3(listFiles, status_t(const std::string&, std::vector<std::string>*, std::string*)); | ||
40 | 45 | ||
41 | status_t fetch(const std::string& path, std::string& fetched, std::string*) override final { | 46 | status_t fetch(const std::string& path, std::string& fetched, std::string*) override final { |
42 | return fetch(path, fetched); | 47 | return fetch(path, fetched); |
diff --git a/test/vintf_object_tests.cpp b/test/vintf_object_tests.cpp index 61eb4df..2dc2d8a 100644 --- a/test/vintf_object_tests.cpp +++ b/test/vintf_object_tests.cpp | |||
@@ -204,6 +204,9 @@ void setupMockFetcher(const std::string& vendorManifestXml, const std::string& s | |||
204 | fetched = systemMatrixXml; | 204 | fetched = systemMatrixXml; |
205 | return 0; | 205 | return 0; |
206 | })); | 206 | })); |
207 | // Don't list /system/etc/vintf unless otherwise specified. | ||
208 | ON_CALL(*fetcher, listFiles(StrEq("/system/etc/vintf/"), _, _)) | ||
209 | .WillByDefault(Return(::android::OK)); | ||
207 | } | 210 | } |
208 | 211 | ||
209 | static MockPartitionMounter &mounter() { | 212 | static MockPartitionMounter &mounter() { |
@@ -521,6 +524,41 @@ TEST_F(VintfObjectRuntimeInfoTest, GetRuntimeInfo) { | |||
521 | VintfObject::GetRuntimeInfo(false /* skipCache */, RuntimeInfo::FetchFlag::ALL); | 524 | VintfObject::GetRuntimeInfo(false /* skipCache */, RuntimeInfo::FetchFlag::ALL); |
522 | } | 525 | } |
523 | 526 | ||
527 | // Test fixture that provides incompatible metadata from the mock device. | ||
528 | class VintfObjectTest : public testing::Test { | ||
529 | protected: | ||
530 | virtual void SetUp() {} | ||
531 | virtual void TearDown() { | ||
532 | Mock::VerifyAndClear(&fetcher()); | ||
533 | Mock::VerifyAndClear(&mounter()); | ||
534 | } | ||
535 | }; | ||
536 | |||
537 | // Test framework compatibility matrix is combined at runtime | ||
538 | TEST_F(VintfObjectTest, FrameworkCompatibilityMatrixCombine) { | ||
539 | EXPECT_CALL(fetcher(), listFiles(StrEq("/system/etc/vintf/"), _, _)) | ||
540 | .WillOnce(Invoke([](const auto&, auto* out, auto*) { | ||
541 | *out = { | ||
542 | "compatibility_matrix.1.xml", | ||
543 | "compatibility_matrix.empty.xml", | ||
544 | }; | ||
545 | return ::android::OK; | ||
546 | })); | ||
547 | EXPECT_CALL(fetcher(), fetch(StrEq("/system/etc/vintf/compatibility_matrix.1.xml"), _)) | ||
548 | .WillOnce(Invoke([](const auto&, auto& out) { | ||
549 | out = "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\"/>"; | ||
550 | return ::android::OK; | ||
551 | })); | ||
552 | EXPECT_CALL(fetcher(), fetch(StrEq("/system/etc/vintf/compatibility_matrix.empty.xml"), _)) | ||
553 | .WillOnce(Invoke([](const auto&, auto& out) { | ||
554 | out = "<compatibility-matrix version=\"1.0\" type=\"framework\"/>"; | ||
555 | return ::android::OK; | ||
556 | })); | ||
557 | EXPECT_CALL(fetcher(), fetch(StrEq("/system/compatibility_matrix.xml"), _)).Times(0); | ||
558 | |||
559 | EXPECT_NE(nullptr, VintfObject::GetFrameworkCompatibilityMatrix(true /* skipCache */)); | ||
560 | } | ||
561 | |||
524 | int main(int argc, char** argv) { | 562 | int main(int argc, char** argv) { |
525 | ::testing::InitGoogleMock(&argc, argv); | 563 | ::testing::InitGoogleMock(&argc, argv); |
526 | 564 | ||
@@ -17,8 +17,11 @@ | |||
17 | #ifndef ANDROID_VINTF_UTILS_H | 17 | #ifndef ANDROID_VINTF_UTILS_H |
18 | #define ANDROID_VINTF_UTILS_H | 18 | #define ANDROID_VINTF_UTILS_H |
19 | 19 | ||
20 | #include <dirent.h> | ||
21 | |||
20 | #include <fstream> | 22 | #include <fstream> |
21 | #include <iostream> | 23 | #include <iostream> |
24 | #include <memory> | ||
22 | #include <sstream> | 25 | #include <sstream> |
23 | 26 | ||
24 | #include <utils/Errors.h> | 27 | #include <utils/Errors.h> |
@@ -58,6 +61,24 @@ class FileFetcher { | |||
58 | virtual status_t fetch(const std::string& path, std::string& fetched) { | 61 | virtual status_t fetch(const std::string& path, std::string& fetched) { |
59 | return fetchInternal(path, fetched, nullptr); | 62 | return fetchInternal(path, fetched, nullptr); |
60 | } | 63 | } |
64 | virtual status_t listFiles(const std::string& path, std::vector<std::string>* out, | ||
65 | std::string* error) { | ||
66 | std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir); | ||
67 | if (!dir) { | ||
68 | if (error) { | ||
69 | *error = "Cannot open " + path; | ||
70 | } | ||
71 | return NAME_NOT_FOUND; | ||
72 | } | ||
73 | |||
74 | dirent* dp; | ||
75 | while ((dp = readdir(dir.get())) != nullptr) { | ||
76 | if (dp->d_type != DT_DIR) { | ||
77 | out->push_back(dp->d_name); | ||
78 | } | ||
79 | } | ||
80 | return OK; | ||
81 | } | ||
61 | }; | 82 | }; |
62 | 83 | ||
63 | extern FileFetcher* gFetcher; | 84 | extern FileFetcher* gFetcher; |