1 /*
2 * Copyright (C) 2019 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 #define LOG_TAG "derive_sdk"
18
19 #include "derive_sdk.h"
20
21 #include <android-base/file.h>
22 #include <android-base/logging.h>
23 #include <android-base/properties.h>
24 #include <android-modules-utils/sdk_level.h>
25 #include <dirent.h>
26 #include <sys/stat.h>
27
28 #include <algorithm>
29 #include <iostream>
30 #include <map>
31 #include <unordered_map>
32 #include <unordered_set>
33 #include <vector>
34
35 #include "packages/modules/common/proto/sdk.pb.h"
36
37 namespace android {
38 namespace derivesdk {
39
40 static const std::unordered_map<std::string, SdkModule> kApexNameToModule = {
41 {"com.android.adservices", SdkModule::AD_SERVICES},
42 {"com.android.appsearch", SdkModule::APPSEARCH},
43 {"com.android.art", SdkModule::ART},
44 {"com.android.configinfrastructure", SdkModule::CONFIG_INFRASTRUCTURE},
45 {"com.android.conscrypt", SdkModule::CONSCRYPT},
46 {"com.android.extservices", SdkModule::EXT_SERVICES},
47 {"com.android.healthfitness", SdkModule::HEALTH_FITNESS},
48 {"com.android.ipsec", SdkModule::IPSEC},
49 {"com.android.media", SdkModule::MEDIA},
50 {"com.android.mediaprovider", SdkModule::MEDIA_PROVIDER},
51 {"com.android.ondevicepersonalization", SdkModule::ON_DEVICE_PERSONALIZATION},
52 {"com.android.permission", SdkModule::PERMISSIONS},
53 {"com.android.scheduling", SdkModule::SCHEDULING},
54 {"com.android.sdkext", SdkModule::SDK_EXTENSIONS},
55 {"com.android.os.statsd", SdkModule::STATSD},
56 {"com.android.tethering", SdkModule::TETHERING},
57 };
58
59 static const std::unordered_set<SdkModule> kRModules = {
60 SdkModule::CONSCRYPT, SdkModule::EXT_SERVICES, SdkModule::IPSEC,
61 SdkModule::MEDIA, SdkModule::MEDIA_PROVIDER, SdkModule::PERMISSIONS,
62 SdkModule::SDK_EXTENSIONS, SdkModule::STATSD, SdkModule::TETHERING,
63 };
64
65 static const std::unordered_set<SdkModule> kSModules = {SdkModule::ART, SdkModule::SCHEDULING};
66
67 static const std::unordered_set<SdkModule> kTModules = {
68 SdkModule::AD_SERVICES, SdkModule::APPSEARCH, SdkModule::ON_DEVICE_PERSONALIZATION};
69
70 static const std::unordered_set<SdkModule> kUModules = {SdkModule::CONFIG_INFRASTRUCTURE,
71 SdkModule::HEALTH_FITNESS};
72
73 static const std::unordered_set<SdkModule> kVModules = {};
74
75 static const std::string kSystemPropertiesPrefix = "build.version.extensions.";
76
ReadSystemProperties(std::map<std::string,std::string> & properties)77 void ReadSystemProperties(std::map<std::string, std::string>& properties) {
78 const std::string default_ = "<not set>";
79
80 for (const auto& dessert : {"r", "s", "t", "ad_services", "u", "v"}) {
81 properties[kSystemPropertiesPrefix + dessert] =
82 android::base::GetProperty(kSystemPropertiesPrefix + dessert, default_);
83 }
84 properties["ro.build.version.sdk"] = android::base::GetProperty("ro.build.version.sdk", default_);
85 }
86
ReadDatabase(const std::string & db_path,ExtensionDatabase & db)87 bool ReadDatabase(const std::string& db_path, ExtensionDatabase& db) {
88 std::string contents;
89 if (!android::base::ReadFileToString(db_path, &contents, true)) {
90 PLOG(ERROR) << "failed to read " << db_path << ": ";
91 return false;
92 }
93 if (!db.ParseFromString(contents)) {
94 LOG(ERROR) << "failed to parse " << db_path;
95 return false;
96 }
97 return true;
98 }
99
VersionRequirementsMet(const ExtensionVersion & ext_version,const std::unordered_set<SdkModule> & relevant_modules,const std::unordered_map<SdkModule,int> & module_versions)100 bool VersionRequirementsMet(
101 const ExtensionVersion& ext_version,
102 const std::unordered_set<SdkModule>& relevant_modules,
103 const std::unordered_map<SdkModule, int>& module_versions) {
104 for (const auto& requirement : ext_version.requirements()) {
105 // Only requirements on modules relevant for this extension matter.
106 if (relevant_modules.find(requirement.module()) == relevant_modules.end())
107 continue;
108
109 auto version = module_versions.find(requirement.module());
110 if (version == module_versions.end()) {
111 LOG(DEBUG) << "Not version " << ext_version.version() << ": Module "
112 << requirement.module() << " is missing";
113 return false;
114 }
115 if (version->second < requirement.version().version()) {
116 LOG(DEBUG) << "Not version " << ext_version.version() << ": Module "
117 << requirement.module() << " version (" << version->second
118 << ") too low. Needed " << requirement.version().version();
119 return false;
120 }
121 }
122 return true;
123 }
124
GetSdkLevel(const ExtensionDatabase & db,const std::unordered_set<SdkModule> & relevant_modules,const std::unordered_map<SdkModule,int> & module_versions)125 int GetSdkLevel(const ExtensionDatabase& db,
126 const std::unordered_set<SdkModule>& relevant_modules,
127 const std::unordered_map<SdkModule, int>& module_versions) {
128 int max = 0;
129
130 for (const auto& ext_version : db.versions()) {
131 if (ext_version.version() > max &&
132 VersionRequirementsMet(ext_version, relevant_modules,
133 module_versions)) {
134 max = ext_version.version();
135 }
136 }
137 return max;
138 }
139
SetExtension(const std::string & extension_name,int version)140 bool SetExtension(const std::string& extension_name, int version) {
141 LOG(INFO) << "extension " << extension_name << " version is " << version;
142
143 const std::string property_name = kSystemPropertiesPrefix + extension_name;
144 if (!android::base::SetProperty(property_name, std::to_string(version))) {
145 LOG(ERROR) << "failed to set sdk_info prop " << property_name;
146 return false;
147 }
148 return true;
149 }
150
GetAndSetExtension(const std::string & extension_name,const ExtensionDatabase & db,const std::unordered_set<SdkModule> & relevant_modules,const std::unordered_map<SdkModule,int> & module_versions)151 bool GetAndSetExtension(const std::string& extension_name, const ExtensionDatabase& db,
152 const std::unordered_set<SdkModule>& relevant_modules,
153 const std::unordered_map<SdkModule, int>& module_versions) {
154 int version = GetSdkLevel(db, relevant_modules, module_versions);
155 return SetExtension(extension_name, version);
156 }
157
ReadSdkInfoFromApexes(const std::string & mountpath,std::unordered_map<SdkModule,int> & versions)158 bool ReadSdkInfoFromApexes(const std::string& mountpath,
159 std::unordered_map<SdkModule, int>& versions) {
160 for (const auto& module_itr : kApexNameToModule) {
161 std::string path = mountpath + "/" + module_itr.first + "/etc/sdkinfo.pb";
162 struct stat statbuf;
163 if (stat(path.c_str(), &statbuf) != 0) {
164 continue;
165 }
166 std::string contents;
167 if (!android::base::ReadFileToString(path, &contents, true)) {
168 LOG(ERROR) << "failed to read " << path;
169 continue;
170 }
171 SdkVersion sdk_version;
172 if (!sdk_version.ParseFromString(contents)) {
173 LOG(ERROR) << "failed to parse " << path;
174 continue;
175 }
176 SdkModule module = module_itr.second;
177 LOG(INFO) << "Read version " << sdk_version.version() << " from " << module;
178 versions[module] = sdk_version.version();
179 }
180 return true;
181 }
182
SetSdkLevels(const std::string & mountpath)183 bool SetSdkLevels(const std::string& mountpath) {
184 ExtensionDatabase db;
185 if (!ReadDatabase(mountpath + "/com.android.sdkext/etc/extensions_db.pb", db)) {
186 LOG(ERROR) << "Failed to read database";
187 return false;
188 }
189
190 std::unordered_map<SdkModule, int> versions;
191 if (!ReadSdkInfoFromApexes(mountpath, versions)) {
192 LOG(ERROR) << "Failed to SDK info from apexes";
193 return false;
194 }
195
196 std::unordered_set<SdkModule> relevant_modules;
197 relevant_modules.insert(kRModules.begin(), kRModules.end());
198 if (!GetAndSetExtension("r", db, relevant_modules, versions)) {
199 return false;
200 }
201
202 relevant_modules.insert(kSModules.begin(), kSModules.end());
203 if (android::modules::sdklevel::IsAtLeastS()) {
204 if (!GetAndSetExtension("s", db, relevant_modules, versions)) {
205 return false;
206 }
207 }
208
209 relevant_modules.insert(kTModules.begin(), kTModules.end());
210 if (android::modules::sdklevel::IsAtLeastT()) {
211 if (!GetAndSetExtension("t", db, relevant_modules, versions)) {
212 return false;
213 }
214 }
215
216 relevant_modules.insert(kUModules.begin(), kUModules.end());
217 if (android::modules::sdklevel::IsAtLeastU()) {
218 if (!GetAndSetExtension("u", db, relevant_modules, versions)) {
219 return false;
220 }
221 }
222
223 relevant_modules.insert(kVModules.begin(), kVModules.end());
224 if (android::modules::sdklevel::IsAtLeastV()) {
225 if (!GetAndSetExtension("v", db, relevant_modules, versions)) {
226 return false;
227 }
228 }
229
230 // Consistency check: verify all modules with requirements is included in some dessert
231 for (const auto& ext_version : db.versions()) {
232 for (const auto& requirement : ext_version.requirements()) {
233 if (relevant_modules.find(requirement.module()) == relevant_modules.end()) {
234 LOG(ERROR) << "version " << ext_version.version() << " requires unmapped module"
235 << requirement.module();
236 return false;
237 }
238 }
239 }
240
241 if (android::modules::sdklevel::IsAtLeastT()) {
242 if (versions[AD_SERVICES] >= 7) {
243 if (!SetExtension("ad_services", versions[AD_SERVICES])) {
244 return false;
245 }
246 } else {
247 relevant_modules.clear();
248 relevant_modules.insert(SdkModule::AD_SERVICES);
249 if (!GetAndSetExtension("ad_services", db, relevant_modules, versions)) {
250 return false;
251 }
252 }
253 }
254 return true;
255 }
256
PrintHeader()257 bool PrintHeader() {
258 std::map<std::string, std::string> properties;
259 ReadSystemProperties(properties);
260
261 bool print_separator = false;
262 std::cout << "[";
263 for (const auto& property : properties) {
264 if (property.first.find(kSystemPropertiesPrefix) == 0) {
265 if (print_separator) {
266 std::cout << ", ";
267 }
268 const auto name = property.first.substr(kSystemPropertiesPrefix.size());
269 std::cout << name << "=" << property.second;
270 print_separator = true;
271 }
272 }
273 std::cout << "]\n";
274 return true;
275 }
276
PrintDump(const std::string & mountpath,std::ostream & ostream)277 bool PrintDump(const std::string& mountpath, std::ostream& ostream) {
278 std::map<std::string, std::string> properties;
279 ReadSystemProperties(properties);
280
281 std::unordered_map<SdkModule, int> versions;
282 if (!ReadSdkInfoFromApexes(mountpath, versions)) {
283 LOG(ERROR) << "Failed to read SDK info from apexes";
284 return false;
285 }
286
287 ostream << "system properties:\n";
288 for (const auto& property : properties) {
289 ostream << " " << property.first << ":" << property.second << "\n";
290 }
291
292 ostream << "apex module versions:\n";
293 for (const auto& version : versions) {
294 ostream << " " << SdkModule_Name(version.first) << ":" << version.second << "\n";
295 }
296
297 ExtensionDatabase db;
298 if (!ReadDatabase(mountpath + "/com.android.sdkext/etc/extensions_db.pb", db)) {
299 LOG(ERROR) << "Failed to read database";
300 return false;
301 }
302 std::map<int, std::unordered_set<SdkModule>> new_requirements;
303 for (const auto& ext_version : db.versions()) {
304 std::unordered_set<SdkModule> new_required;
305 for (const auto& requirement : ext_version.requirements()) {
306 if (requirement.version().version() == ext_version.version())
307 new_required.insert(requirement.module());
308 }
309 new_requirements[ext_version.version()] = new_required;
310 }
311
312 ostream << "last 3 version requirements:\n";
313 int i = 0;
314 for (auto itr = new_requirements.crbegin(); itr != new_requirements.crend() && i < 3;
315 ++itr, ++i) {
316 ostream << " " << itr->first << ": ";
317 for (auto const& module : itr->second) ostream << SdkModule_Name(module) << " ";
318 ostream << std::endl;
319 }
320
321 return true;
322 }
323
324 } // namespace derivesdk
325 } // namespace android
326