summaryrefslogtreecommitdiff
path: root/java/boot_jars.go
blob: 900eb7adf47cb73c8ee08bba73d9778383106d7f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// Copyright 2020 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package java

import (
	"android/soong/android"
)

func init() {
	android.RegisterSingletonType("boot_jars", bootJarsSingletonFactory)
}

func bootJarsSingletonFactory() android.Singleton {
	return &bootJarsSingleton{}
}

type bootJarsSingleton struct{}

func populateMapFromConfiguredJarList(ctx android.SingletonContext, moduleToApex map[string]string, list android.ConfiguredJarList, name string) bool {
	for i := 0; i < list.Len(); i++ {
		module := list.Jar(i)
		// Ignore jacocoagent it is only added when instrumenting and so has no impact on
		// app compatibility.
		if module == "jacocoagent" {
			continue
		}
		apex := list.Apex(i)
		if existing, ok := moduleToApex[module]; ok {
			ctx.Errorf("Configuration property %q is invalid as it contains multiple references to module (%s) in APEXes (%s and %s)",
				module, existing, apex)
			return false
		}

		moduleToApex[module] = apex
	}

	return true
}

func (b *bootJarsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
	config := ctx.Config()
	if config.SkipBootJarsCheck() {
		return
	}

	// Populate a map from module name to APEX from the boot jars. If there is a problem
	// such as duplicate modules then fail and return immediately.
	moduleToApex := make(map[string]string)
	if !populateMapFromConfiguredJarList(ctx, moduleToApex, config.NonUpdatableBootJars(), "BootJars") ||
		!populateMapFromConfiguredJarList(ctx, moduleToApex, config.UpdatableBootJars(), "UpdatableBootJars") {
		return
	}

	// Map from module name to the correct apex variant.
	nameToApexVariant := make(map[string]android.Module)

	// Scan all the modules looking for the module/apex variants corresponding to the
	// boot jars.
	ctx.VisitAllModules(func(module android.Module) {
		name := ctx.ModuleName(module)
		if apex, ok := moduleToApex[name]; ok {
			apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
			if (apex == "platform" && apexInfo.IsForPlatform()) || apexInfo.InApex(apex) {
				// The module name/apex variant should be unique in the system but double check
				// just in case something has gone wrong.
				if existing, ok := nameToApexVariant[name]; ok {
					ctx.Errorf("found multiple variants matching %s:%s: %q and %q", apex, name, existing, module)
				}
				nameToApexVariant[name] = module
			}
		}
	})

	timestamp := android.PathForOutput(ctx, "boot-jars-package-check/stamp")

	rule := android.NewRuleBuilder()
	checkBootJars := rule.Command().BuiltTool(ctx, "check_boot_jars").
		Input(android.PathForSource(ctx, "build/soong/scripts/check_boot_jars/package_allowed_list.txt"))

	// If this is not an unbundled build and missing dependencies are not allowed
	// then all the boot jars listed must have been found.
	strict := !config.UnbundledBuild() && !config.AllowMissingDependencies()

	// Iterate over the module names on the boot classpath in order
	for _, name := range android.SortedStringKeys(moduleToApex) {
		if apexVariant, ok := nameToApexVariant[name]; ok {
			if dep, ok := apexVariant.(Dependency); ok {
				// Add the implementation jars for the module to be checked. This uses implementation
				// and resources jar as that is what the previous make based check uses.
				for _, jar := range dep.ImplementationAndResourcesJars() {
					checkBootJars.Input(jar)
				}
			} else if _, ok := apexVariant.(*DexImport); ok {
				// TODO(b/171479578): ignore deximport when doing package check until boot_jars.go can check dex jars.
			} else {
				ctx.Errorf("module %q is of type %q which is not supported as a boot jar", name, ctx.ModuleType(apexVariant))
			}
		} else if strict {
			ctx.Errorf("boot jars package check failed as it could not find module %q for apex %q", name, moduleToApex[name])
		}
	}

	checkBootJars.Text("&& touch").Output(timestamp)
	rule.Build(pctx, ctx, "boot_jars_package_check", "check boot jar packages")

	// The check-boot-jars phony target depends on the timestamp created if the check succeeds.
	ctx.Phony("check-boot-jars", timestamp)

	// The droidcore phony target depends on the check-boot-jars phony target
	ctx.Phony("droidcore", android.PathForPhony(ctx, "check-boot-jars"))
}