1 /*
2 * Copyright (C) 2021 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 "derive_classpath.h"
18
19 #include <android-base/file.h>
20 #include <android-base/logging.h>
21 #include <android-base/properties.h>
22 #include <android-base/stringprintf.h>
23 #include <android-base/strings.h>
24 #include <gtest/gtest.h>
25 #include <stdlib.h>
26 #include <sys/mman.h>
27 #include <sys/stat.h>
28
29 #include <cstdlib>
30 #include <string_view>
31
32 #include "android-base/unique_fd.h"
33 #include "packages/modules/common/proto/classpaths.pb.h"
34
35 #ifdef SDKEXT_ANDROID
36 #include <android-modules-utils/sdk_level.h>
37 #include <android/api-level.h>
38 #else
39
40 #define __ANDROID_API_R__ 30
41 #define __NR_memfd_create 319
42
memfd_create(const char * name,unsigned int flags)43 int memfd_create(const char* name, unsigned int flags) {
44 return syscall(__NR_memfd_create, name, flags);
45 }
46 #endif
47
48 namespace android {
49 namespace derive_classpath {
50 namespace {
51
52 static const std::string kFrameworkJarFilepath = "/system/framework/framework.jar";
53 static const std::string kLibartJarFilepath = "/apex/com.android.art/javalib/core-libart.jar";
54 static const std::string kSdkExtensionsJarFilepath =
55 "/apex/com.android.sdkext/javalib/framework-sdkextensions.jar";
56 static const std::string kServicesJarFilepath = "/system/framework/services.jar";
57
58 // The fixture for testing derive_classpath.
59 class DeriveClasspathTest : public ::testing::Test {
60 protected:
working_dir()61 const std::string working_dir() { return std::string(temp_dir_.path); }
62
GetOutputPath()63 const std::string GetOutputPath() { return working_dir() + "/classpath"; }
64
65 // Parses the generated classpath exports file and returns each line individually.
ParseExportsFile(const char * file=nullptr)66 std::vector<std::string> ParseExportsFile(const char* file = nullptr) {
67 if (file == nullptr) {
68 file = output_path_.c_str();
69 }
70 std::string contents;
71 EXPECT_TRUE(android::base::ReadFileToString(file, &contents,
72 /*follow_symlinks=*/true));
73 return android::base::Split(contents, "\n");
74 }
75
SplitClasspathExportLine(const std::string & line)76 std::vector<std::string> SplitClasspathExportLine(const std::string& line) {
77 std::vector<std::string> contents = android::base::Split(line, " ");
78 // Export lines are expected to be structured as `export <name> <value>`.
79 EXPECT_EQ(3, contents.size());
80 EXPECT_EQ("export", contents[0]);
81 return contents;
82 }
83
84 // Checks the order of the jars in a given classpath.
85 // Instead of doing a full order check, it assumes the jars are grouped by partition and checks
86 // that partitions come in order of the `prefixes` that is given.
CheckClasspathGroupOrder(const std::string classpath,const std::vector<std::string> prefixes)87 void CheckClasspathGroupOrder(const std::string classpath,
88 const std::vector<std::string> prefixes) {
89 ASSERT_NE(0, prefixes.size());
90 ASSERT_NE(0, classpath.size());
91
92 auto jars = android::base::Split(classpath, ":");
93
94 auto prefix = prefixes.begin();
95 auto jar = jars.begin();
96 for (; jar != jars.end() && prefix != prefixes.end(); ++jar) {
97 if (*jar == "/apex/com.android.i18n/javalib/core-icu4j.jar") {
98 // core-icu4j.jar is special and is out of order in BOOTCLASSPATH;
99 // ignore it when checking for general order
100 continue;
101 }
102 if (!android::base::StartsWith(*jar, *prefix)) {
103 ++prefix;
104 }
105 }
106 EXPECT_NE(prefix, prefixes.end());
107 // All jars have been iterated over, thus they all have valid prefixes
108 EXPECT_EQ(jar, jars.end());
109 }
110
WriteConfig(const ExportedClasspathsJars & exported_jars,const std::string & path)111 void WriteConfig(const ExportedClasspathsJars& exported_jars, const std::string& path) {
112 std::string fragment_path = working_dir() + path;
113 std::string buf;
114 exported_jars.SerializeToString(&buf);
115 std::string cmd("mkdir -p " + android::base::Dirname(fragment_path));
116 ASSERT_EQ(0, system(cmd.c_str()));
117 ASSERT_TRUE(android::base::WriteStringToFile(buf, fragment_path, true));
118 }
119
AddJarToClasspath(const std::string & partition,const std::string & jar_filepath,Classpath classpath)120 void AddJarToClasspath(const std::string& partition, const std::string& jar_filepath,
121 Classpath classpath) {
122 ExportedClasspathsJars exported_jars;
123 Jar* jar = exported_jars.add_jars();
124 jar->set_path(jar_filepath);
125 jar->set_classpath(classpath);
126
127 std::string basename = Classpath_Name(classpath) + ".pb";
128 std::transform(basename.begin(), basename.end(), basename.begin(),
129 [](unsigned char c) { return std::tolower(c); });
130
131 WriteConfig(exported_jars, partition + "/etc/classpaths/" + basename);
132 }
133
134 const TemporaryDir temp_dir_;
135 const std::string output_path_ = working_dir() + "/classpath";
136
137 #ifdef SDKEXT_ANDROID
138 const Args default_args_with_test_dir_ = {
139 .output_path = output_path_,
140 .glob_pattern_prefix = temp_dir_.path,
141 };
142 #else
143 const Args default_args_with_test_dir_ = {
144 .output_path = output_path_,
145 .override_device_sdk_version = 35,
146 .override_device_codename = "REL",
147 .glob_pattern_prefix = temp_dir_.path,
148 };
149 #endif
150 };
151
152 using DeriveClasspathDeathTest = DeriveClasspathTest;
153
154 // Check only known *CLASSPATH variables are exported.
TEST_F(DeriveClasspathTest,DefaultNoUnknownClasspaths)155 TEST_F(DeriveClasspathTest, DefaultNoUnknownClasspaths) {
156 // Re-generate default on device classpaths
157 GenerateClasspathExports(default_args_with_test_dir_);
158
159 const std::vector<std::string> exportLines = ParseExportsFile();
160 // The first four lines are tested below.
161 for (int i = 4; i < exportLines.size(); i++) {
162 EXPECT_EQ(exportLines[i], "");
163 }
164 }
165
166 // Test that all variables are properly generated.
TEST_F(DeriveClasspathTest,AllVariables)167 TEST_F(DeriveClasspathTest, AllVariables) {
168 ExportedClasspathsJars exported_jars;
169 Jar* jar = exported_jars.add_jars();
170 jar->set_path("/apex/com.android.foo/javalib/foo");
171 jar->set_classpath(BOOTCLASSPATH);
172 jar = exported_jars.add_jars();
173 jar->set_path("/apex/com.android.bar/javalib/bar");
174 jar->set_classpath(DEX2OATBOOTCLASSPATH);
175 WriteConfig(exported_jars, "/system/etc/classpaths/bootclasspath.pb");
176
177 exported_jars.clear_jars();
178 jar = exported_jars.add_jars();
179 jar->set_path("/apex/com.android.baz/javalib/baz");
180 jar->set_classpath(SYSTEMSERVERCLASSPATH);
181 jar = exported_jars.add_jars();
182 jar->set_path("/apex/com.android.qux/javalib/qux");
183 jar->set_classpath(STANDALONE_SYSTEMSERVER_JARS);
184 WriteConfig(exported_jars, "/system/etc/classpaths/systemserverclasspath.pb");
185
186 ASSERT_TRUE(GenerateClasspathExports(default_args_with_test_dir_));
187
188 const std::vector<std::string> exportLines = ParseExportsFile();
189 std::vector<std::string> splitExportLine;
190
191 splitExportLine = SplitClasspathExportLine(exportLines[0]);
192 EXPECT_EQ("BOOTCLASSPATH", splitExportLine[1]);
193 EXPECT_EQ("/apex/com.android.foo/javalib/foo", splitExportLine[2]);
194 splitExportLine = SplitClasspathExportLine(exportLines[1]);
195 EXPECT_EQ("DEX2OATBOOTCLASSPATH", splitExportLine[1]);
196 EXPECT_EQ("/apex/com.android.bar/javalib/bar", splitExportLine[2]);
197 splitExportLine = SplitClasspathExportLine(exportLines[2]);
198 EXPECT_EQ("SYSTEMSERVERCLASSPATH", splitExportLine[1]);
199 EXPECT_EQ("/apex/com.android.baz/javalib/baz", splitExportLine[2]);
200 splitExportLine = SplitClasspathExportLine(exportLines[3]);
201 EXPECT_EQ("STANDALONE_SYSTEMSERVER_JARS", splitExportLine[1]);
202 EXPECT_EQ("/apex/com.android.qux/javalib/qux", splitExportLine[2]);
203 }
204
205 // Test that temp directory does not pick up actual jars.
TEST_F(DeriveClasspathTest,TempConfig)206 TEST_F(DeriveClasspathTest, TempConfig) {
207 AddJarToClasspath("/apex/com.android.foo", "/apex/com.android.foo/javalib/foo", BOOTCLASSPATH);
208 AddJarToClasspath("/apex/com.android.baz", "/apex/com.android.baz/javalib/baz",
209 SYSTEMSERVERCLASSPATH);
210
211 ASSERT_TRUE(GenerateClasspathExports(default_args_with_test_dir_));
212
213 const std::vector<std::string> exportLines = ParseExportsFile();
214
215 std::vector<std::string> splitExportLine;
216
217 splitExportLine = SplitClasspathExportLine(exportLines[0]);
218 EXPECT_EQ("BOOTCLASSPATH", splitExportLine[1]);
219 EXPECT_EQ("/apex/com.android.foo/javalib/foo", splitExportLine[2]);
220 splitExportLine = SplitClasspathExportLine(exportLines[2]);
221 EXPECT_EQ("SYSTEMSERVERCLASSPATH", splitExportLine[1]);
222 EXPECT_EQ("/apex/com.android.baz/javalib/baz", splitExportLine[2]);
223 }
224
225 // Test individual modules are sorted by pathnames.
TEST_F(DeriveClasspathTest,ModulesAreSorted)226 TEST_F(DeriveClasspathTest, ModulesAreSorted) {
227 AddJarToClasspath("/apex/com.android.art", "/apex/com.android.art/javalib/art", BOOTCLASSPATH);
228 AddJarToClasspath("/system", "/system/framework/jar", BOOTCLASSPATH);
229 AddJarToClasspath("/apex/com.android.foo", "/apex/com.android.foo/javalib/foo", BOOTCLASSPATH);
230 AddJarToClasspath("/apex/com.android.bar", "/apex/com.android.bar/javalib/bar", BOOTCLASSPATH);
231 AddJarToClasspath("/apex/com.android.baz", "/apex/com.android.baz/javalib/baz", BOOTCLASSPATH);
232
233 ASSERT_TRUE(GenerateClasspathExports(default_args_with_test_dir_));
234
235 const std::vector<std::string> exportLines = ParseExportsFile();
236 const std::vector<std::string> splitExportLine = SplitClasspathExportLine(exportLines[0]);
237 const std::string exportValue = splitExportLine[2];
238
239 const std::string expectedJars(
240 "/apex/com.android.art/javalib/art"
241 ":/system/framework/jar"
242 ":/apex/com.android.bar/javalib/bar"
243 ":/apex/com.android.baz/javalib/baz"
244 ":/apex/com.android.foo/javalib/foo");
245
246 EXPECT_EQ(expectedJars, exportValue);
247 }
248
249 // Test we can output to custom files.
TEST_F(DeriveClasspathTest,CustomOutputLocation)250 TEST_F(DeriveClasspathTest, CustomOutputLocation) {
251 AddJarToClasspath("/apex/com.android.art", "/apex/com.android.art/javalib/art", BOOTCLASSPATH);
252 AddJarToClasspath("/system", "/system/framework/jar", BOOTCLASSPATH);
253 AddJarToClasspath("/apex/com.android.foo", "/apex/com.android.foo/javalib/foo", BOOTCLASSPATH);
254 AddJarToClasspath("/apex/com.android.bar", "/apex/com.android.bar/javalib/bar", BOOTCLASSPATH);
255 AddJarToClasspath("/apex/com.android.baz", "/apex/com.android.baz/javalib/baz", BOOTCLASSPATH);
256
257 android::base::unique_fd fd(memfd_create("temp_file", MFD_CLOEXEC));
258 ASSERT_TRUE(fd.ok()) << "Unable to open temp-file";
259 const std::string file_name = android::base::StringPrintf("/proc/self/fd/%d", fd.get());
260 Args args = {
261 .output_path = file_name,
262 .glob_pattern_prefix = working_dir(),
263 };
264 ASSERT_TRUE(GenerateClasspathExports(args));
265
266 const std::vector<std::string> exportLines = ParseExportsFile(file_name.c_str());
267 const std::vector<std::string> splitExportLine = SplitClasspathExportLine(exportLines[0]);
268 const std::string exportValue = splitExportLine[2];
269
270 const std::string expectedJars(
271 "/apex/com.android.art/javalib/art"
272 ":/system/framework/jar"
273 ":/apex/com.android.bar/javalib/bar"
274 ":/apex/com.android.baz/javalib/baz"
275 ":/apex/com.android.foo/javalib/foo");
276
277 EXPECT_EQ(expectedJars, exportValue);
278 }
279
280 // Test alternative .pb for bootclasspath and systemclasspath.
TEST_F(DeriveClasspathTest,CustomInputLocation)281 TEST_F(DeriveClasspathTest, CustomInputLocation) {
282 AddJarToClasspath("/other", "/other/bcp-jar", BOOTCLASSPATH);
283 AddJarToClasspath("/other", "/other/systemserver-jar", SYSTEMSERVERCLASSPATH);
284 AddJarToClasspath("/apex/com.android.art", "/apex/com.android.art/javalib/art", BOOTCLASSPATH);
285 AddJarToClasspath("/apex/com.android.foo", "/apex/com.android.foo/javalib/foo", BOOTCLASSPATH);
286 AddJarToClasspath("/apex/com.android.baz", "/apex/com.android.baz/javalib/baz",
287 SYSTEMSERVERCLASSPATH);
288
289 Args args = default_args_with_test_dir_;
290 args.system_bootclasspath_fragment = "/other/etc/classpaths/bootclasspath.pb";
291 args.system_systemserverclasspath_fragment = "/other/etc/classpaths/systemserverclasspath.pb";
292
293 ASSERT_TRUE(GenerateClasspathExports(args));
294
295 const std::vector<std::string> exportLines = ParseExportsFile();
296
297 std::vector<std::string> splitExportLine;
298 splitExportLine = SplitClasspathExportLine(exportLines[0]);
299 EXPECT_EQ("BOOTCLASSPATH", splitExportLine[1]);
300 const std::string expectedBcpJars(
301 "/apex/com.android.art/javalib/art"
302 ":/other/bcp-jar"
303 ":/apex/com.android.foo/javalib/foo");
304 EXPECT_EQ(expectedBcpJars, splitExportLine[2]);
305
306 splitExportLine = SplitClasspathExportLine(exportLines[2]);
307 EXPECT_EQ("SYSTEMSERVERCLASSPATH", splitExportLine[1]);
308 const std::string expectedSystemServerJars(
309 "/other/systemserver-jar"
310 ":/apex/com.android.baz/javalib/baz");
311 EXPECT_EQ(expectedSystemServerJars, splitExportLine[2]);
312 }
313
314 // Test output location that can't be written to.
TEST_F(DeriveClasspathTest,NonWriteableOutputLocation)315 TEST_F(DeriveClasspathTest, NonWriteableOutputLocation) {
316 AddJarToClasspath("/apex/com.android.art", "/apex/com.android.art/javalib/art", BOOTCLASSPATH);
317 AddJarToClasspath("/system", "/system/framework/jar", BOOTCLASSPATH);
318
319 Args args = {
320 .output_path = "/system/non_writable_path",
321 .glob_pattern_prefix = working_dir(),
322 };
323 ASSERT_FALSE(GenerateClasspathExports(args));
324 }
325
TEST_F(DeriveClasspathTest,ScanOnlySpecificDirectories)326 TEST_F(DeriveClasspathTest, ScanOnlySpecificDirectories) {
327 AddJarToClasspath("/system", "/system/framework/jar", BOOTCLASSPATH);
328 AddJarToClasspath("/apex/com.android.foo", "/apex/com.android.foo/javalib/foo", BOOTCLASSPATH);
329 AddJarToClasspath("/apex/com.android.foo", "/apex/com.android.foo/javalib/sys",
330 SYSTEMSERVERCLASSPATH);
331 AddJarToClasspath("/apex/com.android.bar", "/apex/com.android.bar/javalib/bar", BOOTCLASSPATH);
332 AddJarToClasspath("/apex/com.android.baz", "/apex/com.android.baz/javalib/baz", BOOTCLASSPATH);
333
334 auto args_with_scan_dirs = default_args_with_test_dir_;
335 args_with_scan_dirs.scan_dirs.push_back("/apex/com.android.foo");
336 args_with_scan_dirs.scan_dirs.push_back("/apex/com.android.bar");
337 ASSERT_TRUE(GenerateClasspathExports(args_with_scan_dirs));
338
339 const std::vector<std::string> exportLines = ParseExportsFile();
340
341 std::vector<std::string> splitExportLine;
342
343 splitExportLine = SplitClasspathExportLine(exportLines[0]);
344 EXPECT_EQ("BOOTCLASSPATH", splitExportLine[1]);
345 // Not sorted. Maintains the ordering provided in scan_dirs
346 const std::string expectedJars(
347 "/apex/com.android.foo/javalib/foo"
348 ":/apex/com.android.bar/javalib/bar");
349 EXPECT_EQ(expectedJars, splitExportLine[2]);
350 splitExportLine = SplitClasspathExportLine(exportLines[2]);
351 EXPECT_EQ("SYSTEMSERVERCLASSPATH", splitExportLine[1]);
352 EXPECT_EQ("/apex/com.android.foo/javalib/sys", splitExportLine[2]);
353 }
354
355 // Test apexes only export their own jars.
TEST_F(DeriveClasspathDeathTest,ApexJarsBelongToApex)356 TEST_F(DeriveClasspathDeathTest, ApexJarsBelongToApex) {
357 // EXPECT_DEATH expects error messages in stderr, log there
358 android::base::SetLogger(android::base::StderrLogger);
359
360 AddJarToClasspath("/system", "/system/framework/jar", BOOTCLASSPATH);
361 ASSERT_TRUE(GenerateClasspathExports(default_args_with_test_dir_));
362
363 AddJarToClasspath("/apex/com.android.foo", "/apex/com.android.foo/javalib/foo", BOOTCLASSPATH);
364 ASSERT_TRUE(GenerateClasspathExports(default_args_with_test_dir_));
365
366 AddJarToClasspath("/apex/com.android.bar@12345.tmp", "/apex/com.android.bar/javalib/bar",
367 BOOTCLASSPATH);
368 ASSERT_TRUE(GenerateClasspathExports(default_args_with_test_dir_));
369
370 AddJarToClasspath("/apex/com.android.baz@12345", "/apex/this/path/is/skipped", BOOTCLASSPATH);
371 ASSERT_TRUE(GenerateClasspathExports(default_args_with_test_dir_));
372
373 AddJarToClasspath("/apex/com.android.bar", "/apex/wrong/path/bar", BOOTCLASSPATH);
374 EXPECT_DEATH(GenerateClasspathExports(default_args_with_test_dir_),
375 "must not export a jar.*wrong/path/bar");
376 }
377
378 // Test only bind mounted apexes are skipped
TEST_F(DeriveClasspathTest,OnlyBindMountedApexIsSkipped)379 TEST_F(DeriveClasspathTest, OnlyBindMountedApexIsSkipped) {
380 AddJarToClasspath("/system", "/system/framework/jar", BOOTCLASSPATH);
381 // Normal APEX with format: /apex/<module-name>/*
382 AddJarToClasspath("/apex/com.android.foo", "/apex/com.android.foo/javalib/foo", BOOTCLASSPATH);
383 // Bind mounted APEX with format: /apex/<module-name>@<version>/*
384 AddJarToClasspath("/apex/com.android.bar@123", "/apex/com.android.bar/javalib/bar",
385 BOOTCLASSPATH);
386 // Temp mounted APEX with format: /apex/<module-name>@<version>.tmp/*
387 AddJarToClasspath("/apex/com.android.baz@123.tmp", "/apex/com.android.baz/javalib/baz",
388 BOOTCLASSPATH);
389
390 ASSERT_TRUE(GenerateClasspathExports(default_args_with_test_dir_));
391
392 const std::vector<std::string> exportLines = ParseExportsFile();
393
394 std::vector<std::string> splitExportLine;
395
396 splitExportLine = SplitClasspathExportLine(exportLines[0]);
397 EXPECT_EQ("BOOTCLASSPATH", splitExportLine[1]);
398 const std::string expectedJars(
399 "/system/framework/jar"
400 ":/apex/com.android.baz/javalib/baz"
401 ":/apex/com.android.foo/javalib/foo");
402 EXPECT_EQ(expectedJars, splitExportLine[2]);
403 }
404
405 // Test classpath fragments export jars for themselves.
TEST_F(DeriveClasspathDeathTest,WrongClasspathInFragments)406 TEST_F(DeriveClasspathDeathTest, WrongClasspathInFragments) {
407 // Valid configs
408 AddJarToClasspath("/system", "/system/framework/framework-jar", BOOTCLASSPATH);
409 AddJarToClasspath("/system", "/system/framework/service-jar", SYSTEMSERVERCLASSPATH);
410
411 // Manually create an invalid config with both BCP and SSCP jars...
412 ExportedClasspathsJars exported_jars;
413 Jar* jar = exported_jars.add_jars();
414 jar->set_path("/apex/com.android.foo/javalib/foo");
415 jar->set_classpath(BOOTCLASSPATH);
416 // note that DEX2OATBOOTCLASSPATH and BOOTCLASSPATH jars are expected to be in the same config
417 jar = exported_jars.add_jars();
418 jar->set_path("/apex/com.android.foo/javalib/foo");
419 jar->set_classpath(DEX2OATBOOTCLASSPATH);
420 jar = exported_jars.add_jars();
421 jar->set_path("/apex/com.android.foo/javalib/service-foo");
422 jar->set_classpath(SYSTEMSERVERCLASSPATH);
423
424 // ...and write this config to bootclasspath.pb
425 WriteConfig(exported_jars, "/apex/com.android.foo/etc/classpaths/bootclasspath.pb");
426
427 EXPECT_DEATH(GenerateClasspathExports(default_args_with_test_dir_),
428 "must not export a jar for SYSTEMSERVERCLASSPATH");
429 }
430
TEST_F(DeriveClasspathDeathTest,CurrentSdkVersion)431 TEST_F(DeriveClasspathDeathTest, CurrentSdkVersion) {
432 #ifndef SDKEXT_ANDROID
433 GTEST_SKIP();
434 #else
435 if (android_get_device_api_level() < __ANDROID_API_S__) {
436 GTEST_SKIP();
437 }
438
439 ExportedClasspathsJars exported_jars;
440 Jar* jar = exported_jars.add_jars();
441 jar->set_path("/apex/com.android.foo/javalib/minsdkcurrent");
442 jar->set_min_sdk_version("current");
443 jar->set_classpath(SYSTEMSERVERCLASSPATH);
444 WriteConfig(exported_jars, "/apex/com.android.foo/etc/classpaths/systemserverclasspath.pb");
445
446 EXPECT_DEATH(GenerateClasspathExports(default_args_with_test_dir_), "no conversion");
447 #endif
448 }
449
450 // Test jars with different sdk versions.
TEST_F(DeriveClasspathTest,SdkVersionsAreRespected)451 TEST_F(DeriveClasspathTest, SdkVersionsAreRespected) {
452 #ifndef SDKEXT_ANDROID
453 GTEST_SKIP();
454 #else
455 if (android_get_device_api_level() < __ANDROID_API_S__) {
456 GTEST_SKIP();
457 }
458
459 // List of jars expected to be in SYSTEMSERVERCLASSPATH
460 std::vector<std::string> expected_jars;
461
462 // Add an unbounded jar
463 AddJarToClasspath("/system", "/system/framework/unbounded", SYSTEMSERVERCLASSPATH);
464 expected_jars.push_back("/system/framework/unbounded");
465
466 // Manually create a config with jars that set sdk versions...
467 ExportedClasspathsJars exported_jars;
468
469 // known released versions:
470 Jar* jar = exported_jars.add_jars();
471 jar->set_path("/apex/com.android.foo/javalib/minsdk30");
472 jar->set_min_sdk_version(std::to_string(__ANDROID_API_R__));
473 jar->set_classpath(SYSTEMSERVERCLASSPATH);
474 expected_jars.push_back("/apex/com.android.foo/javalib/minsdk30");
475 jar = exported_jars.add_jars();
476 jar->set_path("/apex/com.android.foo/javalib/maxsdk30");
477 jar->set_max_sdk_version(std::to_string(__ANDROID_API_R__));
478 jar->set_classpath(SYSTEMSERVERCLASSPATH);
479
480 // Device's reported version:
481 jar = exported_jars.add_jars();
482 jar->set_path("/apex/com.android.foo/javalib/minsdklatest");
483 jar->set_min_sdk_version(std::to_string(android_get_device_api_level()));
484 jar->set_classpath(SYSTEMSERVERCLASSPATH);
485 expected_jars.push_back("/apex/com.android.foo/javalib/minsdklatest");
486 jar = exported_jars.add_jars();
487 jar->set_path("/apex/com.android.foo/javalib/maxsdklatest");
488 jar->set_max_sdk_version(std::to_string(android_get_device_api_level()));
489 jar->set_classpath(SYSTEMSERVERCLASSPATH);
490 if ("REL" == android::base::GetProperty("ro.build.version.codename", "")) {
491 expected_jars.push_back("/apex/com.android.foo/javalib/maxsdklatest");
492 }
493
494 // unknown SDK_INT+1 version
495 jar = exported_jars.add_jars();
496 jar->set_path("/apex/com.android.foo/javalib/minsdk_plus1");
497 jar->set_min_sdk_version(std::to_string(android_get_device_api_level() + 1));
498 jar->set_classpath(SYSTEMSERVERCLASSPATH);
499 jar = exported_jars.add_jars();
500 jar->set_path("/apex/com.android.foo/javalib/maxsdk_plus1");
501 jar->set_max_sdk_version(std::to_string(android_get_device_api_level() + 1));
502 jar->set_classpath(SYSTEMSERVERCLASSPATH);
503 expected_jars.push_back("/apex/com.android.foo/javalib/maxsdk_plus1");
504
505 // known min_sdk_version and future max_sdk_version
506 jar = exported_jars.add_jars();
507 jar->set_path("/apex/com.android.foo/javalib/minsdk30maxsdk10000");
508 jar->set_min_sdk_version(std::to_string(__ANDROID_API_R__));
509 jar->set_max_sdk_version(std::to_string(android_get_device_api_level() + 1));
510 jar->set_classpath(SYSTEMSERVERCLASSPATH);
511 expected_jars.push_back("/apex/com.android.foo/javalib/minsdk30maxsdk10000");
512
513 // codename
514 if ("REL" != android::base::GetProperty("ro.build.version.codename", "")) {
515 jar = exported_jars.add_jars();
516 jar->set_path("/apex/com.android.foo/javalib/minsdkS");
517 jar->set_min_sdk_version("S");
518 jar->set_classpath(SYSTEMSERVERCLASSPATH);
519 expected_jars.push_back("/apex/com.android.foo/javalib/minsdkS");
520
521 jar = exported_jars.add_jars();
522 jar->set_path("/apex/com.android.foo/javalib/minsdkSv2");
523 jar->set_min_sdk_version("Sv2");
524 jar->set_classpath(SYSTEMSERVERCLASSPATH);
525 expected_jars.push_back("/apex/com.android.foo/javalib/minsdkSv2");
526
527 jar = exported_jars.add_jars();
528 jar->set_path("/apex/com.android.foo/javalib/minsdkTiramisu");
529 jar->set_min_sdk_version("Tiramisu");
530 jar->set_classpath(SYSTEMSERVERCLASSPATH);
531 expected_jars.push_back("/apex/com.android.foo/javalib/minsdkTiramisu");
532
533 jar = exported_jars.add_jars();
534 jar->set_path("/apex/com.android.foo/javalib/maxsdkS");
535 jar->set_max_sdk_version("S");
536 jar->set_classpath(SYSTEMSERVERCLASSPATH);
537
538 jar = exported_jars.add_jars();
539 jar->set_path("/apex/com.android.foo/javalib/maxsdkSv2");
540 jar->set_max_sdk_version("Sv2");
541 jar->set_classpath(SYSTEMSERVERCLASSPATH);
542
543 jar = exported_jars.add_jars();
544 jar->set_path("/apex/com.android.foo/javalib/maxsdkZFutureSdkVersion");
545 jar->set_max_sdk_version("ZFutureSdkVersion");
546 jar->set_classpath(SYSTEMSERVERCLASSPATH);
547 expected_jars.push_back("/apex/com.android.foo/javalib/maxsdkZFutureSdkVersion");
548 }
549
550 // ...and write this config to systemserverclasspath.pb
551 WriteConfig(exported_jars, "/apex/com.android.foo/etc/classpaths/systemserverclasspath.pb");
552
553 // Generate and parse SYSTEMSERVERCLASSPATH
554 GenerateClasspathExports(default_args_with_test_dir_);
555 const std::vector<std::string> exportLines = ParseExportsFile();
556 const std::vector<std::string> splitExportLine = SplitClasspathExportLine(exportLines[2]);
557 const std::string exportValue = splitExportLine[2];
558
559 EXPECT_EQ(android::base::Join(expected_jars, ":"), exportValue);
560 #endif
561 }
562
563 // Test jars with different sdk versions against override device values.
TEST_F(DeriveClasspathTest,SdkVersionsAreCheckedAgainstOverrideDeviceValuesRelease)564 TEST_F(DeriveClasspathTest, SdkVersionsAreCheckedAgainstOverrideDeviceValuesRelease) {
565 Args args = default_args_with_test_dir_;
566 args.override_device_sdk_version = 35;
567 args.override_device_codename = "REL";
568
569 // List of jars expected to be in SYSTEMSERVERCLASSPATH.
570 std::vector<std::string> expected_jars;
571
572 // Add an unbounded jar.
573 AddJarToClasspath("/system", "/system/framework/unbounded", SYSTEMSERVERCLASSPATH);
574 expected_jars.push_back("/system/framework/unbounded");
575
576 // Manually create a config with jars that sets sdk versions...
577 ExportedClasspathsJars exported_jars;
578
579 // Known released versions.
580 Jar* jar = exported_jars.add_jars();
581 jar->set_path("/apex/com.android.foo/javalib/minsdk30");
582 jar->set_min_sdk_version(std::to_string(__ANDROID_API_R__));
583 jar->set_classpath(SYSTEMSERVERCLASSPATH);
584 expected_jars.push_back("/apex/com.android.foo/javalib/minsdk30");
585 jar = exported_jars.add_jars();
586 jar->set_path("/apex/com.android.foo/javalib/maxsdk30");
587 jar->set_max_sdk_version(std::to_string(__ANDROID_API_R__));
588 jar->set_classpath(SYSTEMSERVERCLASSPATH);
589
590 // Provided override device sdk version.
591 jar = exported_jars.add_jars();
592 jar->set_path("/apex/com.android.foo/javalib/minsdklatest");
593 jar->set_min_sdk_version(std::to_string(args.override_device_sdk_version));
594 jar->set_classpath(SYSTEMSERVERCLASSPATH);
595 expected_jars.push_back("/apex/com.android.foo/javalib/minsdklatest");
596 jar = exported_jars.add_jars();
597 jar->set_path("/apex/com.android.foo/javalib/maxsdklatest");
598 jar->set_max_sdk_version(std::to_string(args.override_device_sdk_version));
599 jar->set_classpath(SYSTEMSERVERCLASSPATH);
600 expected_jars.push_back("/apex/com.android.foo/javalib/maxsdklatest");
601
602 // Unknown SDK_INT+1 version.
603 jar = exported_jars.add_jars();
604 jar->set_path("/apex/com.android.foo/javalib/minsdk_plus1");
605 jar->set_min_sdk_version(std::to_string(args.override_device_sdk_version + 1));
606 jar->set_classpath(SYSTEMSERVERCLASSPATH);
607 jar = exported_jars.add_jars();
608 jar->set_path("/apex/com.android.foo/javalib/maxsdk_plus1");
609 jar->set_max_sdk_version(std::to_string(args.override_device_sdk_version + 1));
610 jar->set_classpath(SYSTEMSERVERCLASSPATH);
611 expected_jars.push_back("/apex/com.android.foo/javalib/maxsdk_plus1");
612
613 // Known min_sdk_version and future max_sdk_version.
614 jar = exported_jars.add_jars();
615 jar->set_path("/apex/com.android.foo/javalib/minsdk30maxsdk10000");
616 jar->set_min_sdk_version(std::to_string(__ANDROID_API_R__));
617 jar->set_max_sdk_version(std::to_string(args.override_device_sdk_version + 1));
618 jar->set_classpath(SYSTEMSERVERCLASSPATH);
619 expected_jars.push_back("/apex/com.android.foo/javalib/minsdk30maxsdk10000");
620
621 // Codename.
622 jar = exported_jars.add_jars();
623 jar->set_path("/apex/com.android.foo/javalib/minsdkBaklava");
624 jar->set_min_sdk_version("Baklava");
625 jar->set_classpath(SYSTEMSERVERCLASSPATH);
626
627 jar = exported_jars.add_jars();
628 jar->set_path("/apex/com.android.foo/javalib/maxsdkBaklava");
629 jar->set_max_sdk_version("Baklava");
630 jar->set_classpath(SYSTEMSERVERCLASSPATH);
631 expected_jars.push_back("/apex/com.android.foo/javalib/maxsdkBaklava");
632
633 // ...and write this config to systemserverclasspath.pb.
634 WriteConfig(exported_jars, "/apex/com.android.foo/etc/classpaths/systemserverclasspath.pb");
635
636 // Generate and parse SYSTEMSERVERCLASSPATH.
637 GenerateClasspathExports(args);
638 const std::vector<std::string> exportLines = ParseExportsFile();
639 const std::vector<std::string> splitExportLine = SplitClasspathExportLine(exportLines[2]);
640 const std::string exportValue = splitExportLine[2];
641
642 EXPECT_EQ(android::base::Join(expected_jars, ":"), exportValue);
643 }
644
645 // Test jars with different sdk versions against override device values.
TEST_F(DeriveClasspathTest,SdkVersionsAreCheckedAgainstOverrideDeviceValuesDev)646 TEST_F(DeriveClasspathTest, SdkVersionsAreCheckedAgainstOverrideDeviceValuesDev) {
647 Args args = default_args_with_test_dir_;
648 args.override_device_sdk_version = 35;
649 args.override_device_codename = "Baklava";
650 args.override_device_known_codenames = {
651 "S", "Sv2", "Tiramisu", "UpsideDownCake", "VanillaIceCream", "Baklava"};
652
653 // List of jars expected to be in SYSTEMSERVERCLASSPATH.
654 std::vector<std::string> expected_jars;
655
656 // Add an unbounded jar.
657 AddJarToClasspath("/system", "/system/framework/unbounded", SYSTEMSERVERCLASSPATH);
658 expected_jars.push_back("/system/framework/unbounded");
659
660 // Manually create a config with jars that sets sdk versions...
661 ExportedClasspathsJars exported_jars;
662
663 // Known released versions.
664 Jar* jar = exported_jars.add_jars();
665 jar->set_path("/apex/com.android.foo/javalib/minsdk30");
666 jar->set_min_sdk_version(std::to_string(__ANDROID_API_R__));
667 jar->set_classpath(SYSTEMSERVERCLASSPATH);
668 expected_jars.push_back("/apex/com.android.foo/javalib/minsdk30");
669 jar = exported_jars.add_jars();
670 jar->set_path("/apex/com.android.foo/javalib/maxsdk30");
671 jar->set_max_sdk_version(std::to_string(__ANDROID_API_R__));
672 jar->set_classpath(SYSTEMSERVERCLASSPATH);
673
674 // Provided override device sdk version.
675 jar = exported_jars.add_jars();
676 jar->set_path("/apex/com.android.foo/javalib/minsdklatest");
677 jar->set_min_sdk_version(std::to_string(args.override_device_sdk_version));
678 jar->set_classpath(SYSTEMSERVERCLASSPATH);
679 expected_jars.push_back("/apex/com.android.foo/javalib/minsdklatest");
680 jar = exported_jars.add_jars();
681 jar->set_path("/apex/com.android.foo/javalib/maxsdklatest");
682 jar->set_max_sdk_version(std::to_string(args.override_device_sdk_version));
683 jar->set_classpath(SYSTEMSERVERCLASSPATH);
684
685 // Unknown SDK_INT+1 version.
686 jar = exported_jars.add_jars();
687 jar->set_path("/apex/com.android.foo/javalib/minsdk_plus1");
688 jar->set_min_sdk_version(std::to_string(args.override_device_sdk_version + 1));
689 jar->set_classpath(SYSTEMSERVERCLASSPATH);
690 jar = exported_jars.add_jars();
691 jar->set_path("/apex/com.android.foo/javalib/maxsdk_plus1");
692 jar->set_max_sdk_version(std::to_string(args.override_device_sdk_version + 1));
693 jar->set_classpath(SYSTEMSERVERCLASSPATH);
694 expected_jars.push_back("/apex/com.android.foo/javalib/maxsdk_plus1");
695
696 // Known min_sdk_version and future max_sdk_version.
697 jar = exported_jars.add_jars();
698 jar->set_path("/apex/com.android.foo/javalib/minsdk30maxsdk10000");
699 jar->set_min_sdk_version(std::to_string(__ANDROID_API_R__));
700 jar->set_max_sdk_version(std::to_string(args.override_device_sdk_version + 1));
701 jar->set_classpath(SYSTEMSERVERCLASSPATH);
702 expected_jars.push_back("/apex/com.android.foo/javalib/minsdk30maxsdk10000");
703
704 // Codename.
705 jar = exported_jars.add_jars();
706 jar->set_path("/apex/com.android.foo/javalib/minsdkBaklava");
707 jar->set_min_sdk_version("Baklava");
708 jar->set_classpath(SYSTEMSERVERCLASSPATH);
709 expected_jars.push_back("/apex/com.android.foo/javalib/minsdkBaklava");
710
711 jar = exported_jars.add_jars();
712 jar->set_path("/apex/com.android.foo/javalib/maxsdkBaklava");
713 jar->set_max_sdk_version("Baklava");
714 jar->set_classpath(SYSTEMSERVERCLASSPATH);
715 expected_jars.push_back("/apex/com.android.foo/javalib/maxsdkBaklava");
716
717 jar = exported_jars.add_jars();
718 jar->set_path("/apex/com.android.foo/javalib/minsdkTiramisu");
719 jar->set_min_sdk_version("Tiramisu");
720 jar->set_classpath(SYSTEMSERVERCLASSPATH);
721 expected_jars.push_back("/apex/com.android.foo/javalib/minsdkTiramisu");
722
723 jar = exported_jars.add_jars();
724 jar->set_path("/apex/com.android.foo/javalib/maxsdkTiramisu");
725 jar->set_max_sdk_version("Tiramisu");
726 jar->set_classpath(SYSTEMSERVERCLASSPATH);
727
728 // ...and write this config to systemserverclasspath.pb.
729 WriteConfig(exported_jars, "/apex/com.android.foo/etc/classpaths/systemserverclasspath.pb");
730
731 // Generate and parse SYSTEMSERVERCLASSPATH.
732 GenerateClasspathExports(args);
733 const std::vector<std::string> exportLines = ParseExportsFile();
734 const std::vector<std::string> splitExportLine = SplitClasspathExportLine(exportLines[2]);
735 const std::string exportValue = splitExportLine[2];
736
737 EXPECT_EQ(android::base::Join(expected_jars, ":"), exportValue);
738 }
739
740 } // namespace
741 } // namespace derive_classpath
742 } // namespace android
743
main(int argc,char ** argv)744 int main(int argc, char** argv) {
745 ::testing::InitGoogleTest(&argc, argv);
746 // Required for EXPECT_DEATH to work correctly
747 android::base::SetLogger(android::base::StderrLogger);
748 return RUN_ALL_TESTS();
749 }
750