summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/androidmk.go4
-rwxr-xr-xjava/app.go1
-rw-r--r--java/app_import.go1
-rw-r--r--java/boot_image.go53
-rw-r--r--java/dexpreopt.go47
-rw-r--r--java/dexpreopt_bootjars.go16
-rw-r--r--java/dexpreopt_test.go2
-rw-r--r--java/hiddenapi.go49
-rw-r--r--java/hiddenapi_singleton.go61
-rw-r--r--java/testing.go10
10 files changed, 200 insertions, 44 deletions
diff --git a/java/androidmk.go b/java/androidmk.go
index cc454b03d..21f3012a4 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -125,6 +125,10 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries {
entries.SetString("LOCAL_MODULE_STEM", library.Stem())
entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", library.linter.reports)
+
+ if library.dexpreopter.configPath != nil {
+ entries.SetPath("LOCAL_SOONG_DEXPREOPT_CONFIG", library.dexpreopter.configPath)
+ }
},
},
})
diff --git a/java/app.go b/java/app.go
index e6c9a2d98..ce89e9bb6 100755
--- a/java/app.go
+++ b/java/app.go
@@ -455,6 +455,7 @@ func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath
func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
a.dexpreopter.installPath = a.installPath(ctx)
+ a.dexpreopter.isApp = true
if a.dexProperties.Uncompress_dex == nil {
// If the value was not force-set by the user, use reasonable default based on the module.
a.dexProperties.Uncompress_dex = proptools.BoolPtr(a.shouldUncompressDex(ctx))
diff --git a/java/app_import.go b/java/app_import.go
index df940f1ff..6f21bfbbf 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -255,6 +255,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext
installDir = android.PathForModuleInstall(ctx, "app", a.BaseModuleName())
}
+ a.dexpreopter.isApp = true
a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk")
a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
diff --git a/java/boot_image.go b/java/boot_image.go
index 07ef0d841..0a525b752 100644
--- a/java/boot_image.go
+++ b/java/boot_image.go
@@ -15,9 +15,11 @@
package java
import (
+ "fmt"
"strings"
"android/soong/android"
+ "android/soong/dexpreopt"
"github.com/google/blueprint"
)
@@ -38,6 +40,7 @@ type bootImageProperties struct {
type BootImageModule struct {
android.ModuleBase
+ android.ApexModuleBase
properties bootImageProperties
}
@@ -45,7 +48,8 @@ type BootImageModule struct {
func bootImageFactory() android.Module {
m := &BootImageModule{}
m.AddProperties(&m.properties)
- android.InitAndroidArchModule(m, android.HostAndDeviceDefault, android.MultilibCommon)
+ android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon)
+ android.InitApexModule(m)
return m
}
@@ -53,6 +57,9 @@ var BootImageInfoProvider = blueprint.NewProvider(BootImageInfo{})
type BootImageInfo struct {
// The image config, internal to this module (and the dex_bootjars singleton).
+ //
+ // Will be nil if the BootImageInfo has not been provided for a specific module. That can occur
+ // when SkipDexpreoptBootJars(ctx) returns true.
imageConfig *bootImageConfig
}
@@ -60,12 +67,56 @@ func (i BootImageInfo) Modules() android.ConfiguredJarList {
return i.imageConfig.modules
}
+// Get a map from ArchType to the associated boot image's contents for Android.
+//
+// Extension boot images only return their own files, not the files of the boot images they extend.
+func (i BootImageInfo) AndroidBootImageFilesByArchType() map[android.ArchType]android.OutputPaths {
+ files := map[android.ArchType]android.OutputPaths{}
+ if i.imageConfig != nil {
+ for _, variant := range i.imageConfig.variants {
+ // We also generate boot images for host (for testing), but we don't need those in the apex.
+ // TODO(b/177892522) - consider changing this to check Os.OsClass = android.Device
+ if variant.target.Os == android.Android {
+ files[variant.target.Arch.ArchType] = variant.imagesDeps
+ }
+ }
+ }
+ return files
+}
+
+func (b *BootImageModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+ tag := ctx.OtherModuleDependencyTag(dep)
+ if tag == dexpreopt.Dex2oatDepTag {
+ // The dex2oat tool is only needed for building and is not required in the apex.
+ return false
+ }
+ panic(fmt.Errorf("boot_image module %q should not have a dependency on %q via tag %s", b, dep, android.PrettyPrintTag(tag)))
+}
+
+func (b *BootImageModule) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
+ return nil
+}
+
+func (b *BootImageModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+ if SkipDexpreoptBootJars(ctx) {
+ return
+ }
+
+ // Add a dependency onto the dex2oat tool which is needed for creating the boot image. The
+ // path is retrieved from the dependency by GetGlobalSoongConfig(ctx).
+ dexpreopt.RegisterToolDeps(ctx)
+}
+
func (b *BootImageModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// Nothing to do if skipping the dexpreopt of boot image jars.
if SkipDexpreoptBootJars(ctx) {
return
}
+ // Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
+ // GenerateSingletonBuildActions method as it cannot create it for itself.
+ dexpreopt.GetGlobalSoongConfig(ctx)
+
// Get a map of the image configs that are supported.
imageConfigs := genBootImageConfigs(ctx)
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index b5830c744..ac00592a7 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -30,6 +30,7 @@ type dexpreopter struct {
installPath android.InstallPath
uncompressedDex bool
isSDKLibrary bool
+ isApp bool
isTest bool
isPresignedPrebuilt bool
@@ -38,6 +39,11 @@ type dexpreopter struct {
classLoaderContexts dexpreopt.ClassLoaderContextMap
builtInstalled string
+
+ // A path to a dexpreopt.config file generated by Soong for libraries that may be used as a
+ // <uses-library> by Make modules. The path is passed to Make via LOCAL_SOONG_DEXPREOPT_CONFIG
+ // variable. If the path is nil, no config is generated (which is the case for apps and tests).
+ configPath android.WritablePath
}
type DexpreoptProperties struct {
@@ -117,7 +123,40 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo
// the dexpreopter struct hasn't been fully initialized before we're called,
// e.g. in aar.go. This keeps the behaviour that dexpreopting is effectively
// disabled, even if installable is true.
- if d.dexpreoptDisabled(ctx) || d.installPath.Base() == "." {
+ if d.installPath.Base() == "." {
+ return
+ }
+
+ dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
+
+ buildPath := android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath
+
+ providesUsesLib := ctx.ModuleName()
+ if ulib, ok := ctx.Module().(ProvidesUsesLib); ok {
+ name := ulib.ProvidesUsesLib()
+ if name != nil {
+ providesUsesLib = *name
+ }
+ }
+
+ if !d.isApp && !d.isTest {
+ // Slim dexpreopt config is serialized to dexpreopt.config files and used by
+ // dex_preopt_config_merger.py to get information about <uses-library> dependencies.
+ // Note that it might be needed even if dexpreopt is disabled for this module.
+ slimDexpreoptConfig := &dexpreopt.ModuleConfig{
+ Name: ctx.ModuleName(),
+ DexLocation: dexLocation,
+ BuildPath: buildPath,
+ EnforceUsesLibraries: d.enforceUsesLibs,
+ ProvidesUsesLibrary: providesUsesLib,
+ ClassLoaderContexts: d.classLoaderContexts,
+ // The rest of the fields are not needed.
+ }
+ d.configPath = android.PathForModuleOut(ctx, "dexpreopt", "dexpreopt.config")
+ dexpreopt.WriteSlimModuleConfigForMake(ctx, slimDexpreoptConfig, d.configPath)
+ }
+
+ if d.dexpreoptDisabled(ctx) {
return
}
@@ -157,8 +196,6 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo
// The image locations for all Android variants are identical.
imageLocations := bootImage.getAnyAndroidVariant().imageLocations()
- dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
-
var profileClassListing android.OptionalPath
var profileBootListing android.OptionalPath
profileIsTextListing := false
@@ -177,10 +214,11 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo
}
}
+ // Full dexpreopt config, used to create dexpreopt build rules.
dexpreoptConfig := &dexpreopt.ModuleConfig{
Name: ctx.ModuleName(),
DexLocation: dexLocation,
- BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath,
+ BuildPath: buildPath,
DexPath: dexJarFile,
ManifestPath: d.manifestFile,
UncompressedDex: d.uncompressedDex,
@@ -192,6 +230,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo
ProfileBootListing: profileBootListing,
EnforceUsesLibraries: d.enforceUsesLibs,
+ ProvidesUsesLibrary: providesUsesLib,
ClassLoaderContexts: d.classLoaderContexts,
Archs: archs,
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 36d0d3017..2a7eb42dc 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -392,22 +392,6 @@ type dexpreoptBootJars struct {
dexpreoptConfigForMake android.WritablePath
}
-// Accessor function for the apex package. Returns nil if dexpreopt is disabled.
-func DexpreoptedArtApexJars(ctx android.BuilderContext) map[android.ArchType]android.OutputPaths {
- if SkipDexpreoptBootJars(ctx) {
- return nil
- }
- // Include dexpreopt files for the primary boot image.
- files := map[android.ArchType]android.OutputPaths{}
- for _, variant := range artBootImageConfig(ctx).variants {
- // We also generate boot images for host (for testing), but we don't need those in the apex.
- if variant.target.Os == android.Android {
- files[variant.target.Arch.ArchType] = variant.imagesDeps
- }
- }
- return files
-}
-
// Provide paths to boot images for use by modules that depend upon them.
//
// The build rules are created in GenerateSingletonBuildActions().
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index 5550a4c17..a9e0773b7 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -148,7 +148,7 @@ func TestDexpreoptEnabled(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
ctx, _ := testJava(t, test.bp)
- dexpreopt := ctx.ModuleForTests("foo", "android_common").MaybeDescription("dexpreopt")
+ dexpreopt := ctx.ModuleForTests("foo", "android_common").MaybeRule("dexpreopt")
enabled := dexpreopt.Rule != nil
if enabled != test.enabled {
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index 71f1e576d..2cd025e43 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -28,10 +28,40 @@ var hiddenAPIGenerateCSVRule = pctx.AndroidStaticRule("hiddenAPIGenerateCSV", bl
}, "outFlag", "stubAPIFlags")
type hiddenAPI struct {
- bootDexJarPath android.Path
- flagsCSVPath android.Path
- indexCSVPath android.Path
+ // The path to the dex jar that is in the boot class path. If this is nil then the associated
+ // module is not a boot jar, but could be one of the <x>-hiddenapi modules that provide additional
+ // annotations for the <x> boot dex jar but which do not actually provide a boot dex jar
+ // themselves.
+ bootDexJarPath android.Path
+
+ // The path to the CSV file that contains mappings from Java signature to various flags derived
+ // from annotations in the source, e.g. whether it is public or the sdk version above which it
+ // can no longer be used.
+ //
+ // It is created by the Class2NonSdkList tool which processes the .class files in the class
+ // implementation jar looking for UnsupportedAppUsage and CovariantReturnType annotations. The
+ // tool also consumes the hiddenAPISingletonPathsStruct.stubFlags file in order to perform
+ // consistency checks on the information in the annotations and to filter out bridge methods
+ // that are already part of the public API.
+ flagsCSVPath android.Path
+
+ // The path to the CSV file that contains mappings from Java signature to the value of properties
+ // specified on UnsupportedAppUsage annotations in the source.
+ //
+ // Like the flagsCSVPath file this is also created by the Class2NonSdkList in the same way.
+ // Although the two files could potentially be created in a single invocation of the
+ // Class2NonSdkList at the moment they are created using their own invocation, with the behavior
+ // being determined by the property that is used.
metadataCSVPath android.Path
+
+ // The path to the CSV file that contains mappings from Java signature to source location
+ // information.
+ //
+ // It is created by the merge_csv tool which processes the class implementation jar, extracting
+ // all the files ending in .uau (which are CSV files) and merges them together. The .uau files are
+ // created by the unsupported app usage annotation processor during compilation of the class
+ // implementation jar.
+ indexCSVPath android.Path
}
func (h *hiddenAPI) flagsCSV() android.Path {
@@ -78,11 +108,9 @@ func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, name string, primary bo
// not on the list then that will cause failures in the CtsHiddenApiBlacklist...
// tests.
if inList(bootJarName, ctx.Config().BootJars()) {
- // Derive the greylist from classes jar.
- flagsCSV := android.PathForModuleOut(ctx, "hiddenapi", "flags.csv")
- metadataCSV := android.PathForModuleOut(ctx, "hiddenapi", "metadata.csv")
- indexCSV := android.PathForModuleOut(ctx, "hiddenapi", "index.csv")
- h.hiddenAPIGenerateCSV(ctx, flagsCSV, metadataCSV, indexCSV, implementationJar)
+ // Create ninja rules to generate various CSV files needed by hiddenapi and store the paths
+ // in the hiddenAPI structure.
+ h.hiddenAPIGenerateCSV(ctx, implementationJar)
// If this module is actually on the boot jars list and not providing
// hiddenapi information for a module on the boot jars list then encode
@@ -106,9 +134,10 @@ func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, name string, primary bo
return dexJar
}
-func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, flagsCSV, metadataCSV, indexCSV android.WritablePath, classesJar android.Path) {
+func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, classesJar android.Path) {
stubFlagsCSV := hiddenAPISingletonPaths(ctx).stubFlags
+ flagsCSV := android.PathForModuleOut(ctx, "hiddenapi", "flags.csv")
ctx.Build(pctx, android.BuildParams{
Rule: hiddenAPIGenerateCSVRule,
Description: "hiddenapi flags",
@@ -122,6 +151,7 @@ func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, flagsCSV, me
})
h.flagsCSVPath = flagsCSV
+ metadataCSV := android.PathForModuleOut(ctx, "hiddenapi", "metadata.csv")
ctx.Build(pctx, android.BuildParams{
Rule: hiddenAPIGenerateCSVRule,
Description: "hiddenapi metadata",
@@ -135,6 +165,7 @@ func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, flagsCSV, me
})
h.metadataCSVPath = metadataCSV
+ indexCSV := android.PathForModuleOut(ctx, "hiddenapi", "index.csv")
rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
BuiltTool("merge_csv").
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 4bd255cbf..ccb874506 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -28,9 +28,64 @@ func init() {
}
type hiddenAPISingletonPathsStruct struct {
- flags android.OutputPath
- index android.OutputPath
- metadata android.OutputPath
+ // The path to the CSV file that contains the flags that will be encoded into the dex boot jars.
+ //
+ // It is created by the generate_hiddenapi_lists.py tool that is passed the stubFlags along with
+ // a number of additional files that are used to augment the information in the stubFlags with
+ // manually curated data.
+ flags android.OutputPath
+
+ // The path to the CSV index file that contains mappings from Java signature to source location
+ // information for all Java elements annotated with the UnsupportedAppUsage annotation in the
+ // source of all the boot jars.
+ //
+ // It is created by the merge_csv tool which merges all the hiddenAPI.indexCSVPath files that have
+ // been created by the rest of the build. That includes the index files generated for
+ // <x>-hiddenapi modules.
+ index android.OutputPath
+
+ // The path to the CSV metadata file that contains mappings from Java signature to the value of
+ // properties specified on UnsupportedAppUsage annotations in the source of all the boot jars.
+ //
+ // It is created by the merge_csv tool which merges all the hiddenAPI.metadataCSVPath files that
+ // have been created by the rest of the build. That includes the metadata files generated for
+ // <x>-hiddenapi modules.
+ metadata android.OutputPath
+
+ // The path to the CSV metadata file that contains mappings from Java signature to flags obtained
+ // from the public, system and test API stubs.
+ //
+ // This is created by the hiddenapi tool which is given dex files for the public, system and test
+ // API stubs (including product specific stubs) along with dex boot jars, so does not include
+ // <x>-hiddenapi modules. For each API surface (i.e. public, system, test) it records which
+ // members in the dex boot jars match a member in the dex stub jars for that API surface and then
+ // outputs a file containing the signatures of all members in the dex boot jars along with the
+ // flags that indicate which API surface it belongs, if any.
+ //
+ // e.g. a dex member that matches a member in the public dex stubs would have flags
+ // "public-api,system-api,test-api" set (as system and test are both supersets of public). A dex
+ // member that didn't match a member in any of the dex stubs is still output it just has an empty
+ // set of flags.
+ //
+ // The notion of matching is quite complex, it is not restricted to just exact matching but also
+ // follows the Java inheritance rules. e.g. if a method is public then all overriding/implementing
+ // methods are also public. If an interface method is public and a class inherits an
+ // implementation of that method from a super class then that super class method is also public.
+ // That ensures that any method that can be called directly by an App through a public method is
+ // visible to that App.
+ //
+ // Propagating the visibility of members across the inheritance hierarchy at build time will cause
+ // problems when modularizing and unbundling as it that propagation can cross module boundaries.
+ // e.g. Say that a private framework class implements a public interface and inherits an
+ // implementation of one of its methods from a core platform ART class. In that case the ART
+ // implementation method needs to be marked as public which requires the build to have access to
+ // the framework implementation classes at build time. The work to rectify this is being tracked
+ // at http://b/178693149.
+ //
+ // This file (or at least those items marked as being in the public-api) is used by hiddenapi when
+ // creating the metadata and flags for the individual modules in order to perform consistency
+ // checks and filter out bridge methods that are part of the public API. The latter relies on the
+ // propagation of visibility across the inheritance hierarchy.
stubFlags android.OutputPath
}
diff --git a/java/testing.go b/java/testing.go
index 31ff47ff4..5fcf84c6b 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -219,16 +219,6 @@ func GatherRequiredDepsForTest() string {
dex_bootjars {
name: "dex_bootjars",
}
-
- boot_image {
- name: "art-boot-image",
- image_name: "art",
- }
-
- boot_image {
- name: "framework-boot-image",
- image_name: "boot",
- }
`
return bp