blob: ac8107b7c783105f48d47ef3f66d132fafb3be1c [file] [log] [blame]
Paul Duffin9a89a2a2020-10-28 19:20:06 +00001// Copyright 2020 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 "android/soong/android"
19)
20
21func init() {
22 android.RegisterSingletonType("boot_jars", bootJarsSingletonFactory)
23}
24
25func bootJarsSingletonFactory() android.Singleton {
26 return &bootJarsSingleton{}
27}
28
29type bootJarsSingleton struct{}
30
31func populateMapFromConfiguredJarList(ctx android.SingletonContext, moduleToApex map[string]string, list android.ConfiguredJarList, name string) bool {
32 for i := 0; i < list.Len(); i++ {
33 module := list.Jar(i)
34 // Ignore jacocoagent it is only added when instrumenting and so has no impact on
35 // app compatibility.
36 if module == "jacocoagent" {
37 continue
38 }
39 apex := list.Apex(i)
40 if existing, ok := moduleToApex[module]; ok {
41 ctx.Errorf("Configuration property %q is invalid as it contains multiple references to module (%s) in APEXes (%s and %s)",
42 module, existing, apex)
43 return false
44 }
45
46 moduleToApex[module] = apex
47 }
48
49 return true
50}
51
Martin Stjernholm1dc0d6d2021-01-17 21:05:12 +000052// isActiveModule returns true if the given module should be considered for boot
53// jars, i.e. if it's enabled and the preferred one in case of source and
54// prebuilt alternatives.
55func isActiveModule(module android.Module) bool {
56 if !module.Enabled() {
57 return false
58 }
59 if module.IsReplacedByPrebuilt() {
60 // A source module that has been replaced by a prebuilt counterpart.
61 return false
62 }
63 if prebuilt, ok := module.(android.PrebuiltInterface); ok {
64 if p := prebuilt.Prebuilt(); p != nil {
65 return p.UsePrebuilt()
66 }
67 }
68 return true
69}
70
Paul Duffin9a89a2a2020-10-28 19:20:06 +000071func (b *bootJarsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
72 config := ctx.Config()
73 if config.SkipBootJarsCheck() {
74 return
75 }
76
Martin Stjernholm1dc0d6d2021-01-17 21:05:12 +000077 // Populate a map from module name to APEX from the boot jars. If there is a
78 // problem such as duplicate modules then fail and return immediately. Note
79 // that both module and APEX names are tracked by base names here, so we need
80 // to be careful to remove "prebuilt_" prefixes when comparing them with
81 // actual modules and APEX bundles.
Paul Duffin9a89a2a2020-10-28 19:20:06 +000082 moduleToApex := make(map[string]string)
83 if !populateMapFromConfiguredJarList(ctx, moduleToApex, config.NonUpdatableBootJars(), "BootJars") ||
84 !populateMapFromConfiguredJarList(ctx, moduleToApex, config.UpdatableBootJars(), "UpdatableBootJars") {
85 return
86 }
87
88 // Map from module name to the correct apex variant.
89 nameToApexVariant := make(map[string]android.Module)
90
91 // Scan all the modules looking for the module/apex variants corresponding to the
92 // boot jars.
93 ctx.VisitAllModules(func(module android.Module) {
Martin Stjernholm1dc0d6d2021-01-17 21:05:12 +000094 if !isActiveModule(module) {
95 return
96 }
97
98 name := android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName(module))
Paul Duffin9a89a2a2020-10-28 19:20:06 +000099 if apex, ok := moduleToApex[name]; ok {
100 apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
Martin Stjernholm1dc0d6d2021-01-17 21:05:12 +0000101 if (apex == "platform" && apexInfo.IsForPlatform()) || apexInfo.InApexByBaseName(apex) {
Paul Duffin9a89a2a2020-10-28 19:20:06 +0000102 // The module name/apex variant should be unique in the system but double check
103 // just in case something has gone wrong.
104 if existing, ok := nameToApexVariant[name]; ok {
105 ctx.Errorf("found multiple variants matching %s:%s: %q and %q", apex, name, existing, module)
106 }
107 nameToApexVariant[name] = module
108 }
109 }
110 })
111
112 timestamp := android.PathForOutput(ctx, "boot-jars-package-check/stamp")
113
Colin Crossf1a035e2020-11-16 17:32:30 -0800114 rule := android.NewRuleBuilder(pctx, ctx)
115 checkBootJars := rule.Command().BuiltTool("check_boot_jars").
Paul Duffin2d8e1a72020-10-29 12:56:09 +0000116 Input(ctx.Config().HostToolPath(ctx, "dexdump")).
Paul Duffin9a89a2a2020-10-28 19:20:06 +0000117 Input(android.PathForSource(ctx, "build/soong/scripts/check_boot_jars/package_allowed_list.txt"))
118
119 // If this is not an unbundled build and missing dependencies are not allowed
120 // then all the boot jars listed must have been found.
121 strict := !config.UnbundledBuild() && !config.AllowMissingDependencies()
122
123 // Iterate over the module names on the boot classpath in order
124 for _, name := range android.SortedStringKeys(moduleToApex) {
125 if apexVariant, ok := nameToApexVariant[name]; ok {
Paul Duffin2d8e1a72020-10-29 12:56:09 +0000126 if dep, ok := apexVariant.(interface{ DexJarBuildPath() android.Path }); ok {
127 // Add the dex implementation jar for the module to be checked.
128 checkBootJars.Input(dep.DexJarBuildPath())
Paul Duffin9a89a2a2020-10-28 19:20:06 +0000129 } else {
130 ctx.Errorf("module %q is of type %q which is not supported as a boot jar", name, ctx.ModuleType(apexVariant))
131 }
132 } else if strict {
133 ctx.Errorf("boot jars package check failed as it could not find module %q for apex %q", name, moduleToApex[name])
134 }
135 }
136
137 checkBootJars.Text("&& touch").Output(timestamp)
Colin Crossf1a035e2020-11-16 17:32:30 -0800138 rule.Build("boot_jars_package_check", "check boot jar packages")
Paul Duffin9a89a2a2020-10-28 19:20:06 +0000139
140 // The check-boot-jars phony target depends on the timestamp created if the check succeeds.
141 ctx.Phony("check-boot-jars", timestamp)
142
143 // The droidcore phony target depends on the check-boot-jars phony target
144 ctx.Phony("droidcore", android.PathForPhony(ctx, "check-boot-jars"))
145}