1/*
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
19#include "CompatibilityMatrix.h"
20#include "parse_string.h"
21#include "parse_xml.h"
22#include "utils.h"
23
24#include <dirent.h>
25
26#include <functional>
27#include <memory>
28#include <mutex>
29
30#include <android-base/logging.h>
31
32using std::placeholders::_1;
33using std::placeholders::_2;
34
35namespace android {
36namespace vintf {
37
38using namespace details;
39
40template <typename T>
41struct LockedSharedPtr {
42    std::shared_ptr<T> object;
43    std::mutex mutex;
44    bool fetchedOnce = false;
45};
46
47struct LockedRuntimeInfoCache {
48    std::shared_ptr<RuntimeInfo> object;
49    std::mutex mutex;
50    RuntimeInfo::FetchFlags fetchedFlags = RuntimeInfo::FetchFlag::NONE;
51};
52
53template <typename T, typename F>
54static std::shared_ptr<const T> Get(
55        LockedSharedPtr<T> *ptr,
56        bool skipCache,
57        const F &fetchAllInformation) {
58    std::unique_lock<std::mutex> _lock(ptr->mutex);
59    if (skipCache || !ptr->fetchedOnce) {
60        ptr->object = std::make_unique<T>();
61        std::string error;
62        if (fetchAllInformation(ptr->object.get(), &error) != OK) {
63            LOG(WARNING) << error;
64            ptr->object = nullptr; // frees the old object
65        }
66        ptr->fetchedOnce = true;
67    }
68    return ptr->object;
69}
70
71// static
72std::shared_ptr<const HalManifest> VintfObject::GetDeviceHalManifest(bool skipCache) {
73    static LockedSharedPtr<HalManifest> gVendorManifest;
74    return Get(&gVendorManifest, skipCache, &VintfObject::FetchDeviceHalManifest);
75}
76
77// static
78std::shared_ptr<const HalManifest> VintfObject::GetFrameworkHalManifest(bool skipCache) {
79    static LockedSharedPtr<HalManifest> gFrameworkManifest;
80    return Get(&gFrameworkManifest, skipCache, &VintfObject::FetchFrameworkHalManifest);
81}
82
83
84// static
85std::shared_ptr<const CompatibilityMatrix> VintfObject::GetDeviceCompatibilityMatrix(bool skipCache) {
86    static LockedSharedPtr<CompatibilityMatrix> gDeviceMatrix;
87    return Get(&gDeviceMatrix, skipCache, &VintfObject::FetchDeviceMatrix);
88}
89
90// static
91std::shared_ptr<const CompatibilityMatrix> VintfObject::GetFrameworkCompatibilityMatrix(bool skipCache) {
92    static LockedSharedPtr<CompatibilityMatrix> gFrameworkMatrix;
93    static LockedSharedPtr<CompatibilityMatrix> gCombinedFrameworkMatrix;
94    static std::mutex gFrameworkCompatibilityMatrixMutex;
95
96    // To avoid deadlock, get device manifest before any locks.
97    auto deviceManifest = GetDeviceHalManifest();
98
99    std::unique_lock<std::mutex> _lock(gFrameworkCompatibilityMatrixMutex);
100
101    auto combined =
102        Get(&gCombinedFrameworkMatrix, skipCache,
103            std::bind(&VintfObject::GetCombinedFrameworkMatrix, deviceManifest, _1, _2));
104    if (combined != nullptr) {
105        return combined;
106    }
107
108    return Get(&gFrameworkMatrix, skipCache,
109               std::bind(&CompatibilityMatrix::fetchAllInformation, _1, kSystemLegacyMatrix, _2));
110}
111
112status_t VintfObject::GetCombinedFrameworkMatrix(
113    const std::shared_ptr<const HalManifest>& deviceManifest, CompatibilityMatrix* out,
114    std::string* error) {
115    auto matrixFragments = GetAllFrameworkMatrixLevels(error);
116    if (matrixFragments.empty()) {
117        return NAME_NOT_FOUND;
118    }
119
120    Level deviceLevel = Level::UNSPECIFIED;
121
122    if (deviceManifest != nullptr) {
123        deviceLevel = deviceManifest->level();
124    }
125
126    // TODO(b/70628538): Do not infer from Shipping API level.
127    if (deviceLevel == Level::UNSPECIFIED) {
128        auto shippingApi = getPropertyFetcher().getUintProperty("ro.product.first_api_level", 0u);
129        if (shippingApi != 0u) {
130            deviceLevel = details::convertFromApiLevel(shippingApi);
131        }
132    }
133
134    if (deviceLevel == Level::UNSPECIFIED) {
135        // Cannot infer FCM version. Combine all matrices by assuming
136        // Shipping FCM Version == min(all supported FCM Versions in the framework)
137        for (auto&& pair : matrixFragments) {
138            Level fragmentLevel = pair.object.level();
139            if (fragmentLevel != Level::UNSPECIFIED && deviceLevel > fragmentLevel) {
140                deviceLevel = fragmentLevel;
141            }
142        }
143    }
144
145    if (deviceLevel == Level::UNSPECIFIED) {
146        // None of the fragments specify any FCM version. Should never happen except
147        // for inconsistent builds.
148        if (error) {
149            *error = "No framework compatibility matrix files under " + kSystemVintfDir +
150                     " declare FCM version.";
151        }
152        return NAME_NOT_FOUND;
153    }
154
155    CompatibilityMatrix* combined =
156        CompatibilityMatrix::combine(deviceLevel, &matrixFragments, error);
157    if (combined == nullptr) {
158        return BAD_VALUE;
159    }
160    *out = std::move(*combined);
161    return OK;
162}
163
164// Priority for loading vendor manifest:
165// 1. /vendor/etc/vintf/manifest.xml + ODM manifest
166// 2. /vendor/etc/vintf/manifest.xml
167// 3. ODM manifest
168// 4. /vendor/manifest.xml
169// where:
170// A + B means adding <hal> tags from B to A (so that <hal>s from B can override A)
171status_t VintfObject::FetchDeviceHalManifest(HalManifest* out, std::string* error) {
172    status_t vendorStatus = FetchOneHalManifest(kVendorManifest, out, error);
173    if (vendorStatus != OK && vendorStatus != NAME_NOT_FOUND) {
174        return vendorStatus;
175    }
176
177    HalManifest odmManifest;
178    status_t odmStatus = FetchOdmHalManifest(&odmManifest, error);
179    if (odmStatus != OK && odmStatus != NAME_NOT_FOUND) {
180        return odmStatus;
181    }
182
183    if (vendorStatus == OK) {
184        if (odmStatus == OK) {
185            out->addAllHals(&odmManifest);
186        }
187        return OK;
188    }
189
190    // vendorStatus != OK, "out" is not changed.
191    if (odmStatus == OK) {
192        *out = std::move(odmManifest);
193        return OK;
194    }
195
196    // Use legacy /vendor/manifest.xml
197    return out->fetchAllInformation(kVendorLegacyManifest, error);
198}
199
200// "out" is written to iff return status is OK.
201// Priority:
202// 1. if {sku} is defined, /odm/etc/vintf/manifest_{sku}.xml
203// 2. /odm/etc/vintf/manifest.xml
204// 3. if {sku} is defined, /odm/etc/manifest_{sku}.xml
205// 4. /odm/etc/manifest.xml
206// where:
207// {sku} is the value of ro.boot.product.hardware.sku
208status_t VintfObject::FetchOdmHalManifest(HalManifest* out, std::string* error) {
209    status_t status;
210
211    std::string productModel;
212    productModel = getPropertyFetcher().getProperty("ro.boot.product.hardware.sku", "");
213
214    if (!productModel.empty()) {
215        status =
216            FetchOneHalManifest(kOdmVintfDir + "manifest_" + productModel + ".xml", out, error);
217        if (status == OK || status != NAME_NOT_FOUND) {
218            return status;
219        }
220    }
221
222    status = FetchOneHalManifest(kOdmManifest, out, error);
223    if (status == OK || status != NAME_NOT_FOUND) {
224        return status;
225    }
226
227    if (!productModel.empty()) {
228        status = FetchOneHalManifest(kOdmLegacyVintfDir + "manifest_" + productModel + ".xml", out,
229                                     error);
230        if (status == OK || status != NAME_NOT_FOUND) {
231            return status;
232        }
233    }
234
235    status = FetchOneHalManifest(kOdmLegacyManifest, out, error);
236    if (status == OK || status != NAME_NOT_FOUND) {
237        return status;
238    }
239
240    return NAME_NOT_FOUND;
241}
242
243// Fetch one manifest.xml file. "out" is written to iff return status is OK.
244// Returns NAME_NOT_FOUND if file is missing.
245status_t VintfObject::FetchOneHalManifest(const std::string& path, HalManifest* out,
246                                          std::string* error) {
247    HalManifest ret;
248    status_t status = ret.fetchAllInformation(path, error);
249    if (status == OK) {
250        *out = std::move(ret);
251    }
252    return status;
253}
254
255status_t VintfObject::FetchDeviceMatrix(CompatibilityMatrix* out, std::string* error) {
256    CompatibilityMatrix etcMatrix;
257    if (etcMatrix.fetchAllInformation(kVendorMatrix, error) == OK) {
258        *out = std::move(etcMatrix);
259        return OK;
260    }
261    return out->fetchAllInformation(kVendorLegacyMatrix, error);
262}
263
264status_t VintfObject::FetchFrameworkHalManifest(HalManifest* out, std::string* error) {
265    HalManifest etcManifest;
266    if (etcManifest.fetchAllInformation(kSystemManifest, error) == OK) {
267        *out = std::move(etcManifest);
268        return OK;
269    }
270    return out->fetchAllInformation(kSystemLegacyManifest, error);
271}
272
273std::vector<Named<CompatibilityMatrix>> VintfObject::GetAllFrameworkMatrixLevels(
274    std::string* error) {
275    std::vector<std::string> fileNames;
276    std::vector<Named<CompatibilityMatrix>> results;
277
278    if (details::gFetcher->listFiles(kSystemVintfDir, &fileNames, error) != OK) {
279        return {};
280    }
281    for (const std::string& fileName : fileNames) {
282        std::string path = kSystemVintfDir + fileName;
283
284        std::string content;
285        std::string fetchError;
286        status_t status = details::gFetcher->fetch(path, content, &fetchError);
287        if (status != OK) {
288            if (error) {
289                *error += "Framework Matrix: Ignore file " + path + ": " + fetchError + "\n";
290            }
291            continue;
292        }
293
294        auto it = results.emplace(results.end());
295        if (!gCompatibilityMatrixConverter(&it->object, content, error)) {
296            if (error) {
297                *error += "Framework Matrix: Ignore file " + path + ": " + *error + "\n";
298            }
299            results.erase(it);
300            continue;
301        }
302    }
303
304    if (results.empty()) {
305        if (error) {
306            *error = "No framework matrices under " + kSystemVintfDir +
307                     " can be fetched or parsed.\n" + *error;
308        }
309    } else {
310        if (error && !error->empty()) {
311            LOG(WARNING) << *error;
312            *error = "";
313        }
314    }
315
316    return results;
317}
318
319// static
320std::shared_ptr<const RuntimeInfo> VintfObject::GetRuntimeInfo(bool skipCache,
321                                                               RuntimeInfo::FetchFlags flags) {
322    static LockedRuntimeInfoCache gDeviceRuntimeInfo;
323    std::unique_lock<std::mutex> _lock(gDeviceRuntimeInfo.mutex);
324
325    if (!skipCache) {
326        flags &= (~gDeviceRuntimeInfo.fetchedFlags);
327    }
328
329    if (gDeviceRuntimeInfo.object == nullptr) {
330        gDeviceRuntimeInfo.object = details::gRuntimeInfoFactory->make_shared();
331    }
332
333    status_t status = gDeviceRuntimeInfo.object->fetchAllInformation(flags);
334    if (status != OK) {
335        gDeviceRuntimeInfo.fetchedFlags &= (~flags);  // mark the fields as "not fetched"
336        return nullptr;
337    }
338
339    gDeviceRuntimeInfo.fetchedFlags |= flags;
340    return gDeviceRuntimeInfo.object;
341}
342
343namespace details {
344
345enum class ParseStatus {
346    OK,
347    PARSE_ERROR,
348    DUPLICATED_FWK_ENTRY,
349    DUPLICATED_DEV_ENTRY,
350};
351
352static std::string toString(ParseStatus status) {
353    switch(status) {
354        case ParseStatus::OK:                   return "OK";
355        case ParseStatus::PARSE_ERROR:          return "parse error";
356        case ParseStatus::DUPLICATED_FWK_ENTRY: return "duplicated framework";
357        case ParseStatus::DUPLICATED_DEV_ENTRY: return "duplicated device";
358    }
359    return "";
360}
361
362template<typename T>
363static ParseStatus tryParse(const std::string &xml, const XmlConverter<T> &parse,
364        std::shared_ptr<T> *fwk, std::shared_ptr<T> *dev) {
365    std::shared_ptr<T> ret = std::make_shared<T>();
366    if (!parse(ret.get(), xml, nullptr /* error */)) {
367        return ParseStatus::PARSE_ERROR;
368    }
369    if (ret->type() == SchemaType::FRAMEWORK) {
370        if (fwk->get() != nullptr) {
371            return ParseStatus::DUPLICATED_FWK_ENTRY;
372        }
373        *fwk = std::move(ret);
374    } else if (ret->type() == SchemaType::DEVICE) {
375        if (dev->get() != nullptr) {
376            return ParseStatus::DUPLICATED_DEV_ENTRY;
377        }
378        *dev = std::move(ret);
379    }
380    return ParseStatus::OK;
381}
382
383template<typename T, typename GetFunction>
384static status_t getMissing(const std::shared_ptr<T>& pkg, bool mount,
385        std::function<status_t(void)> mountFunction,
386        std::shared_ptr<const T>* updated,
387        GetFunction getFunction) {
388    if (pkg != nullptr) {
389        *updated = pkg;
390    } else {
391        if (mount) {
392            (void)mountFunction(); // ignore mount errors
393        }
394        *updated = getFunction();
395    }
396    return OK;
397}
398
399#define ADD_MESSAGE(__error__)  \
400    if (error != nullptr) {     \
401        *error += (__error__);  \
402    }                           \
403
404struct PackageInfo {
405    struct Pair {
406        std::shared_ptr<HalManifest>         manifest;
407        std::shared_ptr<CompatibilityMatrix> matrix;
408    };
409    Pair dev;
410    Pair fwk;
411};
412
413struct UpdatedInfo {
414    struct Pair {
415        std::shared_ptr<const HalManifest>         manifest;
416        std::shared_ptr<const CompatibilityMatrix> matrix;
417    };
418    Pair dev;
419    Pair fwk;
420    std::shared_ptr<const RuntimeInfo> runtimeInfo;
421};
422
423// Checks given compatibility info against info on the device. If no
424// compatability info is given then the device info will be checked against
425// itself.
426int32_t checkCompatibility(const std::vector<std::string>& xmls, bool mount,
427                           const PartitionMounter& mounter, std::string* error,
428                           DisabledChecks disabledChecks) {
429    status_t status;
430    ParseStatus parseStatus;
431    PackageInfo pkg; // All information from package.
432    UpdatedInfo updated; // All files and runtime info after the update.
433
434    // parse all information from package
435    for (const auto &xml : xmls) {
436        parseStatus = tryParse(xml, gHalManifestConverter, &pkg.fwk.manifest, &pkg.dev.manifest);
437        if (parseStatus == ParseStatus::OK) {
438            continue; // work on next one
439        }
440        if (parseStatus != ParseStatus::PARSE_ERROR) {
441            ADD_MESSAGE(toString(parseStatus) + " manifest");
442            return ALREADY_EXISTS;
443        }
444        parseStatus = tryParse(xml, gCompatibilityMatrixConverter, &pkg.fwk.matrix, &pkg.dev.matrix);
445        if (parseStatus == ParseStatus::OK) {
446            continue; // work on next one
447        }
448        if (parseStatus != ParseStatus::PARSE_ERROR) {
449            ADD_MESSAGE(toString(parseStatus) + " matrix");
450            return ALREADY_EXISTS;
451        }
452        ADD_MESSAGE(toString(parseStatus)); // parse error
453        return BAD_VALUE;
454    }
455
456    // get missing info from device
457    // use functions instead of std::bind because std::bind doesn't work well with mock objects
458    auto mountSystem = [&mounter] { return mounter.mountSystem(); };
459    auto mountVendor = [&mounter] { return mounter.mountVendor(); };
460    if ((status = getMissing(
461             pkg.fwk.manifest, mount, mountSystem, &updated.fwk.manifest,
462             std::bind(VintfObject::GetFrameworkHalManifest, true /* skipCache */))) != OK) {
463        return status;
464    }
465    if ((status = getMissing(
466             pkg.dev.manifest, mount, mountVendor, &updated.dev.manifest,
467             std::bind(VintfObject::GetDeviceHalManifest, true /* skipCache */))) != OK) {
468        return status;
469    }
470    if ((status = getMissing(
471             pkg.fwk.matrix, mount, mountSystem, &updated.fwk.matrix,
472             std::bind(VintfObject::GetFrameworkCompatibilityMatrix, true /* skipCache */))) !=
473        OK) {
474        return status;
475    }
476    if ((status = getMissing(
477             pkg.dev.matrix, mount, mountVendor, &updated.dev.matrix,
478             std::bind(VintfObject::GetDeviceCompatibilityMatrix, true /* skipCache */))) != OK) {
479        return status;
480    }
481
482    if (mount) {
483        (void)mounter.umountSystem(); // ignore errors
484        (void)mounter.umountVendor(); // ignore errors
485    }
486
487    if ((disabledChecks & DISABLE_RUNTIME_INFO) == 0) {
488        updated.runtimeInfo = VintfObject::GetRuntimeInfo(true /* skipCache */);
489    }
490
491    // null checks for files and runtime info after the update
492    if (updated.fwk.manifest == nullptr) {
493        ADD_MESSAGE("No framework manifest file from device or from update package");
494        return NO_INIT;
495    }
496    if (updated.dev.manifest == nullptr) {
497        ADD_MESSAGE("No device manifest file from device or from update package");
498        return NO_INIT;
499    }
500    if (updated.fwk.matrix == nullptr) {
501        ADD_MESSAGE("No framework matrix file from device or from update package");
502        return NO_INIT;
503    }
504    if (updated.dev.matrix == nullptr) {
505        ADD_MESSAGE("No device matrix file from device or from update package");
506        return NO_INIT;
507    }
508
509    if ((disabledChecks & DISABLE_RUNTIME_INFO) == 0) {
510        if (updated.runtimeInfo == nullptr) {
511            ADD_MESSAGE("No runtime info from device");
512            return NO_INIT;
513        }
514    }
515
516    // compatiblity check.
517    if (!updated.dev.manifest->checkCompatibility(*updated.fwk.matrix, error)) {
518        if (error) {
519            error->insert(0,
520                          "Device manifest and framework compatibility matrix are incompatible: ");
521        }
522        return INCOMPATIBLE;
523    }
524    if (!updated.fwk.manifest->checkCompatibility(*updated.dev.matrix, error)) {
525        if (error) {
526            error->insert(0,
527                          "Framework manifest and device compatibility matrix are incompatible: ");
528        }
529        return INCOMPATIBLE;
530    }
531
532    if ((disabledChecks & DISABLE_RUNTIME_INFO) == 0) {
533        if (!updated.runtimeInfo->checkCompatibility(*updated.fwk.matrix, error, disabledChecks)) {
534            if (error) {
535                error->insert(0,
536                              "Runtime info and framework compatibility matrix are incompatible: ");
537            }
538            return INCOMPATIBLE;
539        }
540    }
541
542    return COMPATIBLE;
543}
544
545const std::string kSystemVintfDir = "/system/etc/vintf/";
546const std::string kVendorVintfDir = "/vendor/etc/vintf/";
547const std::string kOdmVintfDir = "/odm/etc/vintf/";
548
549const std::string kVendorManifest = kVendorVintfDir + "manifest.xml";
550const std::string kSystemManifest = kSystemVintfDir + "manifest.xml";
551const std::string kVendorMatrix = kVendorVintfDir + "compatibility_matrix.xml";
552const std::string kOdmManifest = kOdmVintfDir + "manifest.xml";
553
554const std::string kVendorLegacyManifest = "/vendor/manifest.xml";
555const std::string kVendorLegacyMatrix = "/vendor/compatibility_matrix.xml";
556const std::string kSystemLegacyManifest = "/system/manifest.xml";
557const std::string kSystemLegacyMatrix = "/system/compatibility_matrix.xml";
558const std::string kOdmLegacyVintfDir = "/odm/etc/";
559const std::string kOdmLegacyManifest = kOdmLegacyVintfDir + "manifest.xml";
560
561std::vector<std::string> dumpFileList() {
562    return {
563        kSystemVintfDir,       kVendorVintfDir,     kOdmVintfDir,          kOdmLegacyVintfDir,
564
565        kVendorLegacyManifest, kVendorLegacyMatrix, kSystemLegacyManifest, kSystemLegacyMatrix,
566    };
567}
568
569} // namespace details
570
571// static
572int32_t VintfObject::CheckCompatibility(const std::vector<std::string>& xmls, std::string* error,
573                                        DisabledChecks disabledChecks) {
574    return details::checkCompatibility(xmls, false /* mount */, *details::gPartitionMounter, error,
575                                       disabledChecks);
576}
577
578bool VintfObject::isHalDeprecated(const MatrixHal& oldMatrixHal,
579                                  const CompatibilityMatrix& targetMatrix,
580                                  const ListInstances& listInstances, std::string* error) {
581    bool isDeprecated = false;
582    oldMatrixHal.forEachInstance([&](const MatrixInstance& oldMatrixInstance) {
583        if (isInstanceDeprecated(oldMatrixInstance, targetMatrix, listInstances, error)) {
584            isDeprecated = true;
585        }
586        return !isDeprecated;  // continue if no deprecated instance is found.
587    });
588    return isDeprecated;
589}
590
591// Let oldMatrixInstance = package@x.y-w::interface with instancePattern.
592// If any "servedInstance" in listInstances(package@x.y::interface) matches instancePattern, return
593// true iff:
594// 1. package@x.?::interface/servedInstance is not in targetMatrix; OR
595// 2. package@x.z::interface/servedInstance is in targetMatrix but
596//    servedInstance is not in listInstances(package@x.z::interface)
597bool VintfObject::isInstanceDeprecated(const MatrixInstance& oldMatrixInstance,
598                                       const CompatibilityMatrix& targetMatrix,
599                                       const ListInstances& listInstances, std::string* error) {
600    const std::string& package = oldMatrixInstance.package();
601    const Version& version = oldMatrixInstance.versionRange().minVer();
602    const std::string& interface = oldMatrixInstance.interface();
603
604    std::vector<std::string> instanceHint;
605    if (!oldMatrixInstance.isRegex()) {
606        instanceHint.push_back(oldMatrixInstance.exactInstance());
607    }
608
609    auto list = listInstances(package, version, interface, instanceHint);
610    for (const auto& pair : list) {
611        const std::string& servedInstance = pair.first;
612        Version servedVersion = pair.second;
613        if (!oldMatrixInstance.matchInstance(servedInstance)) {
614            continue;
615        }
616
617        // Find any package@x.? in target matrix, and check if instance is in target matrix.
618        bool foundInstance = false;
619        Version targetMatrixMinVer;
620        targetMatrix.forEachInstanceOfPackage(package, [&](const auto& targetMatrixInstance) {
621            if (targetMatrixInstance.versionRange().majorVer == version.majorVer &&
622                targetMatrixInstance.interface() == interface &&
623                targetMatrixInstance.matchInstance(servedInstance)) {
624                targetMatrixMinVer = targetMatrixInstance.versionRange().minVer();
625                foundInstance = true;
626            }
627            return !foundInstance;  // continue if not found
628        });
629        if (!foundInstance) {
630            if (error) {
631                *error = toFQNameString(package, servedVersion, interface, servedInstance) +
632                         " is deprecated in compatibility matrix at FCM Version " +
633                         to_string(targetMatrix.level()) + "; it should not be served.";
634            }
635            return true;
636        }
637
638        // Assuming that targetMatrix requires @x.u-v, require that at least @x.u is served.
639        bool targetVersionServed = false;
640        for (const auto& newPair :
641             listInstances(package, targetMatrixMinVer, interface, instanceHint)) {
642            if (newPair.first == servedInstance) {
643                targetVersionServed = true;
644                break;
645            }
646        }
647
648        if (!targetVersionServed) {
649            if (error) {
650                *error += toFQNameString(package, servedVersion, interface, servedInstance) +
651                          " is deprecated; requires at least " + to_string(targetMatrixMinVer) +
652                          "\n";
653            }
654            return true;
655        }
656    }
657
658    return false;
659}
660
661int32_t VintfObject::CheckDeprecation(const ListInstances& listInstances, std::string* error) {
662    auto matrixFragments = GetAllFrameworkMatrixLevels(error);
663    if (matrixFragments.empty()) {
664        if (error && error->empty())
665            *error = "Cannot get framework matrix for each FCM version for unknown error.";
666        return NAME_NOT_FOUND;
667    }
668    auto deviceManifest = GetDeviceHalManifest();
669    if (deviceManifest == nullptr) {
670        if (error) *error = "No device manifest.";
671        return NAME_NOT_FOUND;
672    }
673    Level deviceLevel = deviceManifest->level();
674    if (deviceLevel == Level::UNSPECIFIED) {
675        if (error) *error = "Device manifest does not specify Shipping FCM Version.";
676        return BAD_VALUE;
677    }
678
679    const CompatibilityMatrix* targetMatrix = nullptr;
680    for (const auto& namedMatrix : matrixFragments) {
681        if (namedMatrix.object.level() == deviceLevel) {
682            targetMatrix = &namedMatrix.object;
683        }
684    }
685    if (targetMatrix == nullptr) {
686        if (error)
687            *error = "Cannot find framework matrix at FCM version " + to_string(deviceLevel) + ".";
688        return NAME_NOT_FOUND;
689    }
690
691    bool hasDeprecatedHals = false;
692    for (const auto& namedMatrix : matrixFragments) {
693        if (namedMatrix.object.level() == Level::UNSPECIFIED) continue;
694        if (namedMatrix.object.level() >= deviceLevel) continue;
695
696        const auto& oldMatrix = namedMatrix.object;
697        for (const MatrixHal& hal : oldMatrix.getHals()) {
698            hasDeprecatedHals |= isHalDeprecated(hal, *targetMatrix, listInstances, error);
699        }
700    }
701
702    return hasDeprecatedHals ? DEPRECATED : NO_DEPRECATED_HALS;
703}
704
705int32_t VintfObject::CheckDeprecation(std::string* error) {
706    using namespace std::placeholders;
707    auto deviceManifest = GetDeviceHalManifest();
708    ListInstances inManifest =
709        [&deviceManifest](const std::string& package, Version version, const std::string& interface,
710                          const std::vector<std::string>& /* hintInstances */) {
711            std::vector<std::pair<std::string, Version>> ret;
712            deviceManifest->forEachInstanceOfInterface(
713                package, version, interface, [&ret](const ManifestInstance& manifestInstance) {
714                    ret.push_back(
715                        std::make_pair(manifestInstance.instance(), manifestInstance.version()));
716                    return true;
717                });
718            return ret;
719        };
720    return CheckDeprecation(inManifest, error);
721}
722
723} // namespace vintf
724} // namespace android
725