xref: /aosp_15_r20/system/libvintf/VintfFm.cpp (revision 70a7ec852fcefd15a4fb57f8f183a8b1c3aacb08)
1*70a7ec85SAndroid Build Coastguard Worker /*
2*70a7ec85SAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*70a7ec85SAndroid Build Coastguard Worker  *
4*70a7ec85SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*70a7ec85SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*70a7ec85SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*70a7ec85SAndroid Build Coastguard Worker  *
8*70a7ec85SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*70a7ec85SAndroid Build Coastguard Worker  *
10*70a7ec85SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*70a7ec85SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*70a7ec85SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*70a7ec85SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*70a7ec85SAndroid Build Coastguard Worker  * limitations under the License.
15*70a7ec85SAndroid Build Coastguard Worker  */
16*70a7ec85SAndroid Build Coastguard Worker 
17*70a7ec85SAndroid Build Coastguard Worker #include <getopt.h>
18*70a7ec85SAndroid Build Coastguard Worker #include <sysexits.h>
19*70a7ec85SAndroid Build Coastguard Worker 
20*70a7ec85SAndroid Build Coastguard Worker #include <algorithm>
21*70a7ec85SAndroid Build Coastguard Worker #include <map>
22*70a7ec85SAndroid Build Coastguard Worker 
23*70a7ec85SAndroid Build Coastguard Worker #include <android-base/file.h>
24*70a7ec85SAndroid Build Coastguard Worker #include <android-base/logging.h>
25*70a7ec85SAndroid Build Coastguard Worker #include <android-base/strings.h>
26*70a7ec85SAndroid Build Coastguard Worker #include <vintf/Dirmap.h>
27*70a7ec85SAndroid Build Coastguard Worker #include <vintf/HostFileSystem.h>
28*70a7ec85SAndroid Build Coastguard Worker #include <vintf/VintfFm.h>
29*70a7ec85SAndroid Build Coastguard Worker #include <vintf/VintfObject.h>
30*70a7ec85SAndroid Build Coastguard Worker #include <vintf/parse_string.h>
31*70a7ec85SAndroid Build Coastguard Worker #include <vintf/parse_xml.h>
32*70a7ec85SAndroid Build Coastguard Worker 
33*70a7ec85SAndroid Build Coastguard Worker #include "utils.h"
34*70a7ec85SAndroid Build Coastguard Worker 
35*70a7ec85SAndroid Build Coastguard Worker namespace android::vintf {
36*70a7ec85SAndroid Build Coastguard Worker 
37*70a7ec85SAndroid Build Coastguard Worker namespace {
38*70a7ec85SAndroid Build Coastguard Worker 
usage()39*70a7ec85SAndroid Build Coastguard Worker int usage() {
40*70a7ec85SAndroid Build Coastguard Worker     LOG(ERROR) << R"(
41*70a7ec85SAndroid Build Coastguard Worker vintffm: Utility to deprecate framework manifest.
42*70a7ec85SAndroid Build Coastguard Worker usage:
43*70a7ec85SAndroid Build Coastguard Worker vintffm <-c|--check> <--dirmap /system:system_dir> frozen_dir
44*70a7ec85SAndroid Build Coastguard Worker   Check framework manifest under system_root against frozen dir. root is the
45*70a7ec85SAndroid Build Coastguard Worker   root directory of the device, e.g. $ANDROID_PRODUCT_OUT.
46*70a7ec85SAndroid Build Coastguard Worker vintffm <-u|--update> <--dirmap /system:system_dir> <-l|--level>=current_level output_frozen_dir
47*70a7ec85SAndroid Build Coastguard Worker   Update ${output_frozen_dir}/${current_level}.xml using framework manifest.
48*70a7ec85SAndroid Build Coastguard Worker vintffm <-h|--help>
49*70a7ec85SAndroid Build Coastguard Worker   Print help message.
50*70a7ec85SAndroid Build Coastguard Worker 
51*70a7ec85SAndroid Build Coastguard Worker Example:
52*70a7ec85SAndroid Build Coastguard Worker 
53*70a7ec85SAndroid Build Coastguard Worker # Freeze a framework manifest for Android R.
54*70a7ec85SAndroid Build Coastguard Worker m check-vintf-all # Build framework manifest.
55*70a7ec85SAndroid Build Coastguard Worker vintffm --update --dirmap /system:$ANDROID_PRODUCT_OUT/system --level 5 \
56*70a7ec85SAndroid Build Coastguard Worker   system/libhidl/vintfdata/frozen
57*70a7ec85SAndroid Build Coastguard Worker 
58*70a7ec85SAndroid Build Coastguard Worker # Check that the framework manifest is aligned with the frozen data.
59*70a7ec85SAndroid Build Coastguard Worker vintffm --check --dirmap /system:$ANDROID_PRODUCT_OUT/system \
60*70a7ec85SAndroid Build Coastguard Worker   system/libhidl/vintfdata/frozen
61*70a7ec85SAndroid Build Coastguard Worker )";
62*70a7ec85SAndroid Build Coastguard Worker     return EX_USAGE;
63*70a7ec85SAndroid Build Coastguard Worker }
64*70a7ec85SAndroid Build Coastguard Worker 
65*70a7ec85SAndroid Build Coastguard Worker class WritableFileSystemImpl : public WritableFileSystem {
66*70a7ec85SAndroid Build Coastguard Worker    public:
fetch(const std::string & path,std::string * fetched,std::string * error) const67*70a7ec85SAndroid Build Coastguard Worker     status_t fetch(const std::string& path, std::string* fetched,
68*70a7ec85SAndroid Build Coastguard Worker                    std::string* error) const override {
69*70a7ec85SAndroid Build Coastguard Worker         return mRoFileSystem.fetch(path, fetched, error);
70*70a7ec85SAndroid Build Coastguard Worker     }
listFiles(const std::string & path,std::vector<std::string> * out,std::string * error) const71*70a7ec85SAndroid Build Coastguard Worker     status_t listFiles(const std::string& path, std::vector<std::string>* out,
72*70a7ec85SAndroid Build Coastguard Worker                        std::string* error) const override {
73*70a7ec85SAndroid Build Coastguard Worker         return mRoFileSystem.listFiles(path, out, error);
74*70a7ec85SAndroid Build Coastguard Worker     }
modifiedTime(const std::string & path,timespec * out,std::string * error) const75*70a7ec85SAndroid Build Coastguard Worker     status_t modifiedTime(const std::string& path, timespec* out,
76*70a7ec85SAndroid Build Coastguard Worker                           std::string* error) const override {
77*70a7ec85SAndroid Build Coastguard Worker         return mRoFileSystem.modifiedTime(path, out, error);
78*70a7ec85SAndroid Build Coastguard Worker     }
write(const std::string & path,const std::string & content,std::string * error) const79*70a7ec85SAndroid Build Coastguard Worker     status_t write(const std::string& path, const std::string& content,
80*70a7ec85SAndroid Build Coastguard Worker                    std::string* error) const override {
81*70a7ec85SAndroid Build Coastguard Worker         if (!android::base::WriteStringToFile(content, path)) {
82*70a7ec85SAndroid Build Coastguard Worker             int saved_errno = errno;
83*70a7ec85SAndroid Build Coastguard Worker             if (error) {
84*70a7ec85SAndroid Build Coastguard Worker                 *error = "Can't write to " + path + ": " + strerror(saved_errno);
85*70a7ec85SAndroid Build Coastguard Worker             }
86*70a7ec85SAndroid Build Coastguard Worker             return saved_errno == 0 ? UNKNOWN_ERROR : -saved_errno;
87*70a7ec85SAndroid Build Coastguard Worker         }
88*70a7ec85SAndroid Build Coastguard Worker         return OK;
89*70a7ec85SAndroid Build Coastguard Worker     }
deleteFile(const std::string & path,std::string * error) const90*70a7ec85SAndroid Build Coastguard Worker     status_t deleteFile(const std::string& path, std::string* error) const override {
91*70a7ec85SAndroid Build Coastguard Worker         if (unlink(path.c_str()) == -1) {
92*70a7ec85SAndroid Build Coastguard Worker             int saved_errno = errno;
93*70a7ec85SAndroid Build Coastguard Worker             if (error) {
94*70a7ec85SAndroid Build Coastguard Worker                 *error = "Can't unlink " + path + ": " + strerror(saved_errno);
95*70a7ec85SAndroid Build Coastguard Worker             }
96*70a7ec85SAndroid Build Coastguard Worker             return saved_errno == 0 ? UNKNOWN_ERROR : -saved_errno;
97*70a7ec85SAndroid Build Coastguard Worker         }
98*70a7ec85SAndroid Build Coastguard Worker         return OK;
99*70a7ec85SAndroid Build Coastguard Worker     }
100*70a7ec85SAndroid Build Coastguard Worker 
101*70a7ec85SAndroid Build Coastguard Worker    private:
102*70a7ec85SAndroid Build Coastguard Worker     details::FileSystemImpl mRoFileSystem;
103*70a7ec85SAndroid Build Coastguard Worker };
104*70a7ec85SAndroid Build Coastguard Worker 
105*70a7ec85SAndroid Build Coastguard Worker }  // namespace
106*70a7ec85SAndroid Build Coastguard Worker 
107*70a7ec85SAndroid Build Coastguard Worker namespace details {
108*70a7ec85SAndroid Build Coastguard Worker 
109*70a7ec85SAndroid Build Coastguard Worker // A VintfObject with a proper framework manifest and a fake device manifest with
110*70a7ec85SAndroid Build Coastguard Worker // only targetFcmVersion.
111*70a7ec85SAndroid Build Coastguard Worker class FmOnlyVintfObject : public VintfObject {
112*70a7ec85SAndroid Build Coastguard Worker    public:
FmOnlyVintfObject(std::unique_ptr<FileSystem> && fs,Level targetFcmVersion)113*70a7ec85SAndroid Build Coastguard Worker     FmOnlyVintfObject(std::unique_ptr<FileSystem>&& fs, Level targetFcmVersion)
114*70a7ec85SAndroid Build Coastguard Worker         : mFs(std::move(fs)) {
115*70a7ec85SAndroid Build Coastguard Worker         mDeviceManifest = std::make_shared<HalManifest>();
116*70a7ec85SAndroid Build Coastguard Worker         mDeviceManifest->mLevel = targetFcmVersion;
117*70a7ec85SAndroid Build Coastguard Worker     }
118*70a7ec85SAndroid Build Coastguard Worker 
getDeviceHalManifest()119*70a7ec85SAndroid Build Coastguard Worker     std::shared_ptr<const HalManifest> getDeviceHalManifest() override { return mDeviceManifest; }
getFrameworkCompatibilityMatrix()120*70a7ec85SAndroid Build Coastguard Worker     std::shared_ptr<const CompatibilityMatrix> getFrameworkCompatibilityMatrix() override {
121*70a7ec85SAndroid Build Coastguard Worker         return nullptr;
122*70a7ec85SAndroid Build Coastguard Worker     }
getDeviceCompatibilityMatrix()123*70a7ec85SAndroid Build Coastguard Worker     std::shared_ptr<const CompatibilityMatrix> getDeviceCompatibilityMatrix() override {
124*70a7ec85SAndroid Build Coastguard Worker         return nullptr;
125*70a7ec85SAndroid Build Coastguard Worker     }
126*70a7ec85SAndroid Build Coastguard Worker 
127*70a7ec85SAndroid Build Coastguard Worker    protected:
getFileSystem()128*70a7ec85SAndroid Build Coastguard Worker     const std::unique_ptr<FileSystem>& getFileSystem() override { return mFs; }
129*70a7ec85SAndroid Build Coastguard Worker     // Set environment to empty to prevent accidentally reading other things.
getPropertyFetcher()130*70a7ec85SAndroid Build Coastguard Worker     const std::unique_ptr<PropertyFetcher>& getPropertyFetcher() override { return mNoOpProp; }
131*70a7ec85SAndroid Build Coastguard Worker 
132*70a7ec85SAndroid Build Coastguard Worker    private:
133*70a7ec85SAndroid Build Coastguard Worker     std::unique_ptr<FileSystem> mFs;
134*70a7ec85SAndroid Build Coastguard Worker     std::shared_ptr<HalManifest> mDeviceManifest;
135*70a7ec85SAndroid Build Coastguard Worker     std::unique_ptr<PropertyFetcher> mNoOpProp = std::make_unique<details::PropertyFetcherNoOp>();
136*70a7ec85SAndroid Build Coastguard Worker };
137*70a7ec85SAndroid Build Coastguard Worker 
138*70a7ec85SAndroid Build Coastguard Worker }  // namespace details
139*70a7ec85SAndroid Build Coastguard Worker 
VintfFm()140*70a7ec85SAndroid Build Coastguard Worker VintfFm::VintfFm() : VintfFm(std::make_unique<WritableFileSystemImpl>()) {}
141*70a7ec85SAndroid Build Coastguard Worker 
main(int argc,char ** argv)142*70a7ec85SAndroid Build Coastguard Worker int VintfFm::main(int argc, char** argv) {
143*70a7ec85SAndroid Build Coastguard Worker     // clang-format off
144*70a7ec85SAndroid Build Coastguard Worker     const struct option longopts[] = {
145*70a7ec85SAndroid Build Coastguard Worker         {"check", no_argument, nullptr, 'c'},
146*70a7ec85SAndroid Build Coastguard Worker         {"dirmap", required_argument, nullptr, 'd'},
147*70a7ec85SAndroid Build Coastguard Worker         {"help", no_argument, nullptr, 'h'},
148*70a7ec85SAndroid Build Coastguard Worker         {"level", required_argument, nullptr, 'l'},
149*70a7ec85SAndroid Build Coastguard Worker         {"update", no_argument, nullptr, 'u'},
150*70a7ec85SAndroid Build Coastguard Worker         {0, 0, 0, 0}};
151*70a7ec85SAndroid Build Coastguard Worker     // clang-format on
152*70a7ec85SAndroid Build Coastguard Worker 
153*70a7ec85SAndroid Build Coastguard Worker     bool checking = false;
154*70a7ec85SAndroid Build Coastguard Worker     bool updating = false;
155*70a7ec85SAndroid Build Coastguard Worker     Level current = Level::UNSPECIFIED;
156*70a7ec85SAndroid Build Coastguard Worker     std::vector<std::string> dirmapVec;
157*70a7ec85SAndroid Build Coastguard Worker 
158*70a7ec85SAndroid Build Coastguard Worker     int res;
159*70a7ec85SAndroid Build Coastguard Worker     optind = 1;
160*70a7ec85SAndroid Build Coastguard Worker     while ((res = getopt_long(argc, argv, "cdhlu", longopts, nullptr)) >= 0) {
161*70a7ec85SAndroid Build Coastguard Worker         switch (res) {
162*70a7ec85SAndroid Build Coastguard Worker             case 'c': {
163*70a7ec85SAndroid Build Coastguard Worker                 checking = true;
164*70a7ec85SAndroid Build Coastguard Worker             } break;
165*70a7ec85SAndroid Build Coastguard Worker 
166*70a7ec85SAndroid Build Coastguard Worker             case 'd': {
167*70a7ec85SAndroid Build Coastguard Worker                 dirmapVec.push_back(optarg);
168*70a7ec85SAndroid Build Coastguard Worker             } break;
169*70a7ec85SAndroid Build Coastguard Worker 
170*70a7ec85SAndroid Build Coastguard Worker             case 'l': {
171*70a7ec85SAndroid Build Coastguard Worker                 if (!parse(optarg, &current)) {
172*70a7ec85SAndroid Build Coastguard Worker                     LOG(ERROR) << "Unable to parse '" << optarg << "' as level.";
173*70a7ec85SAndroid Build Coastguard Worker                     return usage();
174*70a7ec85SAndroid Build Coastguard Worker                 }
175*70a7ec85SAndroid Build Coastguard Worker             } break;
176*70a7ec85SAndroid Build Coastguard Worker 
177*70a7ec85SAndroid Build Coastguard Worker             case 'u': {
178*70a7ec85SAndroid Build Coastguard Worker                 updating = true;
179*70a7ec85SAndroid Build Coastguard Worker             } break;
180*70a7ec85SAndroid Build Coastguard Worker 
181*70a7ec85SAndroid Build Coastguard Worker             case 'h':
182*70a7ec85SAndroid Build Coastguard Worker             default: {
183*70a7ec85SAndroid Build Coastguard Worker                 return usage();
184*70a7ec85SAndroid Build Coastguard Worker             } break;
185*70a7ec85SAndroid Build Coastguard Worker         }
186*70a7ec85SAndroid Build Coastguard Worker     }
187*70a7ec85SAndroid Build Coastguard Worker 
188*70a7ec85SAndroid Build Coastguard Worker     if ((checking + updating) != 1) {
189*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "Exactly one of --check or --update must be set.";
190*70a7ec85SAndroid Build Coastguard Worker         return usage();
191*70a7ec85SAndroid Build Coastguard Worker     }
192*70a7ec85SAndroid Build Coastguard Worker 
193*70a7ec85SAndroid Build Coastguard Worker     auto dirmap = details::getDirmap(dirmapVec);
194*70a7ec85SAndroid Build Coastguard Worker     auto vintfFsFactory = [&] {
195*70a7ec85SAndroid Build Coastguard Worker         return std::make_unique<details::HostFileSystem>(dirmap, NAME_NOT_FOUND, mFs.get());
196*70a7ec85SAndroid Build Coastguard Worker     };
197*70a7ec85SAndroid Build Coastguard Worker 
198*70a7ec85SAndroid Build Coastguard Worker     argc -= optind;
199*70a7ec85SAndroid Build Coastguard Worker     argv += optind;
200*70a7ec85SAndroid Build Coastguard Worker 
201*70a7ec85SAndroid Build Coastguard Worker     if (argc != 1) {
202*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "There must be exactly 1 positional arguments.";
203*70a7ec85SAndroid Build Coastguard Worker         return usage();
204*70a7ec85SAndroid Build Coastguard Worker     }
205*70a7ec85SAndroid Build Coastguard Worker     auto dir = argv[0];
206*70a7ec85SAndroid Build Coastguard Worker 
207*70a7ec85SAndroid Build Coastguard Worker     if (updating) {
208*70a7ec85SAndroid Build Coastguard Worker         return update(vintfFsFactory, dir, current);
209*70a7ec85SAndroid Build Coastguard Worker     }
210*70a7ec85SAndroid Build Coastguard Worker     return check(vintfFsFactory, dir);
211*70a7ec85SAndroid Build Coastguard Worker }
212*70a7ec85SAndroid Build Coastguard Worker 
update(const FsFactory & vintfFsFactory,const std::string & dir,Level level)213*70a7ec85SAndroid Build Coastguard Worker int VintfFm::update(const FsFactory& vintfFsFactory, const std::string& dir, Level level) {
214*70a7ec85SAndroid Build Coastguard Worker     if (level == Level::UNSPECIFIED) {
215*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "Must specify last frozen level with --level for --update option.";
216*70a7ec85SAndroid Build Coastguard Worker         return usage();
217*70a7ec85SAndroid Build Coastguard Worker     }
218*70a7ec85SAndroid Build Coastguard Worker 
219*70a7ec85SAndroid Build Coastguard Worker     auto manifest = getManifestForLevel(vintfFsFactory, level);
220*70a7ec85SAndroid Build Coastguard Worker     if (manifest == nullptr) {
221*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "Unable to determine manifests for level " << level;
222*70a7ec85SAndroid Build Coastguard Worker         return EX_SOFTWARE;
223*70a7ec85SAndroid Build Coastguard Worker     }
224*70a7ec85SAndroid Build Coastguard Worker 
225*70a7ec85SAndroid Build Coastguard Worker     if (!dumpMatrix(*manifest, dir, level)) {
226*70a7ec85SAndroid Build Coastguard Worker         return EX_SOFTWARE;
227*70a7ec85SAndroid Build Coastguard Worker     }
228*70a7ec85SAndroid Build Coastguard Worker 
229*70a7ec85SAndroid Build Coastguard Worker     return EX_OK;
230*70a7ec85SAndroid Build Coastguard Worker }
231*70a7ec85SAndroid Build Coastguard Worker 
check(const FsFactory & vintfFsFactory,const std::string & dir)232*70a7ec85SAndroid Build Coastguard Worker int VintfFm::check(const FsFactory& vintfFsFactory, const std::string& dir) {
233*70a7ec85SAndroid Build Coastguard Worker     auto frozenMatrices = loadMatrices(dir);
234*70a7ec85SAndroid Build Coastguard Worker     if (!frozenMatrices.has_value()) {
235*70a7ec85SAndroid Build Coastguard Worker         return EX_SOFTWARE;
236*70a7ec85SAndroid Build Coastguard Worker     }
237*70a7ec85SAndroid Build Coastguard Worker     for (const auto& [level, matrix] : *frozenMatrices) {
238*70a7ec85SAndroid Build Coastguard Worker         auto manifest = getManifestForLevel(vintfFsFactory, level);
239*70a7ec85SAndroid Build Coastguard Worker         if (manifest == nullptr) {
240*70a7ec85SAndroid Build Coastguard Worker             LOG(ERROR) << "Unable to determine manifests for level " << level;
241*70a7ec85SAndroid Build Coastguard Worker             return EX_SOFTWARE;
242*70a7ec85SAndroid Build Coastguard Worker         }
243*70a7ec85SAndroid Build Coastguard Worker         std::string error;
244*70a7ec85SAndroid Build Coastguard Worker         if (!manifest->checkCompatibility(matrix, &error)) {
245*70a7ec85SAndroid Build Coastguard Worker             LOG(ERROR) << "Framework manifest is incompatible with frozen matrix at level " << level
246*70a7ec85SAndroid Build Coastguard Worker                        << ": " << error;
247*70a7ec85SAndroid Build Coastguard Worker             return EX_SOFTWARE;
248*70a7ec85SAndroid Build Coastguard Worker         }
249*70a7ec85SAndroid Build Coastguard Worker     }
250*70a7ec85SAndroid Build Coastguard Worker     return OK;
251*70a7ec85SAndroid Build Coastguard Worker }
252*70a7ec85SAndroid Build Coastguard Worker 
getManifestForLevel(const FsFactory & vintfFsFactory,Level level)253*70a7ec85SAndroid Build Coastguard Worker std::shared_ptr<const HalManifest> VintfFm::getManifestForLevel(const FsFactory& vintfFsFactory,
254*70a7ec85SAndroid Build Coastguard Worker                                                                 Level level) {
255*70a7ec85SAndroid Build Coastguard Worker     auto vintfObject = std::make_unique<details::FmOnlyVintfObject>(vintfFsFactory(), level);
256*70a7ec85SAndroid Build Coastguard Worker     auto frameworkManifest = vintfObject->getFrameworkHalManifest();
257*70a7ec85SAndroid Build Coastguard Worker     if (frameworkManifest == nullptr) {
258*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "Unable to get framework HAL manifest for target FCM version " << level;
259*70a7ec85SAndroid Build Coastguard Worker     }
260*70a7ec85SAndroid Build Coastguard Worker     return frameworkManifest;
261*70a7ec85SAndroid Build Coastguard Worker }
262*70a7ec85SAndroid Build Coastguard Worker 
dumpMatrix(const HalManifest & frameworkManifest,const std::string & dir,Level level)263*70a7ec85SAndroid Build Coastguard Worker bool VintfFm::dumpMatrix(const HalManifest& frameworkManifest, const std::string& dir,
264*70a7ec85SAndroid Build Coastguard Worker                          Level level) {
265*70a7ec85SAndroid Build Coastguard Worker     auto matrix = frameworkManifest.generateCompatibleMatrix(false /*optional*/);
266*70a7ec85SAndroid Build Coastguard Worker     std::string path = dir + "/" + to_string(level) + ".xml";
267*70a7ec85SAndroid Build Coastguard Worker     std::string error;
268*70a7ec85SAndroid Build Coastguard Worker     if (OK != mFs->write(path, toXml(matrix), &error)) {
269*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "Unable to dump matrix to " << path << ": " << error;
270*70a7ec85SAndroid Build Coastguard Worker         return false;
271*70a7ec85SAndroid Build Coastguard Worker     }
272*70a7ec85SAndroid Build Coastguard Worker     return true;
273*70a7ec85SAndroid Build Coastguard Worker }
274*70a7ec85SAndroid Build Coastguard Worker 
loadMatrices(const std::string & dir)275*70a7ec85SAndroid Build Coastguard Worker std::optional<VintfFm::FrozenMatrices> VintfFm::loadMatrices(const std::string& dir) {
276*70a7ec85SAndroid Build Coastguard Worker     std::string error;
277*70a7ec85SAndroid Build Coastguard Worker     std::vector<std::string> allFiles;
278*70a7ec85SAndroid Build Coastguard Worker     if (OK != mFs->listFiles(dir, &allFiles, &error)) {
279*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "Unable to list files under " << dir << ": " << error;
280*70a7ec85SAndroid Build Coastguard Worker         return std::nullopt;
281*70a7ec85SAndroid Build Coastguard Worker     }
282*70a7ec85SAndroid Build Coastguard Worker     if (allFiles.empty()) {
283*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "Unable to load frozen interfaces under " << dir << ": directory is empty.";
284*70a7ec85SAndroid Build Coastguard Worker         return std::nullopt;
285*70a7ec85SAndroid Build Coastguard Worker     }
286*70a7ec85SAndroid Build Coastguard Worker     auto ret = std::make_optional<FrozenMatrices>();
287*70a7ec85SAndroid Build Coastguard Worker     for (const auto& filename : allFiles) {
288*70a7ec85SAndroid Build Coastguard Worker         std::string path = dir + "/" + filename;
289*70a7ec85SAndroid Build Coastguard Worker         std::string xmlString;
290*70a7ec85SAndroid Build Coastguard Worker         if (OK != mFs->fetch(path, &xmlString, &error)) {
291*70a7ec85SAndroid Build Coastguard Worker             LOG(ERROR) << "Unable to read " << path << ": " << error;
292*70a7ec85SAndroid Build Coastguard Worker             return std::nullopt;
293*70a7ec85SAndroid Build Coastguard Worker         }
294*70a7ec85SAndroid Build Coastguard Worker         CompatibilityMatrix matrix;
295*70a7ec85SAndroid Build Coastguard Worker         if (!fromXml(&matrix, xmlString, &error)) {
296*70a7ec85SAndroid Build Coastguard Worker             LOG(ERROR) << "Unable to parse " << path << ": " << error;
297*70a7ec85SAndroid Build Coastguard Worker             return std::nullopt;
298*70a7ec85SAndroid Build Coastguard Worker         }
299*70a7ec85SAndroid Build Coastguard Worker         std::string_view filenameSv{filename};
300*70a7ec85SAndroid Build Coastguard Worker         (void)android::base::ConsumeSuffix(&filenameSv, ".xml");
301*70a7ec85SAndroid Build Coastguard Worker         std::string levelString{filenameSv};
302*70a7ec85SAndroid Build Coastguard Worker         Level matrixLevel;
303*70a7ec85SAndroid Build Coastguard Worker         if (!parse(levelString, &matrixLevel)) {
304*70a7ec85SAndroid Build Coastguard Worker             LOG(ERROR) << "Unable to parse " << path << ": " << levelString << " is not a level.";
305*70a7ec85SAndroid Build Coastguard Worker             return std::nullopt;
306*70a7ec85SAndroid Build Coastguard Worker         }
307*70a7ec85SAndroid Build Coastguard Worker         if (ret->find(matrixLevel) != ret->end()) {
308*70a7ec85SAndroid Build Coastguard Worker             LOG(ERROR) << "Duplicated level " << matrixLevel << ", second one is at " << path;
309*70a7ec85SAndroid Build Coastguard Worker             return std::nullopt;
310*70a7ec85SAndroid Build Coastguard Worker         }
311*70a7ec85SAndroid Build Coastguard Worker         ret->emplace(matrixLevel, std::move(matrix));
312*70a7ec85SAndroid Build Coastguard Worker     }
313*70a7ec85SAndroid Build Coastguard Worker     return ret;
314*70a7ec85SAndroid Build Coastguard Worker }
315*70a7ec85SAndroid Build Coastguard Worker 
316*70a7ec85SAndroid Build Coastguard Worker }  // namespace android::vintf
317