platform_build_soong/java/boot_jars.go
Paul Duffin 9a89a2a0ea Move boot jars package check from make
Adds a singleton that traverses the module variants finding the ones
that are in the list (updatable and non-updatable) of boot jars and
add a ninja rule to ensure that they only contain packages from an
allowed list.

Replaces a hack that ignored any prebuilt boot jars supplied as dex
file with an equivalent one to ensure that they are still ignored.
A follow up change that switches to checking dex jars will allow the
hack to be removed.

The boot jars check can be strict or lax. If strict then all the boot
jars listed in the configuration must be found, otherwise it will only
check the ones it finds. It is strict by default unless
TARGET_BUILD_UNBUNDLED=true or ALLOW_MISSING_DEPENDENCIES=true.

Moves the script and data file from build/make.

Test: m check-boot-jars - for failing and passing cases
      SKIP_BOOT_JARS_CHECK=true - no check-boot-jars target created
	  ALLOW_MISSING_DEPENDENCIES=true - not strict
	  TARGET_BUILD_UNBUNDLED=true - not strict
      verified manually that apart from path differences the same
      files (same check sum) were checked in both old make checks and
      the new Soong ones
      EMMA_INSTRUMENT=true EMMA_INSTRUMENT_FRAMEWORK=true m check-boot-jars
Bug: 171479578
Change-Id: I9d81d6650ba64fc0d48d2dab4ba5a3ba8dd03dec
2020-10-29 17:20:06 +00:00

123 lines
4.7 KiB
Go

// 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"))
}