Merge "Enable the experimental LLVM new pass manager"
diff --git a/Android.bp b/Android.bp
index 6b59f04..c9a48b4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -70,6 +70,7 @@
"android/testing.go",
"android/util.go",
"android/variable.go",
+ "android/visibility.go",
"android/vts_config.go",
"android/writedocs.go",
@@ -90,6 +91,7 @@
"android/rule_builder_test.go",
"android/util_test.go",
"android/variable_test.go",
+ "android/visibility_test.go",
"android/vts_config_test.go",
],
}
@@ -194,6 +196,7 @@
"cc/gen_test.go",
"cc/genrule_test.go",
"cc/library_test.go",
+ "cc/prebuilt_test.go",
"cc/proto_test.go",
"cc/test_data_test.go",
"cc/util_test.go",
@@ -274,6 +277,7 @@
"java/plugin.go",
"java/prebuilt_apis.go",
"java/proto.go",
+ "java/robolectric.go",
"java/sdk.go",
"java/sdk_library.go",
"java/support_libraries.go",
@@ -441,6 +445,7 @@
defaults: ["linux_bionic_supported"],
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
arch: {
arm: {
@@ -463,6 +468,7 @@
defaults: ["linux_bionic_supported"],
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
arch: {
arm: {
@@ -481,6 +487,118 @@
}
toolchain_library {
+ name: "libgcc_stripped",
+ defaults: ["linux_bionic_supported"],
+ vendor_available: true,
+ recovery_available: true,
+ native_bridge_supported: true,
+
+ arch: {
+ arm: {
+ src: "prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/lib/gcc/arm-linux-androideabi/4.9.x/libgcc.a",
+ strip: {
+ keep_symbols_list: [
+ // unwind-arm.o
+ "_Unwind_Complete",
+ "_Unwind_DeleteException",
+ "_Unwind_GetCFA",
+ "_Unwind_VRS_Get",
+ "_Unwind_VRS_Pop",
+ "_Unwind_VRS_Set",
+ "__aeabi_unwind_cpp_pr0",
+ "__aeabi_unwind_cpp_pr1",
+ "__aeabi_unwind_cpp_pr2",
+ "__gnu_Unwind_Backtrace",
+ "__gnu_Unwind_ForcedUnwind",
+ "__gnu_Unwind_RaiseException",
+ "__gnu_Unwind_Resume",
+ "__gnu_Unwind_Resume_or_Rethrow",
+
+ // libunwind.o
+ "_Unwind_Backtrace",
+ "_Unwind_ForcedUnwind",
+ "_Unwind_RaiseException",
+ "_Unwind_Resume",
+ "_Unwind_Resume_or_Rethrow",
+ "___Unwind_Backtrace",
+ "___Unwind_ForcedUnwind",
+ "___Unwind_RaiseException",
+ "___Unwind_Resume",
+ "___Unwind_Resume_or_Rethrow",
+ "__gnu_Unwind_Restore_VFP",
+ "__gnu_Unwind_Restore_VFP_D",
+ "__gnu_Unwind_Restore_VFP_D_16_to_31",
+ "__gnu_Unwind_Restore_WMMXC",
+ "__gnu_Unwind_Restore_WMMXD",
+ "__gnu_Unwind_Save_VFP",
+ "__gnu_Unwind_Save_VFP_D",
+ "__gnu_Unwind_Save_VFP_D_16_to_31",
+ "__gnu_Unwind_Save_WMMXC",
+ "__gnu_Unwind_Save_WMMXD",
+ "__restore_core_regs",
+ "restore_core_regs",
+
+ // pr-support.o
+ "_Unwind_GetDataRelBase",
+ "_Unwind_GetLanguageSpecificData",
+ "_Unwind_GetRegionStart",
+ "_Unwind_GetTextRelBase",
+ "__gnu_unwind_execute",
+ "__gnu_unwind_frame",
+ ],
+ use_gnu_strip: true,
+ },
+ },
+ arm64: {
+ src: "prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/lib/gcc/aarch64-linux-android/4.9.x/libgcc.a",
+ },
+ x86: {
+ src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/32/libgcc.a",
+
+ },
+ x86_64: {
+ src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/libgcc.a",
+ },
+ },
+ strip: {
+ keep_symbols_list: [
+ // unwind-dw2.o
+ "_Unwind_Backtrace",
+ "_Unwind_DeleteException",
+ "_Unwind_FindEnclosingFunction",
+ "_Unwind_ForcedUnwind",
+ "_Unwind_GetCFA",
+ "_Unwind_GetDataRelBase",
+ "_Unwind_GetGR",
+ "_Unwind_GetIP",
+ "_Unwind_GetIPInfo",
+ "_Unwind_GetLanguageSpecificData",
+ "_Unwind_GetRegionStart",
+ "_Unwind_GetTextRelBase",
+ "_Unwind_RaiseException",
+ "_Unwind_Resume",
+ "_Unwind_Resume_or_Rethrow",
+ "_Unwind_SetGR",
+ "_Unwind_SetIP",
+ "__frame_state_for",
+
+ // unwind-dw2-fde-dip.o
+ "_Unwind_Find_FDE",
+ "__deregister_frame",
+ "__deregister_frame_info",
+ "__deregister_frame_info_bases",
+ "__register_frame",
+ "__register_frame_info",
+ "__register_frame_info_bases",
+ "__register_frame_info_table",
+ "__register_frame_info_table_bases",
+ "__register_frame_table",
+ ],
+ use_gnu_strip: true,
+ },
+}
+
+toolchain_library {
name: "libwinpthread",
host_supported: true,
enabled: false,
@@ -521,6 +639,7 @@
kernel_headers {
name: "device_kernel_headers",
vendor: true,
+ recovery_available: true,
}
cc_genrule {
diff --git a/README.md b/README.md
index 2957940..b0b61a8 100644
--- a/README.md
+++ b/README.md
@@ -107,6 +107,30 @@
}
```
+### Packages
+
+The build is organized into packages where each package is a collection of related files and a
+specification of the dependencies among them in the form of modules.
+
+A package is defined as a directory containing a file named `Android.bp`, residing beneath the
+top-level directory in the build and its name is its path relative to the top-level directory. A
+package includes all files in its directory, plus all subdirectories beneath it, except those which
+themselves contain an `Android.bp` file.
+
+The modules in a package's `Android.bp` and included files are part of the module.
+
+For example, in the following directory tree (where `.../android/` is the top-level Android
+directory) there are two packages, `my/app`, and the subpackage `my/app/tests`. Note that
+`my/app/data` is not a package, but a directory belonging to package `my/app`.
+
+ .../android/my/app/Android.bp
+ .../android/my/app/app.cc
+ .../android/my/app/data/input.txt
+ .../android/my/app/tests/Android.bp
+ .../android/my/app/tests/test.cc
+
+This is based on the Bazel package concept.
+
### Name resolution
Soong provides the ability for modules in different directories to specify
@@ -139,6 +163,54 @@
built by the `m` command. After we have fully converted from Make to Soong, the
details of enabling namespaces could potentially change.
+### Visibility
+
+The `visibility` property on a module controls whether the module can be
+used by other packages. Modules are always visible to other modules declared
+in the same package. This is based on the Bazel visibility mechanism.
+
+If specified the `visibility` property must contain at least one rule.
+
+Each rule in the property must be in one of the following forms:
+* `["//visibility:public"]`: Anyone can use this module.
+* `["//visibility:private"]`: Only rules in the module's package (not its
+subpackages) can use this module.
+* `["//some/package:__pkg__", "//other/package:__pkg__"]`: Only modules in
+`some/package` and `other/package` (defined in `some/package/*.bp` and
+`other/package/*.bp`) have access to this module. Note that sub-packages do not
+have access to the rule; for example, `//some/package/foo:bar` or
+`//other/package/testing:bla` wouldn't have access. `__pkg__` is a special
+module and must be used verbatim. It represents all of the modules in the
+package.
+* `["//project:__subpackages__", "//other:__subpackages__"]`: Only modules in
+packages `project` or `other` or in one of their sub-packages have access to
+this module. For example, `//project:rule`, `//project/library:lib` or
+`//other/testing/internal:munge` are allowed to depend on this rule (but not
+`//independent:evil`)
+* `["//project"]`: This is shorthand for `["//project:__pkg__"]`
+* `[":__subpackages__"]`: This is shorthand for `["//project:__subpackages__"]`
+where `//project` is the module's package. e.g. using `[":__subpackages__"]` in
+`packages/apps/Settings/Android.bp` is equivalent to
+`//packages/apps/Settings:__subpackages__`.
+* `["//visibility:legacy_public"]`: The default visibility, behaves as
+`//visibility:public` for now. It is an error if it is used in a module.
+
+The visibility rules of `//visibility:public` and `//visibility:private` can
+not be combined with any other visibility specifications.
+
+Packages outside `vendor/` cannot make themselves visible to specific packages
+in `vendor/`, e.g. a module in `libcore` cannot declare that it is visible to
+say `vendor/google`, instead it must make itself visible to all packages within
+`vendor/` using `//vendor:__subpackages__`.
+
+If a module does not specify the `visibility` property the module is
+`//visibility:legacy_public`. Once the build has been completely switched over to
+soong it is possible that a global refactoring will be done to change this to
+`//visibility:private` at which point all modules that do not currently specify
+a `visibility` property will be updated to have
+`visibility = [//visibility:legacy_public]` added. It will then be the owner's
+responsibility to replace that with a more appropriate visibility.
+
### Formatter
Soong includes a canonical formatter for blueprint files, similar to
diff --git a/android/androidmk.go b/android/androidmk.go
index 42e1439..7d0aa3b 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -32,6 +32,8 @@
RegisterSingletonType("androidmk", AndroidMkSingleton)
}
+// Deprecated: consider using AndroidMkEntriesProvider instead, especially if you're not going to
+// use the Custom function.
type AndroidMkDataProvider interface {
AndroidMk() AndroidMkData
BaseModuleName() string
@@ -57,6 +59,215 @@
type AndroidMkExtraFunc func(w io.Writer, outputFile Path)
+// Allows modules to customize their Android*.mk output.
+type AndroidMkEntriesProvider interface {
+ AndroidMkEntries() AndroidMkEntries
+ BaseModuleName() string
+}
+
+type AndroidMkEntries struct {
+ Class string
+ SubName string
+ DistFile OptionalPath
+ OutputFile OptionalPath
+ Disabled bool
+ Include string
+ Required []string
+ Host_required []string
+ Target_required []string
+
+ header bytes.Buffer
+ footer bytes.Buffer
+
+ AddCustomEntries func(name, prefix, moduleDir string, entries *AndroidMkEntries)
+
+ EntryMap map[string][]string
+ entryOrder []string
+}
+
+func (a *AndroidMkEntries) SetString(name, value string) {
+ if _, ok := a.EntryMap[name]; !ok {
+ a.entryOrder = append(a.entryOrder, name)
+ }
+ a.EntryMap[name] = []string{value}
+}
+
+func (a *AndroidMkEntries) SetBoolIfTrue(name string, flag bool) {
+ if flag {
+ if _, ok := a.EntryMap[name]; !ok {
+ a.entryOrder = append(a.entryOrder, name)
+ }
+ a.EntryMap[name] = []string{"true"}
+ }
+}
+
+func (a *AndroidMkEntries) AddStrings(name string, value ...string) {
+ if len(value) == 0 {
+ return
+ }
+ if _, ok := a.EntryMap[name]; !ok {
+ a.entryOrder = append(a.entryOrder, name)
+ }
+ a.EntryMap[name] = append(a.EntryMap[name], value...)
+}
+
+func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod blueprint.Module) {
+ a.EntryMap = make(map[string][]string)
+ amod := mod.(Module).base()
+ name := amod.BaseModuleName()
+
+ if a.Include == "" {
+ a.Include = "$(BUILD_PREBUILT)"
+ }
+ a.Required = append(a.Required, amod.commonProperties.Required...)
+ a.Host_required = append(a.Host_required, amod.commonProperties.Host_required...)
+ a.Target_required = append(a.Target_required, amod.commonProperties.Target_required...)
+
+ // Fill in the header part.
+ if len(amod.commonProperties.Dist.Targets) > 0 {
+ distFile := a.DistFile
+ if !distFile.Valid() {
+ distFile = a.OutputFile
+ }
+ if distFile.Valid() {
+ dest := filepath.Base(distFile.String())
+
+ if amod.commonProperties.Dist.Dest != nil {
+ var err error
+ if dest, err = validateSafePath(*amod.commonProperties.Dist.Dest); err != nil {
+ // This was checked in ModuleBase.GenerateBuildActions
+ panic(err)
+ }
+ }
+
+ if amod.commonProperties.Dist.Suffix != nil {
+ ext := filepath.Ext(dest)
+ suffix := *amod.commonProperties.Dist.Suffix
+ dest = strings.TrimSuffix(dest, ext) + suffix + ext
+ }
+
+ if amod.commonProperties.Dist.Dir != nil {
+ var err error
+ if dest, err = validateSafePath(*amod.commonProperties.Dist.Dir, dest); err != nil {
+ // This was checked in ModuleBase.GenerateBuildActions
+ panic(err)
+ }
+ }
+
+ goals := strings.Join(amod.commonProperties.Dist.Targets, " ")
+ fmt.Fprintln(&a.header, ".PHONY:", goals)
+ fmt.Fprintf(&a.header, "$(call dist-for-goals,%s,%s:%s)\n",
+ goals, distFile.String(), dest)
+ }
+ }
+
+ fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS)")
+
+ // Collect make variable assignment entries.
+ a.SetString("LOCAL_PATH", filepath.Dir(bpPath))
+ a.SetString("LOCAL_MODULE", name+a.SubName)
+ a.SetString("LOCAL_MODULE_CLASS", a.Class)
+ a.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String())
+ a.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...)
+ a.AddStrings("LOCAL_HOST_REQUIRED_MODULES", a.Host_required...)
+ a.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", a.Target_required...)
+
+ archStr := amod.Arch().ArchType.String()
+ host := false
+ switch amod.Os().Class {
+ case Host:
+ // Make cannot identify LOCAL_MODULE_HOST_ARCH:= common.
+ if archStr != "common" {
+ a.SetString("LOCAL_MODULE_HOST_ARCH", archStr)
+ }
+ host = true
+ case HostCross:
+ // Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common.
+ if archStr != "common" {
+ a.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr)
+ }
+ host = true
+ case Device:
+ // Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
+ if archStr != "common" {
+ if amod.Target().NativeBridge {
+ // TODO: Unhardcode these rules.
+ guestArchStr := archStr
+ hostArchStr := ""
+ if guestArchStr == "arm" {
+ hostArchStr = "x86"
+ } else if guestArchStr == "arm64" {
+ hostArchStr = "x86_64"
+ }
+
+ if hostArchStr != "" {
+ a.SetString("LOCAL_MODULE_TARGET_ARCH", hostArchStr)
+ }
+ } else {
+ a.SetString("LOCAL_MODULE_TARGET_ARCH", archStr)
+ }
+ }
+
+ a.AddStrings("LOCAL_INIT_RC", amod.commonProperties.Init_rc...)
+ a.AddStrings("LOCAL_VINTF_FRAGMENTS", amod.commonProperties.Vintf_fragments...)
+ a.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(amod.commonProperties.Proprietary))
+ if Bool(amod.commonProperties.Vendor) || Bool(amod.commonProperties.Soc_specific) {
+ a.SetString("LOCAL_VENDOR_MODULE", "true")
+ }
+ a.SetBoolIfTrue("LOCAL_ODM_MODULE", Bool(amod.commonProperties.Device_specific))
+ a.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", Bool(amod.commonProperties.Product_specific))
+ a.SetBoolIfTrue("LOCAL_PRODUCT_SERVICES_MODULE", Bool(amod.commonProperties.Product_services_specific))
+ if amod.commonProperties.Owner != nil {
+ a.SetString("LOCAL_MODULE_OWNER", *amod.commonProperties.Owner)
+ }
+ }
+
+ if amod.noticeFile.Valid() {
+ a.SetString("LOCAL_NOTICE_FILE", amod.noticeFile.String())
+ }
+
+ if host {
+ makeOs := amod.Os().String()
+ if amod.Os() == Linux || amod.Os() == LinuxBionic {
+ makeOs = "linux"
+ }
+ a.SetString("LOCAL_MODULE_HOST_OS", makeOs)
+ a.SetString("LOCAL_IS_HOST_MODULE", "true")
+ }
+
+ prefix := ""
+ if amod.ArchSpecific() {
+ switch amod.Os().Class {
+ case Host:
+ prefix = "HOST_"
+ case HostCross:
+ prefix = "HOST_CROSS_"
+ case Device:
+ prefix = "TARGET_"
+
+ }
+
+ if amod.Arch().ArchType != config.Targets[amod.Os()][0].Arch.ArchType {
+ prefix = "2ND_" + prefix
+ }
+ }
+ blueprintDir := filepath.Dir(bpPath)
+ if a.AddCustomEntries != nil {
+ a.AddCustomEntries(name, prefix, blueprintDir, a)
+ }
+
+ // Write to footer.
+ fmt.Fprintln(&a.footer, "include "+a.Include)
+}
+
+func (a *AndroidMkEntries) write(w io.Writer) {
+ w.Write(a.header.Bytes())
+ for _, name := range a.entryOrder {
+ fmt.Fprintln(w, name+" := "+strings.Join(a.EntryMap[name], " "))
+ }
+ w.Write(a.footer.Bytes())
+}
+
func AndroidMkSingleton() Singleton {
return &androidMkSingleton{}
}
@@ -159,6 +370,8 @@
return translateAndroidModule(ctx, w, mod, x)
case bootstrap.GoBinaryTool:
return translateGoBinaryModule(ctx, w, mod, x)
+ case AndroidMkEntriesProvider:
+ return translateAndroidMkEntriesModule(ctx, w, mod, x)
default:
return nil
}
@@ -178,37 +391,32 @@
func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
provider AndroidMkDataProvider) error {
- name := provider.BaseModuleName()
amod := mod.(Module).base()
-
- if !amod.Enabled() {
- return nil
- }
-
- if amod.commonProperties.SkipInstall {
- return nil
- }
-
- if !amod.commonProperties.NamespaceExportedToMake {
- // TODO(jeffrygaston) do we want to validate that there are no modules being
- // exported to Kati that depend on this module?
+ if shouldSkipAndroidMkProcessing(amod) {
return nil
}
data := provider.AndroidMk()
-
if data.Include == "" {
data.Include = "$(BUILD_PREBUILT)"
}
- data.Required = append(data.Required, amod.commonProperties.Required...)
- data.Host_required = append(data.Host_required, amod.commonProperties.Host_required...)
- data.Target_required = append(data.Target_required, amod.commonProperties.Target_required...)
-
- // Make does not understand LinuxBionic
- if amod.Os() == LinuxBionic {
- return nil
+ // Get the preamble content through AndroidMkEntries logic.
+ entries := AndroidMkEntries{
+ Class: data.Class,
+ SubName: data.SubName,
+ DistFile: data.DistFile,
+ OutputFile: data.OutputFile,
+ Disabled: data.Disabled,
+ Include: data.Include,
+ Required: data.Required,
+ Host_required: data.Host_required,
+ Target_required: data.Target_required,
}
+ entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod)
+ // preamble doesn't need the footer content.
+ entries.footer = bytes.Buffer{}
+ entries.write(&data.preamble)
prefix := ""
if amod.ArchSpecific() {
@@ -227,112 +435,7 @@
}
}
- if len(amod.commonProperties.Dist.Targets) > 0 {
- distFile := data.DistFile
- if !distFile.Valid() {
- distFile = data.OutputFile
- }
- if distFile.Valid() {
- dest := filepath.Base(distFile.String())
-
- if amod.commonProperties.Dist.Dest != nil {
- var err error
- dest, err = validateSafePath(*amod.commonProperties.Dist.Dest)
- if err != nil {
- // This was checked in ModuleBase.GenerateBuildActions
- panic(err)
- }
- }
-
- if amod.commonProperties.Dist.Suffix != nil {
- ext := filepath.Ext(dest)
- suffix := *amod.commonProperties.Dist.Suffix
- dest = strings.TrimSuffix(dest, ext) + suffix + ext
- }
-
- if amod.commonProperties.Dist.Dir != nil {
- var err error
- dest, err = validateSafePath(*amod.commonProperties.Dist.Dir, dest)
- if err != nil {
- // This was checked in ModuleBase.GenerateBuildActions
- panic(err)
- }
- }
-
- goals := strings.Join(amod.commonProperties.Dist.Targets, " ")
- fmt.Fprintln(&data.preamble, ".PHONY:", goals)
- fmt.Fprintf(&data.preamble, "$(call dist-for-goals,%s,%s:%s)\n",
- goals, distFile.String(), dest)
- }
- }
-
- fmt.Fprintln(&data.preamble, "\ninclude $(CLEAR_VARS)")
- fmt.Fprintln(&data.preamble, "LOCAL_PATH :=", filepath.Dir(ctx.BlueprintFile(mod)))
- fmt.Fprintln(&data.preamble, "LOCAL_MODULE :=", name+data.SubName)
- fmt.Fprintln(&data.preamble, "LOCAL_MODULE_CLASS :=", data.Class)
- fmt.Fprintln(&data.preamble, "LOCAL_PREBUILT_MODULE_FILE :=", data.OutputFile.String())
- WriteRequiredModulesSettings(&data.preamble, data)
-
- archStr := amod.Arch().ArchType.String()
- host := false
- switch amod.Os().Class {
- case Host:
- // Make cannot identify LOCAL_MODULE_HOST_ARCH:= common.
- if archStr != "common" {
- fmt.Fprintln(&data.preamble, "LOCAL_MODULE_HOST_ARCH :=", archStr)
- }
- host = true
- case HostCross:
- // Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common.
- if archStr != "common" {
- fmt.Fprintln(&data.preamble, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr)
- }
- host = true
- case Device:
- // Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
- if archStr != "common" {
- fmt.Fprintln(&data.preamble, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
- }
-
- if len(amod.commonProperties.Init_rc) > 0 {
- fmt.Fprintln(&data.preamble, "LOCAL_INIT_RC := ", strings.Join(amod.commonProperties.Init_rc, " "))
- }
- if len(amod.commonProperties.Vintf_fragments) > 0 {
- fmt.Fprintln(&data.preamble, "LOCAL_VINTF_FRAGMENTS := ", strings.Join(amod.commonProperties.Vintf_fragments, " "))
- }
- if Bool(amod.commonProperties.Proprietary) {
- fmt.Fprintln(&data.preamble, "LOCAL_PROPRIETARY_MODULE := true")
- }
- if Bool(amod.commonProperties.Vendor) || Bool(amod.commonProperties.Soc_specific) {
- fmt.Fprintln(&data.preamble, "LOCAL_VENDOR_MODULE := true")
- }
- if Bool(amod.commonProperties.Device_specific) {
- fmt.Fprintln(&data.preamble, "LOCAL_ODM_MODULE := true")
- }
- if Bool(amod.commonProperties.Product_specific) {
- fmt.Fprintln(&data.preamble, "LOCAL_PRODUCT_MODULE := true")
- }
- if Bool(amod.commonProperties.Product_services_specific) {
- fmt.Fprintln(&data.preamble, "LOCAL_PRODUCT_SERVICES_MODULE := true")
- }
- if amod.commonProperties.Owner != nil {
- fmt.Fprintln(&data.preamble, "LOCAL_MODULE_OWNER :=", *amod.commonProperties.Owner)
- }
- }
-
- if amod.noticeFile.Valid() {
- fmt.Fprintln(&data.preamble, "LOCAL_NOTICE_FILE :=", amod.noticeFile.String())
- }
-
- if host {
- makeOs := amod.Os().String()
- if amod.Os() == Linux || amod.Os() == LinuxBionic {
- makeOs = "linux"
- }
- fmt.Fprintln(&data.preamble, "LOCAL_MODULE_HOST_OS :=", makeOs)
- fmt.Fprintln(&data.preamble, "LOCAL_IS_HOST_MODULE := true")
- }
-
+ name := provider.BaseModuleName()
blueprintDir := filepath.Dir(ctx.BlueprintFile(mod))
if data.Custom != nil {
@@ -362,14 +465,29 @@
fmt.Fprintln(w, "include "+data.Include)
}
-func WriteRequiredModulesSettings(w io.Writer, data AndroidMkData) {
- if len(data.Required) > 0 {
- fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(data.Required, " "))
+func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
+ provider AndroidMkEntriesProvider) error {
+ if shouldSkipAndroidMkProcessing(mod.(Module).base()) {
+ return nil
}
- if len(data.Host_required) > 0 {
- fmt.Fprintln(w, "LOCAL_HOST_REQUIRED_MODULES :=", strings.Join(data.Host_required, " "))
+
+ entries := provider.AndroidMkEntries()
+ entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod)
+
+ entries.write(w)
+
+ return nil
+}
+
+func shouldSkipAndroidMkProcessing(module *ModuleBase) bool {
+ if !module.commonProperties.NamespaceExportedToMake {
+ // TODO(jeffrygaston) do we want to validate that there are no modules being
+ // exported to Kati that depend on this module?
+ return true
}
- if len(data.Target_required) > 0 {
- fmt.Fprintln(w, "LOCAL_TARGET_REQUIRED_MODULES :=", strings.Join(data.Target_required, " "))
- }
+
+ return !module.Enabled() ||
+ module.commonProperties.SkipInstall ||
+ // Make does not understand LinuxBionic
+ module.Os() == LinuxBionic
}
diff --git a/android/arch.go b/android/arch.go
index 957a659..68fc149 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -683,13 +683,25 @@
return NoOsType
}
+type NativeBridgeSupport bool
+
+const (
+ NativeBridgeDisabled NativeBridgeSupport = false
+ NativeBridgeEnabled NativeBridgeSupport = true
+)
+
type Target struct {
- Os OsType
- Arch Arch
+ Os OsType
+ Arch Arch
+ NativeBridge NativeBridgeSupport
}
func (target Target) String() string {
- return target.Os.String() + "_" + target.Arch.String()
+ variant := ""
+ if target.NativeBridge {
+ variant = "native_bridge_"
+ }
+ return target.Os.String() + "_" + variant + target.Arch.String()
}
// archMutator splits a module into a variant for each Target requested by the module. Target selection
@@ -750,6 +762,18 @@
continue
}
+ // Filter NativeBridge targets unless they are explicitly supported
+ if os == Android && !Bool(base.commonProperties.Native_bridge_supported) {
+ var targets []Target
+ for _, t := range osTargets {
+ if !t.NativeBridge {
+ targets = append(targets, t)
+ }
+ }
+
+ osTargets = targets
+ }
+
// only the primary arch in the recovery partition
if os == Android && module.InstallInRecovery() {
osTargets = []Target{osTargets[0]}
@@ -1378,7 +1402,8 @@
targets := make(map[OsType][]Target)
var targetErr error
- addTarget := func(os OsType, archName string, archVariant, cpuVariant *string, abi []string) {
+ addTarget := func(os OsType, archName string, archVariant, cpuVariant *string, abi []string,
+ nativeBridgeEnabled NativeBridgeSupport) {
if targetErr != nil {
return
}
@@ -1391,8 +1416,9 @@
targets[os] = append(targets[os],
Target{
- Os: os,
- Arch: arch,
+ Os: os,
+ Arch: arch,
+ NativeBridge: nativeBridgeEnabled,
})
}
@@ -1400,14 +1426,14 @@
return nil, fmt.Errorf("No host primary architecture set")
}
- addTarget(BuildOs, *variables.HostArch, nil, nil, nil)
+ addTarget(BuildOs, *variables.HostArch, nil, nil, nil, NativeBridgeDisabled)
if variables.HostSecondaryArch != nil && *variables.HostSecondaryArch != "" {
- addTarget(BuildOs, *variables.HostSecondaryArch, nil, nil, nil)
+ addTarget(BuildOs, *variables.HostSecondaryArch, nil, nil, nil, NativeBridgeDisabled)
}
if Bool(config.Host_bionic) {
- addTarget(LinuxBionic, "x86_64", nil, nil, nil)
+ addTarget(LinuxBionic, "x86_64", nil, nil, nil, NativeBridgeDisabled)
}
if String(variables.CrossHost) != "" {
@@ -1420,10 +1446,10 @@
return nil, fmt.Errorf("No cross-host primary architecture set")
}
- addTarget(crossHostOs, *variables.CrossHostArch, nil, nil, nil)
+ addTarget(crossHostOs, *variables.CrossHostArch, nil, nil, nil, NativeBridgeDisabled)
if variables.CrossHostSecondaryArch != nil && *variables.CrossHostSecondaryArch != "" {
- addTarget(crossHostOs, *variables.CrossHostSecondaryArch, nil, nil, nil)
+ addTarget(crossHostOs, *variables.CrossHostSecondaryArch, nil, nil, nil, NativeBridgeDisabled)
}
}
@@ -1434,18 +1460,32 @@
}
addTarget(target, *variables.DeviceArch, variables.DeviceArchVariant,
- variables.DeviceCpuVariant, variables.DeviceAbi)
+ variables.DeviceCpuVariant, variables.DeviceAbi, NativeBridgeDisabled)
if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" {
addTarget(Android, *variables.DeviceSecondaryArch,
variables.DeviceSecondaryArchVariant, variables.DeviceSecondaryCpuVariant,
- variables.DeviceSecondaryAbi)
+ variables.DeviceSecondaryAbi, NativeBridgeDisabled)
deviceArches := targets[Android]
if deviceArches[0].Arch.ArchType.Multilib == deviceArches[1].Arch.ArchType.Multilib {
deviceArches[1].Arch.Native = false
}
}
+
+ if variables.NativeBridgeArch != nil && *variables.NativeBridgeArch != "" {
+ addTarget(Android, *variables.NativeBridgeArch,
+ variables.NativeBridgeArchVariant, variables.NativeBridgeCpuVariant,
+ variables.NativeBridgeAbi, NativeBridgeEnabled)
+ }
+
+ if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" &&
+ variables.NativeBridgeSecondaryArch != nil && *variables.NativeBridgeSecondaryArch != "" {
+ addTarget(Android, *variables.NativeBridgeSecondaryArch,
+ variables.NativeBridgeSecondaryArchVariant,
+ variables.NativeBridgeSecondaryCpuVariant,
+ variables.NativeBridgeSecondaryAbi, NativeBridgeEnabled)
+ }
}
if targetErr != nil {
@@ -1465,10 +1505,10 @@
return false
}
-// hasArmArch returns true if targets has at least arm Android arch
+// hasArmArch returns true if targets has at least non-native_bridge arm Android arch
func hasArmAndroidArch(targets []Target) bool {
for _, target := range targets {
- if target.Os == Android && target.Arch.ArchType == Arm {
+ if target.Os == Android && target.Arch.ArchType == Arm && target.NativeBridge == NativeBridgeDisabled {
return true
}
}
diff --git a/android/config.go b/android/config.go
index ca376db..1507c25 100644
--- a/android/config.go
+++ b/android/config.go
@@ -198,6 +198,14 @@
// TestConfig returns a Config object suitable for using for tests
func TestConfig(buildDir string, env map[string]string) Config {
+ envCopy := make(map[string]string)
+ for k, v := range env {
+ envCopy[k] = v
+ }
+
+ // Copy the real PATH value to the test environment, it's needed by HostSystemTool() used in x86_darwin_host.go
+ envCopy["PATH"] = originalEnv["PATH"]
+
config := &config{
productVariables: productVariables{
DeviceName: stringPtr("test_device"),
@@ -212,7 +220,7 @@
buildDir: buildDir,
captureBuild: true,
- env: env,
+ env: envCopy,
}
config.deviceConfig = &deviceConfig{
config: config,
@@ -226,16 +234,30 @@
return Config{config}
}
+func TestArchConfigNativeBridge(buildDir string, env map[string]string) Config {
+ testConfig := TestArchConfig(buildDir, env)
+ config := testConfig.config
+
+ config.Targets[Android] = []Target{
+ {Android, Arch{ArchType: X86_64, ArchVariant: "silvermont", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled},
+ {Android, Arch{ArchType: X86, ArchVariant: "silvermont", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled},
+ {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeEnabled},
+ {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeEnabled},
+ }
+
+ return testConfig
+}
+
func TestArchConfigFuchsia(buildDir string, env map[string]string) Config {
testConfig := TestConfig(buildDir, env)
config := testConfig.config
config.Targets = map[OsType][]Target{
Fuchsia: []Target{
- {Fuchsia, Arch{ArchType: Arm64, ArchVariant: "", Native: true}},
+ {Fuchsia, Arch{ArchType: Arm64, ArchVariant: "", Native: true}, NativeBridgeDisabled},
},
BuildOs: []Target{
- {BuildOs, Arch{ArchType: X86_64}},
+ {BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled},
},
}
@@ -249,17 +271,25 @@
config.Targets = map[OsType][]Target{
Android: []Target{
- {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}},
- {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}},
+ {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled},
+ {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled},
},
BuildOs: []Target{
- {BuildOs, Arch{ArchType: X86_64}},
- {BuildOs, Arch{ArchType: X86}},
+ {BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled},
+ {BuildOs, Arch{ArchType: X86}, NativeBridgeDisabled},
},
}
+ if runtime.GOOS == "darwin" {
+ config.Targets[BuildOs] = config.Targets[BuildOs][:1]
+ }
+
config.BuildOsVariant = config.Targets[BuildOs][0].String()
config.BuildOsCommonVariant = getCommonTargets(config.Targets[BuildOs])[0].String()
+ config.TestProductVariables.DeviceArch = proptools.StringPtr("arm64")
+ config.TestProductVariables.DeviceArchVariant = proptools.StringPtr("armv8-a")
+ config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm")
+ config.TestProductVariables.DeviceSecondaryArchVariant = proptools.StringPtr("armv7-a-neon")
return testConfig
}
@@ -341,14 +371,14 @@
}
func (c *config) fromEnv() error {
- switch c.Getenv("EXPERIMENTAL_USE_OPENJDK9") {
- case "", "1.8":
- // Nothing, we always use OpenJDK9
+ switch c.Getenv("EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9") {
+ case "":
+ // Nothing, this is the default
case "true":
- // Use OpenJDK9 and target 1.9
+ // Use -source 9 -target 9
c.targetOpenJDK9 = true
default:
- return fmt.Errorf(`Invalid value for EXPERIMENTAL_USE_OPENJDK9, should be "", "1.8", or "true"`)
+ return fmt.Errorf(`Invalid value for EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9, should be "" or "true"`)
}
return nil
@@ -924,6 +954,10 @@
return c.config.productVariables.BoardPlatPrivateSepolicyDirs
}
+func (c *deviceConfig) SepolicyM4Defs() []string {
+ return c.config.productVariables.BoardSepolicyM4Defs
+}
+
func (c *deviceConfig) OverrideManifestPackageNameFor(name string) (manifestName string, overridden bool) {
return findOverrideValue(c.config.productVariables.ManifestPackageNameOverrides, name,
"invalid override rule %q in PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES should be <module_name>:<manifest_name>")
@@ -1056,3 +1090,35 @@
func (c *deviceConfig) TargetFSConfigGen() []string {
return c.config.productVariables.TargetFSConfigGen
}
+
+func (c *config) ProductPublicSepolicyDirs() []string {
+ return c.productVariables.ProductPublicSepolicyDirs
+}
+
+func (c *config) ProductPrivateSepolicyDirs() []string {
+ return c.productVariables.ProductPrivateSepolicyDirs
+}
+
+func (c *config) ProductCompatibleProperty() bool {
+ return Bool(c.productVariables.ProductCompatibleProperty)
+}
+
+func (c *deviceConfig) BoardVndkRuntimeDisable() bool {
+ return Bool(c.config.productVariables.BoardVndkRuntimeDisable)
+}
+
+func (c *deviceConfig) DeviceArch() string {
+ return String(c.config.productVariables.DeviceArch)
+}
+
+func (c *deviceConfig) DeviceArchVariant() string {
+ return String(c.config.productVariables.DeviceArchVariant)
+}
+
+func (c *deviceConfig) DeviceSecondaryArch() string {
+ return String(c.config.productVariables.DeviceSecondaryArch)
+}
+
+func (c *deviceConfig) DeviceSecondaryArchVariant() string {
+ return String(c.config.productVariables.DeviceSecondaryArchVariant)
+}
diff --git a/android/module.go b/android/module.go
index b12f0c1..3906fd7 100644
--- a/android/module.go
+++ b/android/module.go
@@ -143,6 +143,7 @@
OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
+ GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module
GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module
GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
@@ -210,6 +211,33 @@
// emit build rules for this module
Enabled *bool `android:"arch_variant"`
+ // Controls the visibility of this module to other modules. Allowable values are one or more of
+ // these formats:
+ //
+ // ["//visibility:public"]: Anyone can use this module.
+ // ["//visibility:private"]: Only rules in the module's package (not its subpackages) can use
+ // this module.
+ // ["//some/package:__pkg__", "//other/package:__pkg__"]: Only modules in some/package and
+ // other/package (defined in some/package/*.bp and other/package/*.bp) have access to
+ // this module. Note that sub-packages do not have access to the rule; for example,
+ // //some/package/foo:bar or //other/package/testing:bla wouldn't have access. __pkg__
+ // is a special module and must be used verbatim. It represents all of the modules in the
+ // package.
+ // ["//project:__subpackages__", "//other:__subpackages__"]: Only modules in packages project
+ // or other or in one of their sub-packages have access to this module. For example,
+ // //project:rule, //project/library:lib or //other/testing/internal:munge are allowed
+ // to depend on this rule (but not //independent:evil)
+ // ["//project"]: This is shorthand for ["//project:__pkg__"]
+ // [":__subpackages__"]: This is shorthand for ["//project:__subpackages__"] where
+ // //project is the module's package. e.g. using [":__subpackages__"] in
+ // packages/apps/Settings/Android.bp is equivalent to
+ // //packages/apps/Settings:__subpackages__.
+ // ["//visibility:legacy_public"]: The default visibility, behaves as //visibility:public
+ // for now. It is an error if it is used in a module.
+ // See https://android.googlesource.com/platform/build/soong/+/master/README.md#visibility for
+ // more details.
+ Visibility []string
+
// control whether this module compiles for 32-bit, 64-bit, or both. Possible values
// are "32" (compile for 32-bit only), "64" (compile for 64-bit only), "both" (compile for both
// architectures), or "first" (compile for 64-bit on a 64-bit platform, and 32-bit on a 32-bit
@@ -262,6 +290,9 @@
// Whether this module is installed to recovery partition
Recovery *bool
+ // Whether this module is built for non-native architecures (also known as native bridge binary)
+ Native_bridge_supported *bool `android:"arch_variant"`
+
// init.rc files to be installed if this module is installed
Init_rc []string `android:"path"`
@@ -1066,6 +1097,18 @@
}
}
+func (a *androidModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module {
+ var deps []Module
+ a.VisitDirectDepsBlueprint(func(m blueprint.Module) {
+ if aModule, _ := m.(Module); aModule != nil {
+ if a.ModuleContext.OtherModuleDependencyTag(aModule) == tag {
+ deps = append(deps, aModule)
+ }
+ }
+ })
+ return deps
+}
+
func (a *androidModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
m, _ := a.getDirectDepInternal(name, tag)
return m
@@ -1256,6 +1299,10 @@
a.commonProperties.Product_services_specific = boolPtr(false)
}
+func (a *ModuleBase) EnableNativeBridgeSupportByDefault() {
+ a.commonProperties.Native_bridge_supported = boolPtr(true)
+}
+
func (a *androidModuleContext) InstallInData() bool {
return a.module.InstallInData()
}
diff --git a/android/mutator.go b/android/mutator.go
index 5ce743a..085c055 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -77,7 +77,7 @@
RegisterNamespaceMutator,
RegisterPrebuiltsPreArchMutators,
RegisterDefaultsPreArchMutators,
- RegisterOverridePreArchMutators,
+ registerVisibilityRuleGatherer,
}
func registerArchMutator(ctx RegisterMutatorsContext) {
@@ -92,7 +92,9 @@
var postDeps = []RegisterMutatorFunc{
registerPathDepsMutator,
RegisterPrebuiltsPostDepsMutators,
+ registerVisibilityRuleEnforcer,
registerNeverallowMutator,
+ RegisterOverridePostDepsMutators,
}
func PreArchMutators(f RegisterMutatorFunc) {
@@ -118,6 +120,7 @@
Module() Module
OtherModuleName(m blueprint.Module) string
+ OtherModuleDir(m blueprint.Module) string
OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
diff --git a/android/namespace.go b/android/namespace.go
index 50bdcba..78d7f3c 100644
--- a/android/namespace.go
+++ b/android/namespace.go
@@ -26,12 +26,6 @@
"github.com/google/blueprint"
)
-// This file implements namespaces
-const (
- namespacePrefix = "//"
- modulePrefix = ":"
-)
-
func init() {
RegisterModuleType("soong_namespace", NamespaceFactory)
}
@@ -215,11 +209,11 @@
// parses a fully-qualified path (like "//namespace_path:module_name") into a namespace name and a
// module name
func (r *NameResolver) parseFullyQualifiedName(name string) (namespaceName string, moduleName string, ok bool) {
- if !strings.HasPrefix(name, namespacePrefix) {
+ if !strings.HasPrefix(name, "//") {
return "", "", false
}
- name = strings.TrimPrefix(name, namespacePrefix)
- components := strings.Split(name, modulePrefix)
+ name = strings.TrimPrefix(name, "//")
+ components := strings.Split(name, ":")
if len(components) != 2 {
return "", "", false
}
diff --git a/android/neverallow.go b/android/neverallow.go
index fba43b3..9314483 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -97,32 +97,15 @@
"external/wycheproof",
}
- var coreModules = []string{
- "core-all",
- "core-oj",
- "core-libart",
- "okhttp",
- "bouncycastle",
- "conscrypt",
- "apache-xml",
- }
-
- // Core library constraints. Prevent targets adding dependencies on core
- // library internals, which could lead to compatibility issues with the ART
- // mainline module. They should use core.platform.api.stubs instead.
+ // Core library constraints. The no_standard_libs can only be used in core
+ // library projects. Access to core library targets is restricted using
+ // visibility rules.
rules := []*rule{
neverallow().
notIn(append(coreLibraryProjects, "development")...).
with("no_standard_libs", "true"),
}
- for _, m := range coreModules {
- r := neverallow().
- notIn(coreLibraryProjects...).
- with("libs", m).
- because("Only core libraries projects can depend on " + m)
- rules = append(rules, r)
- }
return rules
}
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index d55ca57..00c51ea 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -138,17 +138,6 @@
expectedError: "",
},
{
- name: "dependency on core-libart",
- fs: map[string][]byte{
- "Blueprints": []byte(`
- java_library {
- name: "needs_core_libart",
- libs: ["core-libart"],
- }`),
- },
- expectedError: "Only core libraries projects can depend on core-libart",
- },
- {
name: "java_device_for_host",
fs: map[string][]byte{
"Blueprints": []byte(`
diff --git a/android/onceper.go b/android/onceper.go
index 5ad17fa..ff865c2 100644
--- a/android/onceper.go
+++ b/android/onceper.go
@@ -40,7 +40,8 @@
}
// Once computes a value the first time it is called with a given key per OncePer, and returns the
-// value without recomputing when called with the same key. key must be hashable.
+// value without recomputing when called with the same key. key must be hashable. If value panics
+// the panic will be propagated but the next call to Once with the same key will return nil.
func (once *OncePer) Once(key OnceKey, value func() interface{}) interface{} {
// Fast path: check if the key is already in the map
if v, ok := once.values.Load(key); ok {
@@ -54,10 +55,15 @@
return once.maybeWaitFor(key, v)
}
- // The waiter is inserted, call the value constructor, store it, and signal the waiter
- v := value()
- once.values.Store(key, v)
- close(waiter)
+ // The waiter is inserted, call the value constructor, store it, and signal the waiter. Use defer in case
+ // the function panics.
+ var v interface{}
+ defer func() {
+ once.values.Store(key, v)
+ close(waiter)
+ }()
+
+ v = value()
return v
}
diff --git a/android/onceper_test.go b/android/onceper_test.go
index 95303ba..1a55ff4 100644
--- a/android/onceper_test.go
+++ b/android/onceper_test.go
@@ -175,3 +175,43 @@
t.Errorf(`reentrant Once should return "a": %q`, a)
}
}
+
+// Test that a recovered panic in a Once function doesn't deadlock
+func TestOncePerPanic(t *testing.T) {
+ once := OncePer{}
+ key := NewOnceKey("key")
+
+ ch := make(chan interface{})
+
+ var a interface{}
+
+ go func() {
+ defer func() {
+ ch <- recover()
+ }()
+
+ a = once.Once(key, func() interface{} {
+ panic("foo")
+ })
+ }()
+
+ p := <-ch
+
+ if p.(string) != "foo" {
+ t.Errorf(`expected panic with "foo", got %#v`, p)
+ }
+
+ if a != nil {
+ t.Errorf(`expected a to be nil, got %#v`, a)
+ }
+
+ // If the call to Once that panicked leaves the key in a bad state this will deadlock
+ b := once.Once(key, func() interface{} {
+ return "bar"
+ })
+
+ // The second call to Once should return nil inserted by the first call that panicked.
+ if b != nil {
+ t.Errorf(`expected b to be nil, got %#v`, b)
+ }
+}
diff --git a/android/override_module.go b/android/override_module.go
index 119bca1..5a57c93 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -84,8 +84,13 @@
getOverrides() []OverrideModule
override(ctx BaseModuleContext, o OverrideModule)
+ getOverriddenBy() string
setOverridesProperty(overridesProperties *[]string)
+
+ // Due to complications with incoming dependencies, overrides are processed after DepsMutator.
+ // So, overridable properties need to be handled in a separate, dedicated deps mutator.
+ OverridablePropertiesDepsMutator(ctx BottomUpMutatorContext)
}
// Base module struct for overridable module types
@@ -106,6 +111,8 @@
// set this to a pointer to the property through the InitOverridableModule function, so that
// override information is propagated and aggregated correctly.
overridesProperty *[]string
+
+ overriddenBy string
}
func InitOverridableModule(m OverridableModule, overridesProperty *[]string) {
@@ -153,14 +160,23 @@
}
}
}
+ b.overriddenBy = o.Name()
+}
+
+func (b *OverridableModuleBase) getOverriddenBy() string {
+ return b.overriddenBy
+}
+
+func (b *OverridableModuleBase) OverridablePropertiesDepsMutator(ctx BottomUpMutatorContext) {
}
// Mutators for override/overridable modules. All the fun happens in these functions. It is critical
// to keep them in this order and not put any order mutators between them.
-func RegisterOverridePreArchMutators(ctx RegisterMutatorsContext) {
+func RegisterOverridePostDepsMutators(ctx RegisterMutatorsContext) {
ctx.BottomUp("override_deps", overrideModuleDepsMutator).Parallel()
ctx.TopDown("register_override", registerOverrideMutator).Parallel()
ctx.BottomUp("perform_override", performOverrideMutator).Parallel()
+ ctx.BottomUp("overridable_deps", overridableModuleDepsMutator).Parallel()
}
type overrideBaseDependencyTag struct {
@@ -207,5 +223,22 @@
for i, o := range overrides {
mods[i+1].(OverridableModule).override(ctx, o)
}
+ } else if o, ok := ctx.Module().(OverrideModule); ok {
+ // Create a variant of the overriding module with its own name. This matches the above local
+ // variant name rule for overridden modules, and thus allows ReplaceDependencies to match the
+ // two.
+ ctx.CreateLocalVariations(o.Name())
+ }
+}
+
+func overridableModuleDepsMutator(ctx BottomUpMutatorContext) {
+ if b, ok := ctx.Module().(OverridableModule); ok {
+ if o := b.getOverriddenBy(); o != "" {
+ // Redirect dependencies on the overriding module to this overridden module. Overriding
+ // modules are basically pseudo modules, and all build actions are associated to overridden
+ // modules. Therefore, dependencies on overriding modules need to be forwarded there as well.
+ ctx.ReplaceDependencies(o)
+ }
+ b.OverridablePropertiesDepsMutator(ctx)
}
}
diff --git a/android/paths.go b/android/paths.go
index 0f20b84..da387a8 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -967,7 +967,7 @@
// PathForVndkRefAbiDump returns an OptionalPath representing the path of the
// reference abi dump for the given module. This is not guaranteed to be valid.
func PathForVndkRefAbiDump(ctx ModuleContext, version, fileName string,
- isLlndk, isGzip bool) OptionalPath {
+ isLlndkOrNdk, isVndk, isGzip bool) OptionalPath {
arches := ctx.DeviceConfig().Arches()
if len(arches) == 0 {
@@ -980,10 +980,12 @@
}
var dirName string
- if isLlndk {
+ if isLlndkOrNdk {
dirName = "ndk"
- } else {
+ } else if isVndk {
dirName = "vndk"
+ } else {
+ dirName = "platform" // opt-in libs
}
binderBitness := ctx.DeviceConfig().BinderBitness()
diff --git a/android/prebuilt.go b/android/prebuilt.go
index df25a89..5087b18 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -50,6 +50,11 @@
return "prebuilt_" + name
}
+// The below source-related functions and the srcs, src fields are based on an assumption that
+// prebuilt modules have a static source property at the moment. Currently there is only one
+// exception, android_app_import, which chooses a source file depending on the product's DPI
+// preference configs. We'll want to add native support for dynamic source cases if we end up having
+// more modules like this.
func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path {
if p.srcs != nil {
if len(*p.srcs) == 0 {
@@ -74,6 +79,10 @@
}
}
+func (p *Prebuilt) UsePrebuilt() bool {
+ return p.properties.UsePrebuilt
+}
+
func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
p := module.Prebuilt()
module.AddProperties(&p.properties)
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index 3cadaeb..b13ce2a 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -14,10 +14,7 @@
package android
-import (
- "fmt"
- "io"
-)
+import "strconv"
// TODO(jungw): Now that it handles more than the ones in etc/, consider renaming this file.
@@ -26,6 +23,7 @@
RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory)
RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory)
RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
+ RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
PreDepsMutators(func(ctx RegisterMutatorsContext) {
ctx.BottomUp("prebuilt_etc", prebuiltEtcMutator).Parallel()
@@ -134,37 +132,25 @@
})
}
-func (p *PrebuiltEtc) AndroidMk() AndroidMkData {
- return AndroidMkData{
- Custom: func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) {
- nameSuffix := ""
- if p.inRecovery() && !p.onlyInRecovery() {
- nameSuffix = ".recovery"
- }
- fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
- fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
- fmt.Fprintln(w, "LOCAL_MODULE :=", name+nameSuffix)
- fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
- if p.commonProperties.Owner != nil {
- fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", *p.commonProperties.Owner)
- }
- fmt.Fprintln(w, "LOCAL_MODULE_TAGS := optional")
- if p.Host() {
- fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
- }
- fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", p.outputFilePath.String())
- fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
- fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", p.outputFilePath.Base())
- fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !p.Installable())
- WriteRequiredModulesSettings(w, data)
+func (p *PrebuiltEtc) AndroidMkEntries() AndroidMkEntries {
+ nameSuffix := ""
+ if p.inRecovery() && !p.onlyInRecovery() {
+ nameSuffix = ".recovery"
+ }
+ return AndroidMkEntries{
+ Class: "ETC",
+ SubName: nameSuffix,
+ OutputFile: OptionalPathForPath(p.outputFilePath),
+ AddCustomEntries: func(name, prefix, moduleDir string, entries *AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_TAGS", "optional")
+ entries.SetString("LOCAL_MODULE_PATH", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
+ entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
+ entries.SetString("LOCAL_UNINSTALLABLE_MODULE", strconv.FormatBool(!p.Installable()))
if p.additionalDependencies != nil {
- fmt.Fprint(w, "LOCAL_ADDITIONAL_DEPENDENCIES :=")
for _, path := range *p.additionalDependencies {
- fmt.Fprint(w, " "+path.String())
+ entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", path.String())
}
- fmt.Fprintln(w, "")
}
- fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
},
}
}
@@ -255,3 +241,12 @@
}
}
}
+
+// prebuilt_font installs a font in <partition>/fonts directory.
+func PrebuiltFontFactory() Module {
+ module := &PrebuiltEtc{installDirBase: "fonts"}
+ InitPrebuiltEtcModule(module)
+ // This module is device-only
+ InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
+ return module
+}
diff --git a/android/prebuilt_etc_test.go b/android/prebuilt_etc_test.go
index fbdbc97..a5c4480 100644
--- a/android/prebuilt_etc_test.go
+++ b/android/prebuilt_etc_test.go
@@ -15,12 +15,10 @@
package android
import (
- "bufio"
- "bytes"
"io/ioutil"
"os"
"path/filepath"
- "strings"
+ "reflect"
"testing"
)
@@ -32,6 +30,7 @@
ctx.RegisterModuleType("prebuilt_etc_host", ModuleFactoryAdaptor(PrebuiltEtcHostFactory))
ctx.RegisterModuleType("prebuilt_usr_share", ModuleFactoryAdaptor(PrebuiltUserShareFactory))
ctx.RegisterModuleType("prebuilt_usr_share_host", ModuleFactoryAdaptor(PrebuiltUserShareHostFactory))
+ ctx.RegisterModuleType("prebuilt_font", ModuleFactoryAdaptor(PrebuiltFontFactory))
ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
ctx.BottomUp("prebuilt_etc", prebuiltEtcMutator).Parallel()
})
@@ -139,49 +138,37 @@
}
func TestPrebuiltEtcAndroidMk(t *testing.T) {
- ctx, _ := testPrebuiltEtc(t, `
+ ctx, config := testPrebuiltEtc(t, `
prebuilt_etc {
name: "foo",
src: "foo.conf",
owner: "abc",
filename_from_src: true,
+ required: ["modA", "moduleB"],
+ host_required: ["hostModA", "hostModB"],
+ target_required: ["targetModA"],
}
`)
- data := AndroidMkData{}
- data.Required = append(data.Required, "modA", "moduleB")
- data.Host_required = append(data.Host_required, "hostModA", "hostModB")
- data.Target_required = append(data.Target_required, "targetModA")
-
- expected := map[string]string{
- "LOCAL_MODULE": "foo",
- "LOCAL_MODULE_CLASS": "ETC",
- "LOCAL_MODULE_OWNER": "abc",
- "LOCAL_INSTALLED_MODULE_STEM": "foo.conf",
- "LOCAL_REQUIRED_MODULES": "modA moduleB",
- "LOCAL_HOST_REQUIRED_MODULES": "hostModA hostModB",
- "LOCAL_TARGET_REQUIRED_MODULES": "targetModA",
+ expected := map[string][]string{
+ "LOCAL_MODULE": {"foo"},
+ "LOCAL_MODULE_CLASS": {"ETC"},
+ "LOCAL_MODULE_OWNER": {"abc"},
+ "LOCAL_INSTALLED_MODULE_STEM": {"foo.conf"},
+ "LOCAL_REQUIRED_MODULES": {"modA", "moduleB"},
+ "LOCAL_HOST_REQUIRED_MODULES": {"hostModA", "hostModB"},
+ "LOCAL_TARGET_REQUIRED_MODULES": {"targetModA"},
}
mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a_core").Module().(*PrebuiltEtc)
- buf := &bytes.Buffer{}
- mod.AndroidMk().Custom(buf, "foo", "", "", data)
- for k, expected := range expected {
- found := false
- scanner := bufio.NewScanner(bytes.NewReader(buf.Bytes()))
- for scanner.Scan() {
- line := scanner.Text()
- tok := strings.Split(line, " := ")
- if tok[0] == k {
- found = true
- if tok[1] != expected {
- t.Errorf("Incorrect %s '%s', expected '%s'", k, tok[1], expected)
- }
+ entries := AndroidMkEntriesForTest(t, config, "", mod)
+ for k, expectedValue := range expected {
+ if value, ok := entries.EntryMap[k]; ok {
+ if !reflect.DeepEqual(value, expectedValue) {
+ t.Errorf("Incorrect %s '%s', expected '%s'", k, value, expectedValue)
}
- }
-
- if !found {
- t.Errorf("No %s defined, saw %s", k, buf.String())
+ } else {
+ t.Errorf("No %s defined, saw %q", k, entries.EntryMap)
}
}
}
@@ -233,3 +220,18 @@
t.Errorf("expected %q, got %q", expected, p.installDirPath.RelPathString())
}
}
+
+func TestPrebuiltFontInstallDirPath(t *testing.T) {
+ ctx, _ := testPrebuiltEtc(t, `
+ prebuilt_font {
+ name: "foo.conf",
+ src: "foo.conf",
+ }
+ `)
+
+ p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a_core").Module().(*PrebuiltEtc)
+ expected := "target/product/test_device/system/fonts"
+ if p.installDirPath.RelPathString() != expected {
+ t.Errorf("expected %q, got %q", expected, p.installDirPath.RelPathString())
+ }
+}
diff --git a/android/testing.go b/android/testing.go
index aee6855..c0db75e 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -371,3 +371,14 @@
}
}
}
+
+func AndroidMkEntriesForTest(t *testing.T, config Config, bpPath string, mod blueprint.Module) AndroidMkEntries {
+ var p AndroidMkEntriesProvider
+ var ok bool
+ if p, ok = mod.(AndroidMkEntriesProvider); !ok {
+ t.Errorf("module does not implmement AndroidMkEntriesProvider: " + mod.Name())
+ }
+ entries := p.AndroidMkEntries()
+ entries.fillInEntries(config, bpPath, mod)
+ return entries
+}
diff --git a/android/util.go b/android/util.go
index f9dce6f..f7a3437 100644
--- a/android/util.go
+++ b/android/util.go
@@ -52,6 +52,31 @@
return string(ret)
}
+func JoinWithSuffix(strs []string, suffix string, separator string) string {
+ if len(strs) == 0 {
+ return ""
+ }
+
+ if len(strs) == 1 {
+ return strs[0] + suffix
+ }
+
+ n := len(" ") * (len(strs) - 1)
+ for _, s := range strs {
+ n += len(suffix) + len(s)
+ }
+
+ ret := make([]byte, 0, n)
+ for i, s := range strs {
+ if i != 0 {
+ ret = append(ret, separator...)
+ }
+ ret = append(ret, s...)
+ ret = append(ret, suffix...)
+ }
+ return string(ret)
+}
+
func sortedKeys(m map[string][]string) []string {
s := make([]string, 0, len(m))
for k := range m {
diff --git a/android/variable.go b/android/variable.go
index f3da66d..ff3ebaf 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -165,6 +165,16 @@
DeviceSecondaryCpuVariant *string `json:",omitempty"`
DeviceSecondaryAbi []string `json:",omitempty"`
+ NativeBridgeArch *string `json:",omitempty"`
+ NativeBridgeArchVariant *string `json:",omitempty"`
+ NativeBridgeCpuVariant *string `json:",omitempty"`
+ NativeBridgeAbi []string `json:",omitempty"`
+
+ NativeBridgeSecondaryArch *string `json:",omitempty"`
+ NativeBridgeSecondaryArchVariant *string `json:",omitempty"`
+ NativeBridgeSecondaryCpuVariant *string `json:",omitempty"`
+ NativeBridgeSecondaryAbi []string `json:",omitempty"`
+
HostArch *string `json:",omitempty"`
HostSecondaryArch *string `json:",omitempty"`
@@ -267,6 +277,9 @@
BoardOdmSepolicyDirs []string `json:",omitempty"`
BoardPlatPublicSepolicyDirs []string `json:",omitempty"`
BoardPlatPrivateSepolicyDirs []string `json:",omitempty"`
+ BoardSepolicyM4Defs []string `json:",omitempty"`
+
+ BoardVndkRuntimeDisable *bool `json:",omitempty"`
VendorVars map[string]map[string]string `json:",omitempty"`
@@ -288,6 +301,10 @@
ProductHiddenAPIStubsSystem []string `json:",omitempty"`
ProductHiddenAPIStubsTest []string `json:",omitempty"`
+ ProductPublicSepolicyDirs []string `json:",omitempty"`
+ ProductPrivateSepolicyDirs []string `json:",omitempty"`
+ ProductCompatibleProperty *bool `json:",omitempty"`
+
TargetFSConfigGen []string `json:",omitempty"`
}
diff --git a/android/visibility.go b/android/visibility.go
new file mode 100644
index 0000000..36b6f35
--- /dev/null
+++ b/android/visibility.go
@@ -0,0 +1,313 @@
+// 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 android
+
+import (
+ "fmt"
+ "regexp"
+ "strings"
+ "sync"
+)
+
+// Enforces visibility rules between modules.
+//
+// Two stage process:
+// * First stage works bottom up to extract visibility information from the modules, parse it,
+// create visibilityRule structures and store them in a map keyed by the module's
+// qualifiedModuleName instance, i.e. //<pkg>:<name>. The map is stored in the context rather
+// than a global variable for testing. Each test has its own Config so they do not share a map
+// and so can be run in parallel.
+//
+// * Second stage works top down and iterates over all the deps for each module. If the dep is in
+// the same package then it is automatically visible. Otherwise, for each dep it first extracts
+// its visibilityRule from the config map. If one could not be found then it assumes that it is
+// publicly visible. Otherwise, it calls the visibility rule to check that the module can see
+// the dependency. If it cannot then an error is reported.
+//
+// TODO(b/130631145) - Make visibility work properly with prebuilts.
+// TODO(b/130796911) - Make visibility work properly with defaults.
+
+// Patterns for the values that can be specified in visibility property.
+const (
+ packagePattern = `//([^/:]+(?:/[^/:]+)*)`
+ namePattern = `:([^/:]+)`
+ visibilityRulePattern = `^(?:` + packagePattern + `)?(?:` + namePattern + `)?$`
+)
+
+var visibilityRuleRegexp = regexp.MustCompile(visibilityRulePattern)
+
+// Qualified id for a module
+type qualifiedModuleName struct {
+ // The package (i.e. directory) in which the module is defined, without trailing /
+ pkg string
+
+ // The name of the module.
+ name string
+}
+
+func (q qualifiedModuleName) String() string {
+ return fmt.Sprintf("//%s:%s", q.pkg, q.name)
+}
+
+// A visibility rule is associated with a module and determines which other modules it is visible
+// to, i.e. which other modules can depend on the rule's module.
+type visibilityRule interface {
+ // Check to see whether this rules matches m.
+ // Returns true if it does, false otherwise.
+ matches(m qualifiedModuleName) bool
+
+ String() string
+}
+
+// A compositeRule is a visibility rule composed from other visibility rules.
+// This array will only be [] if all the rules are invalid and will behave as if visibility was
+// ["//visibility:private"].
+type compositeRule []visibilityRule
+
+// A compositeRule matches if and only if any of its rules matches.
+func (c compositeRule) matches(m qualifiedModuleName) bool {
+ for _, r := range c {
+ if r.matches(m) {
+ return true
+ }
+ }
+ return false
+}
+
+func (r compositeRule) String() string {
+ s := make([]string, 0, len(r))
+ for _, r := range r {
+ s = append(s, r.String())
+ }
+
+ return "[" + strings.Join(s, ", ") + "]"
+}
+
+// A packageRule is a visibility rule that matches modules in a specific package (i.e. directory).
+type packageRule struct {
+ pkg string
+}
+
+func (r packageRule) matches(m qualifiedModuleName) bool {
+ return m.pkg == r.pkg
+}
+
+func (r packageRule) String() string {
+ return fmt.Sprintf("//%s:__pkg__", r.pkg)
+}
+
+// A subpackagesRule is a visibility rule that matches modules in a specific package (i.e.
+// directory) or any of its subpackages (i.e. subdirectories).
+type subpackagesRule struct {
+ pkgPrefix string
+}
+
+func (r subpackagesRule) matches(m qualifiedModuleName) bool {
+ return isAncestor(r.pkgPrefix, m.pkg)
+}
+
+func isAncestor(p1 string, p2 string) bool {
+ return strings.HasPrefix(p2+"/", p1+"/")
+}
+
+func (r subpackagesRule) String() string {
+ return fmt.Sprintf("//%s:__subpackages__", r.pkgPrefix)
+}
+
+var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
+
+// The map from qualifiedModuleName to visibilityRule.
+func moduleToVisibilityRuleMap(ctx BaseModuleContext) *sync.Map {
+ return ctx.Config().Once(visibilityRuleMap, func() interface{} {
+ return &sync.Map{}
+ }).(*sync.Map)
+}
+
+// Visibility is not dependent on arch so this must be registered before the arch phase to avoid
+// having to process multiple variants for each module.
+func registerVisibilityRuleGatherer(ctx RegisterMutatorsContext) {
+ ctx.BottomUp("visibilityRuleGatherer", visibilityRuleGatherer).Parallel()
+}
+
+// This must be registered after the deps have been resolved.
+func registerVisibilityRuleEnforcer(ctx RegisterMutatorsContext) {
+ ctx.TopDown("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel()
+}
+
+// Gathers the visibility rules, parses the visibility properties, stores them in a map by
+// qualifiedModuleName for retrieval during enforcement.
+//
+// See ../README.md#Visibility for information on the format of the visibility rules.
+
+func visibilityRuleGatherer(ctx BottomUpMutatorContext) {
+ m, ok := ctx.Module().(Module)
+ if !ok {
+ return
+ }
+
+ qualified := createQualifiedModuleName(ctx)
+
+ visibility := m.base().commonProperties.Visibility
+ if visibility != nil {
+ rule := parseRules(ctx, qualified.pkg, visibility)
+ if rule != nil {
+ moduleToVisibilityRuleMap(ctx).Store(qualified, rule)
+ }
+ }
+}
+
+func parseRules(ctx BottomUpMutatorContext, currentPkg string, visibility []string) compositeRule {
+ ruleCount := len(visibility)
+ if ruleCount == 0 {
+ // This prohibits an empty list as its meaning is unclear, e.g. it could mean no visibility and
+ // it could mean public visibility. Requiring at least one rule makes the owner's intent
+ // clearer.
+ ctx.PropertyErrorf("visibility", "must contain at least one visibility rule")
+ return nil
+ }
+
+ rules := make(compositeRule, 0, ruleCount)
+ for _, v := range visibility {
+ ok, pkg, name := splitRule(ctx, v, currentPkg)
+ if !ok {
+ // Visibility rule is invalid so ignore it. Keep going rather than aborting straight away to
+ // ensure all the rules on this module are checked.
+ ctx.PropertyErrorf("visibility",
+ "invalid visibility pattern %q must match"+
+ " //<package>:<module>, //<package> or :<module>",
+ v)
+ continue
+ }
+
+ if pkg == "visibility" {
+ if ruleCount != 1 {
+ ctx.PropertyErrorf("visibility", "cannot mix %q with any other visibility rules", v)
+ continue
+ }
+ switch name {
+ case "private":
+ rules = append(rules, packageRule{currentPkg})
+ continue
+ case "public":
+ return nil
+ case "legacy_public":
+ ctx.PropertyErrorf("visibility", "//visibility:legacy_public must not be used")
+ return nil
+ default:
+ ctx.PropertyErrorf("visibility", "unrecognized visibility rule %q", v)
+ continue
+ }
+ }
+
+ // If the current directory is not in the vendor tree then there are some additional
+ // restrictions on the rules.
+ if !isAncestor("vendor", currentPkg) {
+ if !isAllowedFromOutsideVendor(pkg, name) {
+ ctx.PropertyErrorf("visibility",
+ "%q is not allowed. Packages outside //vendor cannot make themselves visible to specific"+
+ " targets within //vendor, they can only use //vendor:__subpackages__.", v)
+ continue
+ }
+ }
+
+ // Create the rule
+ var r visibilityRule
+ switch name {
+ case "__pkg__":
+ r = packageRule{pkg}
+ case "__subpackages__":
+ r = subpackagesRule{pkg}
+ default:
+ ctx.PropertyErrorf("visibility", "unrecognized visibility rule %q", v)
+ continue
+ }
+
+ rules = append(rules, r)
+ }
+
+ return rules
+}
+
+func isAllowedFromOutsideVendor(pkg string, name string) bool {
+ if pkg == "vendor" {
+ if name == "__subpackages__" {
+ return true
+ }
+ return false
+ }
+
+ return !isAncestor("vendor", pkg)
+}
+
+func splitRule(ctx BaseModuleContext, ruleExpression string, currentPkg string) (bool, string, string) {
+ // Make sure that the rule is of the correct format.
+ matches := visibilityRuleRegexp.FindStringSubmatch(ruleExpression)
+ if ruleExpression == "" || matches == nil {
+ return false, "", ""
+ }
+
+ // Extract the package and name.
+ pkg := matches[1]
+ name := matches[2]
+
+ // Normalize the short hands
+ if pkg == "" {
+ pkg = currentPkg
+ }
+ if name == "" {
+ name = "__pkg__"
+ }
+
+ return true, pkg, name
+}
+
+func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
+ _, ok := ctx.Module().(Module)
+ if !ok {
+ return
+ }
+
+ qualified := createQualifiedModuleName(ctx)
+
+ moduleToVisibilityRule := moduleToVisibilityRuleMap(ctx)
+
+ // Visit all the dependencies making sure that this module has access to them all.
+ ctx.VisitDirectDeps(func(dep Module) {
+ depName := ctx.OtherModuleName(dep)
+ depDir := ctx.OtherModuleDir(dep)
+ depQualified := qualifiedModuleName{depDir, depName}
+
+ // Targets are always visible to other targets in their own package.
+ if depQualified.pkg == qualified.pkg {
+ return
+ }
+
+ rule, ok := moduleToVisibilityRule.Load(depQualified)
+ if ok {
+ if !rule.(compositeRule).matches(qualified) {
+ ctx.ModuleErrorf(
+ "depends on %s which is not visible to this module; %s is only visible to %s",
+ depQualified, depQualified, rule)
+ }
+ }
+ })
+}
+
+func createQualifiedModuleName(ctx BaseModuleContext) qualifiedModuleName {
+ moduleName := ctx.ModuleName()
+ dir := ctx.ModuleDir()
+ qualified := qualifiedModuleName{dir, moduleName}
+ return qualified
+}
diff --git a/android/visibility_test.go b/android/visibility_test.go
new file mode 100644
index 0000000..ea5316c
--- /dev/null
+++ b/android/visibility_test.go
@@ -0,0 +1,489 @@
+package android
+
+import (
+ "io/ioutil"
+ "os"
+ "testing"
+
+ "github.com/google/blueprint"
+)
+
+var visibilityTests = []struct {
+ name string
+ fs map[string][]byte
+ expectedErrors []string
+}{
+ {
+ name: "invalid visibility: empty list",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: [],
+ }`),
+ },
+ expectedErrors: []string{`visibility: must contain at least one visibility rule`},
+ },
+ {
+ name: "invalid visibility: empty rule",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: [""],
+ }`),
+ },
+ expectedErrors: []string{`visibility: invalid visibility pattern ""`},
+ },
+ {
+ name: "invalid visibility: unqualified",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["target"],
+ }`),
+ },
+ expectedErrors: []string{`visibility: invalid visibility pattern "target"`},
+ },
+ {
+ name: "invalid visibility: empty namespace",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["//"],
+ }`),
+ },
+ expectedErrors: []string{`visibility: invalid visibility pattern "//"`},
+ },
+ {
+ name: "invalid visibility: empty module",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: [":"],
+ }`),
+ },
+ expectedErrors: []string{`visibility: invalid visibility pattern ":"`},
+ },
+ {
+ name: "invalid visibility: empty namespace and module",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["//:"],
+ }`),
+ },
+ expectedErrors: []string{`visibility: invalid visibility pattern "//:"`},
+ },
+ {
+ name: "//visibility:unknown",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["//visibility:unknown"],
+ }`),
+ },
+ expectedErrors: []string{`unrecognized visibility rule "//visibility:unknown"`},
+ },
+ {
+ name: "//visibility:public mixed",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["//visibility:public", "//namespace"],
+ }
+
+ mock_library {
+ name: "libother",
+ visibility: ["//visibility:private", "//namespace"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "libother" variant "android_common": visibility: cannot mix "//visibility:private"` +
+ ` with any other visibility rules`,
+ `module "libexample" variant "android_common": visibility: cannot mix` +
+ ` "//visibility:public" with any other visibility rules`,
+ },
+ },
+ {
+ name: "//visibility:legacy_public",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["//visibility:legacy_public"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "libexample" variant "android_common": visibility: //visibility:legacy_public must` +
+ ` not be used`,
+ },
+ },
+ {
+ // Verify that //visibility:public will allow the module to be referenced from anywhere, e.g.
+ // the current directory, a nested directory and a directory in a separate tree.
+ name: "//visibility:public",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["//visibility:public"],
+ }
+
+ mock_library {
+ name: "libsamepackage",
+ deps: ["libexample"],
+ }`),
+ "top/nested/Blueprints": []byte(`
+ mock_library {
+ name: "libnested",
+ deps: ["libexample"],
+ }`),
+ "other/Blueprints": []byte(`
+ mock_library {
+ name: "libother",
+ deps: ["libexample"],
+ }`),
+ },
+ },
+ {
+ // Verify that //visibility:public will allow the module to be referenced from anywhere, e.g.
+ // the current directory, a nested directory and a directory in a separate tree.
+ name: "//visibility:public",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["//visibility:public"],
+ }
+
+ mock_library {
+ name: "libsamepackage",
+ deps: ["libexample"],
+ }`),
+ "top/nested/Blueprints": []byte(`
+ mock_library {
+ name: "libnested",
+ deps: ["libexample"],
+ }`),
+ "other/Blueprints": []byte(`
+ mock_library {
+ name: "libother",
+ deps: ["libexample"],
+ }`),
+ },
+ },
+ {
+ // Verify that //visibility:private allows the module to be referenced from the current
+ // directory only.
+ name: "//visibility:private",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["//visibility:private"],
+ }
+
+ mock_library {
+ name: "libsamepackage",
+ deps: ["libexample"],
+ }`),
+ "top/nested/Blueprints": []byte(`
+ mock_library {
+ name: "libnested",
+ deps: ["libexample"],
+ }`),
+ "other/Blueprints": []byte(`
+ mock_library {
+ name: "libother",
+ deps: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "libnested" variant "android_common": depends on //top:libexample which is not` +
+ ` visible to this module; //top:libexample is only visible to \[//top:__pkg__\]`,
+ `module "libother" variant "android_common": depends on //top:libexample which is not` +
+ ` visible to this module; //top:libexample is only visible to \[//top:__pkg__\]`,
+ },
+ },
+ {
+ // Verify that :__pkg__ allows the module to be referenced from the current directory only.
+ name: ":__pkg__",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: [":__pkg__"],
+ }
+
+ mock_library {
+ name: "libsamepackage",
+ deps: ["libexample"],
+ }`),
+ "top/nested/Blueprints": []byte(`
+ mock_library {
+ name: "libnested",
+ deps: ["libexample"],
+ }`),
+ "other/Blueprints": []byte(`
+ mock_library {
+ name: "libother",
+ deps: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "libnested" variant "android_common": depends on //top:libexample which is not` +
+ ` visible to this module; //top:libexample is only visible to \[//top:__pkg__\]`,
+ `module "libother" variant "android_common": depends on //top:libexample which is not` +
+ ` visible to this module; //top:libexample is only visible to \[//top:__pkg__\]`,
+ },
+ },
+ {
+ // Verify that //top/nested allows the module to be referenced from the current directory and
+ // the top/nested directory only, not a subdirectory of top/nested and not peak directory.
+ name: "//top/nested",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["//top/nested"],
+ }
+
+ mock_library {
+ name: "libsamepackage",
+ deps: ["libexample"],
+ }`),
+ "top/nested/Blueprints": []byte(`
+ mock_library {
+ name: "libnested",
+ deps: ["libexample"],
+ }`),
+ "top/nested/again/Blueprints": []byte(`
+ mock_library {
+ name: "libnestedagain",
+ deps: ["libexample"],
+ }`),
+ "peak/Blueprints": []byte(`
+ mock_library {
+ name: "libother",
+ deps: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "libother" variant "android_common": depends on //top:libexample which is not` +
+ ` visible to this module; //top:libexample is only visible to \[//top/nested:__pkg__\]`,
+ `module "libnestedagain" variant "android_common": depends on //top:libexample which is not` +
+ ` visible to this module; //top:libexample is only visible to \[//top/nested:__pkg__\]`,
+ },
+ },
+ {
+ // Verify that :__subpackages__ allows the module to be referenced from the current directory
+ // and sub directories but nowhere else.
+ name: ":__subpackages__",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: [":__subpackages__"],
+ }
+
+ mock_library {
+ name: "libsamepackage",
+ deps: ["libexample"],
+ }`),
+ "top/nested/Blueprints": []byte(`
+ mock_library {
+ name: "libnested",
+ deps: ["libexample"],
+ }`),
+ "peak/other/Blueprints": []byte(`
+ mock_library {
+ name: "libother",
+ deps: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "libother" variant "android_common": depends on //top:libexample which is not` +
+ ` visible to this module; //top:libexample is only visible to \[//top:__subpackages__\]`,
+ },
+ },
+ {
+ // Verify that //top/nested:__subpackages__ allows the module to be referenced from the current
+ // directory and sub directories but nowhere else.
+ name: "//top/nested:__subpackages__",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["//top/nested:__subpackages__", "//other"],
+ }
+
+ mock_library {
+ name: "libsamepackage",
+ deps: ["libexample"],
+ }`),
+ "top/nested/Blueprints": []byte(`
+ mock_library {
+ name: "libnested",
+ deps: ["libexample"],
+ }`),
+ "top/other/Blueprints": []byte(`
+ mock_library {
+ name: "libother",
+ deps: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "libother" variant "android_common": depends on //top:libexample which is not` +
+ ` visible to this module; //top:libexample is only visible to` +
+ ` \[//top/nested:__subpackages__, //other:__pkg__\]`,
+ },
+ },
+ {
+ // Verify that ["//top/nested", "//peak:__subpackages"] allows the module to be referenced from
+ // the current directory, top/nested and peak and all its subpackages.
+ name: `["//top/nested", "//peak:__subpackages__"]`,
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["//top/nested", "//peak:__subpackages__"],
+ }
+
+ mock_library {
+ name: "libsamepackage",
+ deps: ["libexample"],
+ }`),
+ "top/nested/Blueprints": []byte(`
+ mock_library {
+ name: "libnested",
+ deps: ["libexample"],
+ }`),
+ "peak/other/Blueprints": []byte(`
+ mock_library {
+ name: "libother",
+ deps: ["libexample"],
+ }`),
+ },
+ },
+ {
+ // Verify that //vendor... cannot be used outside vendor apart from //vendor:__subpackages__
+ name: `//vendor`,
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["//vendor:__subpackages__"],
+ }
+
+ mock_library {
+ name: "libsamepackage",
+ visibility: ["//vendor/apps/AcmeSettings"],
+ }`),
+ "vendor/Blueprints": []byte(`
+ mock_library {
+ name: "libvendorexample",
+ deps: ["libexample"],
+ visibility: ["//vendor/nested"],
+ }`),
+ "vendor/nested/Blueprints": []byte(`
+ mock_library {
+ name: "libvendornested",
+ deps: ["libexample", "libvendorexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "libsamepackage" variant "android_common": visibility: "//vendor/apps/AcmeSettings"` +
+ ` is not allowed. Packages outside //vendor cannot make themselves visible to specific` +
+ ` targets within //vendor, they can only use //vendor:__subpackages__.`,
+ },
+ },
+}
+
+func TestVisibility(t *testing.T) {
+ buildDir, err := ioutil.TempDir("", "soong_neverallow_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(buildDir)
+
+ for _, test := range visibilityTests {
+ t.Run(test.name, func(t *testing.T) {
+ _, errs := testVisibility(buildDir, test.fs)
+
+ expectedErrors := test.expectedErrors
+ if expectedErrors == nil {
+ FailIfErrored(t, errs)
+ } else {
+ for _, expectedError := range expectedErrors {
+ FailIfNoMatchingErrors(t, expectedError, errs)
+ }
+ if len(errs) > len(expectedErrors) {
+ t.Errorf("additional errors found, expected %d, found %d", len(expectedErrors), len(errs))
+ for i, expectedError := range expectedErrors {
+ t.Errorf("expectedErrors[%d] = %s", i, expectedError)
+ }
+ for i, err := range errs {
+ t.Errorf("errs[%d] = %s", i, err)
+ }
+ }
+ }
+ })
+ }
+}
+
+func testVisibility(buildDir string, fs map[string][]byte) (*TestContext, []error) {
+
+ // Create a new config per test as visibility information is stored in the config.
+ config := TestArchConfig(buildDir, nil)
+
+ ctx := NewTestArchContext()
+ ctx.RegisterModuleType("mock_library", ModuleFactoryAdaptor(newMockLibraryModule))
+ ctx.PreDepsMutators(registerVisibilityRuleGatherer)
+ ctx.PostDepsMutators(registerVisibilityRuleEnforcer)
+ ctx.Register()
+
+ ctx.MockFileSystem(fs)
+
+ _, errs := ctx.ParseBlueprintsFiles(".")
+ if len(errs) > 0 {
+ return ctx, errs
+ }
+
+ _, errs = ctx.PrepareBuildActions(config)
+ return ctx, errs
+}
+
+type mockLibraryProperties struct {
+ Deps []string
+}
+
+type mockLibraryModule struct {
+ ModuleBase
+ properties mockLibraryProperties
+}
+
+func newMockLibraryModule() Module {
+ m := &mockLibraryModule{}
+ m.AddProperties(&m.properties)
+ InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
+ return m
+}
+
+type dependencyTag struct {
+ blueprint.BaseDependencyTag
+ name string
+}
+
+func (j *mockLibraryModule) DepsMutator(ctx BottomUpMutatorContext) {
+ ctx.AddVariationDependencies(nil, dependencyTag{name: "mockdeps"}, j.properties.Deps...)
+}
+
+func (p *mockLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
+}
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index b54ad5e..cb71725 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -123,6 +123,7 @@
"LOCAL_SYSTEM_SHARED_LIBRARIES": "system_shared_libs",
"LOCAL_ASFLAGS": "asflags",
"LOCAL_CLANG_ASFLAGS": "clang_asflags",
+ "LOCAL_COMPATIBILITY_SUPPORT_FILES": "data",
"LOCAL_CONLYFLAGS": "conlyflags",
"LOCAL_CPPFLAGS": "cppflags",
"LOCAL_REQUIRED_MODULES": "required",
@@ -936,6 +937,7 @@
"STATIC_LIBRARIES": "cc_prebuilt_library_static",
"EXECUTABLES": "cc_prebuilt_binary",
"JAVA_LIBRARIES": "java_import",
+ "APPS": "android_app_import",
"ETC": "prebuilt_etc",
}
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 34e673c..2eab0cc 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -809,6 +809,7 @@
LOCAL_PACKAGE_NAME := FooTest
LOCAL_COMPATIBILITY_SUITE := cts
LOCAL_CTS_TEST_PACKAGE := foo.bar
+LOCAL_COMPATIBILITY_SUPPORT_FILES := file1
include $(BUILD_CTS_PACKAGE)
`,
expected: `
@@ -817,6 +818,7 @@
defaults: ["cts_defaults"],
test_suites: ["cts"],
+ data: ["file1"],
}
`,
},
@@ -879,7 +881,6 @@
}
`,
},
-
{
desc: "prebuilt_etc_PRODUCT_OUT/system/etc",
in: `
@@ -1065,6 +1066,119 @@
`,
},
{
+ desc: "prebuilt_usr_share",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/usr/share
+LOCAL_SRC_FILES := foo.txt
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_usr_share {
+ name: "foo",
+
+ src: "foo.txt",
+}
+`,
+ },
+ {
+ desc: "prebuilt_usr_share subdir_bar",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/usr/share/bar
+LOCAL_SRC_FILES := foo.txt
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_usr_share {
+ name: "foo",
+
+ src: "foo.txt",
+ sub_dir: "bar",
+}
+`,
+ },
+ {
+ desc: "prebuilt_usr_share_host",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(HOST_OUT)/usr/share
+LOCAL_SRC_FILES := foo.txt
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_usr_share_host {
+ name: "foo",
+
+ src: "foo.txt",
+}
+`,
+ },
+ {
+ desc: "prebuilt_font",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := font.ttf
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_font {
+ name: "font.ttf",
+ src: "font.ttf",
+
+}
+`,
+ },
+ {
+ desc: "prebuilt_font",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := font.ttf
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT)/fonts
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_font {
+ name: "font.ttf",
+ src: "font.ttf",
+ product_specific: true,
+
+}
+`,
+ },
+ {
+ desc: "prebuilt_usr_share_host subdir_bar",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(HOST_OUT)/usr/share/bar
+LOCAL_SRC_FILES := foo.txt
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_usr_share_host {
+ name: "foo",
+
+ src: "foo.txt",
+ sub_dir: "bar",
+}
+`,
+ },
+ {
desc: "vts_config",
in: `
include $(CLEAR_VARS)
@@ -1123,6 +1237,32 @@
}
`,
},
+ {
+ desc: "android_app_import",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_SRC_FILES := foo.apk
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_MODULE_CLASS := APPS
+LOCAL_MODULE_TAGS := optional
+LOCAL_DEX_PREOPT := false
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+android_app_import {
+ name: "foo",
+
+ privileged: true,
+
+ dex_preopt: {
+ enabled: false,
+ },
+ apk: "foo.apk",
+
+}
+`,
+ },
}
func TestEndToEnd(t *testing.T) {
diff --git a/apex/apex.go b/apex/apex.go
index 004de86..51d0718 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -521,6 +521,17 @@
a.properties.Multilib.Prefer32.Binaries, target.String(),
a.getImageVariation(config))
}
+
+ if strings.HasPrefix(ctx.ModuleName(), "com.android.runtime") && target.Os.Class == android.Device {
+ for _, sanitizer := range ctx.Config().SanitizeDevice() {
+ if sanitizer == "hwaddress" {
+ addDependenciesForNativeModules(ctx,
+ []string{"libclang_rt.hwasan-aarch64-android"},
+ nil, target.String(), a.getImageVariation(config))
+ break
+ }
+ }
+ }
}
}
@@ -977,6 +988,17 @@
optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String())
}
+ targetSdkVersion := ctx.Config().DefaultAppTargetSdk()
+ if targetSdkVersion == ctx.Config().PlatformSdkCodename() &&
+ ctx.Config().UnbundledBuild() &&
+ !ctx.Config().UnbundledBuildUsePrebuiltSdks() &&
+ ctx.Config().IsEnvTrue("UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT") {
+ apiFingerprint := java.ApiFingerprintPath(ctx)
+ targetSdkVersion += fmt.Sprintf(".$$(cat %s)", apiFingerprint.String())
+ implicitInputs = append(implicitInputs, apiFingerprint)
+ }
+ optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
+
ctx.Build(pctx, android.BuildParams{
Rule: apexRule,
Implicits: implicitInputs,
@@ -1173,8 +1195,11 @@
fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
} else if fi.class == nativeSharedLib || fi.class == nativeExecutable {
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
- if cc, ok := fi.module.(*cc.Module); ok && cc.UnstrippedOutputFile() != nil {
- fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", cc.UnstrippedOutputFile().String())
+ if cc, ok := fi.module.(*cc.Module); ok {
+ if cc.UnstrippedOutputFile() != nil {
+ fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", cc.UnstrippedOutputFile().String())
+ }
+ cc.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
}
fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_prebuilt.mk")
} else {
@@ -1362,11 +1387,15 @@
return android.Paths{p.outputApex}
}
+func (p *Prebuilt) InstallFilename() string {
+ return proptools.StringDefault(p.properties.Filename, p.BaseModuleName()+imageApexSuffix)
+}
+
func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// TODO(jungjw): Check the key validity.
p.inputApex = p.Prebuilt().SingleSourcePath(ctx)
p.installDir = android.PathForModuleInstall(ctx, "apex")
- p.installFilename = proptools.StringDefault(p.properties.Filename, ctx.ModuleName()+imageApexSuffix)
+ p.installFilename = p.InstallFilename()
if !strings.HasSuffix(p.installFilename, imageApexSuffix) {
ctx.ModuleErrorf("filename should end in %s for prebuilt_apex", imageApexSuffix)
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index fce2135..5276ce4 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -93,6 +93,13 @@
}
toolchain_library {
+ name: "libgcc_stripped",
+ src: "",
+ vendor_available: true,
+ recovery_available: true,
+ }
+
+ toolchain_library {
name: "libclang_rt.builtins-aarch64-android",
src: "",
vendor_available: true,
@@ -171,6 +178,7 @@
"testkey2.pem": nil,
"myapex-arm64.apex": nil,
"myapex-arm.apex": nil,
+ "frameworks/base/api/current.txt": nil,
})
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
android.FailIfErrored(t, errs)
@@ -190,6 +198,8 @@
config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
config.TestProductVariables.DefaultAppCertificate = proptools.StringPtr("vendor/foo/devkeys/test")
config.TestProductVariables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"}
+ config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("Q")
+ config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(false)
return
}
diff --git a/apex/key.go b/apex/key.go
index 229d593..08cd45e 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "sort"
"strings"
"android/soong/android"
@@ -105,12 +106,31 @@
func (s *apexKeysText) GenerateBuildActions(ctx android.SingletonContext) {
s.output = android.PathForOutput(ctx, "apexkeys.txt")
- var filecontent strings.Builder
+ apexModulesMap := make(map[string]android.Module)
ctx.VisitAllModules(func(module android.Module) {
- if m, ok := module.(android.Module); ok && !m.Enabled() {
- return
+ if m, ok := module.(*apexBundle); ok && m.Enabled() && m.installable() {
+ apexModulesMap[m.Name()] = m
}
+ })
+ // Find prebuilts and let them override apexBundle if they are preferred
+ ctx.VisitAllModules(func(module android.Module) {
+ if m, ok := module.(*Prebuilt); ok && m.Enabled() && m.installable() &&
+ m.Prebuilt().UsePrebuilt() {
+ apexModulesMap[m.BaseModuleName()] = m
+ }
+ })
+
+ // iterating over map does not give consistent ordering in golang
+ var moduleNames []string
+ for key, _ := range apexModulesMap {
+ moduleNames = append(moduleNames, key)
+ }
+ sort.Strings(moduleNames)
+
+ var filecontent strings.Builder
+ for _, key := range moduleNames {
+ module := apexModulesMap[key]
if m, ok := module.(*apexBundle); ok {
fmt.Fprintf(&filecontent,
"name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q\\n",
@@ -119,8 +139,14 @@
m.private_key_file.String(),
m.container_certificate_file.String(),
m.container_private_key_file.String())
+ } else if m, ok := module.(*Prebuilt); ok {
+ fmt.Fprintf(&filecontent,
+ "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q\\n",
+ m.InstallFilename(),
+ "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED")
}
- })
+ }
+
ctx.Build(pctx, android.BuildParams{
Rule: android.WriteFile,
Description: "apexkeys.txt",
diff --git a/bpf/Android.bp b/bpf/Android.bp
index 7bd4d44..882cd8a 100644
--- a/bpf/Android.bp
+++ b/bpf/Android.bp
@@ -21,10 +21,14 @@
"blueprint",
"blueprint-proptools",
"soong-android",
+ "soong-cc",
"soong-cc-config",
],
srcs: [
"bpf.go",
],
+ testSrcs: [
+ "bpf_test.go",
+ ],
pluginFor: ["soong_build"],
}
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 13468c7..dcbf9ad 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -33,7 +33,7 @@
var (
pctx = android.NewPackageContext("android/soong/bpf")
- cc = pctx.AndroidGomaStaticRule("cc",
+ ccRule = pctx.AndroidGomaStaticRule("ccRule",
blueprint.RuleParams{
Depfile: "${out}.d",
Deps: blueprint.DepsGCC,
@@ -82,7 +82,7 @@
obj := android.ObjPathWithExt(ctx, "", src, "o")
ctx.Build(pctx, android.BuildParams{
- Rule: cc,
+ Rule: ccRule,
Input: src,
Output: obj,
Args: map[string]string{
diff --git a/bpf/bpf_test.go b/bpf/bpf_test.go
index 1d53e41..cbb251f 100644
--- a/bpf/bpf_test.go
+++ b/bpf/bpf_test.go
@@ -20,7 +20,7 @@
"testing"
"android/soong/android"
- cc2 "android/soong/cc"
+ "android/soong/cc"
)
var buildDir string
@@ -49,115 +49,14 @@
}
func testContext(bp string) *android.TestContext {
- ctx := android.NewTestArchContext()
- ctx.RegisterModuleType("bpf", android.ModuleFactoryAdaptor(bpfFactory))
- ctx.RegisterModuleType("cc_test", android.ModuleFactoryAdaptor(cc2.TestFactory))
- ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc2.LibraryFactory))
- ctx.RegisterModuleType("cc_library_static", android.ModuleFactoryAdaptor(cc2.LibraryStaticFactory))
- ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc2.ObjectFactory))
- ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc2.ToolchainLibraryFactory))
- ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("link", cc2.LinkageMutator).Parallel()
- })
- ctx.Register()
-
- // Add some modules that are required by the compiler and/or linker
- bp = bp + `
- toolchain_library {
- name: "libatomic",
- vendor_available: true,
- recovery_available: true,
- src: "",
- }
-
- toolchain_library {
- name: "libclang_rt.builtins-arm-android",
- vendor_available: true,
- recovery_available: true,
- src: "",
- }
-
- toolchain_library {
- name: "libclang_rt.builtins-aarch64-android",
- vendor_available: true,
- recovery_available: true,
- src: "",
- }
-
- toolchain_library {
- name: "libgcc",
- vendor_available: true,
- recovery_available: true,
- src: "",
- }
-
- cc_library {
- name: "libc",
- no_libgcc: true,
- nocrt: true,
- system_shared_libs: [],
- recovery_available: true,
- }
-
- cc_library {
- name: "libm",
- no_libgcc: true,
- nocrt: true,
- system_shared_libs: [],
- recovery_available: true,
- }
-
- cc_library {
- name: "libdl",
- no_libgcc: true,
- nocrt: true,
- system_shared_libs: [],
- recovery_available: true,
- }
-
- cc_library {
- name: "libgtest",
- host_supported: true,
- vendor_available: true,
- }
-
- cc_library {
- name: "libgtest_main",
- host_supported: true,
- vendor_available: true,
- }
-
- cc_object {
- name: "crtbegin_dynamic",
- recovery_available: true,
- vendor_available: true,
- }
-
- cc_object {
- name: "crtend_android",
- recovery_available: true,
- vendor_available: true,
- }
-
- cc_object {
- name: "crtbegin_so",
- recovery_available: true,
- vendor_available: true,
- }
-
- cc_object {
- name: "crtend_so",
- recovery_available: true,
- vendor_available: true,
- }
- `
mockFS := map[string][]byte{
- "Android.bp": []byte(bp),
"bpf.c": nil,
"BpfTest.cpp": nil,
}
- ctx.MockFileSystem(mockFS)
+ ctx := cc.CreateTestContext(bp, mockFS, android.Android)
+ ctx.RegisterModuleType("bpf", android.ModuleFactoryAdaptor(bpfFactory))
+ ctx.Register()
return ctx
}
@@ -174,6 +73,7 @@
name: "vts_test_binary_bpf_module",
srcs: ["BpfTest.cpp"],
data: [":bpf.o"],
+ gtest: false,
}
`
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index 706c0ec..17cff18 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -102,6 +102,10 @@
name: "rewriteAndroidTest",
fix: rewriteAndroidTest,
},
+ {
+ name: "rewriteAndroidAppImport",
+ fix: rewriteAndroidAppImport,
+ },
}
func NewFixRequest() FixRequest {
@@ -431,14 +435,6 @@
return ""
}
-// Create sub_dir: attribute for the given path
-func makePrebuiltEtcDestination(mod *parser.Module, path string) {
- mod.Properties = append(mod.Properties, &parser.Property{
- Name: "sub_dir",
- Value: &parser.String{Value: path},
- })
-}
-
// Set the value of the given attribute to the error message
func indicateAttributeError(mod *parser.Module, attributeName string, format string, a ...interface{}) error {
msg := fmt.Sprintf(format, a...)
@@ -464,18 +460,54 @@
return val
}
-// A prefix to strip before setting 'filename' attribute and an array of boolean attributes to set.
-type filenamePrefixToFlags struct {
+// etcPrebuiltModuleUpdate contains information on updating certain parts of a defined module such as:
+// * changing the module type from prebuilt_etc to a different one
+// * stripping the prefix of the install path based on the module type
+// * appending additional boolean properties to the prebuilt module
+type etcPrebuiltModuleUpdate struct {
+ // The prefix of the install path defined in local_module_path. The prefix is removed from local_module_path
+ // before setting the 'filename' attribute.
prefix string
- flags []string
+
+ // There is only one prebuilt module type in makefiles. In Soong, there are multiple versions of
+ // prebuilts based on local_module_path. By default, it is "prebuilt_etc" if modType is blank. An
+ // example is if the local_module_path contains $(TARGET_OUT)/usr/share, the module type is
+ // considered as prebuilt_usr_share.
+ modType string
+
+ // Additional boolean attributes to be added in the prebuilt module. Each added boolean attribute
+ // has a value of true.
+ flags []string
}
-var localModulePathRewrite = map[string][]filenamePrefixToFlags{
- "HOST_OUT": {{prefix: "/etc"}},
+func (f etcPrebuiltModuleUpdate) update(m *parser.Module, path string) bool {
+ updated := false
+ if path == f.prefix {
+ updated = true
+ } else if trimmedPath := strings.TrimPrefix(path, f.prefix+"/"); trimmedPath != path {
+ m.Properties = append(m.Properties, &parser.Property{
+ Name: "sub_dir",
+ Value: &parser.String{Value: trimmedPath},
+ })
+ updated = true
+ }
+ if updated {
+ for _, flag := range f.flags {
+ m.Properties = append(m.Properties, &parser.Property{Name: flag, Value: &parser.Bool{Value: true, Token: "true"}})
+ }
+ if f.modType != "" {
+ m.Type = f.modType
+ }
+ }
+ return updated
+}
+
+var localModuleUpdate = map[string][]etcPrebuiltModuleUpdate{
+ "HOST_OUT": {{prefix: "/etc", modType: "prebuilt_etc_host"}, {prefix: "/usr/share", modType: "prebuilt_usr_share_host"}},
"PRODUCT_OUT": {{prefix: "/system/etc"}, {prefix: "/vendor/etc", flags: []string{"proprietary"}}},
- "TARGET_OUT": {{prefix: "/etc"}},
+ "TARGET_OUT": {{prefix: "/etc"}, {prefix: "/usr/share", modType: "prebuilt_usr_share"}, {prefix: "/fonts", modType: "prebuilt_font"}},
"TARGET_OUT_ETC": {{prefix: ""}},
- "TARGET_OUT_PRODUCT": {{prefix: "/etc", flags: []string{"product_specific"}}},
+ "TARGET_OUT_PRODUCT": {{prefix: "/etc", flags: []string{"product_specific"}}, {prefix: "/fonts", modType: "prebuilt_font", flags: []string{"product_specific"}}},
"TARGET_OUT_PRODUCT_ETC": {{prefix: "", flags: []string{"product_specific"}}},
"TARGET_OUT_ODM": {{prefix: "/etc", flags: []string{"device_specific"}}},
"TARGET_OUT_PRODUCT_SERVICES": {{prefix: "/etc", flags: []string{"product_services_specific"}}},
@@ -497,27 +529,8 @@
continue
}
- // The rewriter converts LOCAL_SRC_FILES to `srcs` attribute. Convert
- // it to 'src' attribute (which is where the file is installed). If the
- // value 'srcs' is a list, we can convert it only if it contains a single
- // element.
- if srcs, ok := mod.GetProperty("srcs"); ok {
- if srcList, ok := srcs.Value.(*parser.List); ok {
- removeProperty(mod, "srcs")
- if len(srcList.Values) == 1 {
- mod.Properties = append(mod.Properties,
- &parser.Property{Name: "src", NamePos: srcs.NamePos, ColonPos: srcs.ColonPos, Value: resolveLocalModule(mod, srcList.Values[0])})
- } else if len(srcList.Values) > 1 {
- indicateAttributeError(mod, "src", "LOCAL_SRC_FILES should contain at most one item")
- }
- } else if _, ok = srcs.Value.(*parser.Variable); ok {
- removeProperty(mod, "srcs")
- mod.Properties = append(mod.Properties,
- &parser.Property{Name: "src", NamePos: srcs.NamePos, ColonPos: srcs.ColonPos, Value: resolveLocalModule(mod, srcs.Value)})
- } else {
- renameProperty(mod, "srcs", "src")
- }
- }
+ // 'srcs' --> 'src' conversion
+ convertToSingleSource(mod, "src")
// The rewriter converts LOCAL_MODULE_PATH attribute into a struct attribute
// 'local_module_path'. Analyze its contents and create the correct sub_dir:,
@@ -526,37 +539,23 @@
if prop_local_module_path, ok := mod.GetProperty(local_module_path); ok {
removeProperty(mod, local_module_path)
prefixVariableName := getStringProperty(prop_local_module_path, "var")
- path := getStringProperty(prop_local_module_path, "fixed")
- if prefixRewrites, ok := localModulePathRewrite[prefixVariableName]; ok {
- rewritten := false
- for _, prefixRewrite := range prefixRewrites {
- if path == prefixRewrite.prefix {
- rewritten = true
- } else if trimmedPath := strings.TrimPrefix(path, prefixRewrite.prefix+"/"); trimmedPath != path {
- makePrebuiltEtcDestination(mod, trimmedPath)
- rewritten = true
- }
- if rewritten {
- for _, flag := range prefixRewrite.flags {
- mod.Properties = append(mod.Properties, &parser.Property{Name: flag, Value: &parser.Bool{Value: true, Token: "true"}})
- }
- break
- }
+ if moduleUpdates, ok := localModuleUpdate[prefixVariableName]; ok {
+ path := getStringProperty(prop_local_module_path, "fixed")
+ updated := false
+ for i := 0; i < len(moduleUpdates) && !updated; i++ {
+ updated = moduleUpdates[i].update(mod, path)
}
- if !rewritten {
+ if !updated {
expectedPrefices := ""
sep := ""
- for _, prefixRewrite := range prefixRewrites {
+ for _, moduleUpdate := range moduleUpdates {
expectedPrefices += sep
sep = ", "
- expectedPrefices += prefixRewrite.prefix
+ expectedPrefices += moduleUpdate.prefix
}
return indicateAttributeError(mod, "filename",
"LOCAL_MODULE_PATH value under $(%s) should start with %s", prefixVariableName, expectedPrefices)
}
- if prefixVariableName == "HOST_OUT" {
- mod.Type = "prebuilt_etc_host"
- }
} else {
return indicateAttributeError(mod, "filename", "Cannot handle $(%s) for the prebuilt_etc", prefixVariableName)
}
@@ -589,6 +588,62 @@
return nil
}
+func rewriteAndroidAppImport(f *Fixer) error {
+ for _, def := range f.tree.Defs {
+ mod, ok := def.(*parser.Module)
+ if !(ok && mod.Type == "android_app_import") {
+ continue
+ }
+ // 'srcs' --> 'apk' conversion
+ convertToSingleSource(mod, "apk")
+ // Handle special certificate value, "PRESIGNED".
+ if cert, ok := mod.GetProperty("certificate"); ok {
+ if certStr, ok := cert.Value.(*parser.String); ok {
+ if certStr.Value == "PRESIGNED" {
+ removeProperty(mod, "certificate")
+ prop := &parser.Property{
+ Name: "presigned",
+ Value: &parser.Bool{
+ Value: true,
+ },
+ }
+ mod.Properties = append(mod.Properties, prop)
+ }
+ }
+ }
+ }
+ return nil
+}
+
+// Converts the default source list property, 'srcs', to a single source property with a given name.
+// "LOCAL_MODULE" reference is also resolved during the conversion process.
+func convertToSingleSource(mod *parser.Module, srcPropertyName string) {
+ if srcs, ok := mod.GetProperty("srcs"); ok {
+ if srcList, ok := srcs.Value.(*parser.List); ok {
+ removeProperty(mod, "srcs")
+ if len(srcList.Values) == 1 {
+ mod.Properties = append(mod.Properties,
+ &parser.Property{
+ Name: srcPropertyName,
+ NamePos: srcs.NamePos,
+ ColonPos: srcs.ColonPos,
+ Value: resolveLocalModule(mod, srcList.Values[0])})
+ } else if len(srcList.Values) > 1 {
+ indicateAttributeError(mod, srcPropertyName, "LOCAL_SRC_FILES should contain at most one item")
+ }
+ } else if _, ok = srcs.Value.(*parser.Variable); ok {
+ removeProperty(mod, "srcs")
+ mod.Properties = append(mod.Properties,
+ &parser.Property{Name: srcPropertyName,
+ NamePos: srcs.NamePos,
+ ColonPos: srcs.ColonPos,
+ Value: resolveLocalModule(mod, srcs.Value)})
+ } else {
+ renameProperty(mod, "srcs", "apk")
+ }
+ }
+}
+
func runPatchListMod(modFunc func(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error) func(*Fixer) error {
return func(f *Fixer) error {
// Make sure all the offsets are accurate
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 459cd36..5e0b817 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -784,3 +784,52 @@
})
}
}
+
+func TestRewriteAndroidAppImport(t *testing.T) {
+ tests := []struct {
+ name string
+ in string
+ out string
+ }{
+ {
+ name: "android_app_import apk",
+ in: `
+ android_app_import {
+ name: "foo",
+ srcs: ["package.apk"],
+ }
+ `,
+ out: `
+ android_app_import {
+ name: "foo",
+ apk: "package.apk",
+ }
+ `,
+ },
+ {
+ name: "android_app_import presigned",
+ in: `
+ android_app_import {
+ name: "foo",
+ apk: "package.apk",
+ certificate: "PRESIGNED",
+ }
+ `,
+ out: `
+ android_app_import {
+ name: "foo",
+ apk: "package.apk",
+ presigned: true,
+
+ }
+ `,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ runPass(t, test.in, test.out, func(fixer *Fixer) error {
+ return rewriteAndroidAppImport(fixer)
+ })
+ })
+ }
+}
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 02806f9..ae34e3d 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -24,8 +24,9 @@
)
var (
- vendorSuffix = ".vendor"
- recoverySuffix = ".recovery"
+ nativeBridgeSuffix = ".native_bridge"
+ vendorSuffix = ".vendor"
+ recoverySuffix = ".recovery"
)
type AndroidMkContext interface {
@@ -86,7 +87,7 @@
if len(c.Properties.AndroidMkWholeStaticLibs) > 0 {
fmt.Fprintln(w, "LOCAL_WHOLE_STATIC_LIBRARIES := "+strings.Join(c.Properties.AndroidMkWholeStaticLibs, " "))
}
- fmt.Fprintln(w, "LOCAL_SOONG_LINK_TYPE :=", c.getMakeLinkType())
+ fmt.Fprintln(w, "LOCAL_SOONG_LINK_TYPE :=", c.makeLinkType)
if c.useVndk() {
fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
}
@@ -105,6 +106,10 @@
}
c.subAndroidMk(&ret, c.installer)
+ if c.Target().NativeBridge == android.NativeBridgeEnabled {
+ ret.SubName += nativeBridgeSuffix
+ }
+
if c.useVndk() && c.hasVendorVariant() {
// .vendor suffix is added only when we will have two variants: core and vendor.
// The suffix is not added for vendor-only module.
@@ -134,6 +139,18 @@
}
}
+func makeOverrideModuleNames(ctx AndroidMkContext, overrides []string) []string {
+ if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+ var result []string
+ for _, override := range overrides {
+ result = append(result, override+nativeBridgeSuffix)
+ }
+ return result
+ }
+
+ return overrides
+}
+
func (library *libraryDecorator) androidMkWriteExportedFlags(w io.Writer) {
exportedFlags := library.exportedFlags()
if len(exportedFlags) > 0 {
@@ -145,6 +162,16 @@
}
}
+func (library *libraryDecorator) androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
+ if library.sAbiOutputFile.Valid() {
+ fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", library.sAbiOutputFile.String())
+ if library.sAbiDiff.Valid() && !library.static() {
+ fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", library.sAbiDiff.String())
+ fmt.Fprintln(w, "HEADER_ABI_DIFFS +=", library.sAbiDiff.String())
+ }
+ }
+}
+
func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
if library.static() {
ret.Class = "STATIC_LIBRARIES"
@@ -156,7 +183,7 @@
fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
}
if len(library.Properties.Overrides) > 0 {
- fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(library.Properties.Overrides, " "))
+ fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " "))
}
if len(library.post_install_cmds) > 0 {
fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := "+strings.Join(library.post_install_cmds, "&& "))
@@ -169,14 +196,7 @@
ret.DistFile = library.distFile
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
library.androidMkWriteExportedFlags(w)
- fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES := ")
- if library.sAbiOutputFile.Valid() {
- fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES += ", library.sAbiOutputFile.String())
- if library.sAbiDiff.Valid() && !library.static() {
- fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES += ", library.sAbiDiff.String())
- fmt.Fprintln(w, "HEADER_ABI_DIFFS += ", library.sAbiDiff.String())
- }
- }
+ library.androidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
_, _, ext := splitFileExt(outputFile.Base())
@@ -238,7 +258,7 @@
}
if len(binary.Properties.Overrides) > 0 {
- fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(binary.Properties.Overrides, " "))
+ fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " "))
}
if len(binary.post_install_cmds) > 0 {
fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := "+strings.Join(binary.post_install_cmds, "&& "))
diff --git a/cc/binary.go b/cc/binary.go
index 51e68fc..93d1de2 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -440,8 +440,8 @@
// Bionic binaries (e.g. linker) is installed to the bootstrap subdirectory.
// The original path becomes a symlink to the corresponding file in the
// runtime APEX.
- if isBionic(ctx.baseModuleName()) && ctx.Arch().Native && ctx.apexName() == "" && !ctx.inRecovery() {
- if ctx.Device() {
+ if installToBootstrap(ctx.baseModuleName(), ctx.Config()) && ctx.Arch().Native && ctx.apexName() == "" && !ctx.inRecovery() {
+ if ctx.Device() && isBionic(ctx.baseModuleName()) {
binary.installSymlinkToRuntimeApex(ctx, file)
}
binary.baseInstaller.subDir = "bootstrap"
diff --git a/cc/builder.go b/cc/builder.go
index 7b26d51..7cf5c29 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -123,12 +123,25 @@
_ = pctx.SourcePathVariable("stripPath", "build/soong/scripts/strip.sh")
_ = pctx.SourcePathVariable("xzCmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/xz")
+ // b/132822437: objcopy uses a file descriptor per .o file when called on .a files, which runs the system out of
+ // file descriptors on darwin. Limit concurrent calls to 5 on darwin.
+ darwinStripPool = func() blueprint.Pool {
+ if runtime.GOOS == "darwin" {
+ return pctx.StaticPool("darwinStripPool", blueprint.PoolParams{
+ Depth: 5,
+ })
+ } else {
+ return nil
+ }
+ }()
+
strip = pctx.AndroidStaticRule("strip",
blueprint.RuleParams{
Depfile: "${out}.d",
Deps: blueprint.DepsGCC,
Command: "CROSS_COMPILE=$crossCompile XZ=$xzCmd CLANG_BIN=${config.ClangBin} $stripPath ${args} -i ${in} -o ${out} -d ${out}.d",
CommandDeps: []string{"$stripPath", "$xzCmd"},
+ Pool: darwinStripPool,
},
"args", "crossCompile")
@@ -254,10 +267,12 @@
groupStaticLibs bool
- stripKeepSymbols bool
- stripKeepMiniDebugInfo bool
- stripAddGnuDebuglink bool
- stripUseGnuStrip bool
+ stripKeepSymbols bool
+ stripKeepSymbolsList string
+ stripKeepSymbolsAndDebugFrame bool
+ stripKeepMiniDebugInfo bool
+ stripAddGnuDebuglink bool
+ stripUseGnuStrip bool
proto android.ProtoFlags
protoC bool
@@ -835,6 +850,12 @@
if flags.stripKeepSymbols {
args += " --keep-symbols"
}
+ if flags.stripKeepSymbolsList != "" {
+ args += " -k" + flags.stripKeepSymbolsList
+ }
+ if flags.stripKeepSymbolsAndDebugFrame {
+ args += " --keep-symbols-and-debug-frame"
+ }
if flags.stripUseGnuStrip {
args += " --use-gnu-strip"
}
diff --git a/cc/cc.go b/cc/cc.go
index bec39ca..2e551e1 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -19,6 +19,7 @@
// is handled in builder.go
import (
+ "io"
"strconv"
"strings"
@@ -245,14 +246,14 @@
sdkVersion() string
useVndk() bool
isNdk() bool
- isLlndk() bool
- isLlndkPublic() bool
- isVndkPrivate() bool
+ isLlndk(config android.Config) bool
+ isLlndkPublic(config android.Config) bool
+ isVndkPrivate(config android.Config) bool
isVndk() bool
isVndkSp() bool
isVndkExt() bool
inRecovery() bool
- shouldCreateVndkSourceAbiDump() bool
+ shouldCreateVndkSourceAbiDump(config android.Config) bool
selectedStl() string
baseModuleName() string
getVndkExtendsModuleName() string
@@ -407,6 +408,8 @@
// only non-nil when this is a shared library that reuses the objects of a static library
staticVariant *Module
+
+ makeLinkType string
}
func (c *Module) OutputFile() android.OptionalPath {
@@ -509,19 +512,19 @@
return inList(c.Name(), ndkMigratedLibs)
}
-func (c *Module) isLlndk() bool {
+func (c *Module) isLlndk(config android.Config) bool {
// Returns true for both LLNDK (public) and LLNDK-private libs.
- return inList(c.Name(), llndkLibraries)
+ return inList(c.Name(), *llndkLibraries(config))
}
-func (c *Module) isLlndkPublic() bool {
+func (c *Module) isLlndkPublic(config android.Config) bool {
// Returns true only for LLNDK (public) libs.
- return c.isLlndk() && !c.isVndkPrivate()
+ return c.isLlndk(config) && !c.isVndkPrivate(config)
}
-func (c *Module) isVndkPrivate() bool {
+func (c *Module) isVndkPrivate(config android.Config) bool {
// Returns true for LLNDK-private, VNDK-SP-private, and VNDK-core-private.
- return inList(c.Name(), vndkPrivateLibraries)
+ return inList(c.Name(), *vndkPrivateLibraries(config))
}
func (c *Module) isVndk() bool {
@@ -597,6 +600,9 @@
if library, ok := c.linker.(*libraryDecorator); ok {
return len(library.Properties.Stubs.Versions) > 0
}
+ if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
+ return len(library.Properties.Stubs.Versions) > 0
+ }
return false
}
@@ -616,6 +622,13 @@
return false
}
+func installToBootstrap(name string, config android.Config) bool {
+ if name == "libclang_rt.hwasan-aarch64-android" {
+ return inList("hwaddress", config.SanitizeDevice())
+ }
+ return isBionic(name)
+}
+
type baseModuleContext struct {
android.BaseContext
moduleContextImpl
@@ -686,16 +699,16 @@
return ctx.mod.isNdk()
}
-func (ctx *moduleContextImpl) isLlndk() bool {
- return ctx.mod.isLlndk()
+func (ctx *moduleContextImpl) isLlndk(config android.Config) bool {
+ return ctx.mod.isLlndk(config)
}
-func (ctx *moduleContextImpl) isLlndkPublic() bool {
- return ctx.mod.isLlndkPublic()
+func (ctx *moduleContextImpl) isLlndkPublic(config android.Config) bool {
+ return ctx.mod.isLlndkPublic(config)
}
-func (ctx *moduleContextImpl) isVndkPrivate() bool {
- return ctx.mod.isVndkPrivate()
+func (ctx *moduleContextImpl) isVndkPrivate(config android.Config) bool {
+ return ctx.mod.isVndkPrivate(config)
}
func (ctx *moduleContextImpl) isVndk() bool {
@@ -727,7 +740,7 @@
}
// Check whether ABI dumps should be created for this module.
-func (ctx *moduleContextImpl) shouldCreateVndkSourceAbiDump() bool {
+func (ctx *moduleContextImpl) shouldCreateVndkSourceAbiDump(config android.Config) bool {
if ctx.ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") {
return false
}
@@ -752,10 +765,10 @@
if ctx.isNdk() {
return true
}
- if ctx.isLlndkPublic() {
+ if ctx.isLlndkPublic(config) {
return true
}
- if ctx.useVndk() && ctx.isVndk() && !ctx.isVndkPrivate() {
+ if ctx.useVndk() && ctx.isVndk() && !ctx.isVndkPrivate(config) {
// Return true if this is VNDK-core, VNDK-SP, or VNDK-Ext and this is not
// VNDK-private.
return true
@@ -906,6 +919,8 @@
}
func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
+ c.makeLinkType = c.getMakeLinkType(actx)
+
ctx := &moduleContext{
ModuleContext: actx,
moduleContextImpl: moduleContextImpl{
@@ -1006,7 +1021,7 @@
}
}
- if c.installer != nil && !c.Properties.PreventInstall && c.IsForPlatform() && c.outputFile.Valid() {
+ if c.installable() {
c.installer.install(ctx, c.outputFile.Path())
if ctx.Failed() {
return
@@ -1185,6 +1200,9 @@
//
// The caller can then know to add the variantLibs dependencies differently from the
// nonvariantLibs
+
+ llndkLibraries := llndkLibraries(actx.Config())
+ vendorPublicLibraries := vendorPublicLibraries(actx.Config())
rewriteNdkLibs := func(list []string) (nonvariantLibs []string, variantLibs []string) {
variantLibs = []string{}
nonvariantLibs = []string{}
@@ -1197,9 +1215,9 @@
} else {
variantLibs = append(variantLibs, name+ndkLibrarySuffix)
}
- } else if ctx.useVndk() && inList(name, llndkLibraries) {
+ } else if ctx.useVndk() && inList(name, *llndkLibraries) {
nonvariantLibs = append(nonvariantLibs, name+llndkLibrarySuffix)
- } else if (ctx.Platform() || ctx.ProductSpecific()) && inList(name, vendorPublicLibraries) {
+ } else if (ctx.Platform() || ctx.ProductSpecific()) && inList(name, *vendorPublicLibraries) {
vendorPublicLib := name + vendorPublicLibrarySuffix
if actx.OtherModuleExists(vendorPublicLib) {
nonvariantLibs = append(nonvariantLibs, vendorPublicLib)
@@ -1500,6 +1518,7 @@
// it is subject to be double loaded. Such lib should be explicitly marked as double_loadable: true
// or as vndk-sp (vndk: { enabled: true, support_system_process: true}).
func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) {
+ llndkLibraries := llndkLibraries(ctx.Config())
check := func(child, parent android.Module) bool {
to, ok := child.(*Module)
if !ok {
@@ -1516,7 +1535,7 @@
return true
}
- if to.isVndkSp() || inList(child.Name(), llndkLibraries) || Bool(to.VendorProperties.Double_loadable) {
+ if to.isVndkSp() || inList(child.Name(), *llndkLibraries) || Bool(to.VendorProperties.Double_loadable) {
return false
}
@@ -1531,7 +1550,7 @@
}
if module, ok := ctx.Module().(*Module); ok {
if lib, ok := module.linker.(*libraryDecorator); ok && lib.shared() {
- if inList(ctx.ModuleName(), llndkLibraries) || Bool(module.VendorProperties.Double_loadable) {
+ if inList(ctx.ModuleName(), *llndkLibraries) || Bool(module.VendorProperties.Double_loadable) {
ctx.WalkDeps(check)
}
}
@@ -1545,6 +1564,9 @@
directStaticDeps := []*Module{}
directSharedDeps := []*Module{}
+ llndkLibraries := llndkLibraries(ctx.Config())
+ vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
+
ctx.VisitDirectDeps(func(dep android.Module) {
depName := ctx.OtherModuleName(dep)
depTag := ctx.OtherModuleDependencyTag(dep)
@@ -1787,8 +1809,8 @@
libName := strings.TrimSuffix(depName, llndkLibrarySuffix)
libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix)
libName = strings.TrimPrefix(libName, "prebuilt_")
- isLLndk := inList(libName, llndkLibraries)
- isVendorPublicLib := inList(libName, vendorPublicLibraries)
+ isLLndk := inList(libName, *llndkLibraries)
+ isVendorPublicLib := inList(libName, *vendorPublicLibraries)
bothVendorAndCoreVariantsExist := ccDep.hasVendorVariant() || isLLndk
if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.isVndk() && !ccDep.mustUseVendorVariant() {
@@ -1803,6 +1825,8 @@
return libName + vendorPublicLibrarySuffix
} else if ccDep.inRecovery() && !ccDep.onlyInRecovery() {
return libName + recoverySuffix
+ } else if ccDep.Target().NativeBridge == android.NativeBridgeEnabled {
+ return libName + nativeBridgeSuffix
} else {
return libName
}
@@ -1916,17 +1940,22 @@
return false
}
-func (c *Module) getMakeLinkType() string {
+func (c *Module) getMakeLinkType(actx android.ModuleContext) string {
+ name := actx.ModuleName()
if c.useVndk() {
- if inList(c.Name(), vndkCoreLibraries) || inList(c.Name(), vndkSpLibraries) || inList(c.Name(), llndkLibraries) {
- if inList(c.Name(), vndkPrivateLibraries) {
- return "native:vndk_private"
- } else {
+ if lib, ok := c.linker.(*llndkStubDecorator); ok {
+ if Bool(lib.Properties.Vendor_available) {
return "native:vndk"
}
- } else {
- return "native:vendor"
+ return "native:vndk_private"
}
+ if c.isVndk() && !c.isVndkExt() {
+ if Bool(c.VendorProperties.Vendor_available) {
+ return "native:vndk"
+ }
+ return "native:vndk_private"
+ }
+ return "native:vendor"
} else if c.inRecovery() {
return "native:recovery"
} else if c.Target().Os == android.Android && String(c.Properties.Sdk_version) != "" {
@@ -1934,7 +1963,7 @@
// TODO(b/114741097): use the correct ndk stl once build errors have been fixed
//family, link := getNdkStlFamilyAndLinkType(c)
//return fmt.Sprintf("native:ndk:%s:%s", family, link)
- } else if inList(c.Name(), vndkUsingCoreVariantLibraries) {
+ } else if inList(name, *vndkUsingCoreVariantLibraries(actx.Config())) {
return "native:platform_vndk"
} else {
return "native:platform"
@@ -1952,6 +1981,10 @@
return false
}
+func (c *Module) installable() bool {
+ return c.installer != nil && !c.Properties.PreventInstall && c.IsForPlatform() && c.outputFile.Valid()
+}
+
func (c *Module) imageVariation() string {
variation := "core"
if c.useVndk() {
@@ -1966,6 +1999,14 @@
dpInfo.Srcs = append(dpInfo.Srcs, c.Srcs().Strings()...)
}
+func (c *Module) AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
+ if c.linker != nil {
+ if library, ok := c.linker.(*libraryDecorator); ok {
+ library.androidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
+ }
+ }
+}
+
//
// Defaults
//
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 05d74b9..997e11e 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -20,6 +20,7 @@
"fmt"
"io/ioutil"
"os"
+ "path/filepath"
"reflect"
"sort"
"strings"
@@ -51,55 +52,14 @@
os.Exit(run())
}
-func createTestContext(t *testing.T, config android.Config, bp string, os android.OsType) *android.TestContext {
- ctx := android.NewTestArchContext()
- ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(BinaryFactory))
- ctx.RegisterModuleType("cc_binary_host", android.ModuleFactoryAdaptor(binaryHostFactory))
- ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
- ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
- ctx.RegisterModuleType("cc_library_static", android.ModuleFactoryAdaptor(LibraryStaticFactory))
- ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(LibraryHeaderFactory))
- ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(ToolchainLibraryFactory))
- ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(LlndkLibraryFactory))
- ctx.RegisterModuleType("llndk_headers", android.ModuleFactoryAdaptor(llndkHeadersFactory))
- ctx.RegisterModuleType("vendor_public_library", android.ModuleFactoryAdaptor(vendorPublicLibraryFactory))
- ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(ObjectFactory))
- ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
- ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("image", ImageMutator).Parallel()
- ctx.BottomUp("link", LinkageMutator).Parallel()
- ctx.BottomUp("vndk", VndkMutator).Parallel()
- ctx.BottomUp("version", VersionMutator).Parallel()
- ctx.BottomUp("begin", BeginMutator).Parallel()
- })
- ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
- })
- ctx.Register()
-
- // add some modules that are required by the compiler and/or linker
- bp = bp + GatherRequiredDepsForTest(os)
-
- ctx.MockFileSystem(map[string][]byte{
- "Android.bp": []byte(bp),
- "foo.c": nil,
- "bar.c": nil,
- "a.proto": nil,
- "b.aidl": nil,
- "my_include": nil,
- "foo.map.txt": nil,
- })
-
- return ctx
-}
-
func testCcWithConfig(t *testing.T, bp string, config android.Config) *android.TestContext {
return testCcWithConfigForOs(t, bp, config, android.Android)
}
func testCcWithConfigForOs(t *testing.T, bp string, config android.Config, os android.OsType) *android.TestContext {
t.Helper()
- ctx := createTestContext(t, config, bp, os)
+ ctx := CreateTestContext(bp, nil, os)
+ ctx.Register()
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
android.FailIfErrored(t, errs)
@@ -132,7 +92,8 @@
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
- ctx := createTestContext(t, config, bp, android.Android)
+ ctx := CreateTestContext(bp, nil, android.Android)
+ ctx.Register()
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
if len(errs) > 0 {
@@ -286,8 +247,28 @@
}
}
+func checkVndkSnapshot(t *testing.T, ctx *android.TestContext, name, subDir, variant string) {
+ vndkSnapshot := ctx.SingletonForTests("vndk-snapshot")
+
+ snapshotPath := filepath.Join(subDir, name+".so")
+ mod := ctx.ModuleForTests(name, variant).Module().(*Module)
+ if !mod.outputFile.Valid() {
+ t.Errorf("%q must have output\n", name)
+ return
+ }
+
+ out := vndkSnapshot.Output(snapshotPath)
+ if out.Input != mod.outputFile.Path() {
+ t.Errorf("The input of VNDK snapshot must be %q, but %q", out.Input.String(), mod.outputFile.String())
+ }
+}
+
func TestVndk(t *testing.T) {
- ctx := testCc(t, `
+ config := android.TestArchConfig(buildDir, nil)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+
+ ctx := testCcWithConfig(t, `
cc_library {
name: "libvndk",
vendor_available: true,
@@ -325,12 +306,35 @@
},
nocrt: true,
}
- `)
+ `, config)
checkVndkModule(t, ctx, "libvndk", "vndk-VER", false, "")
checkVndkModule(t, ctx, "libvndk_private", "vndk-VER", false, "")
checkVndkModule(t, ctx, "libvndk_sp", "vndk-sp-VER", true, "")
checkVndkModule(t, ctx, "libvndk_sp_private", "vndk-sp-VER", true, "")
+
+ // Check VNDK snapshot output.
+
+ snapshotDir := "vndk-snapshot"
+ snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+
+ vndkLibPath := filepath.Join(snapshotVariantPath, fmt.Sprintf("arch-%s-%s",
+ "arm64", "armv8-a"))
+ vndkLib2ndPath := filepath.Join(snapshotVariantPath, fmt.Sprintf("arch-%s-%s",
+ "arm", "armv7-a-neon"))
+
+ vndkCoreLibPath := filepath.Join(vndkLibPath, "shared", "vndk-core")
+ vndkSpLibPath := filepath.Join(vndkLibPath, "shared", "vndk-sp")
+ vndkCoreLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-core")
+ vndkSpLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-sp")
+
+ variant := "android_arm64_armv8-a_vendor_shared"
+ variant2nd := "android_arm_armv7-a-neon_vendor_shared"
+
+ checkVndkSnapshot(t, ctx, "libvndk", vndkCoreLibPath, variant)
+ checkVndkSnapshot(t, ctx, "libvndk", vndkCoreLib2ndPath, variant2nd)
+ checkVndkSnapshot(t, ctx, "libvndk_sp", vndkSpLibPath, variant)
+ checkVndkSnapshot(t, ctx, "libvndk_sp", vndkSpLib2ndPath, variant2nd)
}
func TestVndkDepError(t *testing.T) {
@@ -1259,6 +1263,110 @@
`)
}
+func TestMakeLinkType(t *testing.T) {
+ config := android.TestArchConfig(buildDir, nil)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ // native:vndk
+ ctx := testCcWithConfig(t, `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ }
+ cc_library {
+ name: "libvndksp",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ }
+ cc_library {
+ name: "libvndkprivate",
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ },
+ }
+ cc_library {
+ name: "libvendor",
+ vendor: true,
+ }
+ cc_library {
+ name: "libvndkext",
+ vendor: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk",
+ },
+ }
+ vndk_prebuilt_shared {
+ name: "prevndk",
+ version: "27",
+ target_arch: "arm",
+ binder32bit: true,
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ arch: {
+ arm: {
+ srcs: ["liba.so"],
+ },
+ },
+ }
+ cc_library {
+ name: "libllndk",
+ }
+ llndk_library {
+ name: "libllndk",
+ symbol_file: "",
+ }
+ cc_library {
+ name: "libllndkprivate",
+ }
+ llndk_library {
+ name: "libllndkprivate",
+ vendor_available: false,
+ symbol_file: "",
+ }`, config)
+
+ assertArrayString(t, *vndkCoreLibraries(config),
+ []string{"libvndk", "libvndkprivate"})
+ assertArrayString(t, *vndkSpLibraries(config),
+ []string{"libc++", "libvndksp"})
+ assertArrayString(t, *llndkLibraries(config),
+ []string{"libc", "libdl", "libllndk", "libllndkprivate", "libm"})
+ assertArrayString(t, *vndkPrivateLibraries(config),
+ []string{"libllndkprivate", "libvndkprivate"})
+
+ tests := []struct {
+ variant string
+ name string
+ expected string
+ }{
+ {vendorVariant, "libvndk", "native:vndk"},
+ {vendorVariant, "libvndksp", "native:vndk"},
+ {vendorVariant, "libvndkprivate", "native:vndk_private"},
+ {vendorVariant, "libvendor", "native:vendor"},
+ {vendorVariant, "libvndkext", "native:vendor"},
+ {vendorVariant, "prevndk.vndk.27.arm.binder32", "native:vndk"},
+ {vendorVariant, "libllndk.llndk", "native:vndk"},
+ {coreVariant, "libvndk", "native:platform"},
+ {coreVariant, "libvndkprivate", "native:platform"},
+ {coreVariant, "libllndk", "native:platform"},
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ module := ctx.ModuleForTests(test.name, test.variant).Module().(*Module)
+ assertString(t, module.makeLinkType, test.expected)
+ })
+ }
+}
+
var (
str11 = "01234567891"
str10 = str11[:10]
@@ -1833,13 +1941,13 @@
// Check the shared version of lib2.
variant := "android_arm64_armv8-a_core_shared"
module := ctx.ModuleForTests("lib2", variant).Module().(*Module)
- checkStaticLibs(t, []string{"lib1", "libclang_rt.builtins-aarch64-android", "libatomic", "libgcc"}, module)
+ checkStaticLibs(t, []string{"lib1", "libclang_rt.builtins-aarch64-android", "libatomic", "libgcc_stripped"}, module)
// Check the static version of lib2.
variant = "android_arm64_armv8-a_core_static"
module = ctx.ModuleForTests("lib2", variant).Module().(*Module)
// libc++_static is linked additionally.
- checkStaticLibs(t, []string{"lib1", "libc++_static", "libclang_rt.builtins-aarch64-android", "libatomic", "libgcc"}, module)
+ checkStaticLibs(t, []string{"lib1", "libc++_static", "libclang_rt.builtins-aarch64-android", "libatomic", "libgcc_stripped"}, module)
}
var compilerFlagsTestCases = []struct {
@@ -2155,3 +2263,25 @@
)
}
}
+
+func assertString(t *testing.T, got, expected string) {
+ t.Helper()
+ if got != expected {
+ t.Errorf("expected %q got %q", expected, got)
+ }
+}
+
+func assertArrayString(t *testing.T, got, expected []string) {
+ t.Helper()
+ if len(got) != len(expected) {
+ t.Errorf("expected %d (%q) got (%d) %q", len(expected), expected, len(got), got)
+ return
+ }
+ for i := range got {
+ if got[i] != expected[i] {
+ t.Errorf("expected %d-th %q (%q) got %q (%q)",
+ i, expected[i], expected, got[i], got)
+ return
+ }
+ }
+}
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 617e3a0..47b60e7 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -101,8 +101,9 @@
// not emit the table by default on Android since NDK still uses GNU binutils.
"-faddrsig",
- // -Wimplicit-fallthrough is not enabled by -Wall.
+ // Make implicit fallthrough an error in the future.
"-Wimplicit-fallthrough",
+ "-Wno-error=implicit-fallthrough",
// Help catch common 32/64-bit errors.
"-Werror=int-conversion",
diff --git a/cc/config/global.go b/cc/config/global.go
index 0a7d984..24075d9 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -84,6 +84,7 @@
"-Wl,--fatal-warnings",
"-Wl,--no-undefined-version",
"-Wl,--exclude-libs,libgcc.a",
+ "-Wl,--exclude-libs,libgcc_stripped.a",
}
deviceGlobalLldflags = append(ClangFilterUnknownLldflags(deviceGlobalLdflags),
diff --git a/cc/installer.go b/cc/installer.go
index bd8f9e7..cb261b7 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -66,7 +66,7 @@
if ctx.toolchain().Is64Bit() && installer.dir64 != "" {
dir = installer.dir64
}
- if !ctx.Host() && !ctx.Arch().Native {
+ if (!ctx.Host() && !ctx.Arch().Native) || ctx.Target().NativeBridge == android.NativeBridgeEnabled {
dir = filepath.Join(dir, ctx.Arch().ArchType.String())
}
if installer.location == InstallInData && ctx.useVndk() {
diff --git a/cc/kernel_headers.go b/cc/kernel_headers.go
index 82a779c..c1da578 100644
--- a/cc/kernel_headers.go
+++ b/cc/kernel_headers.go
@@ -32,6 +32,11 @@
return stub.libraryDecorator.linkStatic(ctx, flags, deps, objs)
}
+// kernel_headers retrieves the list of kernel headers directories from
+// TARGET_BOARD_KERNEL_HEADERS and TARGET_PRODUCT_KERNEL_HEADERS variables in
+// a makefile for compilation. See
+// https://android.googlesource.com/platform/build/+/master/core/config.mk
+// for more details on them.
func kernelHeadersFactory() android.Module {
module, library := NewLibrary(android.HostAndDeviceSupported)
library.HeaderOnly()
diff --git a/cc/library.go b/cc/library.go
index 13972cc..3053831 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -15,6 +15,7 @@
package cc
import (
+ "io"
"path/filepath"
"regexp"
"sort"
@@ -22,7 +23,6 @@
"strings"
"sync"
- "github.com/google/blueprint"
"github.com/google/blueprint/pathtools"
"android/soong/android"
@@ -96,6 +96,9 @@
// Properties for ABI compatibility checker
Header_abi_checker struct {
+ // Enable ABI checks (even if this is not an LLNDK/VNDK lib)
+ Enabled *bool
+
// Path to a symbol file that specifies the symbols to be included in the generated
// ABI dump file
Symbol_file *string `android:"path"`
@@ -421,6 +424,13 @@
return exportedIncludes
}
+func (library *libraryDecorator) shouldCreateVndkSourceAbiDump(ctx ModuleContext) bool {
+ if library.Properties.Header_abi_checker.Enabled != nil {
+ return Bool(library.Properties.Header_abi_checker.Enabled)
+ }
+ return ctx.shouldCreateVndkSourceAbiDump(ctx.Config())
+}
+
func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
if library.buildStubs() {
objs, versionScript := compileStubLibrary(ctx, flags, String(library.Properties.Stubs.Symbol_file), library.MutatedProperties.StubsVersion, "--apex")
@@ -440,7 +450,7 @@
}
return Objects{}
}
- if ctx.shouldCreateVndkSourceAbiDump() || library.sabi.Properties.CreateSAbiDumps {
+ if library.shouldCreateVndkSourceAbiDump(ctx) || library.sabi.Properties.CreateSAbiDumps {
exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
var SourceAbiFlags []string
for _, dir := range exportIncludeDirs.Strings() {
@@ -487,6 +497,9 @@
// Sets whether a specific variant is static or shared
setStatic()
setShared()
+
+ // Write LOCAL_ADDITIONAL_DEPENDENCIES for ABI diff
+ androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer)
}
func (library *libraryDecorator) getLibName(ctx ModuleContext) string {
@@ -769,10 +782,10 @@
}
func getRefAbiDumpFile(ctx ModuleContext, vndkVersion, fileName string) android.Path {
- isLlndk := inList(ctx.baseModuleName(), llndkLibraries) || inList(ctx.baseModuleName(), ndkMigratedLibs)
+ isLlndkOrNdk := inList(ctx.baseModuleName(), *llndkLibraries(ctx.Config())) || inList(ctx.baseModuleName(), ndkMigratedLibs)
- refAbiDumpTextFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isLlndk, false)
- refAbiDumpGzipFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isLlndk, true)
+ refAbiDumpTextFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isLlndkOrNdk, ctx.isVndk(), false)
+ refAbiDumpGzipFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isLlndkOrNdk, ctx.isVndk(), true)
if refAbiDumpTextFile.Valid() {
if refAbiDumpGzipFile.Valid() {
@@ -790,7 +803,7 @@
}
func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
- if len(objs.sAbiDumpFiles) > 0 && ctx.shouldCreateVndkSourceAbiDump() {
+ if len(objs.sAbiDumpFiles) > 0 && library.shouldCreateVndkSourceAbiDump(ctx) {
vndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
if ver := ctx.DeviceConfig().VndkVersion(); ver != "" && ver != "current" {
vndkVersion = ver
@@ -813,7 +826,7 @@
refAbiDumpFile := getRefAbiDumpFile(ctx, vndkVersion, fileName)
if refAbiDumpFile != nil {
library.sAbiDiff = SourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
- refAbiDumpFile, fileName, exportedHeaderFlags, ctx.isLlndk(), ctx.isNdk(), ctx.isVndkExt())
+ refAbiDumpFile, fileName, exportedHeaderFlags, ctx.isLlndk(ctx.Config()), ctx.isNdk(), ctx.isVndkExt())
}
}
}
@@ -948,8 +961,8 @@
// Bionic libraries (e.g. libc.so) is installed to the bootstrap subdirectory.
// The original path becomes a symlink to the corresponding file in the
// runtime APEX.
- if isBionic(ctx.baseModuleName()) && !library.buildStubs() && ctx.Arch().Native && !ctx.inRecovery() {
- if ctx.Device() {
+ if installToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() && ctx.Arch().Native && !ctx.inRecovery() {
+ if ctx.Device() && isBionic(ctx.baseModuleName()) {
library.installSymlinkToRuntimeApex(ctx, file)
}
library.baseInstaller.subDir = "bootstrap"
@@ -1092,10 +1105,28 @@
func LinkageMutator(mctx android.BottomUpMutatorContext) {
if m, ok := mctx.Module().(*Module); ok && m.linker != nil {
- if library, ok := m.linker.(libraryInterface); ok {
- var modules []blueprint.Module
+ switch library := m.linker.(type) {
+ case prebuiltLibraryInterface:
+ // Always create both the static and shared variants for prebuilt libraries, and then disable the one
+ // that is not being used. This allows them to share the name of a cc_library module, which requires that
+ // all the variants of the cc_library also exist on the prebuilt.
+ modules := mctx.CreateLocalVariations("static", "shared")
+ static := modules[0].(*Module)
+ shared := modules[1].(*Module)
+
+ static.linker.(prebuiltLibraryInterface).setStatic()
+ shared.linker.(prebuiltLibraryInterface).setShared()
+
+ if !library.buildStatic() {
+ static.linker.(prebuiltLibraryInterface).disablePrebuilt()
+ }
+ if !library.buildShared() {
+ shared.linker.(prebuiltLibraryInterface).disablePrebuilt()
+ }
+
+ case libraryInterface:
if library.buildStatic() && library.buildShared() {
- modules = mctx.CreateLocalVariations("static", "shared")
+ modules := mctx.CreateLocalVariations("static", "shared")
static := modules[0].(*Module)
shared := modules[1].(*Module)
@@ -1105,10 +1136,10 @@
reuseStaticLibrary(mctx, static, shared)
} else if library.buildStatic() {
- modules = mctx.CreateLocalVariations("static")
+ modules := mctx.CreateLocalVariations("static")
modules[0].(*Module).linker.(libraryInterface).setStatic()
} else if library.buildShared() {
- modules = mctx.CreateLocalVariations("shared")
+ modules := mctx.CreateLocalVariations("shared")
modules[0].(*Module).linker.(libraryInterface).setShared()
}
}
diff --git a/cc/linker.go b/cc/linker.go
index e724df6..986a562 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -228,10 +228,10 @@
// libclang_rt.builtins, libgcc and libatomic have to be last on the command line
if !Bool(linker.Properties.No_libcrt) {
deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
- }
-
- deps.LateStaticLibs = append(deps.LateStaticLibs, "libatomic")
- if !Bool(linker.Properties.No_libgcc) {
+ deps.LateStaticLibs = append(deps.LateStaticLibs, "libatomic")
+ deps.LateStaticLibs = append(deps.LateStaticLibs, "libgcc_stripped")
+ } else if !Bool(linker.Properties.No_libgcc) {
+ deps.LateStaticLibs = append(deps.LateStaticLibs, "libatomic")
deps.LateStaticLibs = append(deps.LateStaticLibs, "libgcc")
}
diff --git a/cc/makevars.go b/cc/makevars.go
index dc91525..a71f479 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -64,6 +64,8 @@
}
func makeVarsProvider(ctx android.MakeVarsContext) {
+ vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
+
ctx.Strict("LLVM_RELEASE_VERSION", "${config.ClangShortVersion}")
ctx.Strict("LLVM_PREBUILTS_VERSION", "${config.ClangVersion}")
ctx.Strict("LLVM_PREBUILTS_BASE", "${config.ClangBase}")
@@ -92,18 +94,31 @@
ctx.Strict("BOARD_VNDK_VERSION", ctx.DeviceConfig().VndkVersion())
- ctx.Strict("VNDK_CORE_LIBRARIES", strings.Join(vndkCoreLibraries, " "))
- ctx.Strict("VNDK_SAMEPROCESS_LIBRARIES", strings.Join(vndkSpLibraries, " "))
- ctx.Strict("LLNDK_LIBRARIES", strings.Join(llndkLibraries, " "))
- ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(vndkPrivateLibraries, " "))
- ctx.Strict("VNDK_USING_CORE_VARIANT_LIBRARIES", strings.Join(vndkUsingCoreVariantLibraries, " "))
+ ctx.Strict("VNDK_CORE_LIBRARIES", strings.Join(*vndkCoreLibraries(ctx.Config()), " "))
+ ctx.Strict("VNDK_SAMEPROCESS_LIBRARIES", strings.Join(*vndkSpLibraries(ctx.Config()), " "))
+
+ // Make uses LLNDK_LIBRARIES to determine which libraries to install.
+ // HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN.
+ // Therefore, by removing the library here, we cause it to only be installed if libc
+ // depends on it.
+ installedLlndkLibraries := []string{}
+ for _, lib := range *llndkLibraries(ctx.Config()) {
+ if strings.HasPrefix(lib, "libclang_rt.hwasan-") {
+ continue
+ }
+ installedLlndkLibraries = append(installedLlndkLibraries, lib)
+ }
+ ctx.Strict("LLNDK_LIBRARIES", strings.Join(installedLlndkLibraries, " "))
+
+ ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(*vndkPrivateLibraries(ctx.Config()), " "))
+ ctx.Strict("VNDK_USING_CORE_VARIANT_LIBRARIES", strings.Join(*vndkUsingCoreVariantLibraries(ctx.Config()), " "))
// Filter vendor_public_library that are exported to make
exportedVendorPublicLibraries := []string{}
ctx.VisitAllModules(func(module android.Module) {
if ccModule, ok := module.(*Module); ok {
baseName := ccModule.BaseModuleName()
- if inList(baseName, vendorPublicLibraries) && module.ExportedToMake() {
+ if inList(baseName, *vendorPublicLibraries) && module.ExportedToMake() {
if !inList(baseName, exportedVendorPublicLibraries) {
exportedVendorPublicLibraries = append(exportedVendorPublicLibraries, baseName)
}
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index c63b200..ff990b5 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -38,9 +38,12 @@
ndkLibrarySuffix = ".ndk"
ndkPrebuiltSharedLibs = []string{
+ "aaudio",
+ "amidi",
"android",
"binder_ndk",
"c",
+ "camera2ndk",
"dl",
"EGL",
"GLESv1_CM",
@@ -49,6 +52,7 @@
"jnigraphics",
"log",
"mediandk",
+ "nativewindow",
"m",
"OpenMAXAL",
"OpenSLES",
@@ -382,5 +386,6 @@
func ndkLibraryFactory() android.Module {
module := newStubLibrary()
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
+ module.ModuleBase.EnableNativeBridgeSupportByDefault()
return module
}
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index 2a7e657..026ff22 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -64,8 +64,13 @@
return deps
}
+// ndk_prebuilt_object exports a precompiled ndk object file for linking
+// operations. Soong's module name format is ndk_<NAME>.o.<sdk_version> where
+// the object is located under
+// ./prebuilts/ndk/current/platforms/android-<sdk_version>/arch-$(HOST_ARCH)/usr/lib/<NAME>.o.
func ndkPrebuiltObjectFactory() android.Module {
module := newBaseModule(android.DeviceSupported, android.MultilibBoth)
+ module.ModuleBase.EnableNativeBridgeSupportByDefault()
module.linker = &ndkPrebuiltObjectLinker{
objectLinker: objectLinker{
baseLinker: NewBaseLinker(nil),
@@ -98,6 +103,10 @@
return deps
}
+// ndk_prebuilt_shared_stl exports a precompiled ndk shared standard template
+// library (stl) library for linking operation. The soong's module name format
+// is ndk_<NAME>.so where the library is located under
+// ./prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/$(HOST_ARCH)/<NAME>.so.
func ndkPrebuiltSharedStlFactory() android.Module {
module, library := NewLibrary(android.DeviceSupported)
library.BuildOnlyShared()
@@ -113,6 +122,10 @@
return module.Init()
}
+// ndk_prebuilt_static_stl exports a precompiled ndk static standard template
+// library (stl) library for linking operation. The soong's module name format
+// is ndk_<NAME>.a where the library is located under
+// ./prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/$(HOST_ARCH)/<NAME>.a.
func ndkPrebuiltStaticStlFactory() android.Module {
module, library := NewLibrary(android.DeviceSupported)
library.BuildOnlyStatic()
@@ -122,6 +135,7 @@
}
module.installer = nil
module.Properties.HideFromMake = true
+ module.ModuleBase.EnableNativeBridgeSupportByDefault()
return module.Init()
}
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 5ffeb32..48e4667 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -53,12 +53,19 @@
return p.properties.Srcs
}
+type prebuiltLibraryInterface interface {
+ libraryInterface
+ prebuiltLinkerInterface
+ disablePrebuilt()
+}
+
type prebuiltLibraryLinker struct {
*libraryDecorator
prebuiltLinker
}
var _ prebuiltLinkerInterface = (*prebuiltLibraryLinker)(nil)
+var _ prebuiltLibraryInterface = (*prebuiltLibraryLinker)(nil)
func (p *prebuiltLibraryLinker) linkerInit(ctx BaseModuleContext) {}
@@ -116,6 +123,10 @@
return false
}
+func (p *prebuiltLibraryLinker) disablePrebuilt() {
+ p.properties.Srcs = nil
+}
+
// cc_prebuilt_library_shared installs a precompiled shared library that are
// listed in the srcs property in the device's directory.
func prebuiltSharedLibraryFactory() android.Module {
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
new file mode 100644
index 0000000..98d78e8
--- /dev/null
+++ b/cc/prebuilt_test.go
@@ -0,0 +1,126 @@
+// 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 cc
+
+import (
+ "testing"
+
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+)
+
+func TestPrebuilt(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "liba",
+ }
+
+ cc_prebuilt_library_shared {
+ name: "liba",
+ srcs: ["liba.so"],
+ }
+
+ cc_library {
+ name: "libb",
+ }
+
+ cc_prebuilt_library_static {
+ name: "libb",
+ srcs: ["libb.a"],
+ }
+
+ cc_library_shared {
+ name: "libd",
+ }
+
+ cc_prebuilt_library_shared {
+ name: "libd",
+ srcs: ["libd.so"],
+ }
+
+ cc_library_static {
+ name: "libe",
+ }
+
+ cc_prebuilt_library_static {
+ name: "libe",
+ srcs: ["libe.a"],
+ }
+ `
+
+ fs := map[string][]byte{
+ "liba.so": nil,
+ "libb.a": nil,
+ "libd.so": nil,
+ "libe.a": nil,
+ }
+
+ config := android.TestArchConfig(buildDir, nil)
+
+ ctx := CreateTestContext(bp, fs, android.Android)
+
+ ctx.RegisterModuleType("cc_prebuilt_library_shared", android.ModuleFactoryAdaptor(prebuiltSharedLibraryFactory))
+ ctx.RegisterModuleType("cc_prebuilt_library_static", android.ModuleFactoryAdaptor(prebuiltStaticLibraryFactory))
+ ctx.RegisterModuleType("cc_prebuilt_binary", android.ModuleFactoryAdaptor(prebuiltBinaryFactory))
+
+ ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
+ ctx.PostDepsMutators(android.RegisterPrebuiltsPostDepsMutators)
+
+ ctx.Register()
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+
+ // Verify that all the modules exist and that their dependencies were connected correctly
+ liba := ctx.ModuleForTests("liba", "android_arm64_armv8-a_core_shared").Module()
+ libb := ctx.ModuleForTests("libb", "android_arm64_armv8-a_core_static").Module()
+ libd := ctx.ModuleForTests("libd", "android_arm64_armv8-a_core_shared").Module()
+ libe := ctx.ModuleForTests("libe", "android_arm64_armv8-a_core_static").Module()
+
+ prebuiltLiba := ctx.ModuleForTests("prebuilt_liba", "android_arm64_armv8-a_core_shared").Module()
+ prebuiltLibb := ctx.ModuleForTests("prebuilt_libb", "android_arm64_armv8-a_core_static").Module()
+ prebuiltLibd := ctx.ModuleForTests("prebuilt_libd", "android_arm64_armv8-a_core_shared").Module()
+ prebuiltLibe := ctx.ModuleForTests("prebuilt_libe", "android_arm64_armv8-a_core_static").Module()
+
+ hasDep := func(m android.Module, wantDep android.Module) bool {
+ t.Helper()
+ var found bool
+ ctx.VisitDirectDeps(m, func(dep blueprint.Module) {
+ if dep == wantDep {
+ found = true
+ }
+ })
+ return found
+ }
+
+ if !hasDep(liba, prebuiltLiba) {
+ t.Errorf("liba missing dependency on prebuilt_liba")
+ }
+
+ if !hasDep(libb, prebuiltLibb) {
+ t.Errorf("libb missing dependency on prebuilt_libb")
+ }
+
+ if !hasDep(libd, prebuiltLibd) {
+ t.Errorf("libd missing dependency on prebuilt_libd")
+ }
+
+ if !hasDep(libe, prebuiltLibe) {
+ t.Errorf("libe missing dependency on prebuilt_libe")
+ }
+}
diff --git a/cc/proto_test.go b/cc/proto_test.go
index a7fcef9..4f0de78 100644
--- a/cc/proto_test.go
+++ b/cc/proto_test.go
@@ -15,7 +15,6 @@
package cc
import (
- "runtime"
"strings"
"testing"
@@ -38,9 +37,6 @@
})
t.Run("plugin", func(t *testing.T) {
- if runtime.GOOS != "linux" {
- t.Skip("TODO(b/129763458): cc_binary_host tests fail on mac when trying to exec xcrun")
- }
ctx := testCc(t, `
cc_binary_host {
name: "protoc-gen-foobar",
diff --git a/cc/sabi.go b/cc/sabi.go
index 4a86499..451176f 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -78,7 +78,7 @@
func sabiDepsMutator(mctx android.TopDownMutatorContext) {
if c, ok := mctx.Module().(*Module); ok &&
- ((c.isVndk() && c.useVndk()) || inList(c.Name(), llndkLibraries) ||
+ ((c.isVndk() && c.useVndk()) || inList(c.Name(), *llndkLibraries(mctx.Config())) ||
(c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) {
mctx.VisitDirectDeps(func(m android.Module) {
tag := mctx.OtherModuleDependencyTag(m)
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 2d80c22..4486d2e 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -392,6 +392,11 @@
if ctx.Device() {
if Bool(sanitize.Properties.Sanitize.Address) {
deps.StaticLibs = append(deps.StaticLibs, asanLibs...)
+ // Compiling asan and having libc_scudo in the same
+ // executable will cause the executable to crash.
+ // Remove libc_scudo since it is only used to override
+ // allocation functions which asan already overrides.
+ _, deps.SharedLibs = removeFromList("libc_scudo", deps.SharedLibs)
}
}
@@ -817,7 +822,7 @@
}
if mctx.Device() && runtimeLibrary != "" {
- if inList(runtimeLibrary, llndkLibraries) && !c.static() && c.useVndk() {
+ if inList(runtimeLibrary, *llndkLibraries(mctx.Config())) && !c.static() && c.useVndk() {
runtimeLibrary = runtimeLibrary + llndkLibrarySuffix
}
diff --git a/cc/strip.go b/cc/strip.go
index 02397f4..4daa759 100644
--- a/cc/strip.go
+++ b/cc/strip.go
@@ -15,15 +15,20 @@
package cc
import (
+ "strings"
+
"android/soong/android"
)
type StripProperties struct {
Strip struct {
- None *bool
- All *bool
- Keep_symbols *bool
- }
+ None *bool `android:"arch_variant"`
+ All *bool `android:"arch_variant"`
+ Keep_symbols *bool `android:"arch_variant"`
+ Keep_symbols_list []string `android:"arch_variant"`
+ Keep_symbols_and_debug_frame *bool `android:"arch_variant"`
+ Use_gnu_strip *bool `android:"arch_variant"`
+ } `android:"arch_variant"`
}
type stripper struct {
@@ -42,9 +47,16 @@
} else {
if Bool(stripper.StripProperties.Strip.Keep_symbols) {
flags.stripKeepSymbols = true
+ } else if Bool(stripper.StripProperties.Strip.Keep_symbols_and_debug_frame) {
+ flags.stripKeepSymbolsAndDebugFrame = true
+ } else if len(stripper.StripProperties.Strip.Keep_symbols_list) > 0 {
+ flags.stripKeepSymbolsList = strings.Join(stripper.StripProperties.Strip.Keep_symbols_list, ",")
} else if !Bool(stripper.StripProperties.Strip.All) {
flags.stripKeepMiniDebugInfo = true
}
+ if Bool(stripper.StripProperties.Strip.Use_gnu_strip) {
+ flags.stripUseGnuStrip = true
+ }
if ctx.Config().Debuggable() && !flags.stripKeepMiniDebugInfo {
flags.stripAddGnuDebuglink = true
}
diff --git a/cc/testing.go b/cc/testing.go
index 2f41de1..d9be900 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -69,6 +69,13 @@
src: "",
}
+ toolchain_library {
+ name: "libgcc_stripped",
+ vendor_available: true,
+ recovery_available: true,
+ src: "",
+ }
+
cc_library {
name: "libc",
no_libgcc: true,
@@ -141,6 +148,12 @@
}
cc_object {
+ name: "crtbegin_dynamic",
+ recovery_available: true,
+ vendor_available: true,
+ }
+
+ cc_object {
name: "crtbegin_static",
recovery_available: true,
vendor_available: true,
@@ -176,3 +189,56 @@
}
return ret
}
+
+func CreateTestContext(bp string, fs map[string][]byte,
+ os android.OsType) *android.TestContext {
+
+ ctx := android.NewTestArchContext()
+ ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(BinaryFactory))
+ ctx.RegisterModuleType("cc_binary_host", android.ModuleFactoryAdaptor(binaryHostFactory))
+ ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
+ ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
+ ctx.RegisterModuleType("cc_library_static", android.ModuleFactoryAdaptor(LibraryStaticFactory))
+ ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(LibraryHeaderFactory))
+ ctx.RegisterModuleType("cc_test", android.ModuleFactoryAdaptor(TestFactory))
+ ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(ToolchainLibraryFactory))
+ ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(LlndkLibraryFactory))
+ ctx.RegisterModuleType("llndk_headers", android.ModuleFactoryAdaptor(llndkHeadersFactory))
+ ctx.RegisterModuleType("vendor_public_library", android.ModuleFactoryAdaptor(vendorPublicLibraryFactory))
+ ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(ObjectFactory))
+ ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
+ ctx.RegisterModuleType("vndk_prebuilt_shared", android.ModuleFactoryAdaptor(vndkPrebuiltSharedFactory))
+ ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("image", ImageMutator).Parallel()
+ ctx.BottomUp("link", LinkageMutator).Parallel()
+ ctx.BottomUp("vndk", VndkMutator).Parallel()
+ ctx.BottomUp("version", VersionMutator).Parallel()
+ ctx.BottomUp("begin", BeginMutator).Parallel()
+ })
+ ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
+ })
+ ctx.RegisterSingletonType("vndk-snapshot", android.SingletonFactoryAdaptor(VndkSnapshotSingleton))
+
+ // add some modules that are required by the compiler and/or linker
+ bp = bp + GatherRequiredDepsForTest(os)
+
+ mockFS := map[string][]byte{
+ "Android.bp": []byte(bp),
+ "foo.c": nil,
+ "bar.c": nil,
+ "a.proto": nil,
+ "b.aidl": nil,
+ "my_include": nil,
+ "foo.map.txt": nil,
+ "liba.so": nil,
+ }
+
+ for k, v := range fs {
+ mockFS[k] = v
+ }
+
+ ctx.MockFileSystem(mockFS)
+
+ return ctx
+}
diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go
index 6494a26..b4c51ab 100644
--- a/cc/toolchain_library.go
+++ b/cc/toolchain_library.go
@@ -34,6 +34,8 @@
type toolchainLibraryDecorator struct {
*libraryDecorator
+ stripper
+
Properties toolchainLibraryProperties
}
@@ -45,7 +47,7 @@
func (library *toolchainLibraryDecorator) linkerProps() []interface{} {
var props []interface{}
props = append(props, library.libraryDecorator.linkerProps()...)
- return append(props, &library.Properties)
+ return append(props, &library.Properties, &library.stripper.StripProperties)
}
// toolchain_library is used internally by the build tool to link the specified
@@ -78,7 +80,17 @@
return android.PathForSource(ctx, "")
}
- return android.PathForSource(ctx, *library.Properties.Src)
+ srcPath := android.PathForSource(ctx, *library.Properties.Src)
+
+ if library.stripper.StripProperties.Strip.Keep_symbols_list != nil {
+ fileName := ctx.ModuleName() + staticLibraryExtension
+ outputFile := android.PathForModuleOut(ctx, fileName)
+ buildFlags := flagsToBuilderFlags(flags)
+ library.stripper.strip(ctx, srcPath, outputFile, buildFlags)
+ return outputFile
+ }
+
+ return srcPath
}
func (library *toolchainLibraryDecorator) nativeCoverage() bool {
diff --git a/cc/vendor_public_library.go b/cc/vendor_public_library.go
index 2072ad9..5738d25 100644
--- a/cc/vendor_public_library.go
+++ b/cc/vendor_public_library.go
@@ -24,10 +24,16 @@
var (
vendorPublicLibrarySuffix = ".vendorpublic"
- vendorPublicLibraries = []string{}
+ vendorPublicLibrariesKey = android.NewOnceKey("vendorPublicLibraries")
vendorPublicLibrariesLock sync.Mutex
)
+func vendorPublicLibraries(config android.Config) *[]string {
+ return config.Once(vendorPublicLibrariesKey, func() interface{} {
+ return &[]string{}
+ }).(*[]string)
+}
+
// Creates a stub shared library for a vendor public library. Vendor public libraries
// are vendor libraries (owned by them and installed to /vendor partition) that are
// exposed to Android apps via JNI. The libraries are made public by being listed in
@@ -82,12 +88,13 @@
vendorPublicLibrariesLock.Lock()
defer vendorPublicLibrariesLock.Unlock()
- for _, lib := range vendorPublicLibraries {
+ vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
+ for _, lib := range *vendorPublicLibraries {
if lib == name {
return
}
}
- vendorPublicLibraries = append(vendorPublicLibraries, name)
+ *vendorPublicLibraries = append(*vendorPublicLibraries, name)
}
func (stub *vendorPublicLibraryStubDecorator) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
diff --git a/cc/vndk.go b/cc/vndk.go
index 44a83e7..a1d67af 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -16,6 +16,8 @@
import (
"errors"
+ "fmt"
+ "path/filepath"
"sort"
"strings"
"sync"
@@ -192,64 +194,345 @@
}
var (
- vndkCoreLibraries []string
- vndkSpLibraries []string
- llndkLibraries []string
- vndkPrivateLibraries []string
- vndkUsingCoreVariantLibraries []string
- vndkLibrariesLock sync.Mutex
+ vndkCoreLibrariesKey = android.NewOnceKey("vndkCoreLibrarires")
+ vndkSpLibrariesKey = android.NewOnceKey("vndkSpLibrarires")
+ llndkLibrariesKey = android.NewOnceKey("llndkLibrarires")
+ vndkPrivateLibrariesKey = android.NewOnceKey("vndkPrivateLibrarires")
+ vndkUsingCoreVariantLibrariesKey = android.NewOnceKey("vndkUsingCoreVariantLibrarires")
+ modulePathsKey = android.NewOnceKey("modulePaths")
+ vndkSnapshotOutputsKey = android.NewOnceKey("vndkSnapshotOutputs")
+ vndkLibrariesLock sync.Mutex
)
+type vndkSnapshotOutputPaths struct {
+ configs android.Paths
+ notices android.Paths
+ vndkCoreLibs android.Paths
+ vndkCoreLibs2nd android.Paths
+ vndkSpLibs android.Paths
+ vndkSpLibs2nd android.Paths
+}
+
+func vndkCoreLibraries(config android.Config) *[]string {
+ return config.Once(vndkCoreLibrariesKey, func() interface{} {
+ return &[]string{}
+ }).(*[]string)
+}
+
+func vndkSpLibraries(config android.Config) *[]string {
+ return config.Once(vndkSpLibrariesKey, func() interface{} {
+ return &[]string{}
+ }).(*[]string)
+}
+
+func llndkLibraries(config android.Config) *[]string {
+ return config.Once(llndkLibrariesKey, func() interface{} {
+ return &[]string{}
+ }).(*[]string)
+}
+
+func vndkPrivateLibraries(config android.Config) *[]string {
+ return config.Once(vndkPrivateLibrariesKey, func() interface{} {
+ return &[]string{}
+ }).(*[]string)
+}
+
+func vndkUsingCoreVariantLibraries(config android.Config) *[]string {
+ return config.Once(vndkUsingCoreVariantLibrariesKey, func() interface{} {
+ return &[]string{}
+ }).(*[]string)
+}
+
+func modulePaths(config android.Config) map[string]string {
+ return config.Once(modulePathsKey, func() interface{} {
+ return make(map[string]string)
+ }).(map[string]string)
+}
+
+func vndkSnapshotOutputs(config android.Config) *vndkSnapshotOutputPaths {
+ return config.Once(vndkSnapshotOutputsKey, func() interface{} {
+ return &vndkSnapshotOutputPaths{}
+ }).(*vndkSnapshotOutputPaths)
+}
+
+func processLlndkLibrary(mctx android.BottomUpMutatorContext, m *Module) {
+ lib := m.linker.(*llndkStubDecorator)
+ name := strings.TrimSuffix(m.Name(), llndkLibrarySuffix)
+
+ vndkLibrariesLock.Lock()
+ defer vndkLibrariesLock.Unlock()
+
+ llndkLibraries := llndkLibraries(mctx.Config())
+ if !inList(name, *llndkLibraries) {
+ *llndkLibraries = append(*llndkLibraries, name)
+ sort.Strings(*llndkLibraries)
+ }
+ if !Bool(lib.Properties.Vendor_available) {
+ vndkPrivateLibraries := vndkPrivateLibraries(mctx.Config())
+ if !inList(name, *vndkPrivateLibraries) {
+ *vndkPrivateLibraries = append(*vndkPrivateLibraries, name)
+ sort.Strings(*vndkPrivateLibraries)
+ }
+ }
+}
+
+func processVndkLibrary(mctx android.BottomUpMutatorContext, m *Module) {
+ name := strings.TrimPrefix(m.Name(), "prebuilt_")
+
+ vndkLibrariesLock.Lock()
+ defer vndkLibrariesLock.Unlock()
+
+ modulePaths := modulePaths(mctx.Config())
+ if mctx.DeviceConfig().VndkUseCoreVariant() && !inList(name, config.VndkMustUseVendorVariantList) {
+ vndkUsingCoreVariantLibraries := vndkUsingCoreVariantLibraries(mctx.Config())
+ if !inList(name, *vndkUsingCoreVariantLibraries) {
+ *vndkUsingCoreVariantLibraries = append(*vndkUsingCoreVariantLibraries, name)
+ sort.Strings(*vndkUsingCoreVariantLibraries)
+ }
+ }
+ if m.vndkdep.isVndkSp() {
+ vndkSpLibraries := vndkSpLibraries(mctx.Config())
+ if !inList(name, *vndkSpLibraries) {
+ *vndkSpLibraries = append(*vndkSpLibraries, name)
+ sort.Strings(*vndkSpLibraries)
+ modulePaths[name] = mctx.ModuleDir()
+ }
+ } else {
+ vndkCoreLibraries := vndkCoreLibraries(mctx.Config())
+ if !inList(name, *vndkCoreLibraries) {
+ *vndkCoreLibraries = append(*vndkCoreLibraries, name)
+ sort.Strings(*vndkCoreLibraries)
+ modulePaths[name] = mctx.ModuleDir()
+ }
+ }
+ if !Bool(m.VendorProperties.Vendor_available) {
+ vndkPrivateLibraries := vndkPrivateLibraries(mctx.Config())
+ if !inList(name, *vndkPrivateLibraries) {
+ *vndkPrivateLibraries = append(*vndkPrivateLibraries, name)
+ sort.Strings(*vndkPrivateLibraries)
+ }
+ }
+}
+
// gather list of vndk-core, vndk-sp, and ll-ndk libs
func VndkMutator(mctx android.BottomUpMutatorContext) {
- if m, ok := mctx.Module().(*Module); ok && m.Enabled() {
- if lib, ok := m.linker.(*llndkStubDecorator); ok {
- vndkLibrariesLock.Lock()
- defer vndkLibrariesLock.Unlock()
- name := strings.TrimSuffix(m.Name(), llndkLibrarySuffix)
- if !inList(name, llndkLibraries) {
- llndkLibraries = append(llndkLibraries, name)
- sort.Strings(llndkLibraries)
- }
- if !Bool(lib.Properties.Vendor_available) {
- if !inList(name, vndkPrivateLibraries) {
- vndkPrivateLibraries = append(vndkPrivateLibraries, name)
- sort.Strings(vndkPrivateLibraries)
- }
- }
- } else {
- lib, is_lib := m.linker.(*libraryDecorator)
- prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
- if (is_lib && lib.shared()) || (is_prebuilt_lib && prebuilt_lib.shared()) {
- name := strings.TrimPrefix(m.Name(), "prebuilt_")
- if m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() {
- vndkLibrariesLock.Lock()
- defer vndkLibrariesLock.Unlock()
- if mctx.DeviceConfig().VndkUseCoreVariant() && !inList(name, config.VndkMustUseVendorVariantList) {
- if !inList(name, vndkUsingCoreVariantLibraries) {
- vndkUsingCoreVariantLibraries = append(vndkUsingCoreVariantLibraries, name)
- sort.Strings(vndkUsingCoreVariantLibraries)
- }
- }
- if m.vndkdep.isVndkSp() {
- if !inList(name, vndkSpLibraries) {
- vndkSpLibraries = append(vndkSpLibraries, name)
- sort.Strings(vndkSpLibraries)
- }
- } else {
- if !inList(name, vndkCoreLibraries) {
- vndkCoreLibraries = append(vndkCoreLibraries, name)
- sort.Strings(vndkCoreLibraries)
- }
- }
- if !Bool(m.VendorProperties.Vendor_available) {
- if !inList(name, vndkPrivateLibraries) {
- vndkPrivateLibraries = append(vndkPrivateLibraries, name)
- sort.Strings(vndkPrivateLibraries)
- }
- }
- }
- }
+ m, ok := mctx.Module().(*Module)
+ if !ok {
+ return
+ }
+
+ if !m.Enabled() {
+ return
+ }
+
+ if _, ok := m.linker.(*llndkStubDecorator); ok {
+ processLlndkLibrary(mctx, m)
+ return
+ }
+
+ lib, is_lib := m.linker.(*libraryDecorator)
+ prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
+
+ if (is_lib && lib.shared()) || (is_prebuilt_lib && prebuilt_lib.shared()) {
+ if m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() {
+ processVndkLibrary(mctx, m)
+ return
}
}
}
+
+func init() {
+ android.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
+ android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
+ outputs := vndkSnapshotOutputs(ctx.Config())
+
+ ctx.Strict("SOONG_VNDK_SNAPSHOT_CONFIGS", strings.Join(outputs.configs.Strings(), " "))
+ ctx.Strict("SOONG_VNDK_SNAPSHOT_NOTICES", strings.Join(outputs.notices.Strings(), " "))
+ ctx.Strict("SOONG_VNDK_SNAPSHOT_CORE_LIBS", strings.Join(outputs.vndkCoreLibs.Strings(), " "))
+ ctx.Strict("SOONG_VNDK_SNAPSHOT_SP_LIBS", strings.Join(outputs.vndkSpLibs.Strings(), " "))
+ ctx.Strict("SOONG_VNDK_SNAPSHOT_CORE_LIBS_2ND", strings.Join(outputs.vndkCoreLibs2nd.Strings(), " "))
+ ctx.Strict("SOONG_VNDK_SNAPSHOT_SP_LIBS_2ND", strings.Join(outputs.vndkSpLibs2nd.Strings(), " "))
+ })
+}
+
+func VndkSnapshotSingleton() android.Singleton {
+ return &vndkSnapshotSingleton{}
+}
+
+type vndkSnapshotSingleton struct{}
+
+func installVndkSnapshotLib(ctx android.SingletonContext, name string, module *Module, dir string) android.Path {
+ if !module.outputFile.Valid() {
+ panic(fmt.Errorf("module %s has no outputFile\n", name))
+ }
+
+ out := android.PathForOutput(ctx, dir, name+".so")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: module.outputFile.Path(),
+ Output: out,
+ Description: "vndk snapshot " + dir + "/" + name + ".so",
+ Args: map[string]string{
+ "cpFlags": "-f -L",
+ },
+ })
+
+ return out
+}
+
+func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ // BOARD_VNDK_VERSION must be set to 'current' in order to generate a VNDK snapshot.
+ if ctx.DeviceConfig().VndkVersion() != "current" {
+ return
+ }
+
+ if ctx.DeviceConfig().PlatformVndkVersion() == "" {
+ return
+ }
+
+ if ctx.DeviceConfig().BoardVndkRuntimeDisable() {
+ return
+ }
+
+ outputs := vndkSnapshotOutputs(ctx.Config())
+
+ snapshotDir := "vndk-snapshot"
+
+ var vndkLibPath, vndkLib2ndPath string
+
+ snapshotVariantPath := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
+ if ctx.DeviceConfig().BinderBitness() == "32" {
+ vndkLibPath = filepath.Join(snapshotVariantPath, "binder32", fmt.Sprintf(
+ "arch-%s-%s", ctx.DeviceConfig().DeviceArch(), ctx.DeviceConfig().DeviceArchVariant()))
+ vndkLib2ndPath = filepath.Join(snapshotVariantPath, "binder32", fmt.Sprintf(
+ "arch-%s-%s", ctx.DeviceConfig().DeviceSecondaryArch(), ctx.DeviceConfig().DeviceSecondaryArchVariant()))
+ } else {
+ vndkLibPath = filepath.Join(snapshotVariantPath, fmt.Sprintf(
+ "arch-%s-%s", ctx.DeviceConfig().DeviceArch(), ctx.DeviceConfig().DeviceArchVariant()))
+ vndkLib2ndPath = filepath.Join(snapshotVariantPath, fmt.Sprintf(
+ "arch-%s-%s", ctx.DeviceConfig().DeviceSecondaryArch(), ctx.DeviceConfig().DeviceSecondaryArchVariant()))
+ }
+
+ vndkCoreLibPath := filepath.Join(vndkLibPath, "shared", "vndk-core")
+ vndkSpLibPath := filepath.Join(vndkLibPath, "shared", "vndk-sp")
+ vndkCoreLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-core")
+ vndkSpLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-sp")
+ noticePath := filepath.Join(snapshotVariantPath, "NOTICE_FILES")
+ noticeBuilt := make(map[string]bool)
+
+ tryBuildNotice := func(m *Module) {
+ name := ctx.ModuleName(m)
+
+ if _, ok := noticeBuilt[name]; ok {
+ return
+ }
+
+ noticeBuilt[name] = true
+
+ if m.NoticeFile().Valid() {
+ out := android.PathForOutput(ctx, noticePath, name+".so.txt")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: m.NoticeFile().Path(),
+ Output: out,
+ Description: "vndk snapshot notice " + name + ".so.txt",
+ Args: map[string]string{
+ "cpFlags": "-f -L",
+ },
+ })
+ outputs.notices = append(outputs.notices, out)
+ }
+ }
+
+ vndkCoreLibraries := vndkCoreLibraries(ctx.Config())
+ vndkSpLibraries := vndkSpLibraries(ctx.Config())
+ vndkPrivateLibraries := vndkPrivateLibraries(ctx.Config())
+
+ ctx.VisitAllModules(func(module android.Module) {
+ m, ok := module.(*Module)
+ if !ok || !m.Enabled() || !m.useVndk() || !m.installable() {
+ return
+ }
+
+ lib, is_lib := m.linker.(*libraryDecorator)
+ prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
+
+ if !(is_lib && lib.shared()) && !(is_prebuilt_lib && prebuilt_lib.shared()) {
+ return
+ }
+
+ is_2nd := m.Target().Arch.ArchType != ctx.Config().DevicePrimaryArchType()
+
+ name := ctx.ModuleName(module)
+
+ if inList(name, *vndkCoreLibraries) {
+ if is_2nd {
+ out := installVndkSnapshotLib(ctx, name, m, vndkCoreLib2ndPath)
+ outputs.vndkCoreLibs2nd = append(outputs.vndkCoreLibs2nd, out)
+ } else {
+ out := installVndkSnapshotLib(ctx, name, m, vndkCoreLibPath)
+ outputs.vndkCoreLibs = append(outputs.vndkCoreLibs, out)
+ }
+ tryBuildNotice(m)
+ } else if inList(name, *vndkSpLibraries) {
+ if is_2nd {
+ out := installVndkSnapshotLib(ctx, name, m, vndkSpLib2ndPath)
+ outputs.vndkSpLibs2nd = append(outputs.vndkSpLibs2nd, out)
+ } else {
+ out := installVndkSnapshotLib(ctx, name, m, vndkSpLibPath)
+ outputs.vndkSpLibs = append(outputs.vndkSpLibs, out)
+ }
+ tryBuildNotice(m)
+ }
+ })
+
+ configsPath := filepath.Join(snapshotVariantPath, "configs")
+ vndkCoreTxt := android.PathForOutput(ctx, configsPath, "vndkcore.libraries.txt")
+ vndkPrivateTxt := android.PathForOutput(ctx, configsPath, "vndkprivate.libraries.txt")
+ modulePathTxt := android.PathForOutput(ctx, configsPath, "module_paths.txt")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.WriteFile,
+ Output: vndkCoreTxt,
+ Description: "vndk snapshot vndkcore.libraries.txt",
+ Args: map[string]string{
+ "content": android.JoinWithSuffix(*vndkCoreLibraries, ".so", "\\n"),
+ },
+ })
+ outputs.configs = append(outputs.configs, vndkCoreTxt)
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.WriteFile,
+ Output: vndkPrivateTxt,
+ Description: "vndk snapshot vndkprivate.libraries.txt",
+ Args: map[string]string{
+ "content": android.JoinWithSuffix(*vndkPrivateLibraries, ".so", "\\n"),
+ },
+ })
+ outputs.configs = append(outputs.configs, vndkPrivateTxt)
+
+ var modulePathTxtBuilder strings.Builder
+
+ first := true
+ for lib, dir := range modulePaths(ctx.Config()) {
+ if first {
+ first = false
+ } else {
+ modulePathTxtBuilder.WriteString("\\n")
+ }
+ modulePathTxtBuilder.WriteString(lib)
+ modulePathTxtBuilder.WriteString(".so ")
+ modulePathTxtBuilder.WriteString(dir)
+ }
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.WriteFile,
+ Output: modulePathTxt,
+ Description: "vndk snapshot module_paths.txt",
+ Args: map[string]string{
+ "content": modulePathTxtBuilder.String(),
+ },
+ })
+ outputs.configs = append(outputs.configs, modulePathTxt)
+}
diff --git a/cmd/diff_target_files/known_nondeterminism.whitelist b/cmd/diff_target_files/known_nondeterminism.whitelist
index 6d71403..a8ade49 100644
--- a/cmd/diff_target_files/known_nondeterminism.whitelist
+++ b/cmd/diff_target_files/known_nondeterminism.whitelist
@@ -3,8 +3,6 @@
[
{
"Paths": [
- // b/120039850
- "system/framework/oat/*/services.art"
]
}
]
diff --git a/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go
index 2dfa546..c858c40 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -126,6 +126,7 @@
var sdkVersion string
var useVersion string
+var staticDeps bool
var jetifier bool
func InList(s string, list []string) bool {
@@ -333,6 +334,38 @@
var bpTemplate = template.Must(template.New("bp").Parse(`
{{.ImportModuleType}} {
+ name: "{{.BpName}}",
+ {{.ImportProperty}}: ["{{.ArtifactFile}}"],
+ sdk_version: "{{.SdkVersion}}",
+ {{- if .Jetifier}}
+ jetifier: true,
+ {{- end}}
+ {{- if .IsAar}}
+ min_sdk_version: "{{.MinSdkVersion}}",
+ static_libs: [
+ {{- range .BpJarDeps}}
+ "{{.}}",
+ {{- end}}
+ {{- range .BpAarDeps}}
+ "{{.}}",
+ {{- end}}
+ {{- range .BpExtraStaticLibs}}
+ "{{.}}",
+ {{- end}}
+ ],
+ {{- if .BpExtraLibs}}
+ libs: [
+ {{- range .BpExtraLibs}}
+ "{{.}}",
+ {{- end}}
+ ],
+ {{- end}}
+ {{- end}}
+}
+`))
+
+var bpDepsTemplate = template.Must(template.New("bp").Parse(`
+{{.ImportModuleType}} {
name: "{{.BpName}}-nodeps",
{{.ImportProperty}}: ["{{.ArtifactFile}}"],
sdk_version: "{{.SdkVersion}}",
@@ -533,8 +566,8 @@
flag.Var(&hostModuleNames, "host", "Specifies that the corresponding module (specified in the form 'module.group:module.artifact') is a host module")
flag.StringVar(&sdkVersion, "sdk-version", "", "What to write to sdk_version")
flag.StringVar(&useVersion, "use-version", "", "Only read artifacts of a specific version")
+ flag.BoolVar(&staticDeps, "static-deps", false, "Statically include direct dependencies")
flag.BoolVar(&jetifier, "jetifier", false, "Sets jetifier: true on all modules")
- flag.Bool("static-deps", false, "Ignored")
flag.StringVar(®en, "regen", "", "Rewrite specified file")
flag.Parse()
@@ -648,7 +681,11 @@
for _, pom := range poms {
var err error
- err = bpTemplate.Execute(buf, pom)
+ if staticDeps {
+ err = bpDepsTemplate.Execute(buf, pom)
+ } else {
+ err = bpTemplate.Execute(buf, pom)
+ }
if err != nil {
fmt.Fprintln(os.Stderr, "Error writing", pom.PomFile, pom.BpName(), err)
os.Exit(1)
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index d6999c5..5f9bd01 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -32,42 +32,89 @@
"android/soong/ui/tracer"
)
+// A command represents an operation to be executed in the soong build
+// system.
+type command struct {
+ // the flag name (must have double dashes)
+ flag string
+
+ // description for the flag (to display when running help)
+ description string
+
+ // Creates the build configuration based on the args and build context.
+ config func(ctx build.Context, args ...string) build.Config
+
+ // Returns what type of IO redirection this Command requires.
+ stdio func() terminal.StdioInterface
+
+ // run the command
+ run func(ctx build.Context, config build.Config, args []string, logsDir string)
+}
+
+const makeModeFlagName = "--make-mode"
+
+// list of supported commands (flags) supported by soong ui
+var commands []command = []command{
+ {
+ flag: makeModeFlagName,
+ description: "build the modules by the target name (i.e. soong_docs)",
+ config: func(ctx build.Context, args ...string) build.Config {
+ return build.NewConfig(ctx, args...)
+ },
+ stdio: func() terminal.StdioInterface {
+ return terminal.StdioImpl{}
+ },
+ run: make,
+ }, {
+ flag: "--dumpvar-mode",
+ description: "print the value of the legacy make variable VAR to stdout",
+ config: dumpVarConfig,
+ stdio: customStdio,
+ run: dumpVar,
+ }, {
+ flag: "--dumpvars-mode",
+ description: "dump the values of one or more legacy make variables, in shell syntax",
+ config: dumpVarConfig,
+ stdio: customStdio,
+ run: dumpVars,
+ },
+}
+
+// indexList returns the index of first found s. -1 is return if s is not
+// found.
func indexList(s string, list []string) int {
for i, l := range list {
if l == s {
return i
}
}
-
return -1
}
+// inList returns true if one or more of s is in the list.
func inList(s string, list []string) bool {
return indexList(s, list) != -1
}
+// Main execution of soong_ui. The command format is as follows:
+//
+// soong_ui <command> [<arg 1> <arg 2> ... <arg n>]
+//
+// Command is the type of soong_ui execution. Only one type of
+// execution is specified. The args are specific to the command.
func main() {
- var stdio terminal.StdioInterface
- stdio = terminal.StdioImpl{}
-
- // dumpvar uses stdout, everything else should be in stderr
- if os.Args[1] == "--dumpvar-mode" || os.Args[1] == "--dumpvars-mode" {
- stdio = terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr)
+ c, args := getCommand(os.Args)
+ if c == nil {
+ fmt.Fprintf(os.Stderr, "The `soong` native UI is not yet available.\n")
+ os.Exit(1)
}
- writer := terminal.NewWriter(stdio)
+ writer := terminal.NewWriter(c.stdio())
defer writer.Finish()
log := logger.New(writer)
defer log.Cleanup()
- if len(os.Args) < 2 || !(inList("--make-mode", os.Args) ||
- os.Args[1] == "--dumpvars-mode" ||
- os.Args[1] == "--dumpvar-mode") {
-
- log.Fatalln("The `soong` native UI is not yet available.")
- }
-
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@@ -96,12 +143,8 @@
Writer: writer,
Status: stat,
}}
- var config build.Config
- if os.Args[1] == "--dumpvars-mode" || os.Args[1] == "--dumpvar-mode" {
- config = build.NewConfig(buildCtx)
- } else {
- config = build.NewConfig(buildCtx, os.Args[1:]...)
- }
+
+ config := c.config(buildCtx, args...)
build.SetupOutDir(buildCtx, config)
@@ -136,31 +179,10 @@
defer f.Shutdown()
build.FindSources(buildCtx, config, f)
- if os.Args[1] == "--dumpvar-mode" {
- dumpVar(buildCtx, config, os.Args[2:])
- } else if os.Args[1] == "--dumpvars-mode" {
- dumpVars(buildCtx, config, os.Args[2:])
- } else {
- if config.IsVerbose() {
- writer.Print("! The argument `showcommands` is no longer supported.")
- writer.Print("! Instead, the verbose log is always written to a compressed file in the output dir:")
- writer.Print("!")
- writer.Print(fmt.Sprintf("! gzip -cd %s/verbose.log.gz | less -R", logsDir))
- writer.Print("!")
- writer.Print("! Older versions are saved in verbose.log.#.gz files")
- writer.Print("")
- time.Sleep(5 * time.Second)
- }
-
- toBuild := build.BuildAll
- if config.Checkbuild() {
- toBuild |= build.RunBuildTests
- }
- build.Build(buildCtx, config, toBuild)
- }
+ c.run(buildCtx, config, args, logsDir)
}
-func dumpVar(ctx build.Context, config build.Config, args []string) {
+func dumpVar(ctx build.Context, config build.Config, args []string, _ string) {
flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
flags.Usage = func() {
fmt.Fprintf(os.Stderr, "usage: %s --dumpvar-mode [--abs] <VAR>\n\n", os.Args[0])
@@ -210,7 +232,7 @@
}
}
-func dumpVars(ctx build.Context, config build.Config, args []string) {
+func dumpVars(ctx build.Context, config build.Config, args []string, _ string) {
flags := flag.NewFlagSet("dumpvars", flag.ExitOnError)
flags.Usage = func() {
fmt.Fprintf(os.Stderr, "usage: %s --dumpvars-mode [--vars=\"VAR VAR ...\"]\n\n", os.Args[0])
@@ -277,3 +299,59 @@
fmt.Printf("%s%s='%s'\n", *absVarPrefix, name, strings.Join(res, " "))
}
}
+
+func customStdio() terminal.StdioInterface {
+ return terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr)
+}
+
+// dumpVarConfig does not require any arguments to be parsed by the NewConfig.
+func dumpVarConfig(ctx build.Context, args ...string) build.Config {
+ return build.NewConfig(ctx)
+}
+
+func make(ctx build.Context, config build.Config, _ []string, logsDir string) {
+ if config.IsVerbose() {
+ writer := ctx.Writer
+ writer.Print("! The argument `showcommands` is no longer supported.")
+ writer.Print("! Instead, the verbose log is always written to a compressed file in the output dir:")
+ writer.Print("!")
+ writer.Print(fmt.Sprintf("! gzip -cd %s/verbose.log.gz | less -R", logsDir))
+ writer.Print("!")
+ writer.Print("! Older versions are saved in verbose.log.#.gz files")
+ writer.Print("")
+ time.Sleep(5 * time.Second)
+ }
+
+ toBuild := build.BuildAll
+ if config.Checkbuild() {
+ toBuild |= build.RunBuildTests
+ }
+ build.Build(ctx, config, toBuild)
+}
+
+// getCommand finds the appropriate command based on args[1] flag. args[0]
+// is the soong_ui filename.
+func getCommand(args []string) (*command, []string) {
+ if len(args) < 2 {
+ return nil, args
+ }
+
+ for _, c := range commands {
+ if c.flag == args[1] {
+ return &c, args[2:]
+ }
+
+ // special case for --make-mode: if soong_ui was called from
+ // build/make/core/main.mk, the makeparallel with --ninja
+ // option specified puts the -j<num> before --make-mode.
+ // TODO: Remove this hack once it has been fixed.
+ if c.flag == makeModeFlagName {
+ if inList(makeModeFlagName, args) {
+ return &c, args[1:]
+ }
+ }
+ }
+
+ // command not found
+ return nil, args
+}
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index f1fa0ff..1e0f862 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -59,6 +59,7 @@
NeverAllowStripping bool // whether stripping should not be done - used as build time check to make sure dex files are always available
NoDebugInfo bool // don't generate debug info by default
+ DontResolveStartupStrings bool // don't resolve string literals loaded during application startup.
AlwaysSystemServerDebugInfo bool // always generate mini debug info for system server modules (overrides NoDebugInfo=true)
NeverSystemServerDebugInfo bool // never generate mini debug info for system server modules (overrides NoDebugInfo=false)
AlwaysOtherDebugInfo bool // always generate mini debug info for non-system server modules (overrides NoDebugInfo=true)
@@ -175,7 +176,7 @@
// LoadGlobalConfig reads the global dexpreopt.config file into a GlobalConfig struct. It is used directly in Soong
// and in dexpreopt_gen called from Make to read the $OUT/dexpreopt.config written by Make.
-func LoadGlobalConfig(ctx android.PathContext, path string) (GlobalConfig, error) {
+func LoadGlobalConfig(ctx android.PathContext, path string) (GlobalConfig, []byte, error) {
type GlobalJSONConfig struct {
GlobalConfig
@@ -198,9 +199,9 @@
}
config := GlobalJSONConfig{}
- err := loadConfig(ctx, path, &config)
+ data, err := loadConfig(ctx, path, &config)
if err != nil {
- return config.GlobalConfig, err
+ return config.GlobalConfig, nil, err
}
// Construct paths that require a PathContext.
@@ -216,7 +217,7 @@
config.GlobalConfig.Tools.VerifyUsesLibraries = constructPath(ctx, config.Tools.VerifyUsesLibraries)
config.GlobalConfig.Tools.ConstructContext = constructPath(ctx, config.Tools.ConstructContext)
- return config.GlobalConfig, nil
+ return config.GlobalConfig, data, nil
}
// LoadModuleConfig reads a per-module dexpreopt.config file into a ModuleConfig struct. It is not used in Soong, which
@@ -240,7 +241,7 @@
config := ModuleJSONConfig{}
- err := loadConfig(ctx, path, &config)
+ _, err := loadConfig(ctx, path, &config)
if err != nil {
return config.ModuleConfig, err
}
@@ -258,24 +259,24 @@
return config.ModuleConfig, nil
}
-func loadConfig(ctx android.PathContext, path string, config interface{}) error {
+func loadConfig(ctx android.PathContext, path string, config interface{}) ([]byte, error) {
r, err := ctx.Fs().Open(path)
if err != nil {
- return err
+ return nil, err
}
defer r.Close()
data, err := ioutil.ReadAll(r)
if err != nil {
- return err
+ return nil, err
}
err = json.Unmarshal(data, config)
if err != nil {
- return err
+ return nil, err
}
- return nil
+ return data, nil
}
func GlobalConfigForTests(ctx android.PathContext) GlobalConfig {
@@ -301,6 +302,7 @@
GenerateDMFiles: false,
NeverAllowStripping: false,
NoDebugInfo: false,
+ DontResolveStartupStrings: false,
AlwaysSystemServerDebugInfo: false,
NeverSystemServerDebugInfo: false,
AlwaysOtherDebugInfo: false,
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 01ee15e..5b658d9 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -461,6 +461,9 @@
appImageInstallPath := pathtools.ReplaceExtension(odexInstallPath, "art")
cmd.FlagWithOutput("--app-image-file=", appImagePath).
FlagWithArg("--image-format=", "lz4")
+ if !global.DontResolveStartupStrings {
+ cmd.FlagWithArg("--resolve-startup-const-strings=", "true")
+ }
rule.Install(appImagePath, appImageInstallPath)
}
diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
index c72f684..d54ddb1 100644
--- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
+++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
@@ -78,7 +78,7 @@
ctx := &pathContext{android.TestConfig(*outDir, nil)}
- globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, *globalConfigPath)
+ globalConfig, _, err := dexpreopt.LoadGlobalConfig(ctx, *globalConfigPath)
if err != nil {
fmt.Fprintf(os.Stderr, "error loading global config %q: %s\n", *globalConfigPath, err)
os.Exit(2)
diff --git a/java/OWNERS b/java/OWNERS
index d68a5b0..16ef4d8 100644
--- a/java/OWNERS
+++ b/java/OWNERS
@@ -1 +1 @@
-per-file dexpreopt.go = ngeoffray@google.com,calin@google.com,mathieuc@google.com
+per-file dexpreopt*.go = ngeoffray@google.com,calin@google.com,mathieuc@google.com
diff --git a/java/aar.go b/java/aar.go
index c621276..7332e76 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -29,7 +29,7 @@
ExportedProguardFlagFiles() android.Paths
ExportedRRODirs() []rroDir
ExportedStaticPackages() android.Paths
- ExportedManifest() android.Path
+ ExportedManifests() android.Paths
}
func init() {
@@ -71,17 +71,19 @@
}
type aapt struct {
- aaptSrcJar android.Path
- exportPackage android.Path
- manifestPath android.Path
- proguardOptionsFile android.Path
- rroDirs []rroDir
- rTxt android.Path
- extraAaptPackagesFile android.Path
- isLibrary bool
- uncompressedJNI bool
- useEmbeddedDex bool
- usesNonSdkApis bool
+ aaptSrcJar android.Path
+ exportPackage android.Path
+ manifestPath android.Path
+ transitiveManifestPaths android.Paths
+ proguardOptionsFile android.Path
+ rroDirs []rroDir
+ rTxt android.Path
+ extraAaptPackagesFile android.Path
+ mergedManifestFile android.Path
+ isLibrary bool
+ useEmbeddedNativeLibs bool
+ useEmbeddedDex bool
+ usesNonSdkApis bool
splitNames []string
splits []split
@@ -103,8 +105,8 @@
return a.rroDirs
}
-func (a *aapt) ExportedManifest() android.Path {
- return a.manifestPath
+func (a *aapt) ExportedManifests() android.Paths {
+ return a.transitiveManifestPaths
}
func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext, manifestPath android.Path) (flags []string,
@@ -192,14 +194,28 @@
}
func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, extraLinkFlags ...string) {
- transitiveStaticLibs, staticLibManifests, staticRRODirs, libDeps, libFlags := aaptLibs(ctx, sdkContext)
+ transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, libDeps, libFlags := aaptLibs(ctx, sdkContext)
// App manifest file
manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
- manifestPath := manifestMerger(ctx, manifestSrcPath, sdkContext, staticLibManifests, a.isLibrary,
- a.uncompressedJNI, a.useEmbeddedDex, a.usesNonSdkApis)
+ manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext,
+ a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex)
+
+ a.transitiveManifestPaths = append(android.Paths{manifestPath}, transitiveStaticLibManifests...)
+
+ if len(transitiveStaticLibManifests) > 0 {
+ a.mergedManifestFile = manifestMerger(ctx, manifestPath, transitiveStaticLibManifests, a.isLibrary)
+ if !a.isLibrary {
+ // Only use the merged manifest for applications. For libraries, the transitive closure of manifests
+ // will be propagated to the final application and merged there. The merged manifest for libraries is
+ // only passed to Make, which can't handle transitive dependencies.
+ manifestPath = a.mergedManifestFile
+ }
+ } else {
+ a.mergedManifestFile = manifestPath
+ }
linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, sdkContext, manifestPath)
@@ -286,7 +302,7 @@
}
// aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
-func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, staticLibManifests android.Paths,
+func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, transitiveStaticLibManifests android.Paths,
staticRRODirs []rroDir, deps android.Paths, flags []string) {
var sharedLibs android.Paths
@@ -314,7 +330,7 @@
if exportPackage != nil {
transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...)
transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
- staticLibManifests = append(staticLibManifests, aarDep.ExportedManifest())
+ transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...)
outer:
for _, d := range aarDep.ExportedRRODirs() {
@@ -341,8 +357,9 @@
}
transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs)
+ transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests)
- return transitiveStaticLibs, staticLibManifests, staticRRODirs, deps, flags
+ return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, deps, flags
}
type AndroidLibrary struct {
@@ -498,8 +515,8 @@
return a.exportedStaticPackages
}
-func (a *AARImport) ExportedManifest() android.Path {
- return a.manifest
+func (a *AARImport) ExportedManifests() android.Paths {
+ return android.Paths{a.manifest}
}
func (a *AARImport) Prebuilt() *android.Prebuilt {
@@ -630,6 +647,10 @@
return nil
}
+func (a *AARImport) SrcJarArgs() ([]string, android.Paths) {
+ return nil, nil
+}
+
var _ android.PrebuiltInterface = (*Import)(nil)
// android_library_import imports an `.aar` file into the build graph as if it was built with android_library.
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 39cf471..5d3cfa5 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -36,13 +36,14 @@
var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger",
blueprint.RuleParams{
- Command: `${config.ManifestMergerCmd} --main $in $libs --out $out`,
+ Command: `${config.ManifestMergerCmd} $args --main $in $libs --out $out`,
CommandDeps: []string{"${config.ManifestMergerCmd}"},
},
- "libs")
+ "args", "libs")
-func manifestMerger(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext,
- staticLibManifests android.Paths, isLibrary, uncompressedJNI, useEmbeddedDex, usesNonSdkApis bool) android.Path {
+// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
+func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext,
+ isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex bool) android.Path {
var args []string
if isLibrary {
@@ -53,8 +54,8 @@
ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
}
if minSdkVersion >= 23 {
- args = append(args, fmt.Sprintf("--extract-native-libs=%v", !uncompressedJNI))
- } else if uncompressedJNI {
+ args = append(args, fmt.Sprintf("--extract-native-libs=%v", !useEmbeddedNativeLibs))
+ } else if useEmbeddedNativeLibs {
ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it",
minSdkVersion)
}
@@ -65,7 +66,7 @@
}
if useEmbeddedDex {
- args = append(args, "--use-embedded-dex=true")
+ args = append(args, "--use-embedded-dex")
}
var deps android.Paths
@@ -74,40 +75,49 @@
ctx.Config().UnbundledBuild() &&
!ctx.Config().UnbundledBuildUsePrebuiltSdks() &&
ctx.Config().IsEnvTrue("UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT") {
- apiFingerprint := apiFingerprintPath(ctx)
+ apiFingerprint := ApiFingerprintPath(ctx)
targetSdkVersion += fmt.Sprintf(".$$(cat %s)", apiFingerprint.String())
deps = append(deps, apiFingerprint)
}
- // Inject minSdkVersion into the manifest
fixedManifest := android.PathForModuleOut(ctx, "manifest_fixer", "AndroidManifest.xml")
ctx.Build(pctx, android.BuildParams{
- Rule: manifestFixerRule,
- Input: manifest,
- Implicits: deps,
- Output: fixedManifest,
+ Rule: manifestFixerRule,
+ Description: "fix manifest",
+ Input: manifest,
+ Implicits: deps,
+ Output: fixedManifest,
Args: map[string]string{
"minSdkVersion": sdkVersionOrDefault(ctx, sdkContext.minSdkVersion()),
"targetSdkVersion": targetSdkVersion,
"args": strings.Join(args, " "),
},
})
- manifest = fixedManifest
- // Merge static aar dependency manifests if necessary
- if len(staticLibManifests) > 0 {
- mergedManifest := android.PathForModuleOut(ctx, "manifest_merger", "AndroidManifest.xml")
- ctx.Build(pctx, android.BuildParams{
- Rule: manifestMergerRule,
- Input: manifest,
- Implicits: staticLibManifests,
- Output: mergedManifest,
- Args: map[string]string{
- "libs": android.JoinWithPrefix(staticLibManifests.Strings(), "--libs "),
- },
- })
- manifest = mergedManifest
+ return fixedManifest
+}
+
+func manifestMerger(ctx android.ModuleContext, manifest android.Path, staticLibManifests android.Paths,
+ isLibrary bool) android.Path {
+
+ var args string
+ if !isLibrary {
+ // Follow Gradle's behavior, only pass --remove-tools-declarations when merging app manifests.
+ args = "--remove-tools-declarations"
}
- return manifest
+ mergedManifest := android.PathForModuleOut(ctx, "manifest_merger", "AndroidManifest.xml")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: manifestMergerRule,
+ Description: "merge manifest",
+ Input: manifest,
+ Implicits: staticLibManifests,
+ Output: mergedManifest,
+ Args: map[string]string{
+ "libs": android.JoinWithPrefix(staticLibManifests.Strings(), "--libs "),
+ "args": args,
+ },
+ })
+
+ return mergedManifest
}
diff --git a/java/androidmk.go b/java/androidmk.go
index d2e0f2e..5491b3e 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -38,7 +38,18 @@
}
fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", library.headerJarFile.String())
fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", library.implementationAndResourcesJar.String())
- android.WriteRequiredModulesSettings(w, data)
+ if len(data.Required) > 0 {
+ fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(data.Required, " "))
+ }
+ if len(data.Host_required) > 0 {
+ fmt.Fprintln(w, "LOCAL_HOST_REQUIRED_MODULES :=", strings.Join(data.Host_required, " "))
+ }
+ if len(data.Target_required) > 0 {
+ fmt.Fprintln(w, "LOCAL_TARGET_REQUIRED_MODULES :=", strings.Join(data.Target_required, " "))
+ }
+ if r := library.deviceProperties.Target.Hostdex.Required; len(r) > 0 {
+ fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(r, " "))
+ }
fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
}
}
@@ -83,6 +94,10 @@
fmt.Fprintln(w, "LOCAL_ADDITIONAL_CHECKED_MODULE +=", strings.Join(library.additionalCheckedModules.Strings(), " "))
}
+ if library.proguardDictionary != nil {
+ fmt.Fprintln(w, "LOCAL_SOONG_PROGUARD_DICT :=", library.proguardDictionary.String())
+ }
+
// Temporary hack: export sources used to compile framework.jar to Make
// to be used for droiddoc
// TODO(ccross): remove this once droiddoc is in soong
@@ -365,9 +380,6 @@
if a.aarFile != nil {
fmt.Fprintln(w, "LOCAL_SOONG_AAR :=", a.aarFile.String())
}
- if a.proguardDictionary != nil {
- fmt.Fprintln(w, "LOCAL_SOONG_PROGUARD_DICT :=", a.proguardDictionary.String())
- }
if a.Name() == "framework-res" {
fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)")
@@ -378,7 +390,7 @@
fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", a.exportPackage.String())
fmt.Fprintln(w, "LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES :=", a.extraAaptPackagesFile.String())
- fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", a.manifestPath.String())
+ fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", a.mergedManifestFile.String())
fmt.Fprintln(w, "LOCAL_SOONG_EXPORT_PROGUARD_FLAGS :=",
strings.Join(a.exportedProguardFlagFiles.Strings(), " "))
fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
@@ -578,6 +590,32 @@
}
}
+func (app *AndroidAppImport) AndroidMk() android.AndroidMkData {
+ return android.AndroidMkData{
+ Class: "APPS",
+ OutputFile: android.OptionalPathForPath(app.outputFile),
+ Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
+ Extra: []android.AndroidMkExtraFunc{
+ func(w io.Writer, outputFile android.Path) {
+ if Bool(app.properties.Privileged) {
+ fmt.Fprintln(w, "LOCAL_PRIVILEGED_MODULE := true")
+ }
+ if app.certificate != nil {
+ fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", app.certificate.Pem.String())
+ } else {
+ fmt.Fprintln(w, "LOCAL_CERTIFICATE := PRESIGNED")
+ }
+ if len(app.properties.Overrides) > 0 {
+ fmt.Fprintln(w, "LOCAL_OVERRIDES_PACKAGES :=", strings.Join(app.properties.Overrides, " "))
+ }
+ if len(app.dexpreopter.builtInstalled) > 0 {
+ fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", app.dexpreopter.builtInstalled)
+ }
+ },
+ },
+ }
+}
+
func androidMkWriteTestData(data android.Paths, ret *android.AndroidMkData) {
var testFiles []string
for _, d := range data {
diff --git a/java/app.go b/java/app.go
index da8024f..f7f08a8 100644
--- a/java/app.go
+++ b/java/app.go
@@ -17,23 +17,43 @@
// This file contains the module types for compiling Android apps.
import (
- "path/filepath"
- "strings"
-
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
+ "path/filepath"
+ "reflect"
+ "strings"
"android/soong/android"
"android/soong/cc"
"android/soong/tradefed"
)
+var supportedDpis = [...]string{"Ldpi", "Mdpi", "Hdpi", "Xhdpi", "Xxhdpi", "Xxxhdpi"}
+var dpiVariantsStruct reflect.Type
+
func init() {
android.RegisterModuleType("android_app", AndroidAppFactory)
android.RegisterModuleType("android_test", AndroidTestFactory)
android.RegisterModuleType("android_test_helper_app", AndroidTestHelperAppFactory)
android.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory)
android.RegisterModuleType("override_android_app", OverrideAndroidAppModuleFactory)
+ android.RegisterModuleType("android_app_import", AndroidAppImportFactory)
+
+ // Dynamically construct a struct for the dpi_variants property in android_app_import.
+ perDpiStruct := reflect.StructOf([]reflect.StructField{
+ {
+ Name: "Apk",
+ Type: reflect.TypeOf((*string)(nil)),
+ },
+ })
+ dpiVariantsFields := make([]reflect.StructField, len(supportedDpis))
+ for i, dpi := range supportedDpis {
+ dpiVariantsFields[i] = reflect.StructField{
+ Name: string(dpi),
+ Type: perDpiStruct,
+ }
+ }
+ dpiVariantsStruct = reflect.StructOf(dpiVariantsFields)
}
// AndroidManifest.xml merging
@@ -65,6 +85,9 @@
// list of native libraries that will be provided in or alongside the resulting jar
Jni_libs []string `android:"arch_variant"`
+ // STL library to use for JNI libraries.
+ Stl *string `android:"arch_variant"`
+
// Store native libraries uncompressed in the APK and set the android:extractNativeLibs="false" manifest
// flag so that they are used from inside the APK at runtime. Defaults to true for android_test modules unless
// sdk_version or min_sdk_version is set to a version that doesn't support it (<23), defaults to false for other
@@ -129,10 +152,15 @@
func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
a.Module.deps(ctx)
+ if String(a.appProperties.Stl) == "c++_shared" && a.sdkVersion() == "" {
+ ctx.PropertyErrorf("stl", "sdk_version must be set in order to use c++_shared")
+ }
+
if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
a.aapt.deps(ctx, sdkContext(a))
}
+ embedJni := a.shouldEmbedJnis(ctx)
for _, jniTarget := range ctx.MultiTargets() {
variation := []blueprint.Variation{
{Mutator: "arch", Variation: jniTarget.String()},
@@ -142,8 +170,15 @@
target: jniTarget,
}
ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
+ if String(a.appProperties.Stl) == "c++_shared" {
+ if embedJni {
+ ctx.AddFarVariationDependencies(variation, tag, "libc++")
+ }
+ }
}
+}
+func (a *AndroidApp) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) {
cert := android.SrcIsModule(a.getCertString(ctx))
if cert != "" {
ctx.AddDependency(ctx.Module(), certificateTag, cert)
@@ -161,14 +196,14 @@
}
func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- a.aapt.uncompressedJNI = a.shouldUncompressJNI(ctx)
+ a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx)
a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
a.generateAndroidBuildActions(ctx)
}
-// shouldUncompressJNI returns true if the native libraries should be stored in the APK uncompressed and the
+// Returns true if the native libraries should be stored in the APK uncompressed and the
// extractNativeLibs application flag should be set to false in the manifest.
-func (a *AndroidApp) shouldUncompressJNI(ctx android.ModuleContext) bool {
+func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool {
minSdkVersion, err := sdkVersionToNumber(ctx, a.minSdkVersion())
if err != nil {
ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.minSdkVersion(), err)
@@ -187,19 +222,17 @@
return false
}
- // Uncompress dex in APKs of privileged apps, and modules used by privileged apps.
- if ctx.Config().UncompressPrivAppDex() &&
- (Bool(a.appProperties.Privileged) ||
- inList(ctx.ModuleName(), ctx.Config().ModulesLoadedByPrivilegedModules())) {
+ // Uncompress dex in APKs of privileged apps
+ if ctx.Config().UncompressPrivAppDex() && Bool(a.appProperties.Privileged) {
return true
}
- // Uncompress if the dex files is preopted on /system.
- if !a.dexpreopter.dexpreoptDisabled(ctx) && (ctx.Host() || !odexOnSystemOther(ctx, a.dexpreopter.installPath)) {
- return true
- }
+ return shouldUncompressDex(ctx, &a.dexpreopter)
+}
- return false
+func (a *AndroidApp) shouldEmbedJnis(ctx android.BaseModuleContext) bool {
+ return ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs) ||
+ a.appProperties.AlwaysPackageNativeLibs
}
func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
@@ -290,11 +323,9 @@
func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext) android.WritablePath {
var jniJarFile android.WritablePath
if len(jniLibs) > 0 {
- embedJni := ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs) ||
- a.appProperties.AlwaysPackageNativeLibs
- if embedJni {
+ if a.shouldEmbedJnis(ctx) {
jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
- TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.shouldUncompressJNI(ctx))
+ TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.useEmbeddedNativeLibs(ctx))
} else {
a.installJniLibs = jniLibs
}
@@ -302,37 +333,38 @@
return jniJarFile
}
-func (a *AndroidApp) certificateBuildActions(certificateDeps []Certificate, ctx android.ModuleContext) []Certificate {
- cert := a.getCertString(ctx)
- certModule := android.SrcIsModule(cert)
- if certModule != "" {
- a.certificate = certificateDeps[0]
- certificateDeps = certificateDeps[1:]
- } else if cert != "" {
- defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
- a.certificate = Certificate{
- defaultDir.Join(ctx, cert+".x509.pem"),
- defaultDir.Join(ctx, cert+".pk8"),
+// Reads and prepends a main cert from the default cert dir if it hasn't been set already, i.e. it
+// isn't a cert module reference. Also checks and enforces system cert restriction if applicable.
+func processMainCert(m android.ModuleBase, certPropValue string, certificates []Certificate, ctx android.ModuleContext) []Certificate {
+ if android.SrcIsModule(certPropValue) == "" {
+ var mainCert Certificate
+ if certPropValue != "" {
+ defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
+ mainCert = Certificate{
+ defaultDir.Join(ctx, certPropValue+".x509.pem"),
+ defaultDir.Join(ctx, certPropValue+".pk8"),
+ }
+ } else {
+ pem, key := ctx.Config().DefaultAppCertificate(ctx)
+ mainCert = Certificate{pem, key}
}
- } else {
- pem, key := ctx.Config().DefaultAppCertificate(ctx)
- a.certificate = Certificate{pem, key}
+ certificates = append([]Certificate{mainCert}, certificates...)
}
- if !a.Module.Platform() {
- certPath := a.certificate.Pem.String()
+ if !m.Platform() {
+ certPath := certificates[0].Pem.String()
systemCertPath := ctx.Config().DefaultAppCertificateDir(ctx).String()
if strings.HasPrefix(certPath, systemCertPath) {
enforceSystemCert := ctx.Config().EnforceSystemCertificate()
whitelist := ctx.Config().EnforceSystemCertificateWhitelist()
- if enforceSystemCert && !inList(a.Module.Name(), whitelist) {
+ if enforceSystemCert && !inList(m.Name(), whitelist) {
ctx.PropertyErrorf("certificate", "The module in product partition cannot be signed with certificate in system.")
}
}
}
- return append([]Certificate{a.certificate}, certificateDeps...)
+ return certificates
}
func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
@@ -346,25 +378,26 @@
dexJarFile := a.dexBuildActions(ctx)
- jniLibs, certificateDeps := a.collectAppDeps(ctx)
+ jniLibs, certificateDeps := collectAppDeps(ctx)
jniJarFile := a.jniBuildActions(jniLibs, ctx)
if ctx.Failed() {
return
}
- certificates := a.certificateBuildActions(certificateDeps, ctx)
+ certificates := processMainCert(a.ModuleBase, a.getCertString(ctx), certificateDeps, ctx)
+ a.certificate = certificates[0]
// Build a final signed app package.
// TODO(jungjw): Consider changing this to installApkName.
packageFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".apk")
- CreateAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates)
+ CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates)
a.outputFile = packageFile
for _, split := range a.aapt.splits {
// Sign the split APKs
packageFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"_"+split.suffix+".apk")
- CreateAppPackage(ctx, packageFile, split.path, nil, nil, certificates)
+ CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates)
a.extraOutputFiles = append(a.extraOutputFiles, packageFile)
}
@@ -390,7 +423,7 @@
}
}
-func (a *AndroidApp) collectAppDeps(ctx android.ModuleContext) ([]jniLib, []Certificate) {
+func collectAppDeps(ctx android.ModuleContext) ([]jniLib, []Certificate) {
var jniLibs []jniLib
var certificates []Certificate
@@ -412,7 +445,6 @@
}
} else {
ctx.ModuleErrorf("jni_libs dependency %q must be a cc library", otherName)
-
}
} else if tag == certificateTag {
if dep, ok := module.(*AndroidAppCertificate); ok {
@@ -487,6 +519,8 @@
a.additionalAaptFlags = append(a.additionalAaptFlags, "--rename-instrumentation-target-package "+manifestPackageName)
}
}
+ a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx)
+ a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
a.generateAndroidBuildActions(ctx)
a.testConfig = tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config, a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites)
@@ -616,7 +650,225 @@
m := &OverrideAndroidApp{}
m.AddProperties(&overridableAppProperties{})
- android.InitAndroidModule(m)
+ android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon)
android.InitOverrideModule(m)
return m
}
+
+type AndroidAppImport struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+ prebuilt android.Prebuilt
+
+ properties AndroidAppImportProperties
+
+ outputFile android.Path
+ certificate *Certificate
+
+ dexpreopter
+}
+
+type AndroidAppImportProperties struct {
+ // A prebuilt apk to import
+ Apk string
+
+ // Per-DPI settings. This property makes it possible to specify a different source apk path for
+ // each DPI.
+ //
+ // Example:
+ //
+ // android_app_import {
+ // name: "example_import",
+ // apk: "prebuilts/example.apk",
+ // dpi_variants: {
+ // mdpi: {
+ // apk: "prebuilts/example_mdpi.apk",
+ // },
+ // xhdpi: {
+ // apk: "prebuilts/example_xhdpi.apk",
+ // },
+ // },
+ // certificate: "PRESIGNED",
+ // }
+ Dpi_variants interface{}
+
+ // The name of a certificate in the default certificate directory, blank to use the default
+ // product certificate, or an android_app_certificate module name in the form ":module".
+ Certificate *string
+
+ // Set this flag to true if the prebuilt apk is already signed. The certificate property must not
+ // be set for presigned modules.
+ Presigned *bool
+
+ // Specifies that this app should be installed to the priv-app directory,
+ // where the system will grant it additional privileges not available to
+ // normal apps.
+ Privileged *bool
+
+ // Names of modules to be overridden. Listed modules can only be other binaries
+ // (in Make or Soong).
+ // This does not completely prevent installation of the overridden binaries, but if both
+ // binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
+ // from PRODUCT_PACKAGES.
+ Overrides []string
+}
+
+func getApkPathForDpi(dpiVariantsValue reflect.Value, dpi string) string {
+ dpiField := dpiVariantsValue.FieldByName(proptools.FieldNameForProperty(dpi))
+ if !dpiField.IsValid() {
+ return ""
+ }
+ apkValue := dpiField.FieldByName("Apk").Elem()
+ if apkValue.IsValid() {
+ return apkValue.String()
+ }
+ return ""
+}
+
+// Chooses a source APK path to use based on the module's per-DPI settings and the product config.
+func (a *AndroidAppImport) getSrcApkPath(ctx android.ModuleContext) string {
+ config := ctx.Config()
+ dpiVariantsValue := reflect.ValueOf(a.properties.Dpi_variants).Elem()
+ if !dpiVariantsValue.IsValid() {
+ return a.properties.Apk
+ }
+ // Match PRODUCT_AAPT_PREF_CONFIG first and then PRODUCT_AAPT_PREBUILT_DPI.
+ if config.ProductAAPTPreferredConfig() != "" {
+ if apk := getApkPathForDpi(dpiVariantsValue, config.ProductAAPTPreferredConfig()); apk != "" {
+ return apk
+ }
+ }
+ for _, dpi := range config.ProductAAPTPrebuiltDPI() {
+ if apk := getApkPathForDpi(dpiVariantsValue, dpi); apk != "" {
+ return apk
+ }
+ }
+
+ // No match. Use the generic one.
+ return a.properties.Apk
+}
+
+func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) {
+ cert := android.SrcIsModule(String(a.properties.Certificate))
+ if cert != "" {
+ ctx.AddDependency(ctx.Module(), certificateTag, cert)
+ }
+}
+
+func (a *AndroidAppImport) uncompressEmbeddedJniLibs(
+ ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
+ rule := android.NewRuleBuilder()
+ rule.Command().
+ Textf(`if (zipinfo %s 'lib/*.so' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, inputPath).
+ Tool(ctx.Config().HostToolPath(ctx, "zip2zip")).
+ FlagWithInput("-i ", inputPath).
+ FlagWithOutput("-o ", outputPath).
+ FlagWithArg("-0 ", "'lib/**/*.so'").
+ Textf(`; else cp -f %s %s; fi`, inputPath, outputPath)
+ rule.Build(pctx, ctx, "uncompress-embedded-jni-libs", "Uncompress embedded JIN libs")
+}
+
+// Returns whether this module should have the dex file stored uncompressed in the APK.
+func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool {
+ if ctx.Config().UnbundledBuild() {
+ return false
+ }
+
+ // Uncompress dex in APKs of privileged apps
+ if ctx.Config().UncompressPrivAppDex() && Bool(a.properties.Privileged) {
+ return true
+ }
+
+ return shouldUncompressDex(ctx, &a.dexpreopter)
+}
+
+func (a *AndroidAppImport) uncompressDex(
+ ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
+ rule := android.NewRuleBuilder()
+ rule.Command().
+ Textf(`if (zipinfo %s '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, inputPath).
+ Tool(ctx.Config().HostToolPath(ctx, "zip2zip")).
+ FlagWithInput("-i ", inputPath).
+ FlagWithOutput("-o ", outputPath).
+ FlagWithArg("-0 ", "'classes*.dex'").
+ Textf(`; else cp -f %s %s; fi`, inputPath, outputPath)
+ rule.Build(pctx, ctx, "uncompress-dex", "Uncompress dex files")
+}
+
+func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ if String(a.properties.Certificate) == "" && !Bool(a.properties.Presigned) {
+ ctx.PropertyErrorf("certificate", "No certificate specified for prebuilt")
+ }
+ if String(a.properties.Certificate) != "" && Bool(a.properties.Presigned) {
+ ctx.PropertyErrorf("certificate", "Certificate can't be specified for presigned modules")
+ }
+
+ _, certificates := collectAppDeps(ctx)
+
+ // TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
+ // TODO: LOCAL_PACKAGE_SPLITS
+
+ srcApk := android.PathForModuleSrc(ctx, a.getSrcApkPath(ctx))
+
+ // TODO: Install or embed JNI libraries
+
+ // Uncompress JNI libraries in the apk
+ jnisUncompressed := android.PathForModuleOut(ctx, "jnis-uncompressed", ctx.ModuleName()+".apk")
+ a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath)
+
+ installDir := android.PathForModuleInstall(ctx, "app", a.BaseModuleName())
+ a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk")
+ a.dexpreopter.isInstallable = true
+ a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
+ a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
+ dexOutput := a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
+ if a.dexpreopter.uncompressedDex {
+ dexUncompressed := android.PathForModuleOut(ctx, "dex-uncompressed", ctx.ModuleName()+".apk")
+ a.uncompressDex(ctx, dexOutput, dexUncompressed.OutputPath)
+ dexOutput = dexUncompressed
+ }
+
+ // Sign or align the package
+ // TODO: Handle EXTERNAL
+ if !Bool(a.properties.Presigned) {
+ certificates = processMainCert(a.ModuleBase, *a.properties.Certificate, certificates, ctx)
+ if len(certificates) != 1 {
+ ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates)
+ }
+ a.certificate = &certificates[0]
+ signed := android.PathForModuleOut(ctx, "signed", ctx.ModuleName()+".apk")
+ SignAppPackage(ctx, signed, dexOutput, certificates)
+ a.outputFile = signed
+ } else {
+ alignedApk := android.PathForModuleOut(ctx, "zip-aligned", ctx.ModuleName()+".apk")
+ TransformZipAlign(ctx, alignedApk, dexOutput)
+ a.outputFile = alignedApk
+ }
+
+ // TODO: Optionally compress the output apk.
+
+ ctx.InstallFile(installDir, a.BaseModuleName()+".apk", a.outputFile)
+
+ // TODO: androidmk converter jni libs
+}
+
+func (a *AndroidAppImport) Prebuilt() *android.Prebuilt {
+ return &a.prebuilt
+}
+
+func (a *AndroidAppImport) Name() string {
+ return a.prebuilt.Name(a.ModuleBase.Name())
+}
+
+// android_app_import imports a prebuilt apk with additional processing specified in the module.
+func AndroidAppImportFactory() android.Module {
+ module := &AndroidAppImport{}
+ module.properties.Dpi_variants = reflect.New(dpiVariantsStruct).Interface()
+ module.AddProperties(&module.properties)
+ module.AddProperties(&module.dexpreoptProperties)
+
+ InitJavaModule(module, android.DeviceSupported)
+ android.InitSingleSourcePrebuiltModule(module, &module.properties.Apk)
+
+ return module
+}
diff --git a/java/app_builder.go b/java/app_builder.go
index 5bacb67..82a390f 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -62,7 +62,7 @@
CommandDeps: []string{"${config.MergeZipsCmd}"},
})
-func CreateAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
+func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate) {
unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk"
@@ -83,6 +83,11 @@
Output: unsignedApk,
})
+ SignAppPackage(ctx, outputFile, unsignedApk, certificates)
+}
+
+func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate) {
+
var certificateArgs []string
var deps android.Paths
for _, c := range certificates {
@@ -93,7 +98,7 @@
ctx.Build(pctx, android.BuildParams{
Rule: Signapk,
Description: "signapk",
- Output: outputFile,
+ Output: signedApk,
Input: unsignedApk,
Implicits: deps,
Args: map[string]string{
diff --git a/java/app_test.go b/java/app_test.go
index a084c9c..40a64af 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -15,15 +15,18 @@
package java
import (
- "android/soong/android"
- "android/soong/cc"
-
"fmt"
"path/filepath"
"reflect"
+ "regexp"
"sort"
"strings"
"testing"
+
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+ "android/soong/cc"
)
var (
@@ -878,7 +881,7 @@
name: "foo",
srcs: ["a.java"],
certificate: "expiredkey",
- overrides: ["baz"],
+ overrides: ["qux"],
}
override_android_app {
@@ -900,6 +903,7 @@
`)
expectedVariants := []struct {
+ moduleName string
variantName string
apkName string
apkPath string
@@ -908,24 +912,27 @@
aaptFlag string
}{
{
+ moduleName: "foo",
variantName: "android_common",
apkPath: "/target/product/test_device/system/app/foo/foo.apk",
signFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
- overrides: []string{"baz"},
+ overrides: []string{"qux"},
aaptFlag: "",
},
{
- variantName: "bar_android_common",
+ moduleName: "bar",
+ variantName: "android_common_bar",
apkPath: "/target/product/test_device/system/app/bar/bar.apk",
signFlag: "cert/new_cert.x509.pem cert/new_cert.pk8",
- overrides: []string{"baz", "foo"},
+ overrides: []string{"qux", "foo"},
aaptFlag: "",
},
{
- variantName: "baz_android_common",
+ moduleName: "baz",
+ variantName: "android_common_baz",
apkPath: "/target/product/test_device/system/app/baz/baz.apk",
signFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
- overrides: []string{"baz", "foo"},
+ overrides: []string{"qux", "foo"},
aaptFlag: "--rename-manifest-package org.dandroid.bp",
},
}
@@ -968,3 +975,267 @@
}
}
}
+
+func TestOverrideAndroidAppDependency(t *testing.T) {
+ ctx := testJava(t, `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ }
+
+ override_android_app {
+ name: "bar",
+ base: "foo",
+ package_name: "org.dandroid.bp",
+ }
+
+ android_test {
+ name: "baz",
+ srcs: ["b.java"],
+ instrumentation_for: "foo",
+ }
+
+ android_test {
+ name: "qux",
+ srcs: ["b.java"],
+ instrumentation_for: "bar",
+ }
+ `)
+
+ // Verify baz, which depends on the overridden module foo, has the correct classpath javac arg.
+ javac := ctx.ModuleForTests("baz", "android_common").Rule("javac")
+ fooTurbine := filepath.Join(buildDir, ".intermediates", "foo", "android_common", "turbine-combined", "foo.jar")
+ if !strings.Contains(javac.Args["classpath"], fooTurbine) {
+ t.Errorf("baz classpath %v does not contain %q", javac.Args["classpath"], fooTurbine)
+ }
+
+ // Verify qux, which depends on the overriding module bar, has the correct classpath javac arg.
+ javac = ctx.ModuleForTests("qux", "android_common").Rule("javac")
+ barTurbine := filepath.Join(buildDir, ".intermediates", "foo", "android_common_bar", "turbine-combined", "foo.jar")
+ if !strings.Contains(javac.Args["classpath"], barTurbine) {
+ t.Errorf("qux classpath %v does not contain %q", javac.Args["classpath"], barTurbine)
+ }
+}
+
+func TestAndroidAppImport(t *testing.T) {
+ ctx := testJava(t, `
+ android_app_import {
+ name: "foo",
+ apk: "prebuilts/apk/app.apk",
+ certificate: "platform",
+ dex_preopt: {
+ enabled: true,
+ },
+ }
+ `)
+
+ variant := ctx.ModuleForTests("foo", "android_common")
+
+ // Check dexpreopt outputs.
+ if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
+ variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
+ t.Errorf("can't find dexpreopt outputs")
+ }
+
+ // Check cert signing flag.
+ signedApk := variant.Output("signed/foo.apk")
+ signingFlag := signedApk.Args["certificates"]
+ expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8"
+ if expected != signingFlag {
+ t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
+ }
+}
+
+func TestAndroidAppImport_NoDexPreopt(t *testing.T) {
+ ctx := testJava(t, `
+ android_app_import {
+ name: "foo",
+ apk: "prebuilts/apk/app.apk",
+ certificate: "platform",
+ dex_preopt: {
+ enabled: false,
+ },
+ }
+ `)
+
+ variant := ctx.ModuleForTests("foo", "android_common")
+
+ // Check dexpreopt outputs. They shouldn't exist.
+ if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule != nil ||
+ variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule != nil {
+ t.Errorf("dexpreopt shouldn't have run.")
+ }
+}
+
+func TestAndroidAppImport_Presigned(t *testing.T) {
+ ctx := testJava(t, `
+ android_app_import {
+ name: "foo",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ dex_preopt: {
+ enabled: true,
+ },
+ }
+ `)
+
+ variant := ctx.ModuleForTests("foo", "android_common")
+
+ // Check dexpreopt outputs.
+ if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
+ variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
+ t.Errorf("can't find dexpreopt outputs")
+ }
+ // Make sure stripping wasn't done.
+ stripRule := variant.Output("dexpreopt/foo.apk")
+ if !strings.HasPrefix(stripRule.RuleParams.Command, "cp -f") {
+ t.Errorf("unexpected, non-skipping strip command: %q", stripRule.RuleParams.Command)
+ }
+
+ // Make sure signing was skipped and aligning was done instead.
+ if variant.MaybeOutput("signed/foo.apk").Rule != nil {
+ t.Errorf("signing rule shouldn't be included.")
+ }
+ if variant.MaybeOutput("zip-aligned/foo.apk").Rule == nil {
+ t.Errorf("can't find aligning rule")
+ }
+}
+
+func TestAndroidAppImport_DpiVariants(t *testing.T) {
+ bp := `
+ android_app_import {
+ name: "foo",
+ apk: "prebuilts/apk/app.apk",
+ dpi_variants: {
+ xhdpi: {
+ apk: "prebuilts/apk/app_xhdpi.apk",
+ },
+ xxhdpi: {
+ apk: "prebuilts/apk/app_xxhdpi.apk",
+ },
+ },
+ certificate: "PRESIGNED",
+ dex_preopt: {
+ enabled: true,
+ },
+ }
+ `
+ testCases := []struct {
+ name string
+ aaptPreferredConfig *string
+ aaptPrebuiltDPI []string
+ expected string
+ }{
+ {
+ name: "no preferred",
+ aaptPreferredConfig: nil,
+ aaptPrebuiltDPI: []string{},
+ expected: "prebuilts/apk/app.apk",
+ },
+ {
+ name: "AAPTPreferredConfig matches",
+ aaptPreferredConfig: proptools.StringPtr("xhdpi"),
+ aaptPrebuiltDPI: []string{"xxhdpi", "lhdpi"},
+ expected: "prebuilts/apk/app_xhdpi.apk",
+ },
+ {
+ name: "AAPTPrebuiltDPI matches",
+ aaptPreferredConfig: proptools.StringPtr("mdpi"),
+ aaptPrebuiltDPI: []string{"xxhdpi", "xhdpi"},
+ expected: "prebuilts/apk/app_xxhdpi.apk",
+ },
+ {
+ name: "non-first AAPTPrebuiltDPI matches",
+ aaptPreferredConfig: proptools.StringPtr("mdpi"),
+ aaptPrebuiltDPI: []string{"ldpi", "xhdpi"},
+ expected: "prebuilts/apk/app_xhdpi.apk",
+ },
+ {
+ name: "no matches",
+ aaptPreferredConfig: proptools.StringPtr("mdpi"),
+ aaptPrebuiltDPI: []string{"ldpi", "xxxhdpi"},
+ expected: "prebuilts/apk/app.apk",
+ },
+ }
+
+ jniRuleRe := regexp.MustCompile("^if \\(zipinfo (\\S+)")
+ for _, test := range testCases {
+ config := testConfig(nil)
+ config.TestProductVariables.AAPTPreferredConfig = test.aaptPreferredConfig
+ config.TestProductVariables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI
+ ctx := testAppContext(config, bp, nil)
+
+ run(t, ctx, config)
+
+ variant := ctx.ModuleForTests("foo", "android_common")
+ jniRuleCommand := variant.Output("jnis-uncompressed/foo.apk").RuleParams.Command
+ matches := jniRuleRe.FindStringSubmatch(jniRuleCommand)
+ if len(matches) != 2 {
+ t.Errorf("failed to extract the src apk path from %q", jniRuleCommand)
+ }
+ if test.expected != matches[1] {
+ t.Errorf("wrong src apk, expected: %q got: %q", test.expected, matches[1])
+ }
+ }
+}
+
+func TestStl(t *testing.T) {
+ ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+ cc_library {
+ name: "libjni",
+ }
+
+ android_test {
+ name: "stl",
+ jni_libs: ["libjni"],
+ compile_multilib: "both",
+ sdk_version: "current",
+ stl: "c++_shared",
+ }
+
+ android_test {
+ name: "system",
+ jni_libs: ["libjni"],
+ compile_multilib: "both",
+ sdk_version: "current",
+ }
+ `)
+
+ testCases := []struct {
+ name string
+ jnis []string
+ }{
+ {"stl",
+ []string{
+ "libjni.so",
+ "libc++.so",
+ },
+ },
+ {"system",
+ []string{
+ "libjni.so",
+ },
+ },
+ }
+
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ app := ctx.ModuleForTests(test.name, "android_common")
+ jniLibZip := app.Output("jnilibs.zip")
+ var jnis []string
+ args := strings.Fields(jniLibZip.Args["jarArgs"])
+ for i := 0; i < len(args); i++ {
+ if args[i] == "-f" {
+ jnis = append(jnis, args[i+1])
+ i += 1
+ }
+ }
+ jnisJoined := strings.Join(jnis, " ")
+ for _, jni := range test.jnis {
+ if !strings.Contains(jnisJoined, jni) {
+ t.Errorf("missing jni %q in %q", jni, jnis)
+ }
+ }
+ })
+ }
+}
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 9f40a6c..030b010 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -15,9 +15,12 @@
package java
import (
- "android/soong/android"
+ "fmt"
+ "io"
"github.com/google/blueprint"
+
+ "android/soong/android"
)
type DeviceHostConverter struct {
@@ -30,6 +33,12 @@
implementationJars android.Paths
implementationAndResourceJars android.Paths
resourceJars android.Paths
+
+ srcJarArgs []string
+ srcJarDeps android.Paths
+
+ combinedHeaderJar android.Path
+ combinedImplementationJar android.Path
}
type DeviceHostConverterProperties struct {
@@ -44,7 +53,7 @@
// java_device_for_host makes the classes.jar output of a device java_library module available to host
// java_library modules.
//
-// It is rarely necessary, and its used is restricted to a few whitelisted projects.
+// It is rarely necessary, and its usage is restricted to a few whitelisted projects.
func DeviceForHostFactory() android.Module {
module := &DeviceForHost{}
@@ -61,7 +70,7 @@
// java_host_for_device makes the classes.jar output of a host java_library module available to device
// java_library modules.
//
-// It is rarely necessary, and its used is restricted to a few whitelisted projects.
+// It is rarely necessary, and its usage is restricted to a few whitelisted projects.
func HostForDeviceFactory() android.Module {
module := &HostForDevice{}
@@ -94,10 +103,35 @@
d.implementationJars = append(d.implementationJars, dep.ImplementationJars()...)
d.implementationAndResourceJars = append(d.implementationAndResourceJars, dep.ImplementationAndResourcesJars()...)
d.resourceJars = append(d.resourceJars, dep.ResourceJars()...)
+
+ srcJarArgs, srcJarDeps := dep.SrcJarArgs()
+ d.srcJarArgs = append(d.srcJarArgs, srcJarArgs...)
+ d.srcJarDeps = append(d.srcJarDeps, srcJarDeps...)
} else {
ctx.PropertyErrorf("libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m))
}
})
+
+ jarName := ctx.ModuleName() + ".jar"
+
+ if len(d.implementationAndResourceJars) > 1 {
+ outputFile := android.PathForModuleOut(ctx, "combined", jarName)
+ TransformJarsToJar(ctx, outputFile, "combine", d.implementationAndResourceJars,
+ android.OptionalPath{}, false, nil, nil)
+ d.combinedImplementationJar = outputFile
+ } else {
+ d.combinedImplementationJar = d.implementationAndResourceJars[0]
+ }
+
+ if len(d.headerJars) > 1 {
+ outputFile := android.PathForModuleOut(ctx, "turbine-combined", jarName)
+ TransformJarsToJar(ctx, outputFile, "turbine combine", d.headerJars,
+ android.OptionalPath{}, false, nil, []string{"META-INF/TRANSITIVE"})
+ d.combinedHeaderJar = outputFile
+ } else {
+ d.combinedHeaderJar = d.headerJars[0]
+ }
+
}
var _ Dependency = (*DeviceHostConverter)(nil)
@@ -129,3 +163,22 @@
func (d *DeviceHostConverter) ExportedSdkLibs() []string {
return nil
}
+
+func (d *DeviceHostConverter) SrcJarArgs() ([]string, android.Paths) {
+ return d.srcJarArgs, d.srcJarDeps
+}
+
+func (d *DeviceHostConverter) AndroidMk() android.AndroidMkData {
+ return android.AndroidMkData{
+ Class: "JAVA_LIBRARIES",
+ OutputFile: android.OptionalPathForPath(d.combinedImplementationJar),
+ Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
+ Extra: []android.AndroidMkExtraFunc{
+ func(w io.Writer, outputFile android.Path) {
+ fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+ fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", d.combinedHeaderJar.String())
+ fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", d.combinedImplementationJar.String())
+ },
+ },
+ }
+}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 9141f9e..08fd06e 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -22,11 +22,12 @@
type dexpreopter struct {
dexpreoptProperties DexpreoptProperties
- installPath android.OutputPath
- uncompressedDex bool
- isSDKLibrary bool
- isTest bool
- isInstallable bool
+ installPath android.OutputPath
+ uncompressedDex bool
+ isSDKLibrary bool
+ isTest bool
+ isInstallable bool
+ isPresignedPrebuilt bool
builtInstalled string
}
@@ -51,7 +52,7 @@
// If set, provides the path to profile relative to the Android.bp file. If not set,
// defaults to searching for a file that matches the name of this module in the default
// profile location set by PRODUCT_DEX_PREOPT_PROFILE_DIR, or empty if not found.
- Profile *string
+ Profile *string `android:"path"`
}
}
@@ -110,7 +111,9 @@
if len(archs) == 0 {
// assume this is a java library, dexpreopt for all arches for now
for _, target := range ctx.Config().Targets[android.Android] {
- archs = append(archs, target.Arch.ArchType)
+ if target.NativeBridge == android.NativeBridgeDisabled {
+ archs = append(archs, target.Arch.ArchType)
+ }
}
if inList(ctx.ModuleName(), global.SystemServerJars) && !d.isSDKLibrary {
// If the module is not an SDK library and it's a system server jar, only preopt the primary arch.
@@ -177,6 +180,8 @@
NoCreateAppImage: !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true),
ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false),
+ PresignedPrebuilt: d.isPresignedPrebuilt,
+
NoStripping: Bool(d.dexpreoptProperties.Dex_preopt.No_stripping),
StripInputPath: dexJarFile,
StripOutputPath: strippedDexJarFile.OutputPath,
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index cb2ea9f..2a1a901 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -56,6 +56,7 @@
dexPaths android.WritablePaths
dir android.OutputPath
symbolsDir android.OutputPath
+ targets []android.Target
images map[android.ArchType]android.OutputPath
zip android.WritablePath
}
@@ -114,6 +115,8 @@
type dexpreoptBootJars struct {
defaultBootImage *bootImage
otherImages []*bootImage
+
+ dexpreoptConfigForMake android.WritablePath
}
// dexpreoptBoot singleton rules
@@ -122,6 +125,9 @@
return
}
+ d.dexpreoptConfigForMake = android.PathForOutput(ctx, ctx.Config().DeviceName(), "dexpreopt.config")
+ writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake)
+
global := dexpreoptGlobalConfig(ctx)
// Skip recompiling the boot image for the second sanitization phase. We'll get separate paths
@@ -191,12 +197,7 @@
var allFiles android.Paths
if !global.DisablePreopt {
- targets := ctx.Config().Targets[android.Android]
- if ctx.Config().SecondArchIsTranslated() {
- targets = targets[:1]
- }
-
- for _, target := range targets {
+ for _, target := range image.targets {
files := buildBootImageRuleForArch(ctx, image, target.Arch.ArchType, profile, missingDeps)
allFiles = append(allFiles, files.Paths()...)
}
@@ -457,8 +458,24 @@
}
+func writeGlobalConfigForMake(ctx android.SingletonContext, path android.WritablePath) {
+ data := dexpreoptGlobalConfigRaw(ctx).data
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.WriteFile,
+ Output: path,
+ Args: map[string]string{
+ "content": string(data),
+ },
+ })
+}
+
// Export paths for default boot image to Make
func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) {
+ if d.dexpreoptConfigForMake != nil {
+ ctx.Strict("DEX_PREOPT_CONFIG_FOR_MAKE", d.dexpreoptConfigForMake.String())
+ }
+
image := d.defaultBootImage
if image != nil {
ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String())
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index b30bd00..d903f45 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -15,40 +15,50 @@
package java
import (
- "android/soong/android"
- "android/soong/dexpreopt"
"path/filepath"
"strings"
+
+ "android/soong/android"
+ "android/soong/dexpreopt"
)
// dexpreoptGlobalConfig returns the global dexpreopt.config. It is loaded once the first time it is called for any
// ctx.Config(), and returns the same data for all future calls with the same ctx.Config(). A value can be inserted
// for tests using setDexpreoptTestGlobalConfig.
func dexpreoptGlobalConfig(ctx android.PathContext) dexpreopt.GlobalConfig {
+ return dexpreoptGlobalConfigRaw(ctx).global
+}
+
+type globalConfigAndRaw struct {
+ global dexpreopt.GlobalConfig
+ data []byte
+}
+
+func dexpreoptGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw {
return ctx.Config().Once(dexpreoptGlobalConfigKey, func() interface{} {
if f := ctx.Config().DexpreoptGlobalConfig(); f != "" {
ctx.AddNinjaFileDeps(f)
- globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, f)
+ globalConfig, data, err := dexpreopt.LoadGlobalConfig(ctx, f)
if err != nil {
panic(err)
}
- return globalConfig
+ return globalConfigAndRaw{globalConfig, data}
}
// No global config filename set, see if there is a test config set
return ctx.Config().Once(dexpreoptTestGlobalConfigKey, func() interface{} {
// Nope, return a config with preopting disabled
- return dexpreopt.GlobalConfig{
+ return globalConfigAndRaw{dexpreopt.GlobalConfig{
DisablePreopt: true,
- }
+ }, nil}
})
- }).(dexpreopt.GlobalConfig)
+ }).(globalConfigAndRaw)
}
// setDexpreoptTestGlobalConfig sets a GlobalConfig that future calls to dexpreoptGlobalConfig will return. It must
// be called before the first call to dexpreoptGlobalConfig for the config.
func setDexpreoptTestGlobalConfig(config android.Config, globalConfig dexpreopt.GlobalConfig) {
- config.Once(dexpreoptTestGlobalConfigKey, func() interface{} { return globalConfig })
+ config.Once(dexpreoptTestGlobalConfigKey, func() interface{} { return globalConfigAndRaw{globalConfig, nil} })
}
var dexpreoptGlobalConfigKey = android.NewOnceKey("DexpreoptGlobalConfig")
@@ -72,6 +82,23 @@
var systemServerClasspathKey = android.NewOnceKey("systemServerClasspath")
+// dexpreoptTargets returns the list of targets that are relevant to dexpreopting, which excludes architectures
+// supported through native bridge.
+func dexpreoptTargets(ctx android.PathContext) []android.Target {
+ var targets []android.Target
+ for i, target := range ctx.Config().Targets[android.Android] {
+ if ctx.Config().SecondArchIsTranslated() && i > 0 {
+ break
+ }
+
+ if target.NativeBridge == android.NativeBridgeDisabled {
+ targets = append(targets, target)
+ }
+ }
+
+ return targets
+}
+
// defaultBootImageConfig returns the bootImageConfig that will be used to dexpreopt modules. It is computed once the
// first time it is called for any ctx.Config(), and returns the same slice for all future calls with the same
// ctx.Config().
@@ -113,7 +140,9 @@
images := make(map[android.ArchType]android.OutputPath)
zip := dir.Join(ctx, "boot.zip")
- for _, target := range ctx.Config().Targets[android.Android] {
+ targets := dexpreoptTargets(ctx)
+
+ for _, target := range targets {
images[target.Arch.ArchType] = dir.Join(ctx,
"system/framework", target.Arch.ArchType.String()).Join(ctx, "boot.art")
}
@@ -126,6 +155,7 @@
dir: dir,
symbolsDir: symbolsDir,
images: images,
+ targets: targets,
zip: zip,
}
}).(bootImageConfig)
@@ -138,21 +168,29 @@
global := dexpreoptGlobalConfig(ctx)
runtimeModules := global.RuntimeApexJars
+ nonFrameworkModules := concat(runtimeModules, global.ProductUpdatableBootModules)
+ frameworkModules := android.RemoveListFromList(global.BootJars, nonFrameworkModules)
+ imageModules := concat(runtimeModules, frameworkModules)
- var runtimeBootLocations []string
+ var bootLocations []string
for _, m := range runtimeModules {
- runtimeBootLocations = append(runtimeBootLocations,
+ bootLocations = append(bootLocations,
filepath.Join("/apex/com.android.runtime/javalib", m+".jar"))
}
+ for _, m := range frameworkModules {
+ bootLocations = append(bootLocations,
+ 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 runtimeBootDexPaths android.WritablePaths
- for _, m := range runtimeModules {
- runtimeBootDexPaths = append(runtimeBootDexPaths,
+ var bootDexPaths android.WritablePaths
+ for _, m := range imageModules {
+ bootDexPaths = append(bootDexPaths,
android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_apexjars_input", m+".jar"))
}
@@ -160,18 +198,21 @@
symbolsDir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_apexjars_unstripped")
images := make(map[android.ArchType]android.OutputPath)
- for _, target := range ctx.Config().Targets[android.Android] {
+ targets := dexpreoptTargets(ctx)
+
+ for _, target := range targets {
images[target.Arch.ArchType] = dir.Join(ctx,
"system/framework", target.Arch.ArchType.String(), "apex.art")
}
return bootImageConfig{
name: "apex",
- modules: runtimeModules,
- dexLocations: runtimeBootLocations,
- dexPaths: runtimeBootDexPaths,
+ modules: imageModules,
+ dexLocations: bootLocations,
+ dexPaths: bootDexPaths,
dir: dir,
symbolsDir: symbolsDir,
+ targets: targets,
images: images,
}
}).(bootImageConfig)
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index 4af2f5c..7d0109f 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -52,14 +52,26 @@
}`,
enabled: true,
},
-
{
name: "app without sources",
bp: `
android_app {
name: "foo",
}`,
- // TODO(ccross): this should probably be false
+ enabled: false,
+ },
+ {
+ name: "app with libraries",
+ bp: `
+ android_app {
+ name: "foo",
+ static_libs: ["lib"],
+ }
+
+ java_library {
+ name: "lib",
+ srcs: ["a.java"],
+ }`,
enabled: true,
},
{
@@ -69,10 +81,8 @@
name: "foo",
installable: true,
}`,
- // TODO(ccross): this should probably be false
- enabled: true,
+ enabled: false,
},
-
{
name: "static java library",
bp: `
diff --git a/java/java.go b/java/java.go
index d6c759b..4483083 100644
--- a/java/java.go
+++ b/java/java.go
@@ -221,6 +221,13 @@
// If true, export a copy of the module as a -hostdex module for host testing.
Hostdex *bool
+ Target struct {
+ Hostdex struct {
+ // Additional required dependencies to add to -hostdex modules.
+ Required []string
+ }
+ }
+
// If set to true, compile dex regardless of installable. Defaults to false.
Compile_dex *bool
@@ -283,6 +290,10 @@
// jar file containing only resources including from static library dependencies
resourceJar android.Path
+ // args and dependencies to package source files into a srcjar
+ srcJarArgs []string
+ srcJarDeps android.Paths
+
// jar file containing implementation classes and resources including static library
// dependencies
implementationAndResourcesJar android.Path
@@ -333,6 +344,9 @@
// list of additional targets for checkbuild
additionalCheckedModules android.Paths
+ // Extra files generated by the module type to be added as java resources.
+ extraResources android.Paths
+
hiddenAPI
dexpreopter
}
@@ -355,6 +369,7 @@
DexJar() android.Path
AidlIncludeDirs() android.Paths
ExportedSdkLibs() []string
+ SrcJarArgs() ([]string, android.Paths)
}
type SdkLibraryDependency interface {
@@ -502,7 +517,8 @@
if j.hasSrcExt(".kt") {
// TODO(ccross): move this to a mutator pass that can tell if generated sources contain
// Kotlin files
- ctx.AddVariationDependencies(nil, kotlinStdlibTag, "kotlin-stdlib")
+ ctx.AddVariationDependencies(nil, kotlinStdlibTag,
+ "kotlin-stdlib", "kotlin-stdlib-jdk7", "kotlin-stdlib-jdk8")
if len(j.properties.Plugins) > 0 {
ctx.AddVariationDependencies(nil, kotlinAnnotationsTag, "kotlin-annotations")
}
@@ -624,7 +640,7 @@
switch {
case name == "core.current.stubs" || name == "core.platform.api.stubs" ||
name == "stub-annotations" || name == "private-stub-annotations-jar" ||
- name == "core-lambda-stubs":
+ name == "core-lambda-stubs" || name == "core-generated-annotation-stubs":
return javaCore, true
case ver == "core_current":
return javaCore, false
@@ -778,7 +794,7 @@
deps.staticResourceJars = append(deps.staticResourceJars, dep.(*AndroidApp).exportPackage)
}
case kotlinStdlibTag:
- deps.kotlinStdlib = dep.HeaderJars()
+ deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars()...)
case kotlinAnnotationsTag:
deps.kotlinAnnotations = dep.HeaderJars()
}
@@ -839,7 +855,7 @@
ret = javaVersion
} else if ctx.Device() && sdk <= 23 {
ret = "1.7"
- } else if ctx.Device() && sdk <= 28 || !ctx.Config().TargetOpenJDK9() {
+ } else if ctx.Device() && sdk <= 29 || !ctx.Config().TargetOpenJDK9() {
ret = "1.8"
} else if ctx.Device() && sdkContext.sdkVersion() != "" && sdk == android.FutureApiLevel {
// TODO(ccross): once we generate stubs we should be able to use 1.9 for sdk_version: "current"
@@ -947,7 +963,9 @@
return flags
}
-func (j *Module) compile(ctx android.ModuleContext, extraSrcJars ...android.Path) {
+func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
+
+ hasSrcs := false
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
@@ -963,10 +981,15 @@
}
srcFiles = j.genSources(ctx, srcFiles, flags)
+ if len(srcFiles) > 0 {
+ hasSrcs = true
+ }
srcJars := srcFiles.FilterByExt(".srcjar")
srcJars = append(srcJars, deps.srcJars...)
- srcJars = append(srcJars, extraSrcJars...)
+ if aaptSrcJar != nil {
+ srcJars = append(srcJars, aaptSrcJar)
+ }
// Collect source files from compiledJavaSrcs, compiledSrcJars and filter out Exclude_srcs
// that IDEInfo struct will use
@@ -1103,9 +1126,18 @@
}
}
+ j.srcJarArgs, j.srcJarDeps = resourcePathsToJarArgs(srcFiles), srcFiles
+
+ var includeSrcJar android.WritablePath
+ if Bool(j.properties.Include_srcs) {
+ includeSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+".srcjar")
+ TransformResourcesToJar(ctx, includeSrcJar, j.srcJarArgs, j.srcJarDeps)
+ }
+
dirArgs, dirDeps := ResourceDirsToJarArgs(ctx, j.properties.Java_resource_dirs,
j.properties.Exclude_java_resource_dirs, j.properties.Exclude_java_resources)
fileArgs, fileDeps := ResourceFilesToJarArgs(ctx, j.properties.Java_resources, j.properties.Exclude_java_resources)
+ extraArgs, extraDeps := resourcePathsToJarArgs(j.extraResources), j.extraResources
var resArgs []string
var resDeps android.Paths
@@ -1116,11 +1148,8 @@
resArgs = append(resArgs, fileArgs...)
resDeps = append(resDeps, fileDeps...)
- if Bool(j.properties.Include_srcs) {
- srcArgs, srcDeps := SourceFilesToJarArgs(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
- resArgs = append(resArgs, srcArgs...)
- resDeps = append(resDeps, srcDeps...)
- }
+ resArgs = append(resArgs, extraArgs...)
+ resDeps = append(resDeps, extraDeps...)
if len(resArgs) > 0 {
resourceJar := android.PathForModuleOut(ctx, "res", jarName)
@@ -1131,20 +1160,28 @@
}
}
- if len(deps.staticResourceJars) > 0 {
- var jars android.Paths
- if j.resourceJar != nil {
- jars = append(jars, j.resourceJar)
- }
- jars = append(jars, deps.staticResourceJars...)
+ var resourceJars android.Paths
+ if j.resourceJar != nil {
+ resourceJars = append(resourceJars, j.resourceJar)
+ }
+ if Bool(j.properties.Include_srcs) {
+ resourceJars = append(resourceJars, includeSrcJar)
+ }
+ resourceJars = append(resourceJars, deps.staticResourceJars...)
+ if len(resourceJars) > 1 {
combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
- TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
+ TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{},
false, nil, nil)
j.resourceJar = combinedJar
+ } else if len(resourceJars) == 1 {
+ j.resourceJar = resourceJars[0]
}
- jars = append(jars, deps.staticJars...)
+ if len(deps.staticJars) > 0 {
+ jars = append(jars, deps.staticJars...)
+ hasSrcs = true
+ }
manifest := j.overrideManifest
if !manifest.Valid() && j.properties.Manifest != nil {
@@ -1246,16 +1283,17 @@
// merge implementation jar with resources if necessary
implementationAndResourcesJar := outputFile
if j.resourceJar != nil {
- jars := android.Paths{implementationAndResourcesJar, j.resourceJar}
+ jars := android.Paths{j.resourceJar, implementationAndResourcesJar}
combinedJar := android.PathForModuleOut(ctx, "withres", jarName)
- TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
+ TransformJarsToJar(ctx, combinedJar, "for resources", jars, manifest,
false, nil, nil)
implementationAndResourcesJar = combinedJar
}
j.implementationAndResourcesJar = implementationAndResourcesJar
- if ctx.Device() && (Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) {
+ if ctx.Device() && hasSrcs &&
+ (Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) {
// Dex compilation
var dexOutputFile android.ModuleOutPath
dexOutputFile = j.compileDex(ctx, flags, outputFile, jarName)
@@ -1354,7 +1392,7 @@
// since we have to strip META-INF/TRANSITIVE dir from turbine.jar
combinedJar := android.PathForModuleOut(ctx, "turbine-combined", jarName)
TransformJarsToJar(ctx, combinedJar, "for turbine", jars, android.OptionalPath{},
- false, nil, []string{"META-INF"})
+ false, nil, []string{"META-INF/TRANSITIVE"})
headerJar = combinedJar
if j.expandJarjarRules != nil {
@@ -1429,6 +1467,10 @@
return j.exportedSdkLibs
}
+func (j *Module) SrcJarArgs() ([]string, android.Paths) {
+ return j.srcJarArgs, j.srcJarDeps
+}
+
var _ logtagsProducer = (*Module)(nil)
func (j *Module) logtags() android.Paths {
@@ -1484,7 +1526,7 @@
j.dexpreopter.isInstallable = Bool(j.properties.Installable)
j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
j.deviceProperties.UncompressDex = j.dexpreopter.uncompressedDex
- j.compile(ctx)
+ j.compile(ctx, nil)
if (Bool(j.properties.Installable) || ctx.Host()) && !android.DirectlyInAnyApex(ctx, ctx.ModuleName()) {
j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
@@ -1632,6 +1674,9 @@
&module.Module.protoProperties,
&module.testHelperLibraryProperties)
+ module.Module.properties.Installable = proptools.BoolPtr(true)
+ module.Module.dexpreopter.isTest = true
+
InitJavaModule(module, android.HostAndDeviceSupported)
return module
}
@@ -1903,6 +1948,10 @@
return j.exportedSdkLibs
}
+func (j *Import) SrcJarArgs() ([]string, android.Paths) {
+ return nil, nil
+}
+
// Add compile time check for interface implementation
var _ android.IDEInfo = (*Import)(nil)
var _ android.IDECustomizedModuleName = (*Import)(nil)
diff --git a/java/java_resources.go b/java/java_resources.go
index 7161168..787d74a 100644
--- a/java/java_resources.go
+++ b/java/java_resources.go
@@ -85,19 +85,19 @@
return resourceFilesToJarArgs(ctx, res, exclude)
}
-// Convert java_resources properties to arguments to soong_zip -jar, keeping files that should
-// normally not used as resources like *.java
-func SourceFilesToJarArgs(ctx android.ModuleContext,
- res, exclude []string) (args []string, deps android.Paths) {
-
- return resourceFilesToJarArgs(ctx, res, exclude)
-}
-
func resourceFilesToJarArgs(ctx android.ModuleContext,
res, exclude []string) (args []string, deps android.Paths) {
files := android.PathsForModuleSrcExcludes(ctx, res, exclude)
+ args = resourcePathsToJarArgs(files)
+
+ return args, files
+}
+
+func resourcePathsToJarArgs(files android.Paths) []string {
+ var args []string
+
lastDir := ""
for i, f := range files {
rel := f.Rel()
@@ -113,5 +113,5 @@
lastDir = dir
}
- return args, files
+ return args
}
diff --git a/java/java_test.go b/java/java_test.go
index 3fab43d..50b1c34 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -63,6 +63,7 @@
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(AndroidAppCertificateFactory))
+ ctx.RegisterModuleType("android_app_import", android.ModuleFactoryAdaptor(AndroidAppImportFactory))
ctx.RegisterModuleType("android_library", android.ModuleFactoryAdaptor(AndroidLibraryFactory))
ctx.RegisterModuleType("android_test", android.ModuleFactoryAdaptor(AndroidTestFactory))
ctx.RegisterModuleType("android_test_helper_app", android.ModuleFactoryAdaptor(AndroidTestHelperAppFactory))
@@ -92,10 +93,10 @@
ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
- ctx.PreArchMutators(android.RegisterOverridePreArchMutators)
ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
ctx.TopDown("prebuilt_apis", PrebuiltApisMutator).Parallel()
})
+ ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory))
ctx.RegisterPreSingletonType("sdk_versions", android.SingletonFactoryAdaptor(sdkPreSingletonFactory))
@@ -163,6 +164,10 @@
"prebuilts/sdk/tools/core-lambda-stubs.jar": nil,
"prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "current"],}`),
+ "prebuilts/apk/app.apk": nil,
+ "prebuilts/apk/app_xhdpi.apk": nil,
+ "prebuilts/apk/app_xxhdpi.apk": nil,
+
// For framework-res, which is an implicit dependency for framework
"AndroidManifest.xml": nil,
"build/make/target/product/security/testkey": nil,
@@ -479,12 +484,6 @@
args: "-C java-res -f java-res/a/a -f java-res/b/b",
},
{
- // Test that a module with "include_srcs: true" includes its source files in the resources jar
- name: "include sources",
- prop: `include_srcs: true`,
- args: "-C . -f a.java -f b.java -f c.java",
- },
- {
// Test that a module with wildcards in java_resource_dirs has the correct path prefixes
name: "wildcard dirs",
prop: `java_resource_dirs: ["java-res/*"]`,
@@ -552,6 +551,69 @@
}
}
+func TestIncludeSrcs(t *testing.T) {
+ ctx := testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: [
+ "a.java",
+ "b.java",
+ "c.java",
+ ],
+ include_srcs: true,
+ }
+
+ java_library {
+ name: "bar",
+ srcs: [
+ "a.java",
+ "b.java",
+ "c.java",
+ ],
+ java_resource_dirs: ["java-res"],
+ include_srcs: true,
+ }
+ `)
+
+ // Test a library with include_srcs: true
+ foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar")
+ fooSrcJar := ctx.ModuleForTests("foo", "android_common").Output("foo.srcjar")
+
+ if g, w := fooSrcJar.Output.String(), foo.Inputs.Strings(); !inList(g, w) {
+ t.Errorf("foo combined jars %v does not contain %q", w, g)
+ }
+
+ if g, w := fooSrcJar.Args["jarArgs"], "-C . -f a.java -f b.java -f c.java"; g != w {
+ t.Errorf("foo source jar args %q is not %q", w, g)
+ }
+
+ // Test a library with include_srcs: true and resources
+ bar := ctx.ModuleForTests("bar", "android_common").Output("withres/bar.jar")
+ barResCombined := ctx.ModuleForTests("bar", "android_common").Output("res-combined/bar.jar")
+ barRes := ctx.ModuleForTests("bar", "android_common").Output("res/bar.jar")
+ barSrcJar := ctx.ModuleForTests("bar", "android_common").Output("bar.srcjar")
+
+ if g, w := barSrcJar.Output.String(), barResCombined.Inputs.Strings(); !inList(g, w) {
+ t.Errorf("bar combined resource jars %v does not contain %q", w, g)
+ }
+
+ if g, w := barRes.Output.String(), barResCombined.Inputs.Strings(); !inList(g, w) {
+ t.Errorf("bar combined resource jars %v does not contain %q", w, g)
+ }
+
+ if g, w := barResCombined.Output.String(), bar.Inputs.Strings(); !inList(g, w) {
+ t.Errorf("bar combined jars %v does not contain %q", w, g)
+ }
+
+ if g, w := barSrcJar.Args["jarArgs"], "-C . -f a.java -f b.java -f c.java"; g != w {
+ t.Errorf("bar source jar args %q is not %q", w, g)
+ }
+
+ if g, w := barRes.Args["jarArgs"], "-C java-res -f java-res/a/a -f java-res/b/b"; g != w {
+ t.Errorf("bar resource jar args %q is not %q", w, g)
+ }
+}
+
func TestGeneratedSources(t *testing.T) {
ctx := testJava(t, `
java_library {
@@ -945,8 +1007,8 @@
}
`
- t.Run("1.8", func(t *testing.T) {
- // Test default javac 1.8
+ t.Run("Java language level 8", func(t *testing.T) {
+ // Test default javac -source 1.8 -target 1.8
ctx := testJava(t, bp)
checkPatchModuleFlag(t, ctx, "foo", "")
@@ -954,9 +1016,9 @@
checkPatchModuleFlag(t, ctx, "baz", "")
})
- t.Run("1.9", func(t *testing.T) {
- // Test again with javac 1.9
- config := testConfig(map[string]string{"EXPERIMENTAL_USE_OPENJDK9": "true"})
+ t.Run("Java language level 9", func(t *testing.T) {
+ // Test again with javac -source 9 -target 9
+ config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "true"})
ctx := testContext(config, bp, nil)
run(t, ctx, config)
diff --git a/java/kotlin.go b/java/kotlin.go
index 54c6b0e..33167ba 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -18,6 +18,7 @@
"bytes"
"encoding/base64"
"encoding/binary"
+ "path/filepath"
"strings"
"android/soong/android"
@@ -30,7 +31,7 @@
Command: `rm -rf "$classesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` +
`mkdir -p "$classesDir" "$srcJarDir" "$emptyDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.GenKotlinBuildFileCmd} $classpath $classesDir $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
+ `${config.GenKotlinBuildFileCmd} $classpath "$name" $classesDir $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
`${config.KotlincCmd} ${config.JavacHeapFlags} $kotlincFlags ` +
`-jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile -kotlin-home $emptyDir && ` +
`${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir && ` +
@@ -50,7 +51,8 @@
Rspfile: "$out.rsp",
RspfileContent: `$in`,
},
- "kotlincFlags", "classpath", "srcJars", "srcJarDir", "classesDir", "kotlinJvmTarget", "kotlinBuildFile", "emptyDir")
+ "kotlincFlags", "classpath", "srcJars", "srcJarDir", "classesDir", "kotlinJvmTarget", "kotlinBuildFile",
+ "emptyDir", "name")
// kotlinCompile takes .java and .kt sources and srcJars, and compiles the .kt sources into a classes jar in outputFile.
func kotlinCompile(ctx android.ModuleContext, outputFile android.WritablePath,
@@ -61,6 +63,9 @@
deps = append(deps, flags.kotlincClasspath...)
deps = append(deps, srcJars...)
+ kotlinName := filepath.Join(ctx.ModuleDir(), ctx.ModuleSubDir(), ctx.ModuleName())
+ kotlinName = strings.ReplaceAll(kotlinName, "/", "__")
+
ctx.Build(pctx, android.BuildParams{
Rule: kotlinc,
Description: "kotlinc",
@@ -77,6 +82,7 @@
"emptyDir": android.PathForModuleOut(ctx, "kotlinc", "empty").String(),
// http://b/69160377 kotlinc only supports -jvm-target 1.6 and 1.8
"kotlinJvmTarget": "1.8",
+ "name": kotlinName,
},
})
}
@@ -85,7 +91,7 @@
blueprint.RuleParams{
Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && mkdir -p "$srcJarDir" "$kaptDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.GenKotlinBuildFileCmd} $classpath "" $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
+ `${config.GenKotlinBuildFileCmd} $classpath "$name" "" $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
`${config.KotlincCmd} ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} $kotlincFlags ` +
`-Xplugin=${config.KotlinKaptJar} ` +
`-P plugin:org.jetbrains.kotlin.kapt3:sources=$kaptDir/sources ` +
@@ -111,7 +117,7 @@
RspfileContent: `$in`,
},
"kotlincFlags", "encodedJavacFlags", "kaptProcessorPath", "kaptProcessor",
- "classpath", "srcJars", "srcJarDir", "kaptDir", "kotlinJvmTarget", "kotlinBuildFile")
+ "classpath", "srcJars", "srcJarDir", "kaptDir", "kotlinJvmTarget", "kotlinBuildFile", "name")
// kotlinKapt performs Kotlin-compatible annotation processing. It takes .kt and .java sources and srcjars, and runs
// annotation processors over all of them, producing a srcjar of generated code in outputFile. The srcjar should be
@@ -138,6 +144,9 @@
{"-target", flags.javaVersion},
})
+ kotlinName := filepath.Join(ctx.ModuleDir(), ctx.ModuleSubDir(), ctx.ModuleName())
+ kotlinName = strings.ReplaceAll(kotlinName, "/", "__")
+
ctx.Build(pctx, android.BuildParams{
Rule: kapt,
Description: "kapt",
@@ -154,6 +163,7 @@
"kaptProcessor": kaptProcessor,
"kaptDir": android.PathForModuleOut(ctx, "kapt/gen").String(),
"encodedJavacFlags": encodedJavacFlags,
+ "name": kotlinName,
},
})
}
diff --git a/java/robolectric.go b/java/robolectric.go
new file mode 100644
index 0000000..26f1e9d
--- /dev/null
+++ b/java/robolectric.go
@@ -0,0 +1,110 @@
+// 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"
+ "io"
+ "strings"
+
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterModuleType("android_robolectric_test", RobolectricTestFactory)
+}
+
+var robolectricDefaultLibs = []string{
+ "robolectric_android-all-stub",
+ "Robolectric_all-target",
+ "mockito-robolectric-prebuilt",
+ "truth-prebuilt",
+}
+
+type robolectricProperties struct {
+ // The name of the android_app module that the tests will run against.
+ Instrumentation_for *string
+
+ Test_options struct {
+ // Timeout in seconds when running the tests.
+ Timeout *string
+ }
+}
+
+type robolectricTest struct {
+ Library
+
+ robolectricProperties robolectricProperties
+
+ libs []string
+}
+
+func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) {
+ r.Library.DepsMutator(ctx)
+
+ if r.robolectricProperties.Instrumentation_for != nil {
+ ctx.AddVariationDependencies(nil, instrumentationForTag, String(r.robolectricProperties.Instrumentation_for))
+ } else {
+ ctx.PropertyErrorf("instrumentation_for", "missing required instrumented module")
+ }
+
+ ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...)
+}
+
+func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ r.Library.GenerateAndroidBuildActions(ctx)
+
+ for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
+ r.libs = append(r.libs, ctx.OtherModuleName(dep))
+ }
+}
+
+func (r *robolectricTest) AndroidMk() android.AndroidMkData {
+ data := r.Library.AndroidMk()
+
+ data.Custom = func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+ android.WriteAndroidMkData(w, data)
+
+ fmt.Fprintln(w, "")
+ fmt.Fprintln(w, "include $(CLEAR_VARS)")
+ fmt.Fprintln(w, "LOCAL_MODULE := Run"+name)
+ fmt.Fprintln(w, "LOCAL_JAVA_LIBRARIES :=", name)
+ fmt.Fprintln(w, "LOCAL_JAVA_LIBRARIES += ", strings.Join(r.libs, " "))
+ fmt.Fprintln(w, "LOCAL_TEST_PACKAGE :=", String(r.robolectricProperties.Instrumentation_for))
+ if t := r.robolectricProperties.Test_options.Timeout; t != nil {
+ fmt.Fprintln(w, "LOCAL_ROBOTEST_TIMEOUT :=", *t)
+ }
+ fmt.Fprintln(w, "-include external/robolectric-shadows/run_robotests.mk")
+ }
+
+ return data
+}
+
+// An android_robolectric_test module compiles tests against the Robolectric framework that can run on the local host
+// instead of on a device. It also generates a rule with the name of the module prefixed with "Run" that can be
+// used to run the tests. Running the tests with build rule will eventually be deprecated and replaced with atest.
+func RobolectricTestFactory() android.Module {
+ module := &robolectricTest{}
+
+ module.AddProperties(
+ &module.Module.properties,
+ &module.Module.protoProperties,
+ &module.robolectricProperties)
+
+ module.Module.dexpreopter.isTest = true
+
+ InitJavaModule(module, android.DeviceSupported)
+ return module
+}
diff --git a/java/sdk.go b/java/sdk.go
index 36010b6..e93f8fb 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -316,7 +316,7 @@
// Create api_fingerprint.txt
func createAPIFingerprint(ctx android.SingletonContext) {
- out := apiFingerprintPath(ctx)
+ out := ApiFingerprintPath(ctx)
rule := android.NewRuleBuilder()
@@ -359,7 +359,7 @@
rule.Build(pctx, ctx, "api_fingerprint", "generate api_fingerprint.txt")
}
-func apiFingerprintPath(ctx android.PathContext) android.OutputPath {
+func ApiFingerprintPath(ctx android.PathContext) android.OutputPath {
return ctx.Config().Once(apiFingerprintPathKey, func() interface{} {
return android.PathForOutput(ctx, "api_fingerprint.txt")
}).(android.OutputPath)
@@ -371,5 +371,5 @@
}
ctx.Strict("FRAMEWORK_AIDL", sdkFrameworkAidlPath(ctx).String())
- ctx.Strict("API_FINGERPRINT", apiFingerprintPath(ctx).String())
+ ctx.Strict("API_FINGERPRINT", ApiFingerprintPath(ctx).String())
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 72c5cfc..5b65c0c 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -126,6 +126,9 @@
// If set to true, the path of dist files is apistubs/core. Defaults to false.
Core_lib *bool
+ // don't create dist rules.
+ No_dist *bool `blueprint:"mutated"`
+
// TODO: determines whether to create HTML doc or not
//Html_doc *bool
}
@@ -212,52 +215,54 @@
android.WriteAndroidMkData(w, data)
module.Library.AndroidMkHostDex(w, name, data)
- // Create a phony module that installs the impl library, for the case when this lib is
- // in PRODUCT_PACKAGES.
- owner := module.ModuleBase.Owner()
- if owner == "" {
- if Bool(module.sdkLibraryProperties.Core_lib) {
- owner = "core"
- } else {
- owner = "android"
+ if !Bool(module.sdkLibraryProperties.No_dist) {
+ // Create a phony module that installs the impl library, for the case when this lib is
+ // in PRODUCT_PACKAGES.
+ owner := module.ModuleBase.Owner()
+ if owner == "" {
+ if Bool(module.sdkLibraryProperties.Core_lib) {
+ owner = "core"
+ } else {
+ owner = "android"
+ }
}
- }
- // Create dist rules to install the stubs libs to the dist dir
- if len(module.publicApiStubsPath) == 1 {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.publicApiStubsImplPath.Strings()[0]+
- ":"+path.Join("apistubs", owner, "public",
- module.BaseModuleName()+".jar")+")")
- }
- if len(module.systemApiStubsPath) == 1 {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.systemApiStubsImplPath.Strings()[0]+
- ":"+path.Join("apistubs", owner, "system",
- module.BaseModuleName()+".jar")+")")
- }
- if len(module.testApiStubsPath) == 1 {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.testApiStubsImplPath.Strings()[0]+
- ":"+path.Join("apistubs", owner, "test",
- module.BaseModuleName()+".jar")+")")
- }
- if module.publicApiFilePath != nil {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.publicApiFilePath.String()+
- ":"+path.Join("apistubs", owner, "public", "api",
- module.BaseModuleName()+".txt")+")")
- }
- if module.systemApiFilePath != nil {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.systemApiFilePath.String()+
- ":"+path.Join("apistubs", owner, "system", "api",
- module.BaseModuleName()+".txt")+")")
- }
- if module.testApiFilePath != nil {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.testApiFilePath.String()+
- ":"+path.Join("apistubs", owner, "test", "api",
- module.BaseModuleName()+".txt")+")")
+ // Create dist rules to install the stubs libs to the dist dir
+ if len(module.publicApiStubsPath) == 1 {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.publicApiStubsImplPath.Strings()[0]+
+ ":"+path.Join("apistubs", owner, "public",
+ module.BaseModuleName()+".jar")+")")
+ }
+ if len(module.systemApiStubsPath) == 1 {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.systemApiStubsImplPath.Strings()[0]+
+ ":"+path.Join("apistubs", owner, "system",
+ module.BaseModuleName()+".jar")+")")
+ }
+ if len(module.testApiStubsPath) == 1 {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.testApiStubsImplPath.Strings()[0]+
+ ":"+path.Join("apistubs", owner, "test",
+ module.BaseModuleName()+".jar")+")")
+ }
+ if module.publicApiFilePath != nil {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.publicApiFilePath.String()+
+ ":"+path.Join("apistubs", owner, "public", "api",
+ module.BaseModuleName()+".txt")+")")
+ }
+ if module.systemApiFilePath != nil {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.systemApiFilePath.String()+
+ ":"+path.Join("apistubs", owner, "system", "api",
+ module.BaseModuleName()+".txt")+")")
+ }
+ if module.testApiFilePath != nil {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.testApiFilePath.String()+
+ ":"+path.Join("apistubs", owner, "test", "api",
+ module.BaseModuleName()+".txt")+")")
+ }
}
}
return data
@@ -641,6 +646,10 @@
}
}
+func (module *SdkLibrary) SetNoDist() {
+ module.sdkLibraryProperties.No_dist = proptools.BoolPtr(true)
+}
+
var javaSdkLibrariesKey = android.NewOnceKey("javaSdkLibraries")
func javaSdkLibraries(config android.Config) *[]string {
diff --git a/java/sdk_test.go b/java/sdk_test.go
index e446129..cc4da2e 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -272,8 +272,8 @@
}
}
- t.Run("1.8", func(t *testing.T) {
- // Test default javac 1.8
+ t.Run("Java language level 8", func(t *testing.T) {
+ // Test default javac -source 1.8 -target 1.8
config := testConfig(nil)
if testcase.unbundled {
config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
@@ -299,9 +299,9 @@
}
})
- // Test again with javac 1.9
- t.Run("1.9", func(t *testing.T) {
- config := testConfig(map[string]string{"EXPERIMENTAL_USE_OPENJDK9": "true"})
+ // Test again with javac -source 9 -target 9
+ t.Run("Java language level 9", func(t *testing.T) {
+ config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "true"})
if testcase.unbundled {
config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
}
diff --git a/java/testing.go b/java/testing.go
index 1be3768..22831c9 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -44,6 +44,8 @@
"core.current.stubs",
"core.platform.api.stubs",
"kotlin-stdlib",
+ "kotlin-stdlib-jdk7",
+ "kotlin-stdlib-jdk8",
"kotlin-annotations",
}
diff --git a/scripts/gen-kotlin-build-file.sh b/scripts/gen-kotlin-build-file.sh
index 1e03f72..177ca1b 100755
--- a/scripts/gen-kotlin-build-file.sh
+++ b/scripts/gen-kotlin-build-file.sh
@@ -17,7 +17,7 @@
# Generates kotlinc module xml file to standard output based on rsp files
if [[ -z "$1" ]]; then
- echo "usage: $0 <classpath> <outDir> <rspFiles>..." >&2
+ echo "usage: $0 <classpath> <name> <outDir> <rspFiles>..." >&2
exit 1
fi
@@ -27,8 +27,9 @@
fi;
classpath=$1
-out_dir=$2
-shift 2
+name=$2
+out_dir=$3
+shift 3
# Path in the build file may be relative to the build file, we need to make them
# absolute
@@ -44,7 +45,7 @@
}
# Print preamble
-echo "<modules><module name=\"name\" type=\"java-production\" outputDir=\"${out_dir}\">"
+echo "<modules><module name=\"${name}\" type=\"java-production\" outputDir=\"${out_dir}\">"
# Print classpath entries
for file in $(echo "$classpath" | tr ":" "\n"); do
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index 4ad9afa..7ec8999 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -231,7 +231,7 @@
def run_test(self, input_manifest, new_uses_libraries):
doc = minidom.parseString(input_manifest)
- manifest_fixer.add_uses_libraries(doc, new_uses_libraries)
+ manifest_fixer.add_uses_libraries(doc, new_uses_libraries, True)
output = StringIO.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
diff --git a/scripts/strip.sh b/scripts/strip.sh
index d536907..bd62619 100755
--- a/scripts/strip.sh
+++ b/scripts/strip.sh
@@ -24,25 +24,28 @@
# -i ${file}: input file (required)
# -o ${file}: output file (required)
# -d ${file}: deps file (required)
+# -k symbols: Symbols to keep (optional)
# --add-gnu-debuglink
# --keep-mini-debug-info
# --keep-symbols
+# --keep-symbols-and-debug-frame
# --use-gnu-strip
# --remove-build-id
set -o pipefail
-OPTSTRING=d:i:o:-:
+OPTSTRING=d:i:o:k:-:
usage() {
cat <<EOF
-Usage: strip.sh [options] -i in-file -o out-file -d deps-file
+Usage: strip.sh [options] -k symbols -i in-file -o out-file -d deps-file
Options:
- --add-gnu-debuglink Add a gnu-debuglink section to out-file
- --keep-mini-debug-info Keep compressed debug info in out-file
- --keep-symbols Keep symbols in out-file
- --use-gnu-strip Use strip/objcopy instead of llvm-{strip,objcopy}
- --remove-build-id Remove the gnu build-id section in out-file
+ --add-gnu-debuglink Add a gnu-debuglink section to out-file
+ --keep-mini-debug-info Keep compressed debug info in out-file
+ --keep-symbols Keep symbols in out-file
+ --keep-symbols-and-debug-frame Keep symbols and .debug_frame in out-file
+ --use-gnu-strip Use strip/objcopy instead of llvm-{strip,objcopy}
+ --remove-build-id Remove the gnu build-id section in out-file
EOF
exit 1
}
@@ -62,6 +65,15 @@
fi
}
+do_strip_keep_symbols_and_debug_frame() {
+ REMOVE_SECTIONS=`"${CROSS_COMPILE}readelf" -S "${infile}" | awk '/.debug_/ {if ($2 != ".debug_frame") {print "--remove-section " $2}}' | xargs`
+ if [ -z "${use_gnu_strip}" ]; then
+ "${CLANG_BIN}/llvm-objcopy" "${infile}" "${outfile}.tmp" ${REMOVE_SECTIONS}
+ else
+ "${CROSS_COMPILE}objcopy" "${infile}" "${outfile}.tmp" ${REMOVE_SECTIONS}
+ fi
+}
+
do_strip_keep_symbols() {
REMOVE_SECTIONS=`"${CROSS_COMPILE}readelf" -S "${infile}" | awk '/.debug_/ {print "--remove-section " $2}' | xargs`
if [ -z "${use_gnu_strip}" ]; then
@@ -71,6 +83,20 @@
fi
}
+do_strip_keep_symbol_list() {
+ if [ -z "${use_gnu_strip}" ]; then
+ echo "do_strip_keep_symbol_list does not work with llvm-objcopy"
+ echo "http://b/131631155"
+ usage
+ fi
+
+ echo "${symbols_to_keep}" | tr ',' '\n' > "${outfile}.symbolList"
+ KEEP_SYMBOLS="-w --strip-unneeded-symbol=* --keep-symbols="
+ KEEP_SYMBOLS+="${outfile}.symbolList"
+
+ "${CROSS_COMPILE}objcopy" "${infile}" "${outfile}.tmp" ${KEEP_SYMBOLS}
+}
+
do_strip_keep_mini_debug_info() {
rm -f "${outfile}.dynsyms" "${outfile}.funcsyms" "${outfile}.keep_symbols" "${outfile}.debug" "${outfile}.mini_debuginfo" "${outfile}.mini_debuginfo.xz"
local fail=
@@ -124,19 +150,22 @@
while getopts $OPTSTRING opt; do
case "$opt" in
- d) depsfile="${OPTARG}" ;;
- i) infile="${OPTARG}" ;;
- o) outfile="${OPTARG}" ;;
- -)
- case "${OPTARG}" in
- add-gnu-debuglink) add_gnu_debuglink=true ;;
- keep-mini-debug-info) keep_mini_debug_info=true ;;
- keep-symbols) keep_symbols=true ;;
- remove-build-id) remove_build_id=true ;;
- *) echo "Unknown option --${OPTARG}"; usage ;;
- esac;;
- ?) usage ;;
- *) echo "'${opt}' '${OPTARG}'"
+ d) depsfile="${OPTARG}" ;;
+ i) infile="${OPTARG}" ;;
+ o) outfile="${OPTARG}" ;;
+ k) symbols_to_keep="${OPTARG}" ;;
+ -)
+ case "${OPTARG}" in
+ add-gnu-debuglink) add_gnu_debuglink=true ;;
+ keep-mini-debug-info) keep_mini_debug_info=true ;;
+ keep-symbols) keep_symbols=true ;;
+ keep-symbols-and-debug-frame) keep_symbols_and_debug_frame=true ;;
+ remove-build-id) remove_build_id=true ;;
+ use-gnu-strip) use_gnu_strip=true ;;
+ *) echo "Unknown option --${OPTARG}"; usage ;;
+ esac;;
+ ?) usage ;;
+ *) echo "'${opt}' '${OPTARG}'"
esac
done
@@ -160,6 +189,21 @@
usage
fi
+if [ ! -z "${keep_symbols}" -a ! -z "${keep_symbols_and_debug_frame}" ]; then
+ echo "--keep-symbols and --keep-symbols-and-debug-frame cannot be used together"
+ usage
+fi
+
+if [ ! -z "${keep_mini_debug_info}" -a ! -z "${keep_symbols_and_debug_frame}" ]; then
+ echo "--keep-symbols-mini-debug-info and --keep-symbols-and-debug-frame cannot be used together"
+ usage
+fi
+
+if [ ! -z "${symbols_to_keep}" -a ! -z "${keep_symbols}" ]; then
+ echo "--keep-symbols and -k cannot be used together"
+ usage
+fi
+
if [ ! -z "${add_gnu_debuglink}" -a ! -z "${keep_mini_debug_info}" ]; then
echo "--add-gnu-debuglink cannot be used with --keep-mini-debug-info"
usage
@@ -169,8 +213,12 @@
if [ ! -z "${keep_symbols}" ]; then
do_strip_keep_symbols
+elif [ ! -z "${symbols_to_keep}" ]; then
+ do_strip_keep_symbol_list
elif [ ! -z "${keep_mini_debug_info}" ]; then
do_strip_keep_mini_debug_info
+elif [ ! -z "${keep_symbols_and_debug_frame}" ]; then
+ do_strip_keep_symbols_and_debug_frame
else
do_strip
fi
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 0313ecd..3f2709e 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -72,6 +72,7 @@
&m.syspropLibraryProperties,
)
m.InitSdkLibraryProperties()
+ m.SetNoDist()
android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, "common")
android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) })
android.AddLoadHook(m, func(ctx android.LoadHookContext) { m.SdkLibrary.CreateInternalModules(ctx) })
diff --git a/ui/build/build.go b/ui/build/build.go
index 0ae06d6..59d1474 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -166,11 +166,13 @@
runMakeProductConfig(ctx, config)
}
- if inList("installclean", config.Arguments()) {
+ if inList("installclean", config.Arguments()) ||
+ inList("install-clean", config.Arguments()) {
installClean(ctx, config, what)
ctx.Println("Deleted images and staging directories.")
return
- } else if inList("dataclean", config.Arguments()) {
+ } else if inList("dataclean", config.Arguments()) ||
+ inList("data-clean", config.Arguments()) {
dataClean(ctx, config, what)
ctx.Println("Deleted data files.")
return
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 483c273..c6e5ddc 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -224,7 +224,6 @@
"BUILD_BROKEN_USES_BUILD_HOST_NATIVE_TEST",
"BUILD_BROKEN_USES_BUILD_HOST_PREBUILT",
"BUILD_BROKEN_USES_BUILD_HOST_SHARED_LIBRARY",
- "BUILD_BROKEN_USES_BUILD_HOST_SHARED_TEST_LIBRARY",
"BUILD_BROKEN_USES_BUILD_HOST_STATIC_LIBRARY",
"BUILD_BROKEN_USES_BUILD_HOST_STATIC_TEST_LIBRARY",
"BUILD_BROKEN_USES_BUILD_HOST_TEST_CONFIG",
@@ -238,7 +237,6 @@
"BUILD_BROKEN_USES_BUILD_PREBUILT",
"BUILD_BROKEN_USES_BUILD_RRO_PACKAGE",
"BUILD_BROKEN_USES_BUILD_SHARED_LIBRARY",
- "BUILD_BROKEN_USES_BUILD_SHARED_TEST_LIBRARY",
"BUILD_BROKEN_USES_BUILD_STATIC_JAVA_LIBRARY",
"BUILD_BROKEN_USES_BUILD_STATIC_LIBRARY",
"BUILD_BROKEN_USES_BUILD_STATIC_TEST_LIBRARY",
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index ed2d9ca..4a30391 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -74,13 +74,16 @@
}
var Configuration = map[string]PathConfig{
- "bash": Allowed,
- "bc": Allowed,
+ "bash": Allowed,
+ "bc": Allowed,
+ // We need bzip2 here even though we provide a bzip2 binary because
+ // GNU tar seems to avoid calling ours.
"bzip2": Allowed,
"date": Allowed,
"dd": Allowed,
"diff": Allowed,
"egrep": Allowed,
+ "expr": Allowed,
"find": Allowed,
"fuser": Allowed,
"getopt": Allowed,
@@ -99,12 +102,12 @@
"python3": Allowed,
"realpath": Allowed,
"rsync": Allowed,
+ "sed": Allowed,
"sh": Allowed,
"tar": Allowed,
"timeout": Allowed,
"tr": Allowed,
"unzip": Allowed,
- "xz": Allowed,
"zip": Allowed,
"zipinfo": Allowed,
@@ -134,7 +137,6 @@
"du": LinuxOnlyPrebuilt,
"echo": LinuxOnlyPrebuilt,
"env": LinuxOnlyPrebuilt,
- "expr": LinuxOnlyPrebuilt,
"head": LinuxOnlyPrebuilt,
"getconf": LinuxOnlyPrebuilt,
"hostname": LinuxOnlyPrebuilt,
@@ -154,7 +156,6 @@
"readlink": LinuxOnlyPrebuilt,
"rm": LinuxOnlyPrebuilt,
"rmdir": LinuxOnlyPrebuilt,
- "sed": LinuxOnlyPrebuilt,
"seq": LinuxOnlyPrebuilt,
"setsid": LinuxOnlyPrebuilt,
"sha1sum": LinuxOnlyPrebuilt,