1 /*
2 * Copyright (C) 2022 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 #include "Apex.h"
17
18 #include <format>
19
20 #include <android-base/logging.h>
21 #include <android-base/strings.h>
22
23 #include "com_android_apex.h"
24 #include "constants-private.h"
25
26 using android::base::StartsWith;
27
28 namespace android::vintf::apex {
29
30 namespace {
31 // Partition tags used in apex-info-list.xml
32 constexpr const char* SYSTEM = "SYSTEM";
33 constexpr const char* SYSTEM_EXT = "SYSTEM_EXT";
34 constexpr const char* PRODUCT = "PRODUCT";
35 constexpr const char* VENDOR = "VENDOR";
36 constexpr const char* ODM = "ODM";
37 } // namespace
38
isApexReady(PropertyFetcher * propertyFetcher)39 static bool isApexReady(PropertyFetcher* propertyFetcher) {
40 #ifdef LIBVINTF_TARGET
41 return propertyFetcher->getBoolProperty("apex.all.ready", false);
42 #else
43 // When running on host, it assumes that /apex is ready.
44 // Reason for still relying on PropertyFetcher API is for host-side tests.
45 return propertyFetcher->getBoolProperty("apex.all.ready", true);
46 #endif
47 }
48
GetVintfDirs(FileSystem * fileSystem,PropertyFetcher * propertyFetcher,std::vector<std::string> * dirs,std::string * error,std::function<bool (const std::string &)> filter)49 static status_t GetVintfDirs(FileSystem* fileSystem, PropertyFetcher* propertyFetcher,
50 std::vector<std::string>* dirs, std::string* error,
51 std::function<bool(const std::string&)> filter) {
52 std::string apexInfoFile = details::kApexInfoFile;
53 std::string apexDir = "/apex";
54 if (!isApexReady(propertyFetcher)) {
55 apexInfoFile = details::kBootstrapApexInfoFile;
56 apexDir = "/bootstrap-apex";
57 }
58
59 // Load apex-info-list
60 std::string xml;
61 auto status = fileSystem->fetch(apexInfoFile, &xml, error);
62 if (status == NAME_NOT_FOUND) {
63 if (error) {
64 error->clear();
65 }
66 return OK;
67 }
68 if (status != OK) return status;
69
70 auto apexInfoList = com::android::apex::parseApexInfoList(xml.c_str());
71 if (!apexInfoList.has_value()) {
72 if (error) {
73 *error = std::string("Not a valid XML: ") + apexInfoFile;
74 }
75 return UNKNOWN_ERROR;
76 }
77
78 // Get vendor apex vintf dirs
79 for (const auto& apexInfo : apexInfoList->getApexInfo()) {
80 // Skip non-active apexes
81 if (!apexInfo.getIsActive()) continue;
82
83 if (filter(apexInfo.getPartition())) {
84 dirs->push_back(std::format("{}/{}/" VINTF_SUB_DIR, apexDir, apexInfo.getModuleName()));
85 }
86 }
87 LOG(INFO) << "Loaded APEX Infos from " << apexInfoFile;
88 return OK;
89 }
90
GetModifiedTime(FileSystem * fileSystem,PropertyFetcher * propertyFetcher)91 std::optional<timespec> GetModifiedTime(FileSystem* fileSystem, PropertyFetcher* propertyFetcher) {
92 std::string apexInfoFile = details::kApexInfoFile;
93 if (!isApexReady(propertyFetcher)) {
94 apexInfoFile = details::kBootstrapApexInfoFile;
95 }
96
97 timespec mtime{};
98 std::string error;
99 status_t status = fileSystem->modifiedTime(apexInfoFile, &mtime, &error);
100 if (status == NAME_NOT_FOUND) {
101 return std::nullopt;
102 }
103 if (status != OK) {
104 LOG(ERROR) << error;
105 return std::nullopt;
106 }
107 return mtime;
108 }
109
GetVendorVintfDirs(FileSystem * fileSystem,PropertyFetcher * propertyFetcher,std::vector<std::string> * dirs,std::string * error)110 status_t GetVendorVintfDirs(FileSystem* fileSystem, PropertyFetcher* propertyFetcher,
111 std::vector<std::string>* dirs, std::string* error) {
112 return GetVintfDirs(fileSystem, propertyFetcher, dirs, error, [](const std::string& partition) {
113 return partition.compare(VENDOR) == 0;
114 });
115 }
116
GetOdmVintfDirs(FileSystem * fileSystem,PropertyFetcher * propertyFetcher,std::vector<std::string> * dirs,std::string * error)117 status_t GetOdmVintfDirs(FileSystem* fileSystem, PropertyFetcher* propertyFetcher,
118 std::vector<std::string>* dirs, std::string* error) {
119 return GetVintfDirs(fileSystem, propertyFetcher, dirs, error,
120 [](const std::string& partition) { return partition.compare(ODM) == 0; });
121 }
122
GetFrameworkVintfDirs(FileSystem * fileSystem,PropertyFetcher * propertyFetcher,std::vector<std::string> * dirs,std::string * error)123 status_t GetFrameworkVintfDirs(FileSystem* fileSystem, PropertyFetcher* propertyFetcher,
124 std::vector<std::string>* dirs, std::string* error) {
125 return GetVintfDirs(fileSystem, propertyFetcher, dirs, error, [](const std::string& partition) {
126 return partition.compare(SYSTEM) == 0 || partition.compare(SYSTEM_EXT) == 0 ||
127 partition.compare(PRODUCT) == 0;
128 });
129 }
130
131 } // namespace android::vintf::apex
132