/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "Apex.h" #include #include #include #include "com_android_apex.h" #include "constants-private.h" using android::base::StartsWith; namespace android::vintf::apex { static bool isApexReady(PropertyFetcher* propertyFetcher) { #ifdef LIBVINTF_TARGET return propertyFetcher->getBoolProperty("apex.all.ready", false); #else // When running on host, it assumes that /apex is ready. // Reason for still relying on PropertyFetcher API is for host-side tests. return propertyFetcher->getBoolProperty("apex.all.ready", true); #endif } static status_t GetVintfDirs(FileSystem* fileSystem, PropertyFetcher* propertyFetcher, std::vector* dirs, std::string* error, std::function filter) { std::string apexInfoFile = details::kApexInfoFile; std::string apexDir = "/apex"; if (!isApexReady(propertyFetcher)) { apexInfoFile = details::kBootstrapApexInfoFile; apexDir = "/bootstrap-apex"; } // Load apex-info-list std::string xml; auto status = fileSystem->fetch(apexInfoFile, &xml, error); if (status == NAME_NOT_FOUND) { if (error) { error->clear(); } return OK; } if (status != OK) return status; auto apexInfoList = com::android::apex::parseApexInfoList(xml.c_str()); if (!apexInfoList.has_value()) { if (error) { *error = std::string("Not a valid XML: ") + apexInfoFile; } return UNKNOWN_ERROR; } // Get vendor apex vintf dirs for (const auto& apexInfo : apexInfoList->getApexInfo()) { // Skip non-active apexes if (!apexInfo.getIsActive()) continue; if (filter(apexInfo.getPartition())) { dirs->push_back(fmt::format("{}/{}/" VINTF_SUB_DIR, apexDir, apexInfo.getModuleName())); } } LOG(INFO) << "Loaded APEX Infos from " << apexInfoFile; return OK; } std::optional GetModifiedTime(FileSystem* fileSystem, PropertyFetcher* propertyFetcher) { std::string apexInfoFile = details::kApexInfoFile; if (!isApexReady(propertyFetcher)) { apexInfoFile = details::kBootstrapApexInfoFile; } timespec mtime{}; std::string error; status_t status = fileSystem->modifiedTime(apexInfoFile, &mtime, &error); if (status == NAME_NOT_FOUND) { return std::nullopt; } if (status != OK) { LOG(ERROR) << error; return std::nullopt; } return mtime; } status_t GetDeviceVintfDirs(FileSystem* fileSystem, PropertyFetcher* propertyFetcher, std::vector* dirs, std::string* error) { return GetVintfDirs(fileSystem, propertyFetcher, dirs, error, [](const std::string& partition) { return partition.compare("VENDOR") == 0 || partition.compare("ODM") == 0; }); } status_t GetFrameworkVintfDirs(FileSystem* fileSystem, PropertyFetcher* propertyFetcher, std::vector* dirs, std::string* error) { return GetVintfDirs(fileSystem, propertyFetcher, dirs, error, [](const std::string& partition) { return partition.compare("SYSTEM") == 0 || partition.compare("SYSTEM_EXT") == 0 || partition.compare("PRODUCT") == 0; }); } } // namespace android::vintf::apex