• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2021 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	"fmt"
19	"reflect"
20	"regexp"
21	"strings"
22	"testing"
23
24	"android/soong/android"
25
26	"github.com/google/blueprint/proptools"
27)
28
29func TestDroidstubs(t *testing.T) {
30	t.Parallel()
31	ctx, _ := testJavaWithFS(t, `
32		droiddoc_exported_dir {
33			name: "droiddoc-templates-sdk",
34			path: ".",
35		}
36
37		droidstubs {
38			name: "bar-stubs",
39			srcs: ["bar-doc/a.java"],
40			api_levels_annotations_dirs: ["droiddoc-templates-sdk"],
41			api_levels_annotations_enabled: true,
42		}
43
44		droidstubs {
45			name: "bar-stubs-other",
46			srcs: ["bar-doc/a.java"],
47			high_mem: true,
48			api_levels_annotations_dirs: ["droiddoc-templates-sdk"],
49			api_levels_annotations_enabled: true,
50			api_levels_jar_filename: "android.other.jar",
51		}
52
53		droidstubs {
54			name: "stubs-applying-api-versions",
55			srcs: ["bar-doc/a.java"],
56			api_levels_module: "bar-stubs-other",
57		}
58		`,
59		map[string][]byte{
60			"bar-doc/a.java": nil,
61		})
62	testcases := []struct {
63		moduleName          string
64		expectedJarFilename string
65		generate_xml        bool
66		high_mem            bool
67	}{
68		{
69			moduleName:          "bar-stubs",
70			generate_xml:        true,
71			expectedJarFilename: "android.jar",
72			high_mem:            false,
73		},
74		{
75			moduleName:          "bar-stubs-other",
76			generate_xml:        true,
77			expectedJarFilename: "android.other.jar",
78			high_mem:            true,
79		},
80		{
81			moduleName:   "stubs-applying-api-versions",
82			generate_xml: false,
83		},
84	}
85	for _, c := range testcases {
86		m := ctx.ModuleForTests(t, c.moduleName, "android_common")
87		manifest := m.Output("metalava.sbox.textproto")
88		sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx, manifest)
89		cmdline := String(sboxProto.Commands[0].Command)
90		android.AssertStringContainsEquals(t, "api-versions generation flag", cmdline, "--generate-api-levels", c.generate_xml)
91		if c.expectedJarFilename != "" {
92			expected := "--android-jar-pattern ./{version:major.minor?}/public/" + c.expectedJarFilename
93			if !strings.Contains(cmdline, expected) {
94				t.Errorf("For %q, expected metalava argument %q, but was not found %q", c.moduleName, expected, cmdline)
95			}
96		}
97
98		metalava := m.Rule("metalava")
99		rp := metalava.RuleParams
100		if actual := rp.Pool != nil && strings.Contains(rp.Pool.String(), "highmem"); actual != c.high_mem {
101			t.Errorf("Expected %q high_mem to be %v, was %v", c.moduleName, c.high_mem, actual)
102		}
103	}
104}
105
106// runs a test for droidstubs with a customizable sdkType argument and returns
107// the list of jar patterns that is passed as `--android-jar-pattern`
108func getAndroidJarPatternsForDroidstubs(t *testing.T, sdkType string) []string {
109	ctx, _ := testJavaWithFS(t, fmt.Sprintf(`
110		droiddoc_exported_dir {
111			name: "some-exported-dir",
112			path: "somedir",
113		}
114
115		droiddoc_exported_dir {
116			name: "some-other-exported-dir",
117			path: "someotherdir",
118		}
119
120		droidstubs {
121			name: "foo-stubs",
122			srcs: ["foo-doc/a.java"],
123			api_levels_annotations_dirs: [
124				"some-exported-dir",
125				"some-other-exported-dir",
126			],
127			api_levels_annotations_enabled: true,
128			api_levels_sdk_type: "%s",
129		}
130		`, sdkType),
131		map[string][]byte{
132			"foo-doc/a.java": nil,
133		})
134
135	m := ctx.ModuleForTests(t, "foo-stubs", "android_common")
136	manifest := m.Output("metalava.sbox.textproto")
137	cmd := String(android.RuleBuilderSboxProtoForTests(t, ctx, manifest).Commands[0].Command)
138	r := regexp.MustCompile(`--android-jar-pattern [^ ]+/android.jar`)
139	return r.FindAllString(cmd, -1)
140}
141
142func TestPublicDroidstubs(t *testing.T) {
143	t.Parallel()
144	patterns := getAndroidJarPatternsForDroidstubs(t, "public")
145
146	android.AssertArrayString(t, "order of patterns", []string{
147		"--android-jar-pattern somedir/{version:major.minor?}/public/android.jar",
148		"--android-jar-pattern someotherdir/{version:major.minor?}/public/android.jar",
149	}, patterns)
150}
151
152func TestSystemDroidstubs(t *testing.T) {
153	t.Parallel()
154	patterns := getAndroidJarPatternsForDroidstubs(t, "system")
155
156	android.AssertArrayString(t, "order of patterns", []string{
157		"--android-jar-pattern somedir/{version:major.minor?}/system/android.jar",
158		"--android-jar-pattern someotherdir/{version:major.minor?}/system/android.jar",
159		"--android-jar-pattern somedir/{version:major.minor?}/public/android.jar",
160		"--android-jar-pattern someotherdir/{version:major.minor?}/public/android.jar",
161	}, patterns)
162}
163
164func TestModuleLibDroidstubs(t *testing.T) {
165	t.Parallel()
166	patterns := getAndroidJarPatternsForDroidstubs(t, "module-lib")
167
168	android.AssertArrayString(t, "order of patterns", []string{
169		"--android-jar-pattern somedir/{version:major.minor?}/module-lib/android.jar",
170		"--android-jar-pattern someotherdir/{version:major.minor?}/module-lib/android.jar",
171		"--android-jar-pattern somedir/{version:major.minor?}/system/android.jar",
172		"--android-jar-pattern someotherdir/{version:major.minor?}/system/android.jar",
173		"--android-jar-pattern somedir/{version:major.minor?}/public/android.jar",
174		"--android-jar-pattern someotherdir/{version:major.minor?}/public/android.jar",
175	}, patterns)
176}
177
178func TestSystemServerDroidstubs(t *testing.T) {
179	patterns := getAndroidJarPatternsForDroidstubs(t, "system-server")
180
181	android.AssertArrayString(t, "order of patterns", []string{
182		"--android-jar-pattern somedir/{version:major.minor?}/system-server/android.jar",
183		"--android-jar-pattern someotherdir/{version:major.minor?}/system-server/android.jar",
184		"--android-jar-pattern somedir/{version:major.minor?}/module-lib/android.jar",
185		"--android-jar-pattern someotherdir/{version:major.minor?}/module-lib/android.jar",
186		"--android-jar-pattern somedir/{version:major.minor?}/system/android.jar",
187		"--android-jar-pattern someotherdir/{version:major.minor?}/system/android.jar",
188		"--android-jar-pattern somedir/{version:major.minor?}/public/android.jar",
189		"--android-jar-pattern someotherdir/{version:major.minor?}/public/android.jar",
190	}, patterns)
191}
192
193func TestDroidstubsSandbox(t *testing.T) {
194	ctx, _ := testJavaWithFS(t, `
195		genrule {
196			name: "foo",
197			out: ["foo.txt"],
198			cmd: "touch $(out)",
199		}
200
201		droidstubs {
202			name: "bar-stubs",
203			srcs: ["bar-doc/a.java"],
204
205			args: "--reference $(location :foo)",
206			arg_files: [":foo"],
207		}
208		`,
209		map[string][]byte{
210			"bar-doc/a.java": nil,
211		})
212
213	m := ctx.ModuleForTests(t, "bar-stubs", "android_common")
214	metalava := m.Rule("metalava")
215	if g, w := metalava.Inputs.Strings(), []string{"bar-doc/a.java"}; !reflect.DeepEqual(w, g) {
216		t.Errorf("Expected inputs %q, got %q", w, g)
217	}
218
219	manifest := android.RuleBuilderSboxProtoForTests(t, ctx, m.Output("metalava.sbox.textproto"))
220	if g, w := manifest.Commands[0].GetCommand(), "reference __SBOX_SANDBOX_DIR__/out/soong/.intermediates/foo/gen/foo.txt"; !strings.Contains(g, w) {
221		t.Errorf("Expected command to contain %q, got %q", w, g)
222	}
223}
224
225func TestDroidstubsWithSystemModules(t *testing.T) {
226	ctx, _ := testJava(t, `
227		droidstubs {
228		    name: "stubs-source-system-modules",
229		    srcs: [
230		        "bar-doc/a.java",
231		    ],
232				sdk_version: "none",
233				system_modules: "source-system-modules",
234		}
235
236		java_library {
237				name: "source-jar",
238		    srcs: [
239		        "a.java",
240		    ],
241		}
242
243		java_system_modules {
244				name: "source-system-modules",
245				libs: ["source-jar"],
246		}
247
248		droidstubs {
249		    name: "stubs-prebuilt-system-modules",
250		    srcs: [
251		        "bar-doc/a.java",
252		    ],
253				sdk_version: "none",
254				system_modules: "prebuilt-system-modules",
255		}
256
257		java_import {
258				name: "prebuilt-jar",
259				jars: ["a.jar"],
260		}
261
262		java_system_modules_import {
263				name: "prebuilt-system-modules",
264				libs: ["prebuilt-jar"],
265		}
266		`)
267
268	checkSystemModulesUseByDroidstubs(t, ctx, "stubs-source-system-modules", "source-jar.jar")
269
270	checkSystemModulesUseByDroidstubs(t, ctx, "stubs-prebuilt-system-modules", "prebuilt-jar.jar")
271}
272
273func checkSystemModulesUseByDroidstubs(t *testing.T, ctx *android.TestContext, moduleName string, systemJar string) {
274	metalavaRule := ctx.ModuleForTests(t, moduleName, "android_common").Rule("metalava")
275	var systemJars []string
276	for _, i := range metalavaRule.Implicits {
277		systemJars = append(systemJars, i.Base())
278	}
279	if len(systemJars) < 1 || systemJars[0] != systemJar {
280		t.Errorf("inputs of %q must be []string{%q}, but was %#v.", moduleName, systemJar, systemJars)
281	}
282}
283
284func TestDroidstubsWithSdkExtensions(t *testing.T) {
285	ctx, _ := testJavaWithFS(t, `
286		droiddoc_exported_dir {
287			name: "sdk-dir",
288			path: "sdk",
289		}
290
291		droidstubs {
292			name: "baz-stubs",
293			api_levels_annotations_dirs: ["sdk-dir"],
294			api_levels_annotations_enabled: true,
295			extensions_info_file: ":info-file",
296		}
297
298		filegroup {
299			name: "info-file",
300			srcs: ["sdk/extensions/info.txt"],
301		}
302		`,
303		map[string][]byte{
304			"sdk/extensions/1/public/some-mainline-module-stubs.jar": nil,
305			"sdk/extensions/info.txt":                                nil,
306		})
307	m := ctx.ModuleForTests(t, "baz-stubs", "android_common")
308	manifest := m.Output("metalava.sbox.textproto")
309	cmdline := String(android.RuleBuilderSboxProtoForTests(t, ctx, manifest).Commands[0].Command)
310	android.AssertStringDoesContain(t, "android-jar-pattern present", cmdline, "--android-jar-pattern sdk/extensions/{version:extension}/public/{module}.jar")
311	android.AssertStringDoesContain(t, "sdk-extensions-info present", cmdline, "--sdk-extensions-info sdk/extensions/info.txt")
312}
313
314func TestDroidStubsApiContributionGeneration(t *testing.T) {
315	ctx, _ := testJavaWithFS(t, `
316		droidstubs {
317			name: "foo",
318			srcs: ["A/a.java"],
319			api_surface: "public",
320			check_api: {
321				current: {
322					api_file: "A/current.txt",
323					removed_api_file: "A/removed.txt",
324				}
325			}
326		}
327		`,
328		map[string][]byte{
329			"A/a.java":      nil,
330			"A/current.txt": nil,
331			"A/removed.txt": nil,
332		},
333	)
334
335	ctx.ModuleForTests(t, "foo.api.contribution", "")
336}
337
338func TestGeneratedApiContributionVisibilityTest(t *testing.T) {
339	library_bp := `
340		java_api_library {
341			name: "bar",
342			api_surface: "public",
343			api_contributions: ["foo.api.contribution"],
344			stubs_type: "everything",
345		}
346	`
347	ctx, _ := testJavaWithFS(t, `
348			droidstubs {
349				name: "foo",
350				srcs: ["A/a.java"],
351				api_surface: "public",
352				check_api: {
353					current: {
354						api_file: "A/current.txt",
355						removed_api_file: "A/removed.txt",
356					}
357				},
358				visibility: ["//a", "//b"],
359			}
360		`,
361		map[string][]byte{
362			"a/a.java":      nil,
363			"a/current.txt": nil,
364			"a/removed.txt": nil,
365			"b/Android.bp":  []byte(library_bp),
366		},
367	)
368
369	ctx.ModuleForTests(t, "bar", "android_common")
370}
371
372func TestAconfigDeclarations(t *testing.T) {
373	result := android.GroupFixturePreparers(
374		prepareForJavaTest,
375		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
376		}),
377		android.FixtureMergeMockFs(map[string][]byte{
378			"a/A.java":      nil,
379			"a/current.txt": nil,
380			"a/removed.txt": nil,
381		}),
382	).RunTestWithBp(t, `
383	aconfig_declarations {
384		name: "bar",
385		package: "com.example.package",
386		container: "com.android.foo",
387		srcs: [
388			"bar.aconfig",
389		],
390	}
391	droidstubs {
392		name: "foo",
393		srcs: ["a/A.java"],
394		api_surface: "public",
395		check_api: {
396			current: {
397				api_file: "a/current.txt",
398				removed_api_file: "a/removed.txt",
399			}
400		},
401		aconfig_declarations: [
402			"bar",
403		],
404	}
405	`)
406
407	// Check that droidstubs depend on aconfig_declarations
408	android.AssertBoolEquals(t, "foo expected to depend on bar",
409		CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "bar"), true)
410
411	m := result.ModuleForTests(t, "foo", "android_common")
412	android.AssertStringDoesContain(t, "foo generates revert annotations file",
413		strings.Join(m.AllOutputs(), ""), "flags-config-exportable.xml")
414
415	// revert-annotations.txt passed to exportable stubs generation metalava command
416	manifest := m.Output("metalava_exportable.sbox.textproto")
417	cmdline := String(android.RuleBuilderSboxProtoForTests(t, result.TestContext, manifest).Commands[0].Command)
418	android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "flags-config-exportable.xml")
419
420	android.AssertStringDoesContain(t, "foo generates exportable stubs jar",
421		strings.Join(m.AllOutputs(), ""), "exportable/foo-stubs.srcjar")
422}
423
424func TestReleaseExportRuntimeApis(t *testing.T) {
425	result := android.GroupFixturePreparers(
426		prepareForJavaTest,
427		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
428			variables.ExportRuntimeApis = proptools.BoolPtr(true)
429		}),
430		android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"),
431		android.FixtureMergeMockFs(map[string][]byte{
432			"a/A.java":      nil,
433			"a/current.txt": nil,
434			"a/removed.txt": nil,
435		}),
436	).RunTestWithBp(t, `
437	aconfig_declarations {
438		name: "bar",
439		package: "com.example.package",
440		container: "com.android.foo",
441		srcs: [
442			"bar.aconfig",
443		],
444	}
445	droidstubs {
446		name: "foo",
447		srcs: ["a/A.java"],
448		api_surface: "public",
449		check_api: {
450			current: {
451				api_file: "a/current.txt",
452				removed_api_file: "a/removed.txt",
453			}
454		},
455		aconfig_declarations: [
456			"bar",
457		],
458	}
459	`)
460
461	m := result.ModuleForTests(t, "foo", "android_common")
462
463	rule := m.Output("released-flags-exportable.pb")
464	exposeWritableApisFilter := "--filter='state:ENABLED+permission:READ_ONLY' --filter='permission:READ_WRITE'"
465	android.AssertStringEquals(t, "Filter argument expected to contain READ_WRITE permissions", exposeWritableApisFilter, rule.Args["filter_args"])
466}
467