Home | History | Annotate | Download | only in libvintf
      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_xml.h"
     21 #include "utils.h"
     22 
     23 #include <functional>
     24 #include <memory>
     25 #include <mutex>
     26 
     27 namespace android {
     28 namespace vintf {
     29 
     30 template <typename T>
     31 struct LockedUniquePtr {
     32     std::unique_ptr<T> object;
     33     std::mutex mutex;
     34 };
     35 
     36 static LockedUniquePtr<HalManifest> gDeviceManifest;
     37 static LockedUniquePtr<HalManifest> gFrameworkManifest;
     38 static LockedUniquePtr<CompatibilityMatrix> gDeviceMatrix;
     39 static LockedUniquePtr<CompatibilityMatrix> gFrameworkMatrix;
     40 static LockedUniquePtr<RuntimeInfo> gDeviceRuntimeInfo;
     41 
     42 template <typename T, typename F>
     43 static const T *Get(
     44         LockedUniquePtr<T> *ptr,
     45         bool skipCache,
     46         const F &fetchAllInformation) {
     47     std::unique_lock<std::mutex> _lock(ptr->mutex);
     48     if (skipCache || ptr->object == nullptr) {
     49         ptr->object = std::make_unique<T>();
     50         if (fetchAllInformation(ptr->object.get()) != OK) {
     51             ptr->object = nullptr; // frees the old object
     52         }
     53     }
     54     return ptr->object.get();
     55 }
     56 
     57 // static
     58 const HalManifest *VintfObject::GetDeviceHalManifest(bool skipCache) {
     59     return Get(&gDeviceManifest, skipCache,
     60             std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1,
     61                 "/vendor/manifest.xml"));
     62 }
     63 
     64 // static
     65 const HalManifest *VintfObject::GetFrameworkHalManifest(bool skipCache) {
     66     return Get(&gFrameworkManifest, skipCache,
     67             std::bind(&HalManifest::fetchAllInformation, std::placeholders::_1,
     68                 "/system/manifest.xml"));
     69 }
     70 
     71 
     72 // static
     73 const CompatibilityMatrix *VintfObject::GetDeviceCompatibilityMatrix(bool skipCache) {
     74     return Get(&gDeviceMatrix, skipCache,
     75             std::bind(&CompatibilityMatrix::fetchAllInformation, std::placeholders::_1,
     76                 "/vendor/compatibility_matrix.xml"));
     77 }
     78 
     79 // static
     80 const CompatibilityMatrix *VintfObject::GetFrameworkCompatibilityMatrix(bool skipCache) {
     81     return Get(&gFrameworkMatrix, skipCache,
     82             std::bind(&CompatibilityMatrix::fetchAllInformation, std::placeholders::_1,
     83                 "/system/compatibility_matrix.xml"));
     84 }
     85 
     86 // static
     87 const RuntimeInfo *VintfObject::GetRuntimeInfo(bool skipCache) {
     88     return Get(&gDeviceRuntimeInfo, skipCache,
     89             std::bind(&RuntimeInfo::fetchAllInformation, std::placeholders::_1));
     90 }
     91 
     92 namespace details {
     93 
     94 enum class ParseStatus {
     95     OK,
     96     PARSE_ERROR,
     97     DUPLICATED_FWK_ENTRY,
     98     DUPLICATED_DEV_ENTRY,
     99 };
    100 
    101 static std::string toString(ParseStatus status) {
    102     switch(status) {
    103         case ParseStatus::OK:                   return "OK";
    104         case ParseStatus::PARSE_ERROR:          return "parse error";
    105         case ParseStatus::DUPLICATED_FWK_ENTRY: return "duplicated framework";
    106         case ParseStatus::DUPLICATED_DEV_ENTRY: return "duplicated device";
    107     }
    108     return "";
    109 }
    110 
    111 template<typename T>
    112 static ParseStatus tryParse(const std::string &xml, const XmlConverter<T> &parse,
    113         std::unique_ptr<T> *fwk, std::unique_ptr<T> *dev) {
    114     std::unique_ptr<T> ret = std::make_unique<T>();
    115     if (!parse(ret.get(), xml)) {
    116         return ParseStatus::PARSE_ERROR;
    117     }
    118     if (ret->type() == SchemaType::FRAMEWORK) {
    119         if (fwk->get() != nullptr) {
    120             return ParseStatus::DUPLICATED_FWK_ENTRY;
    121         }
    122         *fwk = std::move(ret);
    123     } else if (ret->type() == SchemaType::DEVICE) {
    124         if (dev->get() != nullptr) {
    125             return ParseStatus::DUPLICATED_DEV_ENTRY;
    126         }
    127         *dev = std::move(ret);
    128     }
    129     return ParseStatus::OK;
    130 }
    131 
    132 template<typename T, typename GetFunction>
    133 static status_t getMissing(const T *pkg, bool mount,
    134         std::function<status_t(void)> mountFunction,
    135         const T **updated,
    136         GetFunction getFunction) {
    137     if (pkg != nullptr) {
    138         *updated = pkg;
    139     } else {
    140         if (mount) {
    141             (void)mountFunction(); // ignore mount errors
    142         }
    143         *updated = getFunction();
    144     }
    145     return OK;
    146 }
    147 
    148 #define ADD_MESSAGE(__error__)  \
    149     if (error != nullptr) {     \
    150         *error += (__error__);  \
    151     }                           \
    152 
    153 struct PackageInfo {
    154     struct Pair {
    155         std::unique_ptr<HalManifest>         manifest;
    156         std::unique_ptr<CompatibilityMatrix> matrix;
    157     };
    158     Pair dev;
    159     Pair fwk;
    160 };
    161 
    162 struct UpdatedInfo {
    163     struct Pair {
    164         const HalManifest         *manifest;
    165         const CompatibilityMatrix *matrix;
    166     };
    167     Pair dev;
    168     Pair fwk;
    169     const RuntimeInfo *runtimeInfo;
    170 };
    171 
    172 // Checks given compatibility info against info on the device. If no
    173 // compatability info is given then the device info will be checked against
    174 // itself.
    175 int32_t checkCompatibility(const std::vector<std::string>& xmls, bool mount,
    176                            const PartitionMounter& mounter, std::string* error,
    177                            DisabledChecks disabledChecks) {
    178     status_t status;
    179     ParseStatus parseStatus;
    180     PackageInfo pkg; // All information from package.
    181     UpdatedInfo updated; // All files and runtime info after the update.
    182 
    183     // parse all information from package
    184     for (const auto &xml : xmls) {
    185         parseStatus = tryParse(xml, gHalManifestConverter, &pkg.fwk.manifest, &pkg.dev.manifest);
    186         if (parseStatus == ParseStatus::OK) {
    187             continue; // work on next one
    188         }
    189         if (parseStatus != ParseStatus::PARSE_ERROR) {
    190             ADD_MESSAGE(toString(parseStatus) + " manifest");
    191             return ALREADY_EXISTS;
    192         }
    193         parseStatus = tryParse(xml, gCompatibilityMatrixConverter, &pkg.fwk.matrix, &pkg.dev.matrix);
    194         if (parseStatus == ParseStatus::OK) {
    195             continue; // work on next one
    196         }
    197         if (parseStatus != ParseStatus::PARSE_ERROR) {
    198             ADD_MESSAGE(toString(parseStatus) + " matrix");
    199             return ALREADY_EXISTS;
    200         }
    201         ADD_MESSAGE(toString(parseStatus)); // parse error
    202         return BAD_VALUE;
    203     }
    204 
    205     // get missing info from device
    206     // use functions instead of std::bind because std::bind doesn't work well with mock objects
    207     auto mountSystem = [&mounter] { return mounter.mountSystem(); };
    208     auto mountVendor = [&mounter] { return mounter.mountVendor(); };
    209     if ((status = getMissing(
    210              pkg.fwk.manifest.get(), mount, mountSystem, &updated.fwk.manifest,
    211              std::bind(VintfObject::GetFrameworkHalManifest, true /* skipCache */))) != OK) {
    212         return status;
    213     }
    214     if ((status = getMissing(
    215              pkg.dev.manifest.get(), mount, mountVendor, &updated.dev.manifest,
    216              std::bind(VintfObject::GetDeviceHalManifest, true /* skipCache */))) != OK) {
    217         return status;
    218     }
    219     if ((status = getMissing(
    220              pkg.fwk.matrix.get(), mount, mountSystem, &updated.fwk.matrix,
    221              std::bind(VintfObject::GetFrameworkCompatibilityMatrix, true /* skipCache */))) !=
    222         OK) {
    223         return status;
    224     }
    225     if ((status = getMissing(
    226              pkg.dev.matrix.get(), mount, mountVendor, &updated.dev.matrix,
    227              std::bind(VintfObject::GetDeviceCompatibilityMatrix, true /* skipCache */))) != OK) {
    228         return status;
    229     }
    230 
    231     if (mount) {
    232         (void)mounter.umountSystem(); // ignore errors
    233         (void)mounter.umountVendor(); // ignore errors
    234     }
    235 
    236     updated.runtimeInfo = VintfObject::GetRuntimeInfo(true /* skipCache */);
    237 
    238     // null checks for files and runtime info after the update
    239     // TODO(b/37321309) if a compat mat is missing, it is not matched and considered compatible.
    240     if (updated.fwk.manifest == nullptr) {
    241         ADD_MESSAGE("No framework manifest file from device or from update package");
    242         return NO_INIT;
    243     }
    244     if (updated.dev.manifest == nullptr) {
    245         ADD_MESSAGE("No device manifest file from device or from update package");
    246         return NO_INIT;
    247     }
    248     if (updated.fwk.matrix == nullptr) {
    249         ADD_MESSAGE("No framework matrix, skipping;");
    250         // TODO(b/37321309) consider missing matricies as errors.
    251     }
    252     if (updated.dev.matrix == nullptr) {
    253         ADD_MESSAGE("No device matrix, skipping;");
    254         // TODO(b/37321309) consider missing matricies as errors.
    255     }
    256     if (updated.runtimeInfo == nullptr) {
    257         ADD_MESSAGE("No runtime info from device");
    258         return NO_INIT;
    259     }
    260 
    261     // compatiblity check.
    262     // TODO(b/37321309) outer if checks can be removed if we consider missing matrices as errors.
    263     if (updated.dev.manifest && updated.fwk.matrix) {
    264         if (!updated.dev.manifest->checkCompatibility(*updated.fwk.matrix, error)) {
    265             if (error)
    266                 error->insert(0, "Device manifest and framework compatibility matrix "
    267                                  "are incompatible: ");
    268             return INCOMPATIBLE;
    269         }
    270     }
    271     if (updated.fwk.manifest && updated.dev.matrix) {
    272         if (!updated.fwk.manifest->checkCompatibility(*updated.dev.matrix, error)) {
    273             if (error)
    274                 error->insert(0, "Framework manifest and device compatibility matrix "
    275                                  "are incompatible: ");
    276             return INCOMPATIBLE;
    277         }
    278     }
    279     if (updated.runtimeInfo && updated.fwk.matrix) {
    280         if (!updated.runtimeInfo->checkCompatibility(*updated.fwk.matrix, error, disabledChecks)) {
    281             if (error)
    282                 error->insert(0, "Runtime info and framework compatibility matrix "
    283                                  "are incompatible: ");
    284             return INCOMPATIBLE;
    285         }
    286     }
    287 
    288     return COMPATIBLE;
    289 }
    290 
    291 } // namespace details
    292 
    293 // static
    294 int32_t VintfObject::CheckCompatibility(const std::vector<std::string>& xmls, std::string* error,
    295                                         DisabledChecks disabledChecks) {
    296     return details::checkCompatibility(xmls, false /* mount */, *details::gPartitionMounter, error,
    297                                        disabledChecks);
    298 }
    299 
    300 
    301 } // namespace vintf
    302 } // namespace android
    303