1// Copyright 2019 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package java
16
17import (
18	"path/filepath"
19	"strings"
20	"testing"
21
22	"github.com/google/blueprint/proptools"
23
24	"android/soong/android"
25	"android/soong/java/config"
26)
27
28func TestClasspath(t *testing.T) {
29	const frameworkAidl = "-I" + defaultJavaDir + "/framework/aidl"
30	var classpathTestcases = []struct {
31		name       string
32		unbundled  bool
33		moduleType string
34		host       android.OsClass
35		properties string
36
37		// for java 8
38		bootclasspath  []string
39		java8classpath []string
40
41		// for java 9
42		system         string
43		java9classpath []string
44
45		forces8 bool // if set, javac will always be called with java 8 arguments
46
47		aidl string
48	}{
49		{
50			name:           "default",
51			bootclasspath:  config.StableCorePlatformBootclasspathLibraries,
52			system:         config.StableCorePlatformSystemModules,
53			java8classpath: config.FrameworkLibraries,
54			java9classpath: config.FrameworkLibraries,
55			aidl:           frameworkAidl,
56		},
57		{
58			name:           `sdk_version:"core_platform"`,
59			properties:     `sdk_version:"core_platform"`,
60			bootclasspath:  config.StableCorePlatformBootclasspathLibraries,
61			system:         config.StableCorePlatformSystemModules,
62			java8classpath: []string{},
63			aidl:           "",
64		},
65		{
66			name:           "blank sdk version",
67			properties:     `sdk_version: "",`,
68			bootclasspath:  config.StableCorePlatformBootclasspathLibraries,
69			system:         config.StableCorePlatformSystemModules,
70			java8classpath: config.FrameworkLibraries,
71			java9classpath: config.FrameworkLibraries,
72			aidl:           frameworkAidl,
73		},
74		{
75
76			name:           "sdk v29",
77			properties:     `sdk_version: "29",`,
78			bootclasspath:  []string{`""`},
79			forces8:        true,
80			java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
81			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
82		},
83		{
84
85			name:           "sdk v30",
86			properties:     `sdk_version: "30",`,
87			bootclasspath:  []string{`""`},
88			system:         "sdk_public_30_system_modules",
89			java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
90			java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
91			aidl:           "-pprebuilts/sdk/30/public/framework.aidl",
92		},
93		{
94
95			name:           "current",
96			properties:     `sdk_version: "current",`,
97			bootclasspath:  []string{"android_stubs_current", "core-lambda-stubs"},
98			system:         "core-current-stubs-system-modules",
99			java9classpath: []string{"android_stubs_current"},
100			aidl:           "-pout/soong/framework.aidl",
101		},
102		{
103
104			name:           "system_current",
105			properties:     `sdk_version: "system_current",`,
106			bootclasspath:  []string{"android_system_stubs_current", "core-lambda-stubs"},
107			system:         "core-current-stubs-system-modules",
108			java9classpath: []string{"android_system_stubs_current"},
109			aidl:           "-pout/soong/framework.aidl",
110		},
111		{
112
113			name:           "system_29",
114			properties:     `sdk_version: "system_29",`,
115			bootclasspath:  []string{`""`},
116			forces8:        true,
117			java8classpath: []string{"prebuilts/sdk/29/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
118			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
119		},
120		{
121
122			name:           "system_30",
123			properties:     `sdk_version: "system_30",`,
124			bootclasspath:  []string{`""`},
125			system:         "sdk_public_30_system_modules",
126			java8classpath: []string{"prebuilts/sdk/30/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
127			java9classpath: []string{"prebuilts/sdk/30/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
128			aidl:           "-pprebuilts/sdk/30/public/framework.aidl",
129		},
130		{
131
132			name:           "test_current",
133			properties:     `sdk_version: "test_current",`,
134			bootclasspath:  []string{"android_test_stubs_current", "core-lambda-stubs"},
135			system:         "core-current-stubs-system-modules",
136			java9classpath: []string{"android_test_stubs_current"},
137			aidl:           "-pout/soong/framework.aidl",
138		},
139		{
140
141			name:          "core_current",
142			properties:    `sdk_version: "core_current",`,
143			bootclasspath: []string{"core.current.stubs", "core-lambda-stubs"},
144			system:        "core-current-stubs-system-modules",
145		},
146		{
147
148			name:           "nostdlib",
149			properties:     `sdk_version: "none", system_modules: "none"`,
150			system:         "none",
151			bootclasspath:  []string{`""`},
152			java8classpath: []string{},
153		},
154		{
155
156			name:           "nostdlib system_modules",
157			properties:     `sdk_version: "none", system_modules: "stable-core-platform-api-stubs-system-modules"`,
158			system:         "stable-core-platform-api-stubs-system-modules",
159			bootclasspath:  []string{"stable-core-platform-api-stubs-system-modules-lib"},
160			java8classpath: []string{},
161		},
162		{
163
164			name:           "host default",
165			moduleType:     "java_library_host",
166			properties:     ``,
167			host:           android.Host,
168			bootclasspath:  []string{"jdk8/jre/lib/jce.jar", "jdk8/jre/lib/rt.jar"},
169			java8classpath: []string{},
170		},
171		{
172
173			name:           "host supported default",
174			host:           android.Host,
175			properties:     `host_supported: true,`,
176			java8classpath: []string{},
177			bootclasspath:  []string{"jdk8/jre/lib/jce.jar", "jdk8/jre/lib/rt.jar"},
178		},
179		{
180			name:           "host supported nostdlib",
181			host:           android.Host,
182			properties:     `host_supported: true, sdk_version: "none", system_modules: "none"`,
183			java8classpath: []string{},
184		},
185		{
186
187			name:           "unbundled sdk v29",
188			unbundled:      true,
189			properties:     `sdk_version: "29",`,
190			bootclasspath:  []string{`""`},
191			forces8:        true,
192			java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
193			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
194		},
195		{
196
197			name:           "unbundled sdk v30",
198			unbundled:      true,
199			properties:     `sdk_version: "30",`,
200			bootclasspath:  []string{`""`},
201			system:         "sdk_public_30_system_modules",
202			java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
203			java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
204			aidl:           "-pprebuilts/sdk/30/public/framework.aidl",
205		},
206		{
207
208			name:           "unbundled current",
209			unbundled:      true,
210			properties:     `sdk_version: "current",`,
211			bootclasspath:  []string{`""`},
212			system:         "sdk_public_current_system_modules",
213			java8classpath: []string{"prebuilts/sdk/current/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
214			java9classpath: []string{"prebuilts/sdk/current/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
215			aidl:           "-pprebuilts/sdk/current/public/framework.aidl",
216		},
217
218		{
219			name:           "module_current",
220			properties:     `sdk_version: "module_current",`,
221			bootclasspath:  []string{"android_module_lib_stubs_current", "core-lambda-stubs"},
222			system:         "core-module-lib-stubs-system-modules",
223			java9classpath: []string{"android_module_lib_stubs_current"},
224			aidl:           "-pout/soong/framework_non_updatable.aidl",
225		},
226		{
227			name:           "system_server_current",
228			properties:     `sdk_version: "system_server_current",`,
229			bootclasspath:  []string{"android_system_server_stubs_current", "core-lambda-stubs"},
230			system:         "core-module-lib-stubs-system-modules",
231			java9classpath: []string{"android_system_server_stubs_current"},
232			aidl:           "-pout/soong/framework.aidl",
233		},
234	}
235
236	for _, testcase := range classpathTestcases {
237		t.Run(testcase.name, func(t *testing.T) {
238			moduleType := "java_library"
239			if testcase.moduleType != "" {
240				moduleType = testcase.moduleType
241			}
242
243			props := `
244				name: "foo",
245				srcs: ["a.java"],
246				target: {
247					android: {
248						srcs: ["bar-doc/IFoo.aidl"],
249					},
250				},
251				`
252			bp := moduleType + " {" + props + testcase.properties + `
253			}`
254			bpJava8 := moduleType + " {" + props + `java_version: "1.8",
255				` + testcase.properties + `
256			}`
257
258			variant := "android_common"
259			if testcase.host == android.Host {
260				variant = android.BuildOs.String() + "_common"
261			}
262
263			convertModulesToPaths := func(cp []string) []string {
264				ret := make([]string, len(cp))
265				for i, e := range cp {
266					ret[i] = defaultModuleToPath(e)
267				}
268				return ret
269			}
270
271			bootclasspath := convertModulesToPaths(testcase.bootclasspath)
272			java8classpath := convertModulesToPaths(testcase.java8classpath)
273			java9classpath := convertModulesToPaths(testcase.java9classpath)
274
275			bc := ""
276			var bcDeps []string
277			if len(bootclasspath) > 0 {
278				bc = "-bootclasspath " + strings.Join(bootclasspath, ":")
279				if bootclasspath[0] != `""` {
280					bcDeps = bootclasspath
281				}
282			}
283
284			j8c := ""
285			if len(java8classpath) > 0 {
286				j8c = "-classpath " + strings.Join(java8classpath, ":")
287			}
288
289			j9c := ""
290			if len(java9classpath) > 0 {
291				j9c = "-classpath " + strings.Join(java9classpath, ":")
292			}
293
294			system := ""
295			var systemDeps []string
296			if testcase.system == "none" {
297				system = "--system=none"
298			} else if testcase.system != "" {
299				dir := ""
300				if strings.HasPrefix(testcase.system, "sdk_public_") {
301					dir = "prebuilts/sdk"
302				} else {
303					dir = defaultJavaDir
304				}
305				system = "--system=" + filepath.Join("out", "soong", ".intermediates", dir, testcase.system, "android_common", "system")
306				// The module-relative parts of these paths are hardcoded in system_modules.go:
307				systemDeps = []string{
308					filepath.Join("out", "soong", ".intermediates", dir, testcase.system, "android_common", "system", "lib", "modules"),
309					filepath.Join("out", "soong", ".intermediates", dir, testcase.system, "android_common", "system", "lib", "jrt-fs.jar"),
310					filepath.Join("out", "soong", ".intermediates", dir, testcase.system, "android_common", "system", "release"),
311				}
312			}
313
314			checkClasspath := func(t *testing.T, result *android.TestResult, isJava8 bool) {
315				foo := result.ModuleForTests("foo", variant)
316				javac := foo.Rule("javac")
317				var deps []string
318
319				aidl := foo.MaybeRule("aidl")
320				if aidl.Rule != nil {
321					deps = append(deps, android.PathRelativeToTop(aidl.Output))
322				}
323
324				got := javac.Args["bootClasspath"]
325				expected := ""
326				if isJava8 || testcase.forces8 {
327					expected = bc
328					deps = append(deps, bcDeps...)
329				} else {
330					expected = system
331					deps = append(deps, systemDeps...)
332				}
333				if got != expected {
334					t.Errorf("bootclasspath expected %q != got %q", expected, got)
335				}
336
337				if isJava8 || testcase.forces8 {
338					expected = j8c
339					deps = append(deps, java8classpath...)
340				} else {
341					expected = j9c
342					deps = append(deps, java9classpath...)
343				}
344				got = javac.Args["classpath"]
345				if got != expected {
346					t.Errorf("classpath expected %q != got %q", expected, got)
347				}
348
349				android.AssertPathsRelativeToTopEquals(t, "implicits", deps, javac.Implicits)
350			}
351
352			fixtureFactory := android.GroupFixturePreparers(
353				prepareForJavaTest,
354				FixtureWithPrebuiltApis(map[string][]string{
355					"29":      {},
356					"30":      {},
357					"current": {},
358				}),
359				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
360					if testcase.unbundled {
361						variables.Unbundled_build = proptools.BoolPtr(true)
362						variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
363					}
364				}),
365				android.FixtureModifyEnv(func(env map[string]string) {
366					if env["ANDROID_JAVA8_HOME"] == "" {
367						env["ANDROID_JAVA8_HOME"] = "jdk8"
368					}
369				}),
370			)
371
372			// Test with legacy javac -source 1.8 -target 1.8
373			t.Run("Java language level 8", func(t *testing.T) {
374				result := fixtureFactory.RunTestWithBp(t, bpJava8)
375
376				checkClasspath(t, result, true /* isJava8 */)
377
378				if testcase.host != android.Host {
379					aidl := result.ModuleForTests("foo", variant).Rule("aidl")
380
381					android.AssertStringDoesContain(t, "aidl command", aidl.RuleParams.Command, testcase.aidl+" -I.")
382				}
383			})
384
385			// Test with default javac -source 9 -target 9
386			t.Run("Java language level 9", func(t *testing.T) {
387				result := fixtureFactory.RunTestWithBp(t, bp)
388
389				checkClasspath(t, result, false /* isJava8 */)
390
391				if testcase.host != android.Host {
392					aidl := result.ModuleForTests("foo", variant).Rule("aidl")
393
394					android.AssertStringDoesContain(t, "aidl command", aidl.RuleParams.Command, testcase.aidl+" -I.")
395				}
396			})
397
398			prepareWithPlatformVersionRel := android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
399				variables.Platform_sdk_codename = proptools.StringPtr("REL")
400				variables.Platform_sdk_final = proptools.BoolPtr(true)
401			})
402
403			// Test again with PLATFORM_VERSION_CODENAME=REL, javac -source 8 -target 8
404			t.Run("REL + Java language level 8", func(t *testing.T) {
405				result := android.GroupFixturePreparers(
406					fixtureFactory, prepareWithPlatformVersionRel).RunTestWithBp(t, bpJava8)
407
408				checkClasspath(t, result, true /* isJava8 */)
409			})
410
411			// Test again with PLATFORM_VERSION_CODENAME=REL, javac -source 9 -target 9
412			t.Run("REL + Java language level 9", func(t *testing.T) {
413				result := android.GroupFixturePreparers(
414					fixtureFactory, prepareWithPlatformVersionRel).RunTestWithBp(t, bp)
415
416				checkClasspath(t, result, false /* isJava8 */)
417			})
418		})
419	}
420}
421