Merge "Enable coverage for vendor-related libraries"
diff --git a/Android.bp b/Android.bp
index b407314..36a428a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -250,6 +250,7 @@
"java/builder.go",
"java/dex.go",
"java/dexpreopt.go",
+ "java/dexpreopt_bootjars.go",
"java/droiddoc.go",
"java/gen.go",
"java/genrule.go",
@@ -267,6 +268,7 @@
"java/sdk_library.go",
"java/support_libraries.go",
"java/system_modules.go",
+ "java/testing.go",
],
testSrcs: [
"java/app_test.go",
diff --git a/android/config.go b/android/config.go
index 63788b7..9217aab 100644
--- a/android/config.go
+++ b/android/config.go
@@ -779,7 +779,11 @@
return c.productVariables.PreoptBootJars
}
-func (c *config) DisableDexPreopt(name string) bool {
+func (c *config) DisableDexPreopt() bool {
+ return Bool(c.productVariables.DisableDexPreopt)
+}
+
+func (c *config) DisableDexPreoptForModule(name string) bool {
return Bool(c.productVariables.DisableDexPreopt) || InList(name, c.productVariables.DisableDexPreoptModules)
}
diff --git a/android/paths.go b/android/paths.go
index 31500ab..3366db1 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -677,6 +677,15 @@
return OutputPath{basePath{path, ctx.Config(), ""}}
}
+// PathsForOutput returns Paths rooted from buildDir
+func PathsForOutput(ctx PathContext, paths []string) WritablePaths {
+ ret := make(WritablePaths, len(paths))
+ for i, path := range paths {
+ ret[i] = PathForOutput(ctx, path)
+ }
+ return ret
+}
+
func (p OutputPath) writablePath() {}
func (p OutputPath) String() string {
@@ -707,6 +716,18 @@
return ret
}
+// InSameDir creates a new OutputPath from the directory of the current OutputPath joined with the elements in paths.
+func (p OutputPath) InSameDir(ctx PathContext, paths ...string) OutputPath {
+ path, err := validatePath(paths...)
+ if err != nil {
+ reportPathError(ctx, err)
+ }
+
+ ret := PathForOutput(ctx, filepath.Dir(p.path), path)
+ ret.rel = p.rel
+ return ret
+}
+
// PathForIntermediates returns an OutputPath representing the top-level
// intermediates directory.
func PathForIntermediates(ctx PathContext, paths ...string) OutputPath {
@@ -1019,6 +1040,14 @@
return p.path
}
+type testWritablePath struct {
+ testPath
+}
+
+func (p testPath) writablePath() {}
+
+// PathForTesting returns a Path constructed from joining the elements of paths with '/'. It should only be used from
+// within tests.
func PathForTesting(paths ...string) Path {
p, err := validateSafePath(paths...)
if err != nil {
@@ -1027,7 +1056,8 @@
return testPath{basePath{path: p, rel: p}}
}
-func PathsForTesting(strs []string) Paths {
+// PathsForTesting returns a Path constructed from each element in strs. It should only be used from within tests.
+func PathsForTesting(strs ...string) Paths {
p := make(Paths, len(strs))
for i, s := range strs {
p[i] = PathForTesting(s)
@@ -1036,6 +1066,45 @@
return p
}
+// WritablePathForTesting returns a Path constructed from joining the elements of paths with '/'. It should only be
+// used from within tests.
+func WritablePathForTesting(paths ...string) WritablePath {
+ p, err := validateSafePath(paths...)
+ if err != nil {
+ panic(err)
+ }
+ return testWritablePath{testPath{basePath{path: p, rel: p}}}
+}
+
+// WritablePathsForTesting returns a Path constructed from each element in strs. It should only be used from within
+// tests.
+func WritablePathsForTesting(strs ...string) WritablePaths {
+ p := make(WritablePaths, len(strs))
+ for i, s := range strs {
+ p[i] = WritablePathForTesting(s)
+ }
+
+ return p
+}
+
+type testPathContext struct {
+ config Config
+ fs pathtools.FileSystem
+}
+
+func (x *testPathContext) Fs() pathtools.FileSystem { return x.fs }
+func (x *testPathContext) Config() Config { return x.config }
+func (x *testPathContext) AddNinjaFileDeps(...string) {}
+
+// PathContextForTesting returns a PathContext that can be used in tests, for example to create an OutputPath with
+// PathForOutput.
+func PathContextForTesting(config Config, fs map[string][]byte) PathContext {
+ return &testPathContext{
+ config: config,
+ fs: pathtools.MockFs(fs),
+ }
+}
+
// Rel performs the same function as filepath.Rel, but reports errors to a PathContext, and reports an error if
// targetPath is not inside basePath.
func Rel(ctx PathContext, basePath string, targetPath string) string {
diff --git a/android/paths_test.go b/android/paths_test.go
index 1972591..3b6d2ec 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -703,3 +703,15 @@
// Output:
// out/system/framework/boot.art out/system/framework/boot.oat
}
+
+func ExampleOutputPath_FileInSameDir() {
+ ctx := &configErrorWrapper{
+ config: TestConfig("out", nil),
+ }
+ p := PathForOutput(ctx, "system/framework/boot.art")
+ p2 := p.InSameDir(ctx, "oat", "arm", "boot.vdex")
+ fmt.Println(p, p2)
+
+ // Output:
+ // out/system/framework/boot.art out/system/framework/oat/arm/boot.vdex
+}
diff --git a/cc/builder.go b/cc/builder.go
index 6e24d56..97ae806 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -197,8 +197,8 @@
sAbiDiff = pctx.AndroidRuleFunc("sAbiDiff",
func(ctx android.PackageRuleContext) blueprint.RuleParams {
// TODO(b/78139997): Add -check-all-apis back
- commandStr := "($sAbiDiffer $allowFlags -lib $libName -arch $arch -o ${out} -new $in -old $referenceDump)"
- commandStr += "|| (echo ' ---- Please update abi references by running $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l ${libName} ----'"
+ commandStr := "($sAbiDiffer ${allowFlags} -lib ${libName} -arch ${arch} -o ${out} -new ${in} -old ${referenceDump})"
+ commandStr += "|| (echo 'error: Please update ABI references with: $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py ${createReferenceDumpFlags} -l ${libName}'"
commandStr += " && (mkdir -p $$DIST_DIR/abidiffs && cp ${out} $$DIST_DIR/abidiffs/)"
commandStr += " && exit 1)"
return blueprint.RuleParams{
@@ -206,7 +206,7 @@
CommandDeps: []string{"$sAbiDiffer"},
}
},
- "allowFlags", "referenceDump", "libName", "arch")
+ "allowFlags", "referenceDump", "libName", "arch", "createReferenceDumpFlags")
unzipRefSAbiDump = pctx.AndroidStaticRule("unzipRefSAbiDump",
blueprint.RuleParams{
@@ -711,16 +711,19 @@
}
func SourceAbiDiff(ctx android.ModuleContext, inputDump android.Path, referenceDump android.Path,
- baseName, exportedHeaderFlags string, isVndkExt bool) android.OptionalPath {
+ baseName, exportedHeaderFlags string, isLlndk, isVndkExt bool) android.OptionalPath {
outputFile := android.PathForModuleOut(ctx, baseName+".abidiff")
libName := strings.TrimSuffix(baseName, filepath.Ext(baseName))
+ createReferenceDumpFlags := ""
+
localAbiCheckAllowFlags := append([]string(nil), abiCheckAllowFlags...)
if exportedHeaderFlags == "" {
localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-advice-only")
}
- if inList(libName, llndkLibraries) {
+ if isLlndk {
localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-consider-opaque-types-different")
+ createReferenceDumpFlags = "--llndk"
}
if isVndkExt {
localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-allow-extensions")
@@ -733,10 +736,11 @@
Input: inputDump,
Implicit: referenceDump,
Args: map[string]string{
- "referenceDump": referenceDump.String(),
- "libName": libName,
- "arch": ctx.Arch().ArchType.Name,
- "allowFlags": strings.Join(localAbiCheckAllowFlags, " "),
+ "referenceDump": referenceDump.String(),
+ "libName": libName,
+ "arch": ctx.Arch().ArchType.Name,
+ "allowFlags": strings.Join(localAbiCheckAllowFlags, " "),
+ "createReferenceDumpFlags": createReferenceDumpFlags,
},
})
return android.OptionalPathForPath(outputFile)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 22ac0d9..a0914c8 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -1039,7 +1039,7 @@
func TestSplitListForSize(t *testing.T) {
for _, testCase := range splitListForSizeTestCases {
- out, _ := splitListForSize(android.PathsForTesting(testCase.in), testCase.size)
+ out, _ := splitListForSize(android.PathsForTesting(testCase.in...), testCase.size)
var outStrings [][]string
diff --git a/cc/library.go b/cc/library.go
index a48b45d..c23f26b 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -794,7 +794,7 @@
refAbiDumpFile := getRefAbiDumpFile(ctx, vndkVersion, fileName)
if refAbiDumpFile != nil {
library.sAbiDiff = SourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
- refAbiDumpFile, fileName, exportedHeaderFlags, ctx.isVndkExt())
+ refAbiDumpFile, fileName, exportedHeaderFlags, ctx.isLlndk(), ctx.isVndkExt())
}
}
}
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
index c21da44..68fe259 100644
--- a/cmd/merge_zips/merge_zips.go
+++ b/cmd/merge_zips/merge_zips.go
@@ -66,7 +66,6 @@
stripDirEntries = flag.Bool("D", false, "strip directory entries from the output zip file")
manifest = flag.String("m", "", "manifest file to insert in jar")
pyMain = flag.String("pm", "", "__main__.py file to insert in par")
- entrypoint = flag.String("e", "", "par entrypoint file to insert in par")
prefix = flag.String("prefix", "", "A file to prefix to the zip file")
ignoreDuplicates = flag.Bool("ignore-duplicates", false, "take each entry from the first zip it exists in and don't warn")
)
@@ -79,7 +78,7 @@
func main() {
flag.Usage = func() {
- fmt.Fprintln(os.Stderr, "usage: merge_zips [-jpsD] [-m manifest] [--prefix script] [-e entrypoint] [-pm __main__.py] output [inputs...]")
+ fmt.Fprintln(os.Stderr, "usage: merge_zips [-jpsD] [-m manifest] [--prefix script] [-pm __main__.py] output [inputs...]")
flag.PrintDefaults()
}
@@ -139,16 +138,12 @@
log.Fatal(errors.New("must specify -j when specifying a manifest via -m"))
}
- if *entrypoint != "" && !*emulatePar {
- log.Fatal(errors.New("must specify -p when specifying a entrypoint via -e"))
- }
-
if *pyMain != "" && !*emulatePar {
log.Fatal(errors.New("must specify -p when specifying a Python __main__.py via -pm"))
}
// do merge
- err = mergeZips(readers, writer, *manifest, *entrypoint, *pyMain, *sortEntries, *emulateJar, *emulatePar,
+ err = mergeZips(readers, writer, *manifest, *pyMain, *sortEntries, *emulateJar, *emulatePar,
*stripDirEntries, *ignoreDuplicates, []string(stripFiles), []string(stripDirs), map[string]bool(zipsToNotStrip))
if err != nil {
log.Fatal(err)
@@ -249,7 +244,7 @@
source zipSource
}
-func mergeZips(readers []namedZipReader, writer *zip.Writer, manifest, entrypoint, pyMain string,
+func mergeZips(readers []namedZipReader, writer *zip.Writer, manifest, pyMain string,
sortEntries, emulateJar, emulatePar, stripDirEntries, ignoreDuplicates bool,
stripFiles, stripDirs []string, zipsToNotStrip map[string]bool) error {
@@ -289,22 +284,6 @@
addMapping(jar.ManifestFile, fileSource)
}
- if entrypoint != "" {
- buf, err := ioutil.ReadFile(entrypoint)
- if err != nil {
- return err
- }
- fh := &zip.FileHeader{
- Name: "entry_point.txt",
- Method: zip.Store,
- UncompressedSize64: uint64(len(buf)),
- }
- fh.SetMode(0700)
- fh.SetModTime(jar.DefaultTime)
- fileSource := bufferEntry{fh, buf}
- addMapping("entry_point.txt", fileSource)
- }
-
if pyMain != "" {
buf, err := ioutil.ReadFile(pyMain)
if err != nil {
diff --git a/cmd/merge_zips/merge_zips_test.go b/cmd/merge_zips/merge_zips_test.go
index 19fa5ed..dbde270 100644
--- a/cmd/merge_zips/merge_zips_test.go
+++ b/cmd/merge_zips/merge_zips_test.go
@@ -221,7 +221,7 @@
out := &bytes.Buffer{}
writer := zip.NewWriter(out)
- err := mergeZips(readers, writer, "", "", "",
+ err := mergeZips(readers, writer, "", "",
test.sort, test.jar, false, test.stripDirEntries, test.ignoreDuplicates,
test.stripFiles, test.stripDirs, test.zipsToNotStrip)
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index c7f0638..0eb162d 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -34,11 +34,12 @@
DisableGenerateProfile bool // don't generate profiles
- PreoptBootClassPathDexFiles []string // file paths of boot class path files
- PreoptBootClassPathDexLocations []string // virtual locations of boot class path files
+ BootJars []string // modules for jars that form the boot class path
- BootJars []string // modules for jars that form the boot class path
- PreoptBootJars []string // modules for jars that form the boot image
+ TargetCoreJars []string // modules for jars that are in the runtime apex
+ ProductUpdatableBootModules []string
+ ProductUpdatableBootLocations []string
+
SystemServerJars []string // jars that form the system server
SystemServerApps []string // apps that are loaded into system server
SpeedApps []string // apps that should be speed optimized
@@ -64,15 +65,22 @@
DefaultAppImages bool // build app images (TODO: .art files?) by default
- Dex2oatXmx string // max heap size
- Dex2oatXms string // initial heap size
+ Dex2oatXmx string // max heap size for dex2oat
+ Dex2oatXms string // initial heap size for dex2oat
EmptyDirectory string // path to an empty directory
- DefaultDexPreoptImage map[android.ArchType]string // default boot image location for each architecture
CpuVariant map[android.ArchType]string // cpu variant for each architecture
InstructionSetFeatures map[android.ArchType]string // instruction set for each architecture
+ // Only used for boot image
+ DirtyImageObjects string // path to a dirty-image-objects file
+ PreloadedClasses string // path to a preloaded-classes file
+ BootImageProfiles []string // path to a boot-image-profile.txt file
+ BootFlags string // extra flags to pass to dex2oat for the boot image
+ Dex2oatImageXmx string // max heap size for dex2oat for the boot image
+ Dex2oatImageXms string // initial heap size for dex2oat for the boot image
+
Tools Tools // paths to tools possibly used by the generated commands
}
@@ -109,6 +117,9 @@
Archs []android.ArchType
DexPreoptImages []string
+ PreoptBootClassPathDexFiles []string // file paths of boot class path files
+ PreoptBootClassPathDexLocations []string // virtual locations of boot class path files
+
PreoptExtractedApk bool // Overrides OnlyPreoptModules
NoCreateAppImage bool
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 68bd3ea..eacb86a 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -199,9 +199,6 @@
pathtools.ReplaceExtension(filepath.Base(path), "odex"))
}
- bcp := strings.Join(global.PreoptBootClassPathDexFiles, ":")
- bcp_locations := strings.Join(global.PreoptBootClassPathDexLocations, ":")
-
odexPath := toOdexPath(filepath.Join(filepath.Dir(module.BuildPath), base))
odexInstallPath := toOdexPath(module.DexLocation)
if odexOnSystemOther(module, global) {
@@ -320,9 +317,8 @@
FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath).
Flag("--runtime-arg").FlagWithArg("-Xms", global.Dex2oatXms).
Flag("--runtime-arg").FlagWithArg("-Xmx", global.Dex2oatXmx).
- Flag("--runtime-arg").FlagWithArg("-Xbootclasspath:", bcp).
- Implicits(global.PreoptBootClassPathDexFiles).
- Flag("--runtime-arg").FlagWithArg("-Xbootclasspath-locations:", bcp_locations).
+ Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", module.PreoptBootClassPathDexFiles, ":").
+ Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", module.PreoptBootClassPathDexLocations, ":").
Flag("${class_loader_context_arg}").
Flag("${stored_class_loader_context_arg}").
FlagWithArg("--boot-image=", bootImageLocation).Implicit(bootImage).
diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
index 1467a02..cc3c1f1 100644
--- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
+++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
@@ -133,10 +133,10 @@
depFile := &bytes.Buffer{}
fmt.Fprint(depFile, `: \`+"\n")
- for _, tool := range dexpreoptRule.Tools() {
+ for _, tool := range rule.Tools() {
fmt.Fprintf(depFile, ` %s \`+"\n", tool)
}
- for _, input := range dexpreoptRule.Inputs() {
+ for _, input := range rule.Inputs() {
// Assume the rule that ran the script already has a dependency on the input file passed on the
// command line.
if input != "$1" {
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 40c694f..a2c6f77 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -29,6 +29,9 @@
PatternsOnSystemOther: nil,
DisableGenerateProfile: false,
BootJars: nil,
+ TargetCoreJars: nil,
+ ProductUpdatableBootModules: nil,
+ ProductUpdatableBootLocations: nil,
SystemServerJars: nil,
SystemServerApps: nil,
SpeedApps: nil,
@@ -49,9 +52,14 @@
Dex2oatXmx: "",
Dex2oatXms: "",
EmptyDirectory: "",
- DefaultDexPreoptImage: nil,
CpuVariant: nil,
InstructionSetFeatures: nil,
+ DirtyImageObjects: "",
+ PreloadedClasses: "",
+ BootImageProfiles: nil,
+ BootFlags: "",
+ Dex2oatImageXmx: "",
+ Dex2oatImageXms: "",
Tools: Tools{
Profman: "profman",
Dex2oat: "dex2oat",
@@ -64,28 +72,30 @@
}
var testModuleConfig = ModuleConfig{
- Name: "",
- DexLocation: "",
- BuildPath: "",
- DexPath: "",
- UncompressedDex: false,
- HasApkLibraries: false,
- PreoptFlags: nil,
- ProfileClassListing: "",
- ProfileIsTextListing: false,
- EnforceUsesLibraries: false,
- OptionalUsesLibraries: nil,
- UsesLibraries: nil,
- LibraryPaths: nil,
- Archs: []android.ArchType{android.Arm},
- DexPreoptImages: []string{"system/framework/arm/boot.art"},
- PreoptExtractedApk: false,
- NoCreateAppImage: false,
- ForceCreateAppImage: false,
- PresignedPrebuilt: false,
- NoStripping: false,
- StripInputPath: "",
- StripOutputPath: "",
+ Name: "",
+ DexLocation: "",
+ BuildPath: "",
+ DexPath: "",
+ UncompressedDex: false,
+ HasApkLibraries: false,
+ PreoptFlags: nil,
+ ProfileClassListing: "",
+ ProfileIsTextListing: false,
+ EnforceUsesLibraries: false,
+ OptionalUsesLibraries: nil,
+ UsesLibraries: nil,
+ LibraryPaths: nil,
+ Archs: []android.ArchType{android.Arm},
+ DexPreoptImages: []string{"system/framework/arm/boot.art"},
+ PreoptBootClassPathDexFiles: nil,
+ PreoptBootClassPathDexLocations: nil,
+ PreoptExtractedApk: false,
+ NoCreateAppImage: false,
+ ForceCreateAppImage: false,
+ PresignedPrebuilt: false,
+ NoStripping: false,
+ StripInputPath: "",
+ StripOutputPath: "",
}
func TestDexPreopt(t *testing.T) {
diff --git a/java/config/config.go b/java/config/config.go
index 75be9e2..2602e6b 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -33,7 +33,12 @@
DefaultLambdaStubsLibrary = "core-lambda-stubs"
SdkLambdaStubsPath = "prebuilts/sdk/tools/core-lambda-stubs.jar"
- // A list of the jars that provide information about usages of the hidden API.
+ // A list of the non-boot jars that provide hidden APIs, i.e. libraries.
+ HiddenAPIProvidingNonBootJars = []string{
+ "android.test.base",
+ }
+
+ // A list of the non-boot jars that provide information about usages of the hidden API.
HiddenAPIExtraAppUsageJars = []string{
// The core-oj-hiddenapi provides information for the core-oj jar.
"core-oj-hiddenapi",
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 127deab..0a56529 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -56,7 +56,11 @@
}
func (d *dexpreopter) dexpreoptDisabled(ctx android.ModuleContext) bool {
- if ctx.Config().DisableDexPreopt(ctx.ModuleName()) {
+ if ctx.Config().DisableDexPreopt() {
+ return true
+ }
+
+ if ctx.Config().DisableDexPreoptForModule(ctx.ModuleName()) {
return true
}
@@ -83,8 +87,8 @@
var dexpreoptGlobalConfigKey = android.NewOnceKey("DexpreoptGlobalConfig")
-func getGlobalConfig(ctx android.ModuleContext) dexpreopt.GlobalConfig {
- globalConfig := ctx.Config().Once(dexpreoptGlobalConfigKey, func() interface{} {
+func dexpreoptGlobalConfig(ctx android.PathContext) dexpreopt.GlobalConfig {
+ return ctx.Config().Once(dexpreoptGlobalConfigKey, func() interface{} {
if f := ctx.Config().DexpreoptGlobalConfig(); f != "" {
ctx.AddNinjaFileDeps(f)
globalConfig, err := dexpreopt.LoadGlobalConfig(f)
@@ -95,11 +99,10 @@
}
return dexpreopt.GlobalConfig{}
}).(dexpreopt.GlobalConfig)
- return globalConfig
}
func odexOnSystemOther(ctx android.ModuleContext, installPath android.OutputPath) bool {
- return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), getGlobalConfig(ctx))
+ return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), dexpreoptGlobalConfig(ctx))
}
func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.ModuleOutPath) android.ModuleOutPath {
@@ -107,7 +110,7 @@
return dexJarFile
}
- globalConfig := getGlobalConfig(ctx)
+ info := dexpreoptBootJarsInfo(ctx)
var archs []android.ArchType
for _, a := range ctx.MultiTargets() {
@@ -118,7 +121,7 @@
for _, target := range ctx.Config().Targets[android.Android] {
archs = append(archs, target.Arch.ArchType)
}
- if inList(ctx.ModuleName(), globalConfig.SystemServerJars) && !d.isSDKLibrary {
+ if inList(ctx.ModuleName(), info.global.SystemServerJars) && !d.isSDKLibrary {
// If the module is not an SDK library and it's a system server jar, only preopt the primary arch.
archs = archs[:1]
}
@@ -130,7 +133,7 @@
var images []string
for _, arch := range archs {
- images = append(images, globalConfig.DefaultDexPreoptImage[arch])
+ images = append(images, info.images[arch].String())
}
dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
@@ -178,6 +181,9 @@
Archs: archs,
DexPreoptImages: images,
+ PreoptBootClassPathDexFiles: info.preoptBootDex.Strings(),
+ PreoptBootClassPathDexLocations: info.preoptBootLocations,
+
PreoptExtractedApk: false,
NoCreateAppImage: !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true),
@@ -188,7 +194,7 @@
StripOutputPath: strippedDexJarFile.String(),
}
- dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(globalConfig, dexpreoptConfig)
+ dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(info.global, dexpreoptConfig)
if err != nil {
ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error())
return dexJarFile
@@ -198,7 +204,7 @@
d.builtInstalled = dexpreoptRule.Installs().String()
- stripRule, err := dexpreopt.GenerateStripRule(globalConfig, dexpreoptConfig)
+ stripRule, err := dexpreopt.GenerateStripRule(info.global, dexpreoptConfig)
if err != nil {
ctx.ModuleErrorf("error generating dexpreopt strip rule: %s", err.Error())
return dexJarFile
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
new file mode 100644
index 0000000..0656ff4
--- /dev/null
+++ b/java/dexpreopt_bootjars.go
@@ -0,0 +1,463 @@
+// Copyright 2019 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 (
+ "path/filepath"
+ "strings"
+
+ "android/soong/android"
+ "android/soong/dexpreopt"
+
+ "github.com/google/blueprint/pathtools"
+ "github.com/google/blueprint/proptools"
+)
+
+func init() {
+ android.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
+}
+
+// The image "location" is a symbolic path that with multiarchitecture
+// support doesn't really exist on the device. Typically it is
+// /system/framework/boot.art and should be the same for all supported
+// architectures on the device. The concrete architecture specific
+// content actually ends up in a "filename" that contains an
+// architecture specific directory name such as arm, arm64, mips,
+// mips64, x86, x86_64.
+//
+// Here are some example values for an x86_64 / x86 configuration:
+//
+// bootImages["x86_64"] = "out/soong/generic_x86_64/dex_bootjars/system/framework/x86_64/boot.art"
+// dexpreopt.PathToLocation(bootImages["x86_64"], "x86_64") = "out/soong/generic_x86_64/dex_bootjars/system/framework/boot.art"
+//
+// bootImages["x86"] = "out/soong/generic_x86_64/dex_bootjars/system/framework/x86/boot.art"
+// dexpreopt.PathToLocation(bootImages["x86"])= "out/soong/generic_x86_64/dex_bootjars/system/framework/boot.art"
+//
+// The location is passed as an argument to the ART tools like dex2oat instead of the real path. The ART tools
+// will then reconstruct the real path, so the rules must have a dependency on the real path.
+
+type bootJarsInfo struct {
+ dir android.OutputPath
+ symbolsDir android.OutputPath
+ images map[android.ArchType]android.OutputPath
+ installs map[android.ArchType]android.RuleBuilderInstalls
+
+ vdexInstalls map[android.ArchType]android.RuleBuilderInstalls
+ unstrippedInstalls map[android.ArchType]android.RuleBuilderInstalls
+ profileInstalls android.RuleBuilderInstalls
+
+ global dexpreopt.GlobalConfig
+
+ preoptBootModules []string
+ preoptBootLocations []string
+ preoptBootDex android.WritablePaths
+ allBootModules []string
+ allBootLocations []string
+ bootclasspath string
+ systemServerClasspath string
+}
+
+var dexpreoptBootJarsInfoKey = android.NewOnceKey("dexpreoptBootJarsInfoKey")
+
+// dexpreoptBootJarsInfo creates all the paths for singleton files the first time it is called, which may be
+// from a ModuleContext that needs to reference a file that will be created by a singleton rule that hasn't
+// yet been created.
+func dexpreoptBootJarsInfo(ctx android.PathContext) *bootJarsInfo {
+ return ctx.Config().Once(dexpreoptBootJarsInfoKey, func() interface{} {
+
+ info := &bootJarsInfo{
+ dir: android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_bootjars"),
+ symbolsDir: android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_bootjars_unstripped"),
+ images: make(map[android.ArchType]android.OutputPath),
+ installs: make(map[android.ArchType]android.RuleBuilderInstalls),
+
+ vdexInstalls: make(map[android.ArchType]android.RuleBuilderInstalls),
+ unstrippedInstalls: make(map[android.ArchType]android.RuleBuilderInstalls),
+ }
+
+ for _, target := range ctx.Config().Targets[android.Android] {
+ info.images[target.Arch.ArchType] = info.dir.Join(ctx,
+ "system/framework", target.Arch.ArchType.String(), "boot.art")
+ }
+
+ info.global = dexpreoptGlobalConfig(ctx)
+ computeBootClasspath(ctx, info)
+ computeSystemServerClasspath(ctx, info)
+
+ return info
+ }).(*bootJarsInfo)
+}
+
+func concat(lists ...[]string) []string {
+ var size int
+ for _, l := range lists {
+ size += len(l)
+ }
+ ret := make([]string, 0, size)
+ for _, l := range lists {
+ ret = append(ret, l...)
+ }
+ return ret
+}
+
+func computeBootClasspath(ctx android.PathContext, info *bootJarsInfo) {
+ runtimeModules := android.RemoveListFromList(info.global.TargetCoreJars, info.global.ProductUpdatableBootModules)
+ nonFrameworkModules := concat(runtimeModules, info.global.ProductUpdatableBootModules)
+ frameworkModules := android.RemoveListFromList(info.global.BootJars, nonFrameworkModules)
+
+ var nonUpdatableBootModules []string
+ var nonUpdatableBootLocations []string
+
+ for _, m := range runtimeModules {
+ nonUpdatableBootModules = append(nonUpdatableBootModules, m)
+ nonUpdatableBootLocations = append(nonUpdatableBootLocations,
+ filepath.Join("/apex/com.android.runtime/javalib", m+".jar"))
+ }
+
+ for _, m := range frameworkModules {
+ nonUpdatableBootModules = append(nonUpdatableBootModules, m)
+ nonUpdatableBootLocations = append(nonUpdatableBootLocations,
+ filepath.Join("/system/framework", m+".jar"))
+ }
+
+ // The path to bootclasspath dex files needs to be known at module GenerateAndroidBuildAction time, before
+ // the bootclasspath modules have been compiled. Set up known paths for them, the singleton rules will copy
+ // them there.
+ // TODO: use module dependencies instead
+ var nonUpdatableBootDex android.WritablePaths
+ for _, m := range nonUpdatableBootModules {
+ nonUpdatableBootDex = append(nonUpdatableBootDex,
+ android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_bootjars_input", m+".jar"))
+ }
+
+ allBootModules := concat(nonUpdatableBootModules, info.global.ProductUpdatableBootModules)
+ allBootLocations := concat(nonUpdatableBootLocations, info.global.ProductUpdatableBootLocations)
+
+ bootclasspath := strings.Join(allBootLocations, ":")
+
+ info.preoptBootModules = nonUpdatableBootModules
+ info.preoptBootLocations = nonUpdatableBootLocations
+ info.preoptBootDex = nonUpdatableBootDex
+ info.allBootModules = allBootModules
+ info.allBootLocations = allBootLocations
+ info.bootclasspath = bootclasspath
+}
+
+func computeSystemServerClasspath(ctx android.PathContext, info *bootJarsInfo) {
+ var systemServerClasspathLocations []string
+ for _, m := range info.global.SystemServerJars {
+ systemServerClasspathLocations = append(systemServerClasspathLocations,
+ filepath.Join("/system/framework", m+".jar"))
+ }
+
+ info.systemServerClasspath = strings.Join(systemServerClasspathLocations, ":")
+}
+func dexpreoptBootJarsFactory() android.Singleton {
+ return dexpreoptBootJars{}
+}
+
+func skipDexpreoptBootJars(ctx android.PathContext) bool {
+ if ctx.Config().UnbundledBuild() {
+ return true
+ }
+
+ if len(ctx.Config().Targets[android.Android]) == 0 {
+ // Host-only build
+ return true
+ }
+
+ return false
+}
+
+type dexpreoptBootJars struct{}
+
+// dexpreoptBoot singleton rules
+func (dexpreoptBootJars) GenerateBuildActions(ctx android.SingletonContext) {
+ if skipDexpreoptBootJars(ctx) {
+ return
+ }
+
+ info := dexpreoptBootJarsInfo(ctx)
+
+ // Skip recompiling the boot image for the second sanitization phase. We'll get separate paths
+ // and invalidate first-stage artifacts which are crucial to SANITIZE_LITE builds.
+ // Note: this is technically incorrect. Compiled code contains stack checks which may depend
+ // on ASAN settings.
+ if len(ctx.Config().SanitizeDevice()) == 1 &&
+ ctx.Config().SanitizeDevice()[0] == "address" &&
+ info.global.SanitizeLite {
+ return
+ }
+
+ bootDexJars := make(android.Paths, len(info.preoptBootModules))
+
+ ctx.VisitAllModules(func(module android.Module) {
+ // Collect dex jar paths for the modules listed above.
+ if j, ok := module.(Dependency); ok {
+ name := ctx.ModuleName(module)
+ if i := android.IndexList(name, info.preoptBootModules); i != -1 {
+ bootDexJars[i] = j.DexJar()
+ }
+ }
+ })
+
+ var missingDeps []string
+ // Ensure all modules were converted to paths
+ for i := range bootDexJars {
+ if bootDexJars[i] == nil {
+ if ctx.Config().AllowMissingDependencies() {
+ missingDeps = append(missingDeps, info.preoptBootModules[i])
+ bootDexJars[i] = android.PathForOutput(ctx, "missing")
+ } else {
+ ctx.Errorf("failed to find dex jar path for module %q",
+ info.preoptBootModules[i])
+ }
+ }
+ }
+
+ // The path to bootclasspath dex files needs to be known at module GenerateAndroidBuildAction time, before
+ // the bootclasspath modules have been compiled. Copy the dex jars there so the module rules that have
+ // already been set up can find them.
+ for i := range bootDexJars {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: bootDexJars[i],
+ Output: info.preoptBootDex[i],
+ })
+ }
+
+ profile := bootImageProfileRule(ctx, info, missingDeps)
+
+ if !ctx.Config().DisableDexPreopt() {
+ targets := ctx.Config().Targets[android.Android]
+ if ctx.Config().SecondArchIsTranslated() {
+ targets = targets[:1]
+ }
+
+ for _, target := range targets {
+ dexPreoptBootImageRule(ctx, info, target.Arch.ArchType, profile, missingDeps)
+ }
+ }
+}
+
+func dexPreoptBootImageRule(ctx android.SingletonContext, info *bootJarsInfo,
+ arch android.ArchType, profile android.Path, missingDeps []string) {
+
+ symbolsDir := info.symbolsDir.Join(ctx, "system/framework", arch.String())
+ symbolsFile := symbolsDir.Join(ctx, "boot.oat")
+ outputDir := info.dir.Join(ctx, "system/framework", arch.String())
+ outputPath := info.images[arch]
+ oatLocation := pathtools.ReplaceExtension(dexpreopt.PathToLocation(outputPath.String(), arch), "oat")
+
+ rule := android.NewRuleBuilder()
+ rule.MissingDeps(missingDeps)
+
+ rule.Command().Text("mkdir").Flag("-p").Flag(symbolsDir.String())
+ rule.Command().Text("rm").Flag("-f").
+ Flag(symbolsDir.Join(ctx, "*.art").String()).
+ Flag(symbolsDir.Join(ctx, "*.oat").String()).
+ Flag(symbolsDir.Join(ctx, "*.invocation").String())
+ rule.Command().Text("rm").Flag("-f").
+ Flag(outputDir.Join(ctx, "*.art").String()).
+ Flag(outputDir.Join(ctx, "*.oat").String()).
+ Flag(outputDir.Join(ctx, "*.invocation").String())
+
+ cmd := rule.Command()
+
+ extraFlags := ctx.Config().Getenv("ART_BOOT_IMAGE_EXTRA_ARGS")
+ if extraFlags == "" {
+ // Use ANDROID_LOG_TAGS to suppress most logging by default...
+ cmd.Text(`ANDROID_LOG_TAGS="*:e"`)
+ } else {
+ // ...unless the boot image is generated specifically for testing, then allow all logging.
+ cmd.Text(`ANDROID_LOG_TAGS="*:v"`)
+ }
+
+ invocationPath := outputPath.ReplaceExtension(ctx, "invocation")
+
+ cmd.Tool(info.global.Tools.Dex2oat).
+ Flag("--avoid-storing-invocation").
+ FlagWithOutput("--write-invocation-to=", invocationPath.String()).ImplicitOutput(invocationPath.String()).
+ Flag("--runtime-arg").FlagWithArg("-Xms", info.global.Dex2oatImageXms).
+ Flag("--runtime-arg").FlagWithArg("-Xmx", info.global.Dex2oatImageXmx)
+
+ if profile == nil {
+ cmd.FlagWithArg("--image-classes=", info.global.PreloadedClasses)
+ } else {
+ cmd.FlagWithArg("--compiler-filter=", "speed-profile")
+ cmd.FlagWithInput("--profile-file=", profile.String())
+ }
+
+ if info.global.DirtyImageObjects != "" {
+ cmd.FlagWithArg("--dirty-image-objects=", info.global.DirtyImageObjects)
+ }
+
+ cmd.
+ FlagForEachInput("--dex-file=", info.preoptBootDex.Strings()).
+ FlagForEachArg("--dex-location=", info.preoptBootLocations).
+ Flag("--generate-debug-info").
+ Flag("--generate-build-id").
+ FlagWithArg("--oat-symbols=", symbolsFile.String()).
+ Flag("--strip").
+ FlagWithOutput("--oat-file=", outputPath.ReplaceExtension(ctx, "oat").String()).
+ FlagWithArg("--oat-location=", oatLocation).
+ FlagWithOutput("--image=", outputPath.String()).
+ FlagWithArg("--base=", ctx.Config().LibartImgDeviceBaseAddress()).
+ FlagWithArg("--instruction-set=", arch.String()).
+ FlagWithArg("--instruction-set-variant=", info.global.CpuVariant[arch]).
+ FlagWithArg("--instruction-set-features=", info.global.InstructionSetFeatures[arch]).
+ FlagWithArg("--android-root=", info.global.EmptyDirectory).
+ FlagWithArg("--no-inline-from=", "core-oj.jar").
+ Flag("--abort-on-hard-verifier-error")
+
+ if info.global.BootFlags != "" {
+ cmd.Flag(info.global.BootFlags)
+ }
+
+ if extraFlags != "" {
+ cmd.Flag(extraFlags)
+ }
+
+ cmd.Textf(`|| ( echo %s ; false )`, proptools.ShellEscape([]string{failureMessage})[0])
+
+ installDir := filepath.Join("/system/framework", arch.String())
+ vdexInstallDir := filepath.Join("/system/framework")
+
+ var extraFiles android.WritablePaths
+ var vdexInstalls android.RuleBuilderInstalls
+ var unstrippedInstalls android.RuleBuilderInstalls
+
+ // dex preopt on the bootclasspath produces multiple files. The first dex file
+ // is converted into to boot.art (to match the legacy assumption that boot.art
+ // exists), and the rest are converted to boot-<name>.art.
+ // In addition, each .art file has an associated .oat and .vdex file, and an
+ // unstripped .oat file
+ for i, m := range info.preoptBootModules {
+ name := "boot"
+ if i != 0 {
+ name += "-" + m
+ }
+
+ art := outputDir.Join(ctx, name+".art")
+ oat := outputDir.Join(ctx, name+".oat")
+ vdex := outputDir.Join(ctx, name+".vdex")
+ unstrippedOat := symbolsDir.Join(ctx, name+".oat")
+
+ extraFiles = append(extraFiles, art, oat, vdex, unstrippedOat)
+
+ // Install the .oat and .art files.
+ rule.Install(art.String(), filepath.Join(installDir, art.Base()))
+ rule.Install(oat.String(), filepath.Join(installDir, oat.Base()))
+
+ // The vdex files are identical between architectures, install them to a shared location. The Make rules will
+ // only use the install rules for one architecture, and will create symlinks into the architecture-specific
+ // directories.
+ vdexInstalls = append(vdexInstalls,
+ android.RuleBuilderInstall{vdex.String(), filepath.Join(vdexInstallDir, vdex.Base())})
+
+ // Install the unstripped oat files. The Make rules will put these in $(TARGET_OUT_UNSTRIPPED)
+ unstrippedInstalls = append(unstrippedInstalls,
+ android.RuleBuilderInstall{unstrippedOat.String(), filepath.Join(installDir, unstrippedOat.Base())})
+ }
+
+ cmd.ImplicitOutputs(extraFiles.Strings())
+
+ rule.Build(pctx, ctx, "bootJarsDexpreopt_"+arch.String(), "dexpreopt boot jars "+arch.String())
+
+ // save output and installed files for makevars
+ info.installs[arch] = rule.Installs()
+ info.vdexInstalls[arch] = vdexInstalls
+ info.unstrippedInstalls[arch] = unstrippedInstalls
+}
+
+const failureMessage = `ERROR: Dex2oat failed to compile a boot image.
+It is likely that the boot classpath is inconsistent.
+Rebuild with ART_BOOT_IMAGE_EXTRA_ARGS="--runtime-arg -verbose:verifier" to see verification errors.`
+
+func bootImageProfileRule(ctx android.SingletonContext, info *bootJarsInfo, missingDeps []string) android.WritablePath {
+ if len(info.global.BootImageProfiles) == 0 {
+ return nil
+ }
+
+ tools := info.global.Tools
+
+ rule := android.NewRuleBuilder()
+ rule.MissingDeps(missingDeps)
+
+ var bootImageProfile string
+ if len(info.global.BootImageProfiles) > 1 {
+ combinedBootImageProfile := info.dir.Join(ctx, "boot-image-profile.txt")
+ rule.Command().Text("cat").Inputs(info.global.BootImageProfiles).Output(combinedBootImageProfile.String())
+ bootImageProfile = combinedBootImageProfile.String()
+ } else {
+ bootImageProfile = info.global.BootImageProfiles[0]
+ }
+
+ profile := info.dir.Join(ctx, "boot.prof")
+
+ rule.Command().
+ Text(`ANDROID_LOG_TAGS="*:e"`).
+ Tool(tools.Profman).
+ FlagWithArg("--create-profile-from=", bootImageProfile).
+ FlagForEachInput("--apk=", info.preoptBootDex.Strings()).
+ FlagForEachArg("--dex-location=", info.preoptBootLocations).
+ FlagWithOutput("--reference-profile-file=", profile.String())
+
+ rule.Install(profile.String(), "/system/etc/boot-image.prof")
+
+ rule.Build(pctx, ctx, "bootJarsProfile", "profile boot jars")
+
+ info.profileInstalls = rule.Installs()
+
+ return profile
+}
+
+func init() {
+ android.RegisterMakeVarsProvider(pctx, bootImageMakeVars)
+}
+
+// Export paths to Make. INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/.
+// Both paths are used to call dist-for-goals.
+func bootImageMakeVars(ctx android.MakeVarsContext) {
+ if skipDexpreoptBootJars(ctx) {
+ return
+ }
+
+ info := dexpreoptBootJarsInfo(ctx)
+ for arch, _ := range info.images {
+ ctx.Strict("DEXPREOPT_IMAGE_"+arch.String(), info.images[arch].String())
+
+ var builtInstalled []string
+ for _, install := range info.installs[arch] {
+ builtInstalled = append(builtInstalled, install.From+":"+install.To)
+ }
+
+ var unstrippedBuiltInstalled []string
+ for _, install := range info.unstrippedInstalls[arch] {
+ unstrippedBuiltInstalled = append(unstrippedBuiltInstalled, install.From+":"+install.To)
+ }
+
+ ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+arch.String(), info.installs[arch].String())
+ ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+arch.String(), info.unstrippedInstalls[arch].String())
+ ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+arch.String(), info.vdexInstalls[arch].String())
+ }
+
+ ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", info.profileInstalls.String())
+
+ ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(info.preoptBootDex.Strings(), " "))
+ ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(info.preoptBootLocations, " "))
+ ctx.Strict("PRODUCT_BOOTCLASSPATH", info.bootclasspath)
+ ctx.Strict("PRODUCT_SYSTEM_SERVER_CLASSPATH", info.systemServerClasspath)
+}
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index f199051..01e2c5e 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -59,7 +59,14 @@
if !ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
isBootJar := inList(ctx.ModuleName(), ctx.Config().BootJars())
- if isBootJar || inList(ctx.ModuleName(), config.HiddenAPIExtraAppUsageJars) {
+ // Check to see if this module provides part of the hiddenapi, i.e. is a boot jar or a white listed
+ // library.
+ isProvidingJar := isBootJar || inList(ctx.ModuleName(), config.HiddenAPIProvidingNonBootJars)
+
+ // If this module provides part of the hiddenapi or is a special module that simply provides information
+ // about the hiddenapi then extract information about the hiddenapi from the UnsupportedAppUsage
+ // annotations compiled into the classes.jar.
+ if isProvidingJar || inList(ctx.ModuleName(), config.HiddenAPIExtraAppUsageJars) {
// Derive the greylist from classes jar.
flagsCSV := android.PathForModuleOut(ctx, "hiddenapi", "flags.csv")
metadataCSV := android.PathForModuleOut(ctx, "hiddenapi", "metadata.csv")
@@ -67,7 +74,10 @@
h.flagsCSVPath = flagsCSV
h.metadataCSVPath = metadataCSV
}
- if isBootJar {
+
+ // If this module provides part of the hiddenapi then encode the information about the hiddenapi into
+ // the dex file created for this module.
+ if isProvidingJar {
hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", ctx.ModuleName()+".jar")
h.bootDexJarPath = dexJar
hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex)
diff --git a/java/java_test.go b/java/java_test.go
index 034e905..8d3efcb 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -15,7 +15,6 @@
package java
import (
- "fmt"
"io/ioutil"
"os"
"path/filepath"
@@ -54,16 +53,7 @@
}
func testConfig(env map[string]string) android.Config {
- if env == nil {
- env = make(map[string]string)
- }
- if env["ANDROID_JAVA8_HOME"] == "" {
- env["ANDROID_JAVA8_HOME"] = "jdk8"
- }
- config := android.TestArchConfig(buildDir, env)
- config.TestProductVariables.DeviceSystemSdkVersions = []string{"14", "15"}
- return config
-
+ return TestConfig(buildDir, env)
}
func testContext(config android.Config, bp string,
@@ -113,53 +103,7 @@
ctx.Register()
- extraModules := []string{
- "core-lambda-stubs",
- "framework",
- "ext",
- "android_stubs_current",
- "android_system_stubs_current",
- "android_test_stubs_current",
- "core.current.stubs",
- "core.platform.api.stubs",
- "kotlin-stdlib",
- "kotlin-annotations",
- }
-
- for _, extra := range extraModules {
- bp += fmt.Sprintf(`
- java_library {
- name: "%s",
- srcs: ["a.java"],
- no_standard_libs: true,
- sdk_version: "core_current",
- system_modules: "core-platform-api-stubs-system-modules",
- }
- `, extra)
- }
-
- bp += `
- android_app {
- name: "framework-res",
- no_framework_libs: true,
- }
- `
-
- systemModules := []string{
- "core-system-modules",
- "core-platform-api-stubs-system-modules",
- "android_stubs_current_system_modules",
- "android_system_stubs_current_system_modules",
- "android_test_stubs_current_system_modules",
- }
-
- for _, extra := range systemModules {
- bp += fmt.Sprintf(`
- java_system_modules {
- name: "%s",
- }
- `, extra)
- }
+ bp += GatherRequiredDepsForTest()
mockFS := map[string][]byte{
"Android.bp": []byte(bp),
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 49cc931..02b9b45 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -103,19 +103,25 @@
mctx.CreateModule(android.ModuleFactoryAdaptor(android.FileGroupFactory), &filegroupProps)
}
-func prebuiltSdkStubs(mctx android.TopDownMutatorContext) {
+func getPrebuiltFiles(mctx android.TopDownMutatorContext, name string) []string {
mydir := mctx.ModuleDir() + "/"
- // <apiver>/<scope>/<module>.jar
var files []string
for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs {
for _, scope := range []string{"public", "system", "test", "core"} {
- vfiles, err := mctx.GlobWithDeps(mydir+apiver+"/"+scope+"*/*.jar", nil)
+ vfiles, err := mctx.GlobWithDeps(mydir+apiver+"/"+scope+"/"+name, nil)
if err != nil {
- mctx.ModuleErrorf("failed to glob jar files under %q: %s", mydir+apiver+"/"+scope, err)
+ mctx.ModuleErrorf("failed to glob %s files under %q: %s", name, mydir+apiver+"/"+scope, err)
}
files = append(files, vfiles...)
}
}
+ return files
+}
+
+func prebuiltSdkStubs(mctx android.TopDownMutatorContext) {
+ mydir := mctx.ModuleDir() + "/"
+ // <apiver>/<scope>/<module>.jar
+ files := getPrebuiltFiles(mctx, "*.jar")
for _, f := range files {
// create a Import module for each jar file
@@ -128,10 +134,8 @@
func prebuiltApiFiles(mctx android.TopDownMutatorContext) {
mydir := mctx.ModuleDir() + "/"
// <apiver>/<scope>/api/<module>.txt
- files, err := mctx.GlobWithDeps(mydir+"*/*/api/*.txt", nil)
- if err != nil {
- mctx.ModuleErrorf("failed to glob api txt files under %q: %s", mydir, err)
- }
+ files := getPrebuiltFiles(mctx, "api/*.txt")
+
if len(files) == 0 {
mctx.ModuleErrorf("no api file found under %q", mydir)
}
@@ -161,6 +165,7 @@
strings.Compare(apiver, info.apiver) > 0) {
info.apiver = apiver
info.path = localPath
+ m[key] = info
}
}
// create filegroups for the latest version of (<module>, <scope>) pairs
diff --git a/java/testing.go b/java/testing.go
new file mode 100644
index 0000000..6febfa1
--- /dev/null
+++ b/java/testing.go
@@ -0,0 +1,88 @@
+// Copyright 2019 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 (
+ "fmt"
+
+ "android/soong/android"
+)
+
+func TestConfig(buildDir string, env map[string]string) android.Config {
+ if env == nil {
+ env = make(map[string]string)
+ }
+ if env["ANDROID_JAVA8_HOME"] == "" {
+ env["ANDROID_JAVA8_HOME"] = "jdk8"
+ }
+ config := android.TestArchConfig(buildDir, env)
+ config.TestProductVariables.DeviceSystemSdkVersions = []string{"14", "15"}
+
+ return config
+}
+
+func GatherRequiredDepsForTest() string {
+ var bp string
+
+ extraModules := []string{
+ "core-lambda-stubs",
+ "framework",
+ "ext",
+ "android_stubs_current",
+ "android_system_stubs_current",
+ "android_test_stubs_current",
+ "core.current.stubs",
+ "core.platform.api.stubs",
+ "kotlin-stdlib",
+ "kotlin-annotations",
+ }
+
+ for _, extra := range extraModules {
+ bp += fmt.Sprintf(`
+ java_library {
+ name: "%s",
+ srcs: ["a.java"],
+ no_standard_libs: true,
+ sdk_version: "core_current",
+ system_modules: "core-platform-api-stubs-system-modules",
+ }
+ `, extra)
+ }
+
+ bp += `
+ android_app {
+ name: "framework-res",
+ no_framework_libs: true,
+ }
+ `
+
+ systemModules := []string{
+ "core-system-modules",
+ "core-platform-api-stubs-system-modules",
+ "android_stubs_current_system_modules",
+ "android_system_stubs_current_system_modules",
+ "android_test_stubs_current_system_modules",
+ }
+
+ for _, extra := range systemModules {
+ bp += fmt.Sprintf(`
+ java_system_modules {
+ name: "%s",
+ }
+ `, extra)
+ }
+
+ return bp
+}
diff --git a/python/binary.go b/python/binary.go
index bf9acb4..140f07a 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -42,6 +42,11 @@
// list of compatibility suites (for example "cts", "vts") that the module should be
// installed into.
Test_suites []string `android:"arch_variant"`
+
+ // whether to use `main` when starting the executable. The default is true, when set to
+ // false it will act much like the normal `python` executable, but with the sources and
+ // libraries automatically included in the PYTHONPATH.
+ Autorun *bool `android:"arch_variant"`
}
type binaryDecorator struct {
@@ -74,6 +79,10 @@
return module.Init()
}
+func (binary *binaryDecorator) autorun() bool {
+ return BoolDefault(binary.binaryProperties.Autorun, true)
+}
+
func (binary *binaryDecorator) bootstrapperProps() []interface{} {
return []interface{}{&binary.binaryProperties}
}
@@ -82,7 +91,10 @@
embeddedLauncher bool, srcsPathMappings []pathMapping, srcsZip android.Path,
depsSrcsZips android.Paths) android.OptionalPath {
- main := binary.getPyMainFile(ctx, srcsPathMappings)
+ main := ""
+ if binary.autorun() {
+ main = binary.getPyMainFile(ctx, srcsPathMappings)
+ }
var launcherPath android.OptionalPath
if embeddedLauncher {
diff --git a/python/builder.go b/python/builder.go
index cbbe56e..e3b490c 100644
--- a/python/builder.go
+++ b/python/builder.go
@@ -54,15 +54,21 @@
embeddedPar = pctx.AndroidStaticRule("embeddedPar",
blueprint.RuleParams{
- // `echo -n` to trim the newline, since the python code just wants the name.
- // /bin/sh (used by ninja) on Mac turns off posix mode, and stops supporting -n.
- // Explicitly use bash instead.
- Command: `/bin/bash -c "echo -n '$main' > $entryPoint" &&` +
- `$mergeParCmd -p --prefix $launcher -e $entryPoint $out $srcsZips && ` +
- `chmod +x $out && (rm -f $entryPoint)`,
+ Command: `rm -f $out.main && ` +
+ `sed 's/ENTRY_POINT/$main/' build/soong/python/scripts/main.py >$out.main &&` +
+ `$mergeParCmd -p -pm $out.main --prefix $launcher $out $srcsZips && ` +
+ `chmod +x $out && rm -rf $out.main`,
+ CommandDeps: []string{"$mergeParCmd", "$parCmd", "build/soong/python/scripts/main.py"},
+ },
+ "main", "srcsZips", "launcher")
+
+ embeddedParNoMain = pctx.AndroidStaticRule("embeddedParNoMain",
+ blueprint.RuleParams{
+ Command: `$mergeParCmd -p --prefix $launcher $out $srcsZips && ` +
+ `chmod +x $out`,
CommandDeps: []string{"$mergeParCmd"},
},
- "main", "entryPoint", "srcsZips", "launcher")
+ "srcsZips", "launcher")
)
func init() {
@@ -108,21 +114,30 @@
// added launcherPath to the implicits Ninja dependencies.
implicits = append(implicits, launcherPath.Path())
- // .intermediate output path for entry_point.txt
- entryPoint := android.PathForModuleOut(ctx, entryPointFile).String()
-
- ctx.Build(pctx, android.BuildParams{
- Rule: embeddedPar,
- Description: "embedded python archive",
- Output: binFile,
- Implicits: implicits,
- Args: map[string]string{
- "main": strings.Replace(strings.TrimSuffix(main, pyExt), "/", ".", -1),
- "entryPoint": entryPoint,
- "srcsZips": strings.Join(srcsZips.Strings(), " "),
- "launcher": launcherPath.String(),
- },
- })
+ if main == "" {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: embeddedParNoMain,
+ Description: "embedded python archive",
+ Output: binFile,
+ Implicits: implicits,
+ Args: map[string]string{
+ "srcsZips": strings.Join(srcsZips.Strings(), " "),
+ "launcher": launcherPath.String(),
+ },
+ })
+ } else {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: embeddedPar,
+ Description: "embedded python archive",
+ Output: binFile,
+ Implicits: implicits,
+ Args: map[string]string{
+ "main": strings.Replace(strings.TrimSuffix(main, pyExt), "/", ".", -1),
+ "srcsZips": strings.Join(srcsZips.Strings(), " "),
+ "launcher": launcherPath.String(),
+ },
+ })
+ }
}
return binFile
diff --git a/python/python.go b/python/python.go
index ddc3f1f..4445f40 100644
--- a/python/python.go
+++ b/python/python.go
@@ -156,6 +156,8 @@
bootstrap(ctx android.ModuleContext, ActualVersion string, embeddedLauncher bool,
srcsPathMappings []pathMapping, srcsZip android.Path,
depsSrcsZips android.Paths) android.OptionalPath
+
+ autorun() bool
}
type installer interface {
@@ -307,9 +309,14 @@
if p.bootstrapper != nil && p.isEmbeddedLauncherEnabled(pyVersion2) {
ctx.AddVariationDependencies(nil, pythonLibTag, "py2-stdlib")
+
+ launcherModule := "py2-launcher"
+ if p.bootstrapper.autorun() {
+ launcherModule = "py2-launcher-autorun"
+ }
ctx.AddFarVariationDependencies([]blueprint.Variation{
{Mutator: "arch", Variation: ctx.Target().String()},
- }, launcherTag, "py2-launcher")
+ }, launcherTag, launcherModule)
// Add py2-launcher shared lib dependencies. Ideally, these should be
// derived from the `shared_libs` property of "py2-launcher". However, we
@@ -422,7 +429,11 @@
p.properties.Actual_version, ctx.ModuleName()))
}
expandedSrcs := ctx.ExpandSources(srcs, exclude_srcs)
- if len(expandedSrcs) == 0 {
+ requiresSrcs := true
+ if p.bootstrapper != nil && !p.bootstrapper.autorun() {
+ requiresSrcs = false
+ }
+ if len(expandedSrcs) == 0 && requiresSrcs {
ctx.ModuleErrorf("doesn't have any source files!")
}
@@ -656,4 +667,5 @@
}
var Bool = proptools.Bool
+var BoolDefault = proptools.BoolDefault
var String = proptools.String
diff --git a/python/scripts/main.py b/python/scripts/main.py
new file mode 100644
index 0000000..225dbe4
--- /dev/null
+++ b/python/scripts/main.py
@@ -0,0 +1,12 @@
+import runpy
+import sys
+
+sys.argv[0] = __loader__.archive
+
+# Set sys.executable to None. The real executable is available as
+# sys.argv[0], and too many things assume sys.executable is a regular Python
+# binary, which isn't available. By setting it to None we get clear errors
+# when people try to use it.
+sys.executable = None
+
+runpy._run_module_as_main("ENTRY_POINT", alter_argv=False)
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 92e0af4..745e424 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -19,7 +19,6 @@
"android/soong/cc"
"android/soong/java"
- "fmt"
"io/ioutil"
"os"
"strings"
@@ -90,54 +89,7 @@
ctx.Register()
- extraModules := []string{
- "core-lambda-stubs",
- "framework",
- "ext",
- "updatable_media_stubs",
-
- "android_stubs_current",
- "android_system_stubs_current",
- "android_test_stubs_current",
- "core.current.stubs",
- "core.platform.api.stubs",
- }
-
- for _, extra := range extraModules {
- bp += fmt.Sprintf(`
- java_library {
- name: "%s",
- srcs: ["a.java"],
- no_standard_libs: true,
- sdk_version: "core_current",
- system_modules: "core-platform-api-stubs-system-modules",
- }
- `, extra)
- }
-
- bp += `
- android_app {
- name: "framework-res",
- no_framework_libs: true,
- }
- `
-
- systemModules := []string{
- "core-system-modules",
- "core-platform-api-stubs-system-modules",
- "android_stubs_current_system_modules",
- "android_system_stubs_current_system_modules",
- "android_test_stubs_current_system_modules",
- }
-
- for _, extra := range systemModules {
- bp += fmt.Sprintf(`
- java_system_modules {
- name: "%s",
- }
- `, extra)
- }
-
+ bp += java.GatherRequiredDepsForTest()
bp += cc.GatherRequiredDepsForTest(android.Android)
mockFS := map[string][]byte{
@@ -224,16 +176,12 @@
}
func testConfig(env map[string]string) android.Config {
- if env == nil {
- env = make(map[string]string)
- }
- if env["ANDROID_JAVA8_HOME"] == "" {
- env["ANDROID_JAVA8_HOME"] = "jdk8"
- }
- config := android.TestArchConfig(buildDir, env)
+ config := java.TestConfig(buildDir, env)
+
config.TestProductVariables.DeviceSystemSdkVersions = []string{"28"}
config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER")
+
return config
}
diff --git a/ui/build/path.go b/ui/build/path.go
index ee72cfd..0e1c02c 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -147,11 +147,10 @@
myPath, _ = filepath.Abs(myPath)
- // Use the toybox prebuilts on linux
- if runtime.GOOS == "linux" {
- toyboxPath, _ := filepath.Abs("prebuilts/build-tools/toybox/linux-x86")
- myPath = toyboxPath + string(os.PathListSeparator) + myPath
- }
+ // We put some prebuilts in $PATH, since it's infeasible to add dependencies for all of
+ // them.
+ prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
+ myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
config.Environment().Set("PATH", myPath)
config.pathReplaced = true
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index b9713fe..d4922f3 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -26,9 +26,9 @@
// Whether to exit with an error instead of invoking the underlying tool.
Error bool
- // Whether we use a toybox prebuilt for this tool. Since we don't have
- // toybox for Darwin, we'll use the host version instead.
- Toybox bool
+ // Whether we use a linux-specific prebuilt for this tool. On Darwin,
+ // we'll allow the host executable instead.
+ LinuxOnlyPrebuilt bool
}
var Allowed = PathConfig{
@@ -59,11 +59,11 @@
Error: true,
}
-var Toybox = PathConfig{
- Symlink: false,
- Log: true,
- Error: true,
- Toybox: true,
+var LinuxOnlyPrebuilt = PathConfig{
+ Symlink: false,
+ Log: true,
+ Error: true,
+ LinuxOnlyPrebuilt: true,
}
func GetConfig(name string) PathConfig {
@@ -101,7 +101,6 @@
"python3": Allowed,
"realpath": Allowed,
"rsync": Allowed,
- "sed": Allowed,
"sh": Allowed,
"tar": Allowed,
"timeout": Allowed,
@@ -126,57 +125,57 @@
"pkg-config": Forbidden,
// On Linux we'll use the toybox versions of these instead.
- "awk": Toybox, // Strictly one-true-awk, but...
- "basename": Toybox,
- "cat": Toybox,
- "chmod": Toybox,
- "cmp": Toybox,
- "cp": Toybox,
- "comm": Toybox,
- "cut": Toybox,
- "dirname": Toybox,
- "du": Toybox,
- "echo": Toybox,
- "env": Toybox,
- "expr": Toybox,
- "head": Toybox,
- "getconf": Toybox,
- "hostname": Toybox,
- "id": Toybox,
- "ln": Toybox,
- "ls": Toybox,
- "md5sum": Toybox,
- "mkdir": Toybox,
- "mktemp": Toybox,
- "mv": Toybox,
- "od": Toybox,
- "paste": Toybox,
- "pgrep": Toybox,
- "pkill": Toybox,
- "ps": Toybox,
- "pwd": Toybox,
- "readlink": Toybox,
- "rm": Toybox,
- "rmdir": Toybox,
- "setsid": Toybox,
- "sha1sum": Toybox,
- "sha256sum": Toybox,
- "sha512sum": Toybox,
- "sleep": Toybox,
- "sort": Toybox,
- "stat": Toybox,
- "tail": Toybox,
- "tee": Toybox,
- "touch": Toybox,
- "true": Toybox,
- "uname": Toybox,
- "uniq": Toybox,
- "unix2dos": Toybox,
- "wc": Toybox,
- "whoami": Toybox,
- "which": Toybox,
- "xargs": Toybox,
- "xxd": Toybox,
+ "basename": LinuxOnlyPrebuilt,
+ "cat": LinuxOnlyPrebuilt,
+ "chmod": LinuxOnlyPrebuilt,
+ "cmp": LinuxOnlyPrebuilt,
+ "cp": LinuxOnlyPrebuilt,
+ "comm": LinuxOnlyPrebuilt,
+ "cut": LinuxOnlyPrebuilt,
+ "dirname": LinuxOnlyPrebuilt,
+ "du": LinuxOnlyPrebuilt,
+ "echo": LinuxOnlyPrebuilt,
+ "env": LinuxOnlyPrebuilt,
+ "expr": LinuxOnlyPrebuilt,
+ "head": LinuxOnlyPrebuilt,
+ "getconf": LinuxOnlyPrebuilt,
+ "hostname": LinuxOnlyPrebuilt,
+ "id": LinuxOnlyPrebuilt,
+ "ln": LinuxOnlyPrebuilt,
+ "ls": LinuxOnlyPrebuilt,
+ "md5sum": LinuxOnlyPrebuilt,
+ "mkdir": LinuxOnlyPrebuilt,
+ "mktemp": LinuxOnlyPrebuilt,
+ "mv": LinuxOnlyPrebuilt,
+ "od": LinuxOnlyPrebuilt,
+ "paste": LinuxOnlyPrebuilt,
+ "pgrep": LinuxOnlyPrebuilt,
+ "pkill": LinuxOnlyPrebuilt,
+ "ps": LinuxOnlyPrebuilt,
+ "pwd": LinuxOnlyPrebuilt,
+ "readlink": LinuxOnlyPrebuilt,
+ "rm": LinuxOnlyPrebuilt,
+ "rmdir": LinuxOnlyPrebuilt,
+ "sed": LinuxOnlyPrebuilt,
+ "setsid": LinuxOnlyPrebuilt,
+ "sha1sum": LinuxOnlyPrebuilt,
+ "sha256sum": LinuxOnlyPrebuilt,
+ "sha512sum": LinuxOnlyPrebuilt,
+ "sleep": LinuxOnlyPrebuilt,
+ "sort": LinuxOnlyPrebuilt,
+ "stat": LinuxOnlyPrebuilt,
+ "tail": LinuxOnlyPrebuilt,
+ "tee": LinuxOnlyPrebuilt,
+ "touch": LinuxOnlyPrebuilt,
+ "true": LinuxOnlyPrebuilt,
+ "uname": LinuxOnlyPrebuilt,
+ "uniq": LinuxOnlyPrebuilt,
+ "unix2dos": LinuxOnlyPrebuilt,
+ "wc": LinuxOnlyPrebuilt,
+ "whoami": LinuxOnlyPrebuilt,
+ "which": LinuxOnlyPrebuilt,
+ "xargs": LinuxOnlyPrebuilt,
+ "xxd": LinuxOnlyPrebuilt,
}
func init() {
@@ -185,10 +184,10 @@
Configuration["sw_vers"] = Allowed
Configuration["xcrun"] = Allowed
- // We don't have toybox prebuilts for darwin, so allow the
- // host versions.
+ // We don't have darwin prebuilts for some tools (like toybox),
+ // so allow the host versions.
for name, config := range Configuration {
- if config.Toybox {
+ if config.LinuxOnlyPrebuilt {
Configuration[name] = Allowed
}
}