diff options
author | 2021-09-30 09:38:19 +0000 | |
---|---|---|
committer | 2021-10-29 11:55:20 +0000 | |
commit | 0a0a2fbea9025c23fa6305c9b481f72955a88ecf (patch) | |
tree | 7cae791d1d50846b6bba547947e6618f7b114058 | |
parent | bc909df73215735a98490a3da5bf375c7edb3d0c (diff) |
Add a build-time check for dexpreopting system server jars.
This change adds a Soong module that stores the paths to the compilation
artifacts of system server jars in a variable, which will then be
consumed by Make to check if the artifacts are installed. When the check
fails, it means that dexpreopting is not working for some system server
jars and needs to be fixed.
Bug: 201371822
Test: m nothing
Test: manual -
1. Add "service-permission" to DEXPREOPT_DISABLED_MODULES (https://cs.android.com/android/platform/superproject/+/master:build/make/core/product_config.mk?q=DEXPREOPT_DISABLED_MODULES)
2. m nothing
3. See the error:
Missing compilation artifacts. Dexpreopting is not working for some system server jars
Offending entries:
system/framework/oat/x86_64/apex@com.android.permission@javalib@service-permission.jar@classes.odex
system/framework/oat/x86_64/apex@com.android.permission@javalib@service-permission.jar@classes.vdex
Change-Id: I4816f19668f1dae180a34adafdbfa448c97aa0db
-rw-r--r-- | Android.bp | 4 | ||||
-rw-r--r-- | dexpreopt/dexpreopt.go | 28 | ||||
-rw-r--r-- | java/Android.bp | 1 | ||||
-rw-r--r-- | java/dexpreopt_check.go | 96 |
4 files changed, 113 insertions, 16 deletions
diff --git a/Android.bp b/Android.bp index b5ddaa4e4..0e8d86d3b 100644 --- a/Android.bp +++ b/Android.bp @@ -127,3 +127,7 @@ genrule { srcs: ["cc/config/global.go"], out: ["clang-prebuilts-version.txt"], } + +dexpreopt_systemserver_check { + name: "dexpreopt_systemserver_check", +} diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index 965b7552d..3145315e3 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -204,6 +204,17 @@ func GetSystemServerDexLocation(global *GlobalConfig, lib string) string { return fmt.Sprintf("/system/framework/%s.jar", lib) } +// Returns the location to the odex file for the dex file at `path`. +func ToOdexPath(path string, arch android.ArchType) string { + if strings.HasPrefix(path, "/apex/") { + return filepath.Join("/system/framework/oat", arch.String(), + strings.ReplaceAll(path[1:], "/", "@")+"@classes.odex") + } + + return filepath.Join(filepath.Dir(path), "oat", arch.String(), + pathtools.ReplaceExtension(filepath.Base(path), "odex")) +} + func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig, module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath, appImage bool, generateDM bool) { @@ -218,23 +229,8 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g base = "package.apk" } - toOdexPath := func(path string) string { - if global.ApexSystemServerJars.ContainsJar(module.Name) { - return filepath.Join( - "/system/framework/oat", - arch.String(), - strings.ReplaceAll(path[1:], "/", "@")+"@classes.odex") - } - - return filepath.Join( - filepath.Dir(path), - "oat", - arch.String(), - pathtools.ReplaceExtension(filepath.Base(path), "odex")) - } - odexPath := module.BuildPath.InSameDir(ctx, "oat", arch.String(), pathtools.ReplaceExtension(base, "odex")) - odexInstallPath := toOdexPath(module.DexLocation) + odexInstallPath := ToOdexPath(module.DexLocation, arch) if odexOnSystemOther(module, global) { odexInstallPath = filepath.Join(SystemOtherPartition, odexInstallPath) } diff --git a/java/Android.bp b/java/Android.bp index 9ffa12384..78d0cc1a9 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -40,6 +40,7 @@ bootstrap_go_package { "dex.go", "dexpreopt.go", "dexpreopt_bootjars.go", + "dexpreopt_check.go", "dexpreopt_config.go", "droiddoc.go", "droidstubs.go", diff --git a/java/dexpreopt_check.go b/java/dexpreopt_check.go new file mode 100644 index 000000000..565901d35 --- /dev/null +++ b/java/dexpreopt_check.go @@ -0,0 +1,96 @@ +// Copyright 2021 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 ( + "strings" + + "android/soong/android" + "android/soong/dexpreopt" + + "github.com/google/blueprint/pathtools" +) + +func init() { + RegisterDexpreoptCheckBuildComponents(android.InitRegistrationContext) +} + +func RegisterDexpreoptCheckBuildComponents(ctx android.RegistrationContext) { + ctx.RegisterSingletonModuleType("dexpreopt_systemserver_check", dexpreoptSystemserverCheckFactory) +} + +// A build-time check to verify if all compilation artifacts of system server jars are installed +// into the system image. When the check fails, it means that dexpreopting is not working for some +// system server jars and needs to be fixed. +// This singleton module generates a list of the paths to the artifacts based on +// PRODUCT_SYSTEM_SERVER_JARS and PRODUCT_APEX_SYSTEM_SERVER_JARS, and passes it to Make via a +// variable. Make will then do the actual check. +// Currently, it only checks artifacts of modules defined in Soong. Artifacts of modules defined in +// Makefile are generated by a script generated by dexpreopt_gen, and their existence is unknown to +// Make and Ninja. +type dexpreoptSystemserverCheck struct { + android.SingletonModuleBase + + // Mapping from the module name to the install paths to the compilation artifacts. + artifactsByModuleName map[string][]string + + // The install paths to the compilation artifacts. + artifacts []string +} + +func dexpreoptSystemserverCheckFactory() android.SingletonModule { + m := &dexpreoptSystemserverCheck{} + m.artifactsByModuleName = make(map[string][]string) + android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) + return m +} + +func getInstallPath(ctx android.ModuleContext, location string) android.InstallPath { + return android.PathForModuleInPartitionInstall( + ctx, "", strings.TrimPrefix(location, "/")).ToMakePath() +} + +func (m *dexpreoptSystemserverCheck) GenerateAndroidBuildActions(ctx android.ModuleContext) { + global := dexpreopt.GetGlobalConfig(ctx) + targets := ctx.Config().Targets[android.Android] + + // The check should be skipped on unbundled builds because system server jars are not preopted on + // unbundled builds since the artifacts are installed into the system image, not the APEXes. + if global.DisablePreopt || len(targets) == 0 || ctx.Config().UnbundledBuild() { + return + } + + systemServerJars := dexpreopt.AllSystemServerJars(ctx, global) + for _, jar := range systemServerJars.CopyOfJars() { + dexLocation := dexpreopt.GetSystemServerDexLocation(global, jar) + odexLocation := dexpreopt.ToOdexPath(dexLocation, targets[0].Arch.ArchType) + odexPath := getInstallPath(ctx, odexLocation) + vdexPath := getInstallPath(ctx, pathtools.ReplaceExtension(odexLocation, "vdex")) + m.artifactsByModuleName[jar] = []string{odexPath.String(), vdexPath.String()} + } +} + +func (m *dexpreoptSystemserverCheck) GenerateSingletonBuildActions(ctx android.SingletonContext) { + // Only keep modules defined in Soong. + ctx.VisitAllModules(func(module android.Module) { + if artifacts, ok := m.artifactsByModuleName[module.Name()]; ok { + m.artifacts = append(m.artifacts, artifacts...) + } + }) +} + +func (m *dexpreoptSystemserverCheck) MakeVars(ctx android.MakeVarsContext) { + ctx.Strict("DEXPREOPT_SYSTEMSERVER_ARTIFACTS", strings.Join(m.artifacts, " ")) +} |