1// Copyright 2018 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 android
16
17import (
18	"testing"
19
20	"github.com/google/blueprint"
21)
22
23var neverallowTests = []struct {
24	// The name of the test.
25	name string
26
27	// Optional test specific rules. If specified then they are used instead of the default rules.
28	rules []Rule
29
30	// Additional contents to add to the virtual filesystem used by the tests.
31	fs map[string][]byte
32
33	// The expected error patterns. If empty then no errors are expected, otherwise each error
34	// reported must be matched by at least one of these patterns. A pattern matches if the error
35	// message contains the pattern. A pattern does not have to match the whole error message.
36	expectedErrors []string
37}{
38	// Test General Functionality
39
40	// in direct deps tests
41	{
42		name: "not_allowed_in_direct_deps",
43		rules: []Rule{
44			NeverAllow().InDirectDeps("not_allowed_in_direct_deps"),
45		},
46		fs: map[string][]byte{
47			"top/Android.bp": []byte(`
48				cc_library {
49					name: "not_allowed_in_direct_deps",
50				}`),
51			"other/Android.bp": []byte(`
52				cc_library {
53					name: "libother",
54					static_libs: ["not_allowed_in_direct_deps"],
55				}`),
56		},
57		expectedErrors: []string{
58			`module "libother": violates neverallow deps:not_allowed_in_direct_deps`,
59		},
60	},
61
62	// Test android specific rules
63
64	// include_dir rule tests
65	{
66		name: "include_dir not allowed to reference art",
67		fs: map[string][]byte{
68			"other/Android.bp": []byte(`
69				cc_library {
70					name: "libother",
71					include_dirs: ["art/libdexfile/include"],
72				}`),
73		},
74		expectedErrors: []string{
75			"all usages of 'art' have been migrated",
76		},
77	},
78	{
79		name: "include_dir can reference another location",
80		fs: map[string][]byte{
81			"other/Android.bp": []byte(`
82				cc_library {
83					name: "libother",
84					include_dirs: ["another/include"],
85				}`),
86		},
87	},
88	// Treble rule tests
89	{
90		name: "no vndk.enabled under vendor directory",
91		fs: map[string][]byte{
92			"vendor/Android.bp": []byte(`
93				cc_library {
94					name: "libvndk",
95					vendor_available: true,
96					vndk: {
97						enabled: true,
98					},
99				}`),
100		},
101		expectedErrors: []string{
102			"VNDK can never contain a library that is device dependent",
103		},
104	},
105	{
106		name: "no vndk.enabled under device directory",
107		fs: map[string][]byte{
108			"device/Android.bp": []byte(`
109				cc_library {
110					name: "libvndk",
111					vendor_available: true,
112					vndk: {
113						enabled: true,
114					},
115				}`),
116		},
117		expectedErrors: []string{
118			"VNDK can never contain a library that is device dependent",
119		},
120	},
121	{
122		name: "vndk-ext under vendor or device directory",
123		fs: map[string][]byte{
124			"device/Android.bp": []byte(`
125				cc_library {
126					name: "libvndk1_ext",
127					vendor: true,
128					vndk: {
129						enabled: true,
130					},
131				}`),
132			"vendor/Android.bp": []byte(`
133				cc_library {
134					name: "libvndk2_ext",
135					vendor: true,
136					vndk: {
137						enabled: true,
138					},
139				}`),
140		},
141	},
142
143	{
144		name: "no enforce_vintf_manifest.cflags",
145		fs: map[string][]byte{
146			"Android.bp": []byte(`
147				cc_library {
148					name: "libexample",
149					product_variables: {
150						enforce_vintf_manifest: {
151							cflags: ["-DSHOULD_NOT_EXIST"],
152						},
153					},
154				}`),
155		},
156		expectedErrors: []string{
157			"manifest enforcement should be independent",
158		},
159	},
160
161	{
162		name: "no treble_linker_namespaces.cflags",
163		fs: map[string][]byte{
164			"Android.bp": []byte(`
165				cc_library {
166					name: "libexample",
167					product_variables: {
168						treble_linker_namespaces: {
169							cflags: ["-DSHOULD_NOT_EXIST"],
170						},
171					},
172				}`),
173		},
174		expectedErrors: []string{
175			"nothing should care if linker namespaces are enabled or not",
176		},
177	},
178	{
179		name: "libc_bionic_ndk treble_linker_namespaces.cflags",
180		fs: map[string][]byte{
181			"Android.bp": []byte(`
182				cc_library {
183					name: "libc_bionic_ndk",
184					product_variables: {
185						treble_linker_namespaces: {
186							cflags: ["-DSHOULD_NOT_EXIST"],
187						},
188					},
189				}`),
190		},
191	},
192	{
193		name: "dependency on updatable-media",
194		fs: map[string][]byte{
195			"Android.bp": []byte(`
196				java_library {
197					name: "needs_updatable_media",
198					libs: ["updatable-media"],
199				}`),
200		},
201		expectedErrors: []string{
202			"updatable-media includes private APIs. Use updatable_media_stubs instead.",
203		},
204	},
205	{
206		name: "java_device_for_host",
207		fs: map[string][]byte{
208			"Android.bp": []byte(`
209				java_device_for_host {
210					name: "device_for_host",
211					libs: ["core-libart"],
212				}`),
213		},
214		expectedErrors: []string{
215			"java_device_for_host can only be used in allowed projects",
216		},
217	},
218	// Libcore rule tests
219	{
220		name: "sdk_version: \"none\" inside core libraries",
221		fs: map[string][]byte{
222			"libcore/Android.bp": []byte(`
223				java_library {
224					name: "inside_core_libraries",
225					sdk_version: "none",
226				}`),
227		},
228	},
229	{
230		name: "sdk_version: \"none\" on android_*stubs_current stub",
231		fs: map[string][]byte{
232			"frameworks/base/Android.bp": []byte(`
233				java_library {
234					name: "android_stubs_current",
235					sdk_version: "none",
236				}`),
237		},
238	},
239	{
240		name: "sdk_version: \"none\" outside core libraries",
241		fs: map[string][]byte{
242			"Android.bp": []byte(`
243				java_library {
244					name: "outside_core_libraries",
245					sdk_version: "none",
246				}`),
247		},
248		expectedErrors: []string{
249			"module \"outside_core_libraries\": violates neverallow",
250		},
251	},
252	{
253		name: "sdk_version: \"current\"",
254		fs: map[string][]byte{
255			"Android.bp": []byte(`
256				java_library {
257					name: "outside_core_libraries",
258					sdk_version: "current",
259				}`),
260		},
261	},
262	// CC sdk rule tests
263	{
264		name: `"sdk_variant_only" outside allowed list`,
265		fs: map[string][]byte{
266			"Android.bp": []byte(`
267				cc_library {
268					name: "outside_allowed_list",
269					sdk_version: "current",
270					sdk_variant_only: true,
271				}`),
272		},
273		expectedErrors: []string{
274			`module "outside_allowed_list": violates neverallow`,
275		},
276	},
277	{
278		name: `"sdk_variant_only: false" outside allowed list`,
279		fs: map[string][]byte{
280			"Android.bp": []byte(`
281				cc_library {
282					name: "outside_allowed_list",
283					sdk_version: "current",
284					sdk_variant_only: false,
285				}`),
286		},
287		expectedErrors: []string{
288			`module "outside_allowed_list": violates neverallow`,
289		},
290	},
291	{
292		name: `"platform" outside allowed list`,
293		fs: map[string][]byte{
294			"Android.bp": []byte(`
295				cc_library {
296					name: "outside_allowed_list",
297					platform: {
298						shared_libs: ["libfoo"],
299					},
300				}`),
301		},
302		expectedErrors: []string{
303			`module "outside_allowed_list": violates neverallow`,
304		},
305	},
306	{
307		name: "uncompress_dex inside art",
308		fs: map[string][]byte{
309			"art/Android.bp": []byte(`
310				java_library {
311					name: "inside_art_libraries",
312					uncompress_dex: true,
313				}`),
314		},
315	},
316	{
317		name: "uncompress_dex outside art",
318		fs: map[string][]byte{
319			"other/Android.bp": []byte(`
320				java_library {
321					name: "outside_art_libraries",
322					uncompress_dex: true,
323				}`),
324		},
325		expectedErrors: []string{
326			"module \"outside_art_libraries\": violates neverallow",
327		},
328	},
329	{
330		name: "disallowed makefile_goal",
331		fs: map[string][]byte{
332			"Android.bp": []byte(`
333				makefile_goal {
334					name: "foo",
335					product_out_path: "boot/trap.img"
336				}
337			`),
338		},
339		expectedErrors: []string{
340			"Only boot images may be imported as a makefile goal.",
341		},
342	},
343}
344
345func TestNeverallow(t *testing.T) {
346	for _, test := range neverallowTests {
347		// Create a test per config to allow for test specific config, e.g. test rules.
348		config := TestConfig(buildDir, nil, "", test.fs)
349
350		t.Run(test.name, func(t *testing.T) {
351			// If the test has its own rules then use them instead of the default ones.
352			if test.rules != nil {
353				SetTestNeverallowRules(config, test.rules)
354			}
355			_, errs := testNeverallow(config)
356			CheckErrorsAgainstExpectations(t, errs, test.expectedErrors)
357		})
358	}
359}
360
361func testNeverallow(config Config) (*TestContext, []error) {
362	ctx := NewTestContext()
363	ctx.RegisterModuleType("cc_library", newMockCcLibraryModule)
364	ctx.RegisterModuleType("java_library", newMockJavaLibraryModule)
365	ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule)
366	ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule)
367	ctx.RegisterModuleType("makefile_goal", newMockMakefileGoalModule)
368	ctx.PostDepsMutators(RegisterNeverallowMutator)
369	ctx.Register(config)
370
371	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
372	if len(errs) > 0 {
373		return ctx, errs
374	}
375
376	_, errs = ctx.PrepareBuildActions(config)
377	return ctx, errs
378}
379
380type mockCcLibraryProperties struct {
381	Include_dirs     []string
382	Vendor_available *bool
383	Static_libs      []string
384	Sdk_version      *string
385	Sdk_variant_only *bool
386
387	Vndk struct {
388		Enabled                *bool
389		Support_system_process *bool
390		Extends                *string
391	}
392
393	Product_variables struct {
394		Enforce_vintf_manifest struct {
395			Cflags []string
396		}
397
398		Treble_linker_namespaces struct {
399			Cflags []string
400		}
401	}
402
403	Platform struct {
404		Shared_libs []string
405	}
406}
407
408type mockCcLibraryModule struct {
409	ModuleBase
410	properties mockCcLibraryProperties
411}
412
413func newMockCcLibraryModule() Module {
414	m := &mockCcLibraryModule{}
415	m.AddProperties(&m.properties)
416	InitAndroidModule(m)
417	return m
418}
419
420type neverallowTestDependencyTag struct {
421	blueprint.BaseDependencyTag
422	name string
423}
424
425var staticDepTag = neverallowTestDependencyTag{name: "static"}
426
427func (c *mockCcLibraryModule) DepsMutator(ctx BottomUpMutatorContext) {
428	for _, lib := range c.properties.Static_libs {
429		ctx.AddDependency(ctx.Module(), staticDepTag, lib)
430	}
431}
432
433func (p *mockCcLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
434}
435
436type mockJavaLibraryProperties struct {
437	Libs           []string
438	Sdk_version    *string
439	Uncompress_dex *bool
440}
441
442type mockJavaLibraryModule struct {
443	ModuleBase
444	properties mockJavaLibraryProperties
445}
446
447func newMockJavaLibraryModule() Module {
448	m := &mockJavaLibraryModule{}
449	m.AddProperties(&m.properties)
450	InitAndroidModule(m)
451	return m
452}
453
454func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
455}
456
457type mockMakefileGoalProperties struct {
458	Product_out_path *string
459}
460
461type mockMakefileGoalModule struct {
462	ModuleBase
463	properties mockMakefileGoalProperties
464}
465
466func newMockMakefileGoalModule() Module {
467	m := &mockMakefileGoalModule{}
468	m.AddProperties(&m.properties)
469	InitAndroidModule(m)
470	return m
471}
472
473func (p *mockMakefileGoalModule) GenerateAndroidBuildActions(ModuleContext) {
474}
475