Merge "Soong: Refactor the soong_ui arguments processing to be more like bazel."
diff --git a/Android.bp b/Android.bp
index a4e6e7d..afac2b5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -37,6 +37,7 @@
"blueprint-bootstrap",
"soong",
"soong-env",
+ "soong-shared",
],
srcs: [
"android/androidmk.go",
@@ -69,6 +70,7 @@
"android/testing.go",
"android/util.go",
"android/variable.go",
+ "android/visibility.go",
"android/vts_config.go",
"android/writedocs.go",
@@ -89,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",
],
}
@@ -273,6 +276,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",
@@ -440,6 +444,7 @@
defaults: ["linux_bionic_supported"],
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
arch: {
arm: {
@@ -462,6 +467,7 @@
defaults: ["linux_bionic_supported"],
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
arch: {
arm: {
@@ -480,6 +486,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,
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..2bbd452 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -28,10 +28,16 @@
"github.com/google/blueprint/bootstrap"
)
+var (
+ NativeBridgeSuffix = ".native_bridge"
+)
+
func init() {
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 +63,219 @@
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)
+ }
+ }
+
+ if amod.Target().NativeBridge {
+ a.SubName += NativeBridgeSuffix
+ }
+
+ 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 +378,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 +399,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 +443,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 +473,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..c68fe46 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 {
diff --git a/android/config.go b/android/config.go
index ed05c72..b142042 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,36 @@
return Config{config}
}
+func TestArchConfigNativeBridge(buildDir string, env map[string]string) Config {
+ testConfig := TestConfig(buildDir, env)
+ config := testConfig.config
+
+ config.Targets = map[OsType][]Target{
+ 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},
+ },
+ BuildOs: []Target{
+ {BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled},
+ {BuildOs, Arch{ArchType: X86}, NativeBridgeDisabled},
+ },
+ }
+
+ 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,12 +277,12 @@
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},
},
}
@@ -405,6 +433,10 @@
return fmt.Sprintf("%s/prebuilts/go/%s", c.srcDir, c.PrebuiltOS())
}
+func (c *config) PrebuiltBuildTool(ctx PathContext, tool string) Path {
+ return PathForSource(ctx, "prebuilts/build-tools", c.PrebuiltOS(), "bin", tool)
+}
+
func (c *config) CpPreserveSymlinksFlags() string {
switch runtime.GOOS {
case "darwin":
@@ -618,7 +650,7 @@
return Bool(c.productVariables.Unbundled_build)
}
-func (c *config) UnbundledBuildPrebuiltSdks() bool {
+func (c *config) UnbundledBuildUsePrebuiltSdks() bool {
return Bool(c.productVariables.Unbundled_build) && !Bool(c.productVariables.Unbundled_build_sdks_from_source)
}
@@ -920,6 +952,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>")
@@ -1049,6 +1085,18 @@
return c.productVariables.ProductHiddenAPIStubsTest
}
-func (c *deviceConfig) TargetFSConfigGen() *string {
+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)
+}
diff --git a/android/hooks.go b/android/hooks.go
index 6b2468d..d55678e 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -123,6 +123,10 @@
install []func(InstallHookContext)
}
+func registerLoadHookMutator(ctx RegisterMutatorsContext) {
+ ctx.TopDown("load_hooks", LoadHookMutator).Parallel()
+}
+
func LoadHookMutator(ctx TopDownMutatorContext) {
if m, ok := ctx.Module().(Module); ok {
// Cast through *androidTopDownMutatorContext because AppendProperties is implemented
diff --git a/android/module.go b/android/module.go
index 93966e1..fb5c00a 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"`
@@ -1042,6 +1073,51 @@
return aModule
}
+func (a *androidModuleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) {
+ type dep struct {
+ mod blueprint.Module
+ tag blueprint.DependencyTag
+ }
+ var deps []dep
+ a.VisitDirectDepsBlueprint(func(m blueprint.Module) {
+ if aModule, _ := m.(Module); aModule != nil && aModule.base().BaseModuleName() == name {
+ returnedTag := a.ModuleContext.OtherModuleDependencyTag(aModule)
+ if tag == nil || returnedTag == tag {
+ deps = append(deps, dep{aModule, returnedTag})
+ }
+ }
+ })
+ if len(deps) == 1 {
+ return deps[0].mod, deps[0].tag
+ } else if len(deps) >= 2 {
+ panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
+ name, a.ModuleName()))
+ } else {
+ return nil, nil
+ }
+}
+
+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
+}
+
+func (a *androidModuleContext) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) {
+ return a.getDirectDepInternal(name, nil)
+}
+
func (a *androidModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) {
a.ModuleContext.VisitDirectDeps(visit)
}
diff --git a/android/mutator.go b/android/mutator.go
index 71237a1..45954d3 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -73,13 +73,12 @@
type RegisterMutatorFunc func(RegisterMutatorsContext)
var preArch = []RegisterMutatorFunc{
- func(ctx RegisterMutatorsContext) {
- ctx.TopDown("load_hooks", LoadHookMutator).Parallel()
- },
+ registerLoadHookMutator,
RegisterNamespaceMutator,
RegisterPrebuiltsPreArchMutators,
RegisterDefaultsPreArchMutators,
RegisterOverridePreArchMutators,
+ registerVisibilityRuleGatherer,
}
func registerArchMutator(ctx RegisterMutatorsContext) {
@@ -94,6 +93,7 @@
var postDeps = []RegisterMutatorFunc{
registerPathDepsMutator,
RegisterPrebuiltsPostDepsMutators,
+ registerVisibilityRuleEnforcer,
registerNeverallowMutator,
}
@@ -120,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 f63f461..9314483 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -97,37 +97,21 @@
"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
}
func createJavaDeviceForHostRules() []*rule {
javaDeviceForHostProjectsWhitelist := []string{
+ "external/guava",
"external/robolectric-shadows",
"framework/layoutlib",
}
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/paths.go b/android/paths.go
index 8cc7057..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()
@@ -1267,16 +1269,23 @@
// MaybeRel performs the same function as filepath.Rel, but reports errors to a PathContext, and returns false if
// targetPath is not inside basePath.
func MaybeRel(ctx PathContext, basePath string, targetPath string) (string, bool) {
+ rel, isRel, err := maybeRelErr(basePath, targetPath)
+ if err != nil {
+ reportPathError(ctx, err)
+ }
+ return rel, isRel
+}
+
+func maybeRelErr(basePath string, targetPath string) (string, bool, error) {
// filepath.Rel returns an error if one path is absolute and the other is not, handle that case first.
if filepath.IsAbs(basePath) != filepath.IsAbs(targetPath) {
- return "", false
+ return "", false, nil
}
rel, err := filepath.Rel(basePath, targetPath)
if err != nil {
- reportPathError(ctx, err)
- return "", false
+ return "", false, err
} else if rel == ".." || strings.HasPrefix(rel, "../") || strings.HasPrefix(rel, "/") {
- return "", false
+ return "", false, nil
}
- return rel, true
+ return rel, true, nil
}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index df25a89..2556770 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -74,6 +74,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..bec24c7 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.
@@ -134,37 +131,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)")
},
}
}
diff --git a/android/prebuilt_etc_test.go b/android/prebuilt_etc_test.go
index fbdbc97..08700ae 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"
)
@@ -139,49 +137,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)
}
}
}
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index 319c15d..e182641 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -41,7 +41,7 @@
prebuilt {
name: "bar",
prefer: false,
- srcs: ["prebuilt"],
+ srcs: ["prebuilt_file"],
}`,
prebuilt: true,
},
@@ -51,7 +51,7 @@
prebuilt {
name: "bar",
prefer: true,
- srcs: ["prebuilt"],
+ srcs: ["prebuilt_file"],
}`,
prebuilt: true,
},
@@ -65,7 +65,7 @@
prebuilt {
name: "bar",
prefer: false,
- srcs: ["prebuilt"],
+ srcs: ["prebuilt_file"],
}`,
prebuilt: false,
},
@@ -79,7 +79,7 @@
prebuilt {
name: "bar",
prefer: true,
- srcs: ["prebuilt"],
+ srcs: ["prebuilt_file"],
}`,
prebuilt: true,
},
@@ -114,6 +114,7 @@
modules: `
filegroup {
name: "fg",
+ srcs: ["prebuilt_file"],
}
prebuilt {
name: "bar",
@@ -143,10 +144,12 @@
ctx.RegisterModuleType("source", ModuleFactoryAdaptor(newSourceModule))
ctx.Register()
ctx.MockFileSystem(map[string][]byte{
+ "prebuilt_file": nil,
+ "source_file": nil,
"Blueprints": []byte(`
source {
name: "foo",
- deps: ["bar"],
+ deps: [":bar"],
}
` + test.modules),
})
@@ -171,21 +174,45 @@
}
})
+ deps := foo.Module().(*sourceModule).deps
+ if deps == nil || len(deps) != 1 {
+ t.Errorf("deps does not have single path, but is %v", deps)
+ }
+ var usingSourceFile, usingPrebuiltFile bool
+ if deps[0].String() == "source_file" {
+ usingSourceFile = true
+ }
+ if deps[0].String() == "prebuilt_file" {
+ usingPrebuiltFile = true
+ }
+
if test.prebuilt {
if !dependsOnPrebuiltModule {
t.Errorf("doesn't depend on prebuilt module")
}
+ if !usingPrebuiltFile {
+ t.Errorf("doesn't use prebuilt_file")
+ }
if dependsOnSourceModule {
t.Errorf("depends on source module")
}
+ if usingSourceFile {
+ t.Errorf("using source_file")
+ }
} else {
if dependsOnPrebuiltModule {
t.Errorf("depends on prebuilt module")
}
+ if usingPrebuiltFile {
+ t.Errorf("using prebuilt_file")
+ }
if !dependsOnSourceModule {
- t.Errorf("doens't depend on source module")
+ t.Errorf("doesn't depend on source module")
+ }
+ if !usingSourceFile {
+ t.Errorf("doesn't use source_file")
}
}
})
@@ -198,6 +225,7 @@
properties struct {
Srcs []string `android:"path"`
}
+ src Path
}
func newPrebuiltModule() Module {
@@ -212,19 +240,28 @@
return p.prebuilt.Name(p.ModuleBase.Name())
}
-func (p *prebuiltModule) GenerateAndroidBuildActions(ModuleContext) {
+func (p *prebuiltModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ if len(p.properties.Srcs) >= 1 {
+ p.src = p.prebuilt.SingleSourcePath(ctx)
+ }
}
func (p *prebuiltModule) Prebuilt() *Prebuilt {
return &p.prebuilt
}
+func (p *prebuiltModule) Srcs() Paths {
+ return Paths{p.src}
+}
+
type sourceModule struct {
ModuleBase
properties struct {
- Deps []string
+ Deps []string `android:"path"`
}
dependsOnSourceModule, dependsOnPrebuiltModule bool
+ deps Paths
+ src Path
}
func newSourceModule() Module {
@@ -235,10 +272,15 @@
}
func (s *sourceModule) DepsMutator(ctx BottomUpMutatorContext) {
- for _, d := range s.properties.Deps {
- ctx.AddDependency(ctx.Module(), nil, d)
- }
+ // s.properties.Deps are annotated with android:path, so they are
+ // automatically added to the dependency by pathDeps mutator
}
func (s *sourceModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ s.deps = PathsForModuleSrc(ctx, s.properties.Deps)
+ s.src = PathForModuleSrc(ctx, "source_file")
+}
+
+func (s *sourceModule) Srcs() Paths {
+ return Paths{s.src}
}
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 2d0fac1..4a3b022 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -21,6 +21,8 @@
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
+
+ "android/soong/shared"
)
// RuleBuilder provides an alternative to ModuleContext.Rule and ModuleContext.Build to add a command line to the build
@@ -30,6 +32,8 @@
installs RuleBuilderInstalls
temporariesSet map[WritablePath]bool
restat bool
+ sbox bool
+ sboxOutDir WritablePath
missingDeps []string
}
@@ -73,11 +77,36 @@
}
// Restat marks the rule as a restat rule, which will be passed to ModuleContext.Rule in BuildParams.Restat.
+//
+// Restat is not compatible with Sbox()
func (r *RuleBuilder) Restat() *RuleBuilder {
+ if r.sbox {
+ panic("Restat() is not compatible with Sbox()")
+ }
r.restat = true
return r
}
+// Sbox marks the rule as needing to be wrapped by sbox. The WritablePath should point to the output
+// directory that sbox will wipe. It should not be written to by any other rule. sbox will ensure
+// that all outputs have been written, and will discard any output files that were not specified.
+//
+// Sbox is not compatible with Restat()
+func (r *RuleBuilder) Sbox(outputDir WritablePath) *RuleBuilder {
+ if r.sbox {
+ panic("Sbox() may not be called more than once")
+ }
+ if len(r.commands) > 0 {
+ panic("Sbox() may not be called after Command()")
+ }
+ if r.restat {
+ panic("Sbox() is not compatible with Restat()")
+ }
+ r.sbox = true
+ r.sboxOutDir = outputDir
+ return r
+}
+
// Install associates an output of the rule with an install location, which can be retrieved later using
// RuleBuilder.Installs.
func (r *RuleBuilder) Install(from Path, to string) {
@@ -88,7 +117,10 @@
// created by this method. That can be mutated through their methods in any order, as long as the mutations do not
// race with any call to Build.
func (r *RuleBuilder) Command() *RuleBuilderCommand {
- command := &RuleBuilderCommand{}
+ command := &RuleBuilderCommand{
+ sbox: r.sbox,
+ sboxOutDir: r.sboxOutDir,
+ }
r.commands = append(r.commands, command)
return command
}
@@ -120,12 +152,16 @@
// that are also outputs of another command in the same RuleBuilder are filtered out.
func (r *RuleBuilder) Inputs() Paths {
outputs := r.outputSet()
+ depFiles := r.depFileSet()
inputs := make(map[string]Path)
for _, c := range r.commands {
for _, input := range c.inputs {
- if _, isOutput := outputs[input.String()]; !isOutput {
- inputs[input.String()] = input
+ inputStr := input.String()
+ if _, isOutput := outputs[inputStr]; !isOutput {
+ if _, isDepFile := depFiles[inputStr]; !isDepFile {
+ inputs[input.String()] = input
+ }
}
}
}
@@ -171,6 +207,16 @@
return outputList
}
+func (r *RuleBuilder) depFileSet() map[string]WritablePath {
+ depFiles := make(map[string]WritablePath)
+ for _, c := range r.commands {
+ for _, depFile := range c.depFiles {
+ depFiles[depFile.String()] = depFile
+ }
+ }
+ return depFiles
+}
+
// DepFiles returns the list of paths that were passed to the RuleBuilderCommand methods that take depfile paths, such
// as RuleBuilderCommand.DepFile or RuleBuilderCommand.FlagWithDepFile.
func (r *RuleBuilder) DepFiles() WritablePaths {
@@ -237,9 +283,9 @@
var _ BuilderContext = SingletonContext(nil)
func (r *RuleBuilder) depFileMergerCmd(ctx PathContext, depFiles WritablePaths) *RuleBuilderCommand {
- return (&RuleBuilderCommand{}).
+ return r.Command().
Tool(ctx.Config().HostToolPath(ctx, "dep_fixer")).
- Flags(depFiles.Strings())
+ Inputs(depFiles.Paths())
}
// Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
@@ -259,9 +305,6 @@
return
}
- tools := r.Tools()
- commands := r.Commands()
-
var depFile WritablePath
var depFormat blueprint.Deps
if depFiles := r.DepFiles(); len(depFiles) > 0 {
@@ -269,37 +312,75 @@
depFormat = blueprint.DepsGCC
if len(depFiles) > 1 {
// Add a command locally that merges all depfiles together into the first depfile.
- cmd := r.depFileMergerCmd(ctx, depFiles)
- commands = append(commands, string(cmd.buf))
- tools = append(tools, cmd.tools...)
+ r.depFileMergerCmd(ctx, depFiles)
+
+ if r.sbox {
+ // Check for Rel() errors, as all depfiles should be in the output dir
+ for _, path := range depFiles[1:] {
+ Rel(ctx, r.sboxOutDir.String(), path.String())
+ }
+ }
}
}
+ tools := r.Tools()
+ commands := r.Commands()
+ outputs := r.Outputs()
+
+ if len(commands) == 0 {
+ return
+ }
+ if len(outputs) == 0 {
+ panic("No outputs specified from any Commands")
+ }
+
+ commandString := strings.Join(proptools.NinjaEscapeList(commands), " && ")
+
+ if r.sbox {
+ sboxOutputs := make([]string, len(outputs))
+ for i, output := range outputs {
+ sboxOutputs[i] = "__SBOX_OUT_DIR__/" + Rel(ctx, r.sboxOutDir.String(), output.String())
+ }
+
+ if depFile != nil {
+ sboxOutputs = append(sboxOutputs, "__SBOX_OUT_DIR__/"+Rel(ctx, r.sboxOutDir.String(), depFile.String()))
+ }
+
+ commandString = proptools.ShellEscape(commandString)
+ if !strings.HasPrefix(commandString, `'`) {
+ commandString = `'` + commandString + `'`
+ }
+
+ sboxCmd := &RuleBuilderCommand{}
+ sboxCmd.Tool(ctx.Config().HostToolPath(ctx, "sbox")).
+ Flag("-c").Text(commandString).
+ Flag("--sandbox-path").Text(shared.TempDirForOutDir(PathForOutput(ctx).String())).
+ Flag("--output-root").Text(r.sboxOutDir.String()).
+ Flags(sboxOutputs)
+
+ commandString = string(sboxCmd.buf)
+ tools = append(tools, sboxCmd.tools...)
+ }
+
// Ninja doesn't like multiple outputs when depfiles are enabled, move all but the first output to
// ImplicitOutputs. RuleBuilder never uses "$out", so the distinction between Outputs and ImplicitOutputs
// doesn't matter.
- var output WritablePath
- var implicitOutputs WritablePaths
- if outputs := r.Outputs(); len(outputs) > 0 {
- output = outputs[0]
- implicitOutputs = outputs[1:]
- }
+ output := outputs[0]
+ implicitOutputs := outputs[1:]
- if len(commands) > 0 {
- ctx.Build(pctx, BuildParams{
- Rule: ctx.Rule(pctx, name, blueprint.RuleParams{
- Command: strings.Join(proptools.NinjaEscapeList(commands), " && "),
- CommandDeps: tools.Strings(),
- Restat: r.restat,
- }),
- Implicits: r.Inputs(),
- Output: output,
- ImplicitOutputs: implicitOutputs,
- Depfile: depFile,
- Deps: depFormat,
- Description: desc,
- })
- }
+ ctx.Build(pctx, BuildParams{
+ Rule: ctx.Rule(pctx, name, blueprint.RuleParams{
+ Command: commandString,
+ CommandDeps: tools.Strings(),
+ Restat: r.restat,
+ }),
+ Implicits: r.Inputs(),
+ Output: output,
+ ImplicitOutputs: implicitOutputs,
+ Depfile: depFile,
+ Deps: depFormat,
+ Description: desc,
+ })
}
// RuleBuilderCommand is a builder for a command in a command line. It can be mutated by its methods to add to the
@@ -312,6 +393,28 @@
outputs WritablePaths
depFiles WritablePaths
tools Paths
+
+ sbox bool
+ sboxOutDir WritablePath
+}
+
+func (c *RuleBuilderCommand) addInput(path Path) string {
+ if c.sbox {
+ if rel, isRel, _ := maybeRelErr(c.sboxOutDir.String(), path.String()); isRel {
+ return "__SBOX_OUT_DIR__/" + rel
+ }
+ }
+ c.inputs = append(c.inputs, path)
+ return path.String()
+}
+
+func (c *RuleBuilderCommand) outputStr(path Path) string {
+ if c.sbox {
+ // Errors will be handled in RuleBuilder.Build where we have a context to report them
+ rel, _, _ := maybeRelErr(c.sboxOutDir.String(), path.String())
+ return "__SBOX_OUT_DIR__/" + rel
+ }
+ return path.String()
}
// Text adds the specified raw text to the command line. The text should not contain input or output paths or the
@@ -378,8 +481,7 @@
// Input adds the specified input path to the command line. The path will also be added to the dependencies returned by
// RuleBuilder.Inputs.
func (c *RuleBuilderCommand) Input(path Path) *RuleBuilderCommand {
- c.inputs = append(c.inputs, path)
- return c.Text(path.String())
+ return c.Text(c.addInput(path))
}
// Inputs adds the specified input paths to the command line, separated by spaces. The paths will also be added to the
@@ -394,14 +496,16 @@
// Implicit adds the specified input path to the dependencies returned by RuleBuilder.Inputs without modifying the
// command line.
func (c *RuleBuilderCommand) Implicit(path Path) *RuleBuilderCommand {
- c.inputs = append(c.inputs, path)
+ c.addInput(path)
return c
}
// Implicits adds the specified input paths to the dependencies returned by RuleBuilder.Inputs without modifying the
// command line.
func (c *RuleBuilderCommand) Implicits(paths Paths) *RuleBuilderCommand {
- c.inputs = append(c.inputs, paths...)
+ for _, path := range paths {
+ c.addInput(path)
+ }
return c
}
@@ -409,7 +513,7 @@
// RuleBuilder.Outputs.
func (c *RuleBuilderCommand) Output(path WritablePath) *RuleBuilderCommand {
c.outputs = append(c.outputs, path)
- return c.Text(path.String())
+ return c.Text(c.outputStr(path))
}
// Outputs adds the specified output paths to the command line, separated by spaces. The paths will also be added to
@@ -426,7 +530,7 @@
// commands in a single RuleBuilder then RuleBuilder.Build will add an extra command to merge the depfiles together.
func (c *RuleBuilderCommand) DepFile(path WritablePath) *RuleBuilderCommand {
c.depFiles = append(c.depFiles, path)
- return c.Text(path.String())
+ return c.Text(c.outputStr(path))
}
// ImplicitOutput adds the specified output path to the dependencies returned by RuleBuilder.Outputs without modifying
@@ -455,16 +559,18 @@
// FlagWithInput adds the specified flag and input path to the command line, with no separator between them. The path
// will also be added to the dependencies returned by RuleBuilder.Inputs.
func (c *RuleBuilderCommand) FlagWithInput(flag string, path Path) *RuleBuilderCommand {
- c.inputs = append(c.inputs, path)
- return c.Text(flag + path.String())
+ return c.Text(flag + c.addInput(path))
}
// FlagWithInputList adds the specified flag and input paths to the command line, with the inputs joined by sep
// and no separator between the flag and inputs. The input paths will also be added to the dependencies returned by
// RuleBuilder.Inputs.
func (c *RuleBuilderCommand) FlagWithInputList(flag string, paths Paths, sep string) *RuleBuilderCommand {
- c.inputs = append(c.inputs, paths...)
- return c.FlagWithList(flag, paths.Strings(), sep)
+ strs := make([]string, len(paths))
+ for i, path := range paths {
+ strs[i] = c.addInput(path)
+ }
+ return c.FlagWithList(flag, strs, sep)
}
// FlagForEachInput adds the specified flag joined with each input path to the command line. The input paths will also
@@ -481,14 +587,14 @@
// will also be added to the outputs returned by RuleBuilder.Outputs.
func (c *RuleBuilderCommand) FlagWithOutput(flag string, path WritablePath) *RuleBuilderCommand {
c.outputs = append(c.outputs, path)
- return c.Text(flag + path.String())
+ return c.Text(flag + c.outputStr(path))
}
// FlagWithDepFile adds the specified flag and depfile path to the command line, with no separator between them. The path
// will also be added to the outputs returned by RuleBuilder.Outputs.
func (c *RuleBuilderCommand) FlagWithDepFile(flag string, path WritablePath) *RuleBuilderCommand {
c.depFiles = append(c.depFiles, path)
- return c.Text(flag + path.String())
+ return c.Text(flag + c.outputStr(path))
}
// String returns the command line.
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index 7bad025..df0f256 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -22,6 +22,10 @@
"reflect"
"strings"
"testing"
+
+ "github.com/google/blueprint"
+
+ "android/soong/shared"
)
func pathContext() PathContext {
@@ -234,8 +238,6 @@
}
func TestRuleBuilder(t *testing.T) {
- rule := NewRuleBuilder()
-
fs := map[string][]byte{
"dep_fixer": nil,
"input": nil,
@@ -249,73 +251,114 @@
ctx := PathContextForTesting(TestConfig("out", nil), fs)
- cmd := rule.Command().
- DepFile(PathForOutput(ctx, "DepFile")).
- Flag("Flag").
- FlagWithArg("FlagWithArg=", "arg").
- FlagWithDepFile("FlagWithDepFile=", PathForOutput(ctx, "depfile")).
- FlagWithInput("FlagWithInput=", PathForSource(ctx, "input")).
- FlagWithOutput("FlagWithOutput=", PathForOutput(ctx, "output")).
- Implicit(PathForSource(ctx, "Implicit")).
- ImplicitDepFile(PathForOutput(ctx, "ImplicitDepFile")).
- ImplicitOutput(PathForOutput(ctx, "ImplicitOutput")).
- Input(PathForSource(ctx, "Input")).
- Output(PathForOutput(ctx, "Output")).
- Text("Text").
- Tool(PathForSource(ctx, "Tool"))
+ addCommands := func(rule *RuleBuilder) {
+ cmd := rule.Command().
+ DepFile(PathForOutput(ctx, "DepFile")).
+ Flag("Flag").
+ FlagWithArg("FlagWithArg=", "arg").
+ FlagWithDepFile("FlagWithDepFile=", PathForOutput(ctx, "depfile")).
+ FlagWithInput("FlagWithInput=", PathForSource(ctx, "input")).
+ FlagWithOutput("FlagWithOutput=", PathForOutput(ctx, "output")).
+ Implicit(PathForSource(ctx, "Implicit")).
+ ImplicitDepFile(PathForOutput(ctx, "ImplicitDepFile")).
+ ImplicitOutput(PathForOutput(ctx, "ImplicitOutput")).
+ Input(PathForSource(ctx, "Input")).
+ Output(PathForOutput(ctx, "Output")).
+ Text("Text").
+ Tool(PathForSource(ctx, "Tool"))
- rule.Command().
- Text("command2").
- DepFile(PathForOutput(ctx, "depfile2")).
- Input(PathForSource(ctx, "input2")).
- Output(PathForOutput(ctx, "output2")).
- Tool(PathForSource(ctx, "tool2"))
+ rule.Command().
+ Text("command2").
+ DepFile(PathForOutput(ctx, "depfile2")).
+ Input(PathForSource(ctx, "input2")).
+ Output(PathForOutput(ctx, "output2")).
+ Tool(PathForSource(ctx, "tool2"))
- // Test updates to the first command after the second command has been started
- cmd.Text("after command2")
- // Test updating a command when the previous update did not replace the cmd variable
- cmd.Text("old cmd")
+ // Test updates to the first command after the second command has been started
+ cmd.Text("after command2")
+ // Test updating a command when the previous update did not replace the cmd variable
+ cmd.Text("old cmd")
- // Test a command that uses the output of a previous command as an input
- rule.Command().
- Text("command3").
- Input(PathForSource(ctx, "input3")).
- Input(PathForOutput(ctx, "output2")).
- Output(PathForOutput(ctx, "output3"))
-
- wantCommands := []string{
- "out/DepFile Flag FlagWithArg=arg FlagWithDepFile=out/depfile FlagWithInput=input FlagWithOutput=out/output Input out/Output Text Tool after command2 old cmd",
- "command2 out/depfile2 input2 out/output2 tool2",
- "command3 input3 out/output2 out/output3",
+ // Test a command that uses the output of a previous command as an input
+ rule.Command().
+ Text("command3").
+ Input(PathForSource(ctx, "input3")).
+ Input(PathForOutput(ctx, "output2")).
+ Output(PathForOutput(ctx, "output3"))
}
- wantDepMergerCommand := "out/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer out/DepFile out/depfile out/ImplicitDepFile out/depfile2"
-
wantInputs := PathsForSource(ctx, []string{"Implicit", "Input", "input", "input2", "input3"})
wantOutputs := PathsForOutput(ctx, []string{"ImplicitOutput", "Output", "output", "output2", "output3"})
wantDepFiles := PathsForOutput(ctx, []string{"DepFile", "depfile", "ImplicitDepFile", "depfile2"})
wantTools := PathsForSource(ctx, []string{"Tool", "tool2"})
- if g, w := rule.Commands(), wantCommands; !reflect.DeepEqual(g, w) {
- t.Errorf("\nwant rule.Commands() = %#v\n got %#v", w, g)
- }
+ t.Run("normal", func(t *testing.T) {
+ rule := NewRuleBuilder()
+ addCommands(rule)
- if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w {
- t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n got %#v", w, g)
- }
+ wantCommands := []string{
+ "out/DepFile Flag FlagWithArg=arg FlagWithDepFile=out/depfile FlagWithInput=input FlagWithOutput=out/output Input out/Output Text Tool after command2 old cmd",
+ "command2 out/depfile2 input2 out/output2 tool2",
+ "command3 input3 out/output2 out/output3",
+ }
- if g, w := rule.Inputs(), wantInputs; !reflect.DeepEqual(w, g) {
- t.Errorf("\nwant rule.Inputs() = %#v\n got %#v", w, g)
- }
- if g, w := rule.Outputs(), wantOutputs; !reflect.DeepEqual(w, g) {
- t.Errorf("\nwant rule.Outputs() = %#v\n got %#v", w, g)
- }
- if g, w := rule.DepFiles(), wantDepFiles; !reflect.DeepEqual(w, g) {
- t.Errorf("\nwant rule.DepFiles() = %#v\n got %#v", w, g)
- }
- if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
- t.Errorf("\nwant rule.Tools() = %#v\n got %#v", w, g)
- }
+ wantDepMergerCommand := "out/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer out/DepFile out/depfile out/ImplicitDepFile out/depfile2"
+
+ if g, w := rule.Commands(), wantCommands; !reflect.DeepEqual(g, w) {
+ t.Errorf("\nwant rule.Commands() = %#v\n got %#v", w, g)
+ }
+
+ if g, w := rule.Inputs(), wantInputs; !reflect.DeepEqual(w, g) {
+ t.Errorf("\nwant rule.Inputs() = %#v\n got %#v", w, g)
+ }
+ if g, w := rule.Outputs(), wantOutputs; !reflect.DeepEqual(w, g) {
+ t.Errorf("\nwant rule.Outputs() = %#v\n got %#v", w, g)
+ }
+ if g, w := rule.DepFiles(), wantDepFiles; !reflect.DeepEqual(w, g) {
+ t.Errorf("\nwant rule.DepFiles() = %#v\n got %#v", w, g)
+ }
+ if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
+ t.Errorf("\nwant rule.Tools() = %#v\n got %#v", w, g)
+ }
+
+ if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w {
+ t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n got %#v", w, g)
+ }
+ })
+
+ t.Run("sbox", func(t *testing.T) {
+ rule := NewRuleBuilder().Sbox(PathForOutput(ctx))
+ addCommands(rule)
+
+ wantCommands := []string{
+ "__SBOX_OUT_DIR__/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_OUT_DIR__/depfile FlagWithInput=input FlagWithOutput=__SBOX_OUT_DIR__/output Input __SBOX_OUT_DIR__/Output Text Tool after command2 old cmd",
+ "command2 __SBOX_OUT_DIR__/depfile2 input2 __SBOX_OUT_DIR__/output2 tool2",
+ "command3 input3 __SBOX_OUT_DIR__/output2 __SBOX_OUT_DIR__/output3",
+ }
+
+ wantDepMergerCommand := "out/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer __SBOX_OUT_DIR__/DepFile __SBOX_OUT_DIR__/depfile __SBOX_OUT_DIR__/ImplicitDepFile __SBOX_OUT_DIR__/depfile2"
+
+ if g, w := rule.Commands(), wantCommands; !reflect.DeepEqual(g, w) {
+ t.Errorf("\nwant rule.Commands() = %#v\n got %#v", w, g)
+ }
+
+ if g, w := rule.Inputs(), wantInputs; !reflect.DeepEqual(w, g) {
+ t.Errorf("\nwant rule.Inputs() = %#v\n got %#v", w, g)
+ }
+ if g, w := rule.Outputs(), wantOutputs; !reflect.DeepEqual(w, g) {
+ t.Errorf("\nwant rule.Outputs() = %#v\n got %#v", w, g)
+ }
+ if g, w := rule.DepFiles(), wantDepFiles; !reflect.DeepEqual(w, g) {
+ t.Errorf("\nwant rule.DepFiles() = %#v\n got %#v", w, g)
+ }
+ if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
+ t.Errorf("\nwant rule.Tools() = %#v\n got %#v", w, g)
+ }
+
+ if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w {
+ t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n got %#v", w, g)
+ }
+ })
}
func testRuleBuilderFactory() Module {
@@ -329,14 +372,19 @@
ModuleBase
properties struct {
Src string
+
+ Restat bool
+ Sbox bool
}
}
func (t *testRuleBuilderModule) GenerateAndroidBuildActions(ctx ModuleContext) {
in := PathForSource(ctx, t.properties.Src)
out := PathForModuleOut(ctx, ctx.ModuleName())
+ outDep := PathForModuleOut(ctx, ctx.ModuleName()+".d")
+ outDir := PathForModuleOut(ctx)
- testRuleBuilder_Build(ctx, in, out)
+ testRuleBuilder_Build(ctx, in, out, outDep, outDir, t.properties.Restat, t.properties.Sbox)
}
type testRuleBuilderSingleton struct{}
@@ -348,15 +396,23 @@
func (t *testRuleBuilderSingleton) GenerateBuildActions(ctx SingletonContext) {
in := PathForSource(ctx, "bar")
out := PathForOutput(ctx, "baz")
- testRuleBuilder_Build(ctx, in, out)
+ outDep := PathForOutput(ctx, "baz.d")
+ outDir := PathForOutput(ctx)
+ testRuleBuilder_Build(ctx, in, out, outDep, outDir, true, false)
}
-func testRuleBuilder_Build(ctx BuilderContext, in Path, out WritablePath) {
+func testRuleBuilder_Build(ctx BuilderContext, in Path, out, outDep, outDir WritablePath, restat, sbox bool) {
rule := NewRuleBuilder()
- rule.Command().Tool(PathForSource(ctx, "cp")).Input(in).Output(out)
+ if sbox {
+ rule.Sbox(outDir)
+ }
- rule.Restat()
+ rule.Command().Tool(PathForSource(ctx, "cp")).Input(in).Output(out).ImplicitDepFile(outDep)
+
+ if restat {
+ rule.Restat()
+ }
rule.Build(pctx, ctx, "rule", "desc")
}
@@ -372,6 +428,12 @@
rule_builder_test {
name: "foo",
src: "bar",
+ restat: true,
+ }
+ rule_builder_test {
+ name: "foo_sbox",
+ src: "bar",
+ sbox: true,
}
`
@@ -391,9 +453,18 @@
_, errs = ctx.PrepareBuildActions(config)
FailIfErrored(t, errs)
- check := func(t *testing.T, params TestingBuildParams, wantOutput string) {
- if len(params.RuleParams.CommandDeps) != 1 || params.RuleParams.CommandDeps[0] != "cp" {
- t.Errorf("want RuleParams.CommandDeps = [%q], got %q", "cp", params.RuleParams.CommandDeps)
+ check := func(t *testing.T, params TestingBuildParams, wantCommand, wantOutput, wantDepfile string, wantRestat bool, extraCmdDeps []string) {
+ if params.RuleParams.Command != wantCommand {
+ t.Errorf("\nwant RuleParams.Command = %q\n got %q", wantCommand, params.RuleParams.Command)
+ }
+
+ wantDeps := append([]string{"cp"}, extraCmdDeps...)
+ if !reflect.DeepEqual(params.RuleParams.CommandDeps, wantDeps) {
+ t.Errorf("\nwant RuleParams.CommandDeps = %q\n got %q", wantDeps, params.RuleParams.CommandDeps)
+ }
+
+ if params.RuleParams.Restat != wantRestat {
+ t.Errorf("want RuleParams.Restat = %v, got %v", wantRestat, params.RuleParams.Restat)
}
if len(params.Implicits) != 1 || params.Implicits[0].String() != "bar" {
@@ -404,17 +475,39 @@
t.Errorf("want Output = %q, got %q", wantOutput, params.Output)
}
- if !params.RuleParams.Restat {
- t.Errorf("want RuleParams.Restat = true, got %v", params.RuleParams.Restat)
+ if len(params.ImplicitOutputs) != 0 {
+ t.Errorf("want ImplicitOutputs = [], got %q", params.ImplicitOutputs.Strings())
+ }
+
+ if params.Depfile.String() != wantDepfile {
+ t.Errorf("want Depfile = %q, got %q", wantDepfile, params.Depfile)
+ }
+
+ if params.Deps != blueprint.DepsGCC {
+ t.Errorf("want Deps = %q, got %q", blueprint.DepsGCC, params.Deps)
}
}
t.Run("module", func(t *testing.T) {
+ outFile := filepath.Join(buildDir, ".intermediates", "foo", "foo")
check(t, ctx.ModuleForTests("foo", "").Rule("rule"),
- filepath.Join(buildDir, ".intermediates", "foo", "foo"))
+ "cp bar "+outFile,
+ outFile, outFile+".d", true, nil)
+ })
+ t.Run("sbox", func(t *testing.T) {
+ outDir := filepath.Join(buildDir, ".intermediates", "foo_sbox")
+ outFile := filepath.Join(outDir, "foo_sbox")
+ sbox := filepath.Join(buildDir, "host", config.PrebuiltOS(), "bin/sbox")
+ sandboxPath := shared.TempDirForOutDir(buildDir)
+
+ cmd := sbox + ` -c 'cp bar __SBOX_OUT_DIR__/foo_sbox' --sandbox-path ` + sandboxPath + " --output-root " + outDir + " __SBOX_OUT_DIR__/foo_sbox __SBOX_OUT_DIR__/foo_sbox.d"
+
+ check(t, ctx.ModuleForTests("foo_sbox", "").Rule("rule"),
+ cmd, outFile, outFile+".d", false, []string{sbox})
})
t.Run("singleton", func(t *testing.T) {
+ outFile := filepath.Join(buildDir, "baz")
check(t, ctx.SingletonForTests("rule_builder_test").Rule("rule"),
- filepath.Join(buildDir, "baz"))
+ "cp bar "+outFile, outFile, outFile+".d", true, nil)
})
}
diff --git a/android/testing.go b/android/testing.go
index 0ec5af5..c0db75e 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -37,6 +37,8 @@
ctx.SetNameInterface(nameResolver)
+ ctx.preArch = append(ctx.preArch, registerLoadHookMutator)
+
ctx.postDeps = append(ctx.postDeps, registerPathDepsMutator)
return ctx
@@ -369,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/variable.go b/android/variable.go
index 666f29f..c500671 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,7 @@
BoardOdmSepolicyDirs []string `json:",omitempty"`
BoardPlatPublicSepolicyDirs []string `json:",omitempty"`
BoardPlatPrivateSepolicyDirs []string `json:",omitempty"`
+ BoardSepolicyM4Defs []string `json:",omitempty"`
VendorVars map[string]map[string]string `json:",omitempty"`
@@ -288,7 +299,11 @@
ProductHiddenAPIStubsSystem []string `json:",omitempty"`
ProductHiddenAPIStubsTest []string `json:",omitempty"`
- TargetFSConfigGen *string `json:",omitempty"`
+ ProductPublicSepolicyDirs []string `json:",omitempty"`
+ ProductPrivateSepolicyDirs []string `json:",omitempty"`
+ ProductCompatibleProperty *bool `json:",omitempty"`
+
+ TargetFSConfigGen []string `json:",omitempty"`
}
func boolPtr(v bool) *bool {
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..6809914
--- /dev/null
+++ b/android/visibility_test.go
@@ -0,0 +1,474 @@
+package android
+
+import (
+ "github.com/google/blueprint"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+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"],
+ }`),
+ },
+ 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__\]`,
+ },
+ },
+ {
+ // 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"],
+ }`),
+ },
+ 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__\]`,
+ },
+ },
+ {
+ // 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 e0932af..b54ad5e 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -131,7 +131,7 @@
"LOCAL_OVERRIDES_MODULES": "overrides",
"LOCAL_LDLIBS": "host_ldlibs",
"LOCAL_CLANG_CFLAGS": "clang_cflags",
- "LOCAL_YACCFLAGS": "yaccflags",
+ "LOCAL_YACCFLAGS": "yacc.flags",
"LOCAL_SANITIZE_RECOVER": "sanitize.recover",
"LOCAL_LOGTAGS_FILES": "logtags",
"LOCAL_EXPORT_HEADER_LIBRARY_HEADERS": "export_header_lib_headers",
diff --git a/apex/apex.go b/apex/apex.go
index 004de86..68d0bc1 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -977,6 +977,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 +1184,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 +1376,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/cc/androidmk.go b/cc/androidmk.go
index 02806f9..79469ee 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -145,6 +145,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"
@@ -169,14 +179,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())
diff --git a/cc/binary.go b/cc/binary.go
index 35c3d85..51e68fc 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -384,7 +384,7 @@
TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs, deps.StaticLibs,
deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,
- builderFlags, outputFile)
+ builderFlags, outputFile, nil)
objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
diff --git a/cc/builder.go b/cc/builder.go
index 65369d6..c99e461 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -26,6 +26,7 @@
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/pathtools"
"android/soong/android"
"android/soong/cc/config"
@@ -239,7 +240,6 @@
cppFlags string
ldFlags string
libFlags string
- yaccFlags string
tidyFlags string
sAbiFlags string
yasmFlags string
@@ -255,6 +255,7 @@
groupStaticLibs bool
stripKeepSymbols bool
+ stripKeepSymbolsList string
stripKeepMiniDebugInfo bool
stripAddGnuDebuglink bool
stripUseGnuStrip bool
@@ -262,6 +263,8 @@
proto android.ProtoFlags
protoC bool
protoOptionsFile bool
+
+ yacc *YaccProperties
}
type Objects struct {
@@ -595,7 +598,7 @@
// and shared libraries, to a shared library (.so) or dynamic executable
func TransformObjToDynamicBinary(ctx android.ModuleContext,
objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps android.Paths,
- crtBegin, crtEnd android.OptionalPath, groupLate bool, flags builderFlags, outputFile android.WritablePath) {
+ crtBegin, crtEnd android.OptionalPath, groupLate bool, flags builderFlags, outputFile android.WritablePath, implicitOutputs android.WritablePaths) {
ldCmd := "${config.ClangBin}/clang++"
@@ -632,7 +635,11 @@
}
for _, lib := range sharedLibs {
- libFlagsList = append(libFlagsList, lib.String())
+ libFile := lib.String()
+ if ctx.Windows() {
+ libFile = pathtools.ReplaceExtension(libFile, "lib")
+ }
+ libFlagsList = append(libFlagsList, libFile)
}
deps = append(deps, staticLibs...)
@@ -643,11 +650,12 @@
}
ctx.Build(pctx, android.BuildParams{
- Rule: ld,
- Description: "link " + outputFile.Base(),
- Output: outputFile,
- Inputs: objFiles,
- Implicits: deps,
+ Rule: ld,
+ Description: "link " + outputFile.Base(),
+ Output: outputFile,
+ ImplicitOutputs: implicitOutputs,
+ Inputs: objFiles,
+ Implicits: deps,
Args: map[string]string{
"ldCmd": ldCmd,
"crtBegin": crtBegin.String(),
@@ -828,6 +836,9 @@
if flags.stripKeepSymbols {
args += " --keep-symbols"
}
+ if flags.stripKeepSymbolsList != "" {
+ args += " -k" + flags.stripKeepSymbolsList
+ }
if flags.stripUseGnuStrip {
args += " --use-gnu-strip"
}
diff --git a/cc/cc.go b/cc/cc.go
index 0668fd9..bb24942 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -19,6 +19,7 @@
// is handled in builder.go
import (
+ "io"
"strconv"
"strings"
@@ -136,7 +137,6 @@
ConlyFlags []string // Flags that apply to C source files
CppFlags []string // Flags that apply to C++ source files
ToolingCppFlags []string // Flags that apply to C++ source files parsed by clang LibTooling tools
- YaccFlags []string // Flags that apply to Yacc source files
aidlFlags []string // Flags that apply to aidl source files
rsFlags []string // Flags that apply to renderscript source files
LdFlags []string // Flags that apply to linker command lines
@@ -165,6 +165,8 @@
proto android.ProtoFlags
protoC bool // Whether to use C instead of C++
protoOptionsFile bool // Whether to look for a .options file next to the .proto
+
+ Yacc *YaccProperties
}
type ObjectLinkerProperties struct {
@@ -1802,6 +1804,8 @@
return libName + vendorPublicLibrarySuffix
} else if ccDep.inRecovery() && !ccDep.onlyInRecovery() {
return libName + recoverySuffix
+ } else if ccDep.Target().NativeBridge == android.NativeBridgeEnabled {
+ return libName + android.NativeBridgeSuffix
} else {
return libName
}
@@ -1965,6 +1969,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..f3d5e60 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -1833,13 +1833,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 {
diff --git a/cc/compiler.go b/cc/compiler.go
index f9af4d8..7667ae7 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -57,9 +57,6 @@
// compiling with clang
Clang_asflags []string `android:"arch_variant"`
- // list of module-specific flags that will be used for .y and .yy compiles
- Yaccflags []string
-
// the instruction set architecture to use to compile the C/C++
// module.
Instruction_set *string `android:"arch_variant"`
@@ -103,6 +100,8 @@
// if set to false, use -std=c++* instead of -std=gnu++*
Gnu_extensions *bool
+ Yacc *YaccProperties
+
Aidl struct {
// list of directories that will be added to the aidl include paths.
Include_dirs []string
@@ -275,7 +274,8 @@
flags.ConlyFlags = append(flags.ConlyFlags, esc(compiler.Properties.Conlyflags)...)
flags.AsFlags = append(flags.AsFlags, esc(compiler.Properties.Asflags)...)
flags.YasmFlags = append(flags.YasmFlags, esc(compiler.Properties.Asflags)...)
- flags.YaccFlags = append(flags.YaccFlags, esc(compiler.Properties.Yaccflags)...)
+
+ flags.Yacc = compiler.Properties.Yacc
// Include dir cflags
localIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Local_include_dirs)
diff --git a/cc/config/global.go b/cc/config/global.go
index 8fc9ff2..0a7d984 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -121,8 +121,8 @@
// prebuilts/clang default settings.
ClangDefaultBase = "prebuilts/clang/host"
- ClangDefaultVersion = "clang-r353983b"
- ClangDefaultShortVersion = "9.0.2"
+ ClangDefaultVersion = "clang-r353983c"
+ ClangDefaultShortVersion = "9.0.3"
// Directories with warnings from Android.bp files.
WarningAllowedProjects = []string{
diff --git a/cc/gen.go b/cc/gen.go
index 0c3d089..ae761d0 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -24,21 +24,12 @@
func init() {
pctx.SourcePathVariable("lexCmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/flex")
- pctx.SourcePathVariable("yaccCmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/bison")
- pctx.SourcePathVariable("yaccDataDir", "prebuilts/build-tools/common/bison")
pctx.HostBinToolVariable("aidlCmd", "aidl-cpp")
pctx.HostBinToolVariable("syspropCmd", "sysprop_cpp")
}
var (
- yacc = pctx.AndroidStaticRule("yacc",
- blueprint.RuleParams{
- Command: "BISON_PKGDATADIR=$yaccDataDir $yaccCmd -d $yaccFlags --defines=$hFile -o $out $in",
- CommandDeps: []string{"$yaccCmd"},
- },
- "yaccFlags", "hFile")
-
lex = pctx.AndroidStaticRule("lex",
blueprint.RuleParams{
Command: "$lexCmd -o$out $in",
@@ -70,22 +61,57 @@
"windmcCmd")
)
-func genYacc(ctx android.ModuleContext, yaccFile android.Path, outFile android.ModuleGenPath, yaccFlags string) (headerFile android.ModuleGenPath) {
- headerFile = android.GenPathWithExt(ctx, "yacc", yaccFile, "h")
+type YaccProperties struct {
+ // list of module-specific flags that will be used for .y and .yy compiles
+ Flags []string
- ctx.Build(pctx, android.BuildParams{
- Rule: yacc,
- Description: "yacc " + yaccFile.Rel(),
- Output: outFile,
- ImplicitOutput: headerFile,
- Input: yaccFile,
- Args: map[string]string{
- "yaccFlags": yaccFlags,
- "hFile": headerFile.String(),
- },
- })
+ // whether the yacc files will produce a location.hh file
+ Gen_location_hh *bool
- return headerFile
+ // whether the yacc files will product a position.hh file
+ Gen_position_hh *bool
+}
+
+func genYacc(ctx android.ModuleContext, rule *android.RuleBuilder, yaccFile android.Path,
+ outFile android.ModuleGenPath, props *YaccProperties) (headerFiles android.Paths) {
+
+ outDir := android.PathForModuleGen(ctx, "yacc")
+ headerFile := android.GenPathWithExt(ctx, "yacc", yaccFile, "h")
+ ret := android.Paths{headerFile}
+
+ cmd := rule.Command()
+
+ // Fix up #line markers to not use the sbox temporary directory
+ sedCmd := "sed -i.bak 's#__SBOX_OUT_DIR__#" + outDir.String() + "#'"
+ rule.Command().Text(sedCmd).Input(outFile)
+ rule.Command().Text(sedCmd).Input(headerFile)
+
+ var flags []string
+ if props != nil {
+ flags = props.Flags
+
+ if Bool(props.Gen_location_hh) {
+ locationHeader := outFile.InSameDir(ctx, "location.hh")
+ ret = append(ret, locationHeader)
+ cmd.ImplicitOutput(locationHeader)
+ rule.Command().Text(sedCmd).Input(locationHeader)
+ }
+ if Bool(props.Gen_position_hh) {
+ positionHeader := outFile.InSameDir(ctx, "position.hh")
+ ret = append(ret, positionHeader)
+ cmd.ImplicitOutput(positionHeader)
+ rule.Command().Text(sedCmd).Input(positionHeader)
+ }
+ }
+
+ cmd.Text("BISON_PKGDATADIR=prebuilts/build-tools/common/bison").
+ Tool(ctx.Config().PrebuiltBuildTool(ctx, "bison")).
+ Flag("-d").
+ Flags(flags).
+ FlagWithOutput("--defines=", headerFile).
+ Flag("-o").Output(outFile).Input(yaccFile)
+
+ return ret
}
func genAidl(ctx android.ModuleContext, aidlFile android.Path, outFile android.ModuleGenPath, aidlFlags string) android.Paths {
@@ -159,19 +185,26 @@
buildFlags builderFlags) (android.Paths, android.Paths) {
var deps android.Paths
-
var rsFiles android.Paths
+ var yaccRule_ *android.RuleBuilder
+ yaccRule := func() *android.RuleBuilder {
+ if yaccRule_ == nil {
+ yaccRule_ = android.NewRuleBuilder().Sbox(android.PathForModuleGen(ctx, "yacc"))
+ }
+ return yaccRule_
+ }
+
for i, srcFile := range srcFiles {
switch srcFile.Ext() {
case ".y":
cFile := android.GenPathWithExt(ctx, "yacc", srcFile, "c")
srcFiles[i] = cFile
- deps = append(deps, genYacc(ctx, srcFile, cFile, buildFlags.yaccFlags))
+ deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cFile, buildFlags.yacc)...)
case ".yy":
cppFile := android.GenPathWithExt(ctx, "yacc", srcFile, "cpp")
srcFiles[i] = cppFile
- deps = append(deps, genYacc(ctx, srcFile, cppFile, buildFlags.yaccFlags))
+ deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cppFile, buildFlags.yacc)...)
case ".l":
cFile := android.GenPathWithExt(ctx, "lex", srcFile, "c")
srcFiles[i] = cFile
@@ -203,6 +236,10 @@
}
}
+ if yaccRule_ != nil {
+ yaccRule_.Build(pctx, ctx, "yacc", "gen yacc")
+ }
+
if len(rsFiles) > 0 {
deps = append(deps, rsGenerateCpp(ctx, rsFiles, buildFlags.rsFlags)...)
}
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 a594b91..1f79bec 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -15,6 +15,7 @@
package cc
import (
+ "io"
"path/filepath"
"regexp"
"sort"
@@ -96,6 +97,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"`
@@ -357,9 +361,10 @@
)
}
} else {
- f = append(f,
- "-shared",
- "-Wl,-soname,"+libName+flags.Toolchain.ShlibSuffix())
+ f = append(f, "-shared")
+ if !ctx.Windows() {
+ f = append(f, "-Wl,-soname,"+libName+flags.Toolchain.ShlibSuffix())
+ }
}
flags.LdFlags = append(f, flags.LdFlags...)
@@ -420,6 +425,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()
+}
+
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")
@@ -439,7 +451,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() {
@@ -486,6 +498,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 {
@@ -683,6 +698,14 @@
outputFile := android.PathForModuleOut(ctx, fileName)
ret := outputFile
+ var implicitOutputs android.WritablePaths
+ if ctx.Windows() {
+ importLibraryPath := android.PathForModuleOut(ctx, pathtools.ReplaceExtension(fileName, "lib"))
+
+ flags.LdFlags = append(flags.LdFlags, "-Wl,--out-implib="+importLibraryPath.String())
+ implicitOutputs = append(implicitOutputs, importLibraryPath)
+ }
+
builderFlags := flagsToBuilderFlags(flags)
// Optimize out relinking against shared libraries whose interface hasn't changed by
@@ -734,7 +757,7 @@
TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs,
deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
- linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile)
+ linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs)
objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
@@ -760,10 +783,10 @@
}
func getRefAbiDumpFile(ctx ModuleContext, vndkVersion, fileName string) android.Path {
- isLlndk := inList(ctx.baseModuleName(), llndkLibraries) || inList(ctx.baseModuleName(), ndkMigratedLibs)
+ isLlndkOrNdk := inList(ctx.baseModuleName(), llndkLibraries) || 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() {
@@ -781,7 +804,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
diff --git a/cc/linker.go b/cc/linker.go
index b279c06..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")
}
@@ -301,10 +301,6 @@
if ctx.Darwin() {
return false
}
- // http://b/110800681 - lld cannot link Android's Windows modules yet.
- if ctx.Windows() {
- return false
- }
if linker.Properties.Use_clang_lld != nil {
return Bool(linker.Properties.Use_clang_lld)
}
@@ -358,7 +354,7 @@
// darwin defaults to treating undefined symbols as errors
flags.LdFlags = append(flags.LdFlags, "-Wl,-undefined,dynamic_lookup")
}
- } else if !ctx.Darwin() {
+ } else if !ctx.Darwin() && !ctx.Windows() {
flags.LdFlags = append(flags.LdFlags, "-Wl,--no-undefined")
}
@@ -395,7 +391,7 @@
flags.LdFlags = append(flags.LdFlags, proptools.NinjaAndShellEscapeList(linker.Properties.Ldflags)...)
- if ctx.Host() {
+ if ctx.Host() && !ctx.Windows() {
rpath_prefix := `\$$ORIGIN/`
if ctx.Darwin() {
rpath_prefix = "@loader_path/"
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 5a36b7f..6cdf5c7 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -182,6 +182,7 @@
module.installer = nil
module.AddProperties(
+ &module.Properties,
&stub.Properties,
&library.MutatedProperties,
&library.flagExporter.Properties)
@@ -189,6 +190,14 @@
return module
}
+// llndk_library creates a stub llndk shared library based on the provided
+// version file. Example:
+//
+// llndk_library {
+// name: "libfoo",
+// symbol_file: "libfoo.map.txt",
+// export_include_dirs: ["include_vndk"],
+// }
func LlndkLibraryFactory() android.Module {
module := NewLLndkStubLibrary()
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
@@ -203,6 +212,8 @@
return name + llndkHeadersSuffix
}
+// llndk_headers contains a set of c/c++ llndk headers files which are imported
+// by other soongs cc modules.
func llndkHeadersFactory() android.Module {
module, library := NewLibrary(android.DeviceSupported)
library.HeaderOnly()
@@ -215,7 +226,10 @@
module.linker = decorator
module.installer = nil
- module.AddProperties(&library.MutatedProperties, &library.flagExporter.Properties)
+ module.AddProperties(
+ &module.Properties,
+ &library.MutatedProperties,
+ &library.flagExporter.Properties)
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 5e45c1a..4065128 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -159,6 +159,16 @@
}
}
+// ndk_headers installs the sets of ndk headers defined in the srcs property
+// to the sysroot base + "usr/include" + to directory + directory component.
+// ndk_headers requires the license file to be specified. Example:
+//
+// Given:
+// sysroot base = "ndk/sysroot"
+// from = "include/foo"
+// to = "bar"
+// header = "include/foo/woodly/doodly.h"
+// output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
func ndkHeadersFactory() android.Module {
module := &headerModule{}
module.AddProperties(&module.properties)
@@ -278,6 +288,11 @@
return timestampFile
}
+// versioned_ndk_headers preprocesses the headers with the bionic versioner:
+// https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md.
+// Unlike the ndk_headers soong module, versioned_ndk_headers operates on a
+// directory level specified in `from` property. This is only used to process
+// the bionic/libc/include directory.
func versionedNdkHeadersFactory() android.Module {
module := &versionedHeaderModule{}
@@ -360,6 +375,8 @@
}
}
+// preprocessed_ndk_headers preprocesses all the ndk headers listed in the srcs
+// property by executing the command defined in the preprocessor property.
func preprocessedNdkHeadersFactory() android.Module {
module := &preprocessedHeadersModule{}
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 7199467..c63b200 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -377,6 +377,8 @@
return module
}
+// ndk_library creates a stub library that exposes dummy implementation
+// of functions and variables for use at build time only.
func ndkLibraryFactory() android.Module {
module := newStubLibrary()
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index 2a7e657..8451295 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -64,6 +64,10 @@
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.linker = &ndkPrebuiltObjectLinker{
@@ -98,6 +102,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 +121,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()
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/strip.go b/cc/strip.go
index 02397f4..7122585 100644
--- a/cc/strip.go
+++ b/cc/strip.go
@@ -15,15 +15,19 @@
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"`
+ Use_gnu_strip *bool `android:"arch_variant"`
+ } `android:"arch_variant"`
}
type stripper struct {
@@ -42,9 +46,14 @@
} else {
if Bool(stripper.StripProperties.Strip.Keep_symbols) {
flags.stripKeepSymbols = 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..8d76c2f 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,
diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go
index ae08b1c..b4c51ab 100644
--- a/cc/toolchain_library.go
+++ b/cc/toolchain_library.go
@@ -34,6 +34,8 @@
type toolchainLibraryDecorator struct {
*libraryDecorator
+ stripper
+
Properties toolchainLibraryProperties
}
@@ -45,9 +47,12 @@
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
+// static library in src property to the device libraries that are shipped with
+// gcc.
func ToolchainLibraryFactory() android.Module {
module, library := NewLibrary(android.HostAndDeviceSupported)
library.BuildOnlyStatic()
@@ -75,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/util.go b/cc/util.go
index 5dcbaef..3862728 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -67,7 +67,6 @@
toolingCppFlags: strings.Join(in.ToolingCppFlags, " "),
conlyFlags: strings.Join(in.ConlyFlags, " "),
cppFlags: strings.Join(in.CppFlags, " "),
- yaccFlags: strings.Join(in.YaccFlags, " "),
aidlFlags: strings.Join(in.aidlFlags, " "),
rsFlags: strings.Join(in.rsFlags, " "),
ldFlags: strings.Join(in.LdFlags, " "),
@@ -87,6 +86,8 @@
proto: in.proto,
protoC: in.protoC,
protoOptionsFile: in.protoOptionsFile,
+
+ yacc: in.Yacc,
}
}
diff --git a/cc/vendor_public_library.go b/cc/vendor_public_library.go
index da41cbc..2072ad9 100644
--- a/cc/vendor_public_library.go
+++ b/cc/vendor_public_library.go
@@ -122,6 +122,15 @@
return stub.libraryDecorator.link(ctx, flags, deps, objs)
}
+// vendor_public_library creates a stub shared library for a vendor public
+// library. This stub library is a build-time only artifact that provides
+// symbols that are exposed from a vendor public library. Example:
+//
+// vendor_public_library {
+// name: "libfoo",
+// symbol_file: "libfoo.map.txt",
+// export_public_headers: ["libfoo_headers"],
+// }
func vendorPublicLibraryFactory() android.Module {
module, library := NewLibrary(android.DeviceSupported)
library.BuildOnlyShared()
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 c2ad944..c858c40 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -89,7 +89,9 @@
return nil
}
-var extraDeps = make(ExtraDeps)
+var extraStaticLibs = make(ExtraDeps)
+
+var extraLibs = make(ExtraDeps)
type Exclude map[string]bool
@@ -124,6 +126,8 @@
var sdkVersion string
var useVersion string
+var staticDeps bool
+var jetifier bool
func InList(s string, list []string) bool {
for _, l := range list {
@@ -229,8 +233,12 @@
return p.BpDeps("aar", []string{"compile", "runtime"})
}
-func (p Pom) BpExtraDeps() []string {
- return extraDeps[p.BpName()]
+func (p Pom) BpExtraStaticLibs() []string {
+ return extraStaticLibs[p.BpName()]
+}
+
+func (p Pom) BpExtraLibs() []string {
+ return extraLibs[p.BpName()]
}
// BpDeps obtains dependencies filtered by type and scope. The results of this
@@ -251,6 +259,10 @@
return sdkVersion
}
+func (p Pom) Jetifier() bool {
+ return jetifier
+}
+
func (p *Pom) FixDeps(modules map[string]*Pom) {
for _, d := range p.Dependencies {
if d.Type == "" {
@@ -322,9 +334,12 @@
var bpTemplate = template.Must(template.New("bp").Parse(`
{{.ImportModuleType}} {
- name: "{{.BpName}}-nodeps",
+ name: "{{.BpName}}",
{{.ImportProperty}}: ["{{.ArtifactFile}}"],
sdk_version: "{{.SdkVersion}}",
+ {{- if .Jetifier}}
+ jetifier: true,
+ {{- end}}
{{- if .IsAar}}
min_sdk_version: "{{.MinSdkVersion}}",
static_libs: [
@@ -334,10 +349,49 @@
{{- range .BpAarDeps}}
"{{.}}",
{{- end}}
- {{- range .BpExtraDeps}}
+ {{- 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}}",
+ {{- 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}}
}
@@ -358,10 +412,17 @@
{{- range .BpAarDeps}}
"{{.}}",
{{- end}}
- {{- range .BpExtraDeps}}
+ {{- range .BpExtraStaticLibs}}
"{{.}}",
{{- end}}
],
+ {{- if .BpExtraLibs}}
+ libs: [
+ {{- range .BpExtraLibs}}
+ "{{.}}",
+ {{- end}}
+ ],
+ {{- end}}
java_version: "1.7",
}
`))
@@ -461,7 +522,7 @@
The tool will extract the necessary information from *.pom files to create an Android.bp whose
aar libraries can be linked against when using AAPT2.
-Usage: %s [--rewrite <regex>=<replace>] [-exclude <module>] [--extra-deps <module>=<module>[,<module>]] [<dir>] [-regen <file>]
+Usage: %s [--rewrite <regex>=<replace>] [-exclude <module>] [--extra-static-libs <module>=<module>[,<module>]] [--extra-libs <module>=<module>[,<module>]] [<dir>] [-regen <file>]
-rewrite <regex>=<replace>
rewrite can be used to specify mappings between Maven projects and Android.bp modules. The -rewrite
@@ -471,15 +532,21 @@
the Android.bp module name using <replace>. If no matches are found, <artifactId> is used.
-exclude <module>
Don't put the specified module in the Android.bp file.
- -extra-deps <module>=<module>[,<module>]
- Some Android.bp modules have transitive dependencies that must be specified when they are
- depended upon (like android-support-v7-mediarouter requires android-support-v7-appcompat).
+ -extra-static-libs <module>=<module>[,<module>]
+ Some Android.bp modules have transitive static dependencies that must be specified when they
+ are depended upon (like android-support-v7-mediarouter requires android-support-v7-appcompat).
+ This may be specified multiple times to declare these dependencies.
+ -extra-libs <module>=<module>[,<module>]
+ Some Android.bp modules have transitive runtime dependencies that must be specified when they
+ are depended upon (like androidx.test.rules requires android.test.base).
This may be specified multiple times to declare these dependencies.
-sdk-version <version>
- Sets LOCAL_SDK_VERSION := <version> for all modules.
+ Sets sdk_version: "<version>" for all modules.
-use-version <version>
If the maven directory contains multiple versions of artifacts and their pom files,
-use-version can be used to only write Android.bp files for a specific version of those artifacts.
+ -jetifier
+ Sets jetifier: true for all modules.
<dir>
The directory to search for *.pom files under.
The contents are written to stdout, to be put in the current directory (often as Android.bp)
@@ -493,12 +560,14 @@
var regen string
flag.Var(&excludes, "exclude", "Exclude module")
- flag.Var(&extraDeps, "extra-deps", "Extra dependencies needed when depending on a module")
+ flag.Var(&extraStaticLibs, "extra-static-libs", "Extra static dependencies needed when depending on a module")
+ flag.Var(&extraLibs, "extra-libs", "Extra runtime dependencies needed when depending on a module")
flag.Var(&rewriteNames, "rewrite", "Regex(es) to rewrite artifact names")
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 LOCAL_SDK_VERSION")
+ flag.StringVar(&sdkVersion, "sdk-version", "", "What to write to sdk_version")
flag.StringVar(&useVersion, "use-version", "", "Only read artifacts of a specific version")
- flag.Bool("static-deps", false, "Ignored")
+ flag.BoolVar(&staticDeps, "static-deps", false, "Statically include direct dependencies")
+ flag.BoolVar(&jetifier, "jetifier", false, "Sets jetifier: true on all modules")
flag.StringVar(®en, "regen", "", "Rewrite specified file")
flag.Parse()
@@ -612,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/pom2mk/pom2mk.go b/cmd/pom2mk/pom2mk.go
index 94e5619..b347155 100644
--- a/cmd/pom2mk/pom2mk.go
+++ b/cmd/pom2mk/pom2mk.go
@@ -104,6 +104,7 @@
var sdkVersion string
var useVersion string
var staticDeps bool
+var jetifier bool
func InList(s string, list []string) bool {
for _, l := range list {
@@ -195,6 +196,10 @@
return sdkVersion
}
+func (p Pom) Jetifier() bool {
+ return jetifier
+}
+
func (p *Pom) FixDeps(modules map[string]*Pom) {
for _, d := range p.Dependencies {
if d.Type == "" {
@@ -229,6 +234,7 @@
{{.}}{{end}}
LOCAL_STATIC_ANDROID_LIBRARIES :={{range .MkAarDeps}} \
{{.}}{{end}}
+LOCAL_JETIFIER_ENABLED := {{if .Jetifier}}true{{end}}
include $(BUILD_PREBUILT)
`))
@@ -367,6 +373,8 @@
-use-version can be used to only write makefiles for a specific version of those artifacts.
-static-deps
Whether to statically include direct dependencies.
+ -jetifier
+ Enable jetifier in order to use androidx
<dir>
The directory to search for *.pom files under.
The makefile is written to stdout, to be put in the current directory (often as Android.mk)
@@ -383,6 +391,7 @@
flag.StringVar(&sdkVersion, "sdk-version", "", "What to write to LOCAL_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, "Enable jetifier in order to use androidx")
flag.StringVar(®en, "regen", "", "Rewrite specified file")
flag.Parse()
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index 4167edb..4ac9295 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -56,7 +56,7 @@
}
fmt.Fprintf(os.Stderr,
- "Usage: sbox -c <commandToRun> --sandbox-path <sandboxPath> --output-root <outputRoot> --overwrite [--depfile-out depFile] <outputFile> [<outputFile>...]\n"+
+ "Usage: sbox -c <commandToRun> --sandbox-path <sandboxPath> --output-root <outputRoot> [--depfile-out depFile] <outputFile> [<outputFile>...]\n"+
"\n"+
"Deletes <outputRoot>,"+
"runs <commandToRun>,"+
diff --git a/cmd/soong_build/writedocs.go b/cmd/soong_build/writedocs.go
index d011e77..9424b6c 100644
--- a/cmd/soong_build/writedocs.go
+++ b/cmd/soong_build/writedocs.go
@@ -152,7 +152,6 @@
<html>
<head>
<title>Build Docs</title>
-<link rel="stylesheet" href="https://www.gstatic.com/devrel-devsite/vc67ef93e81a468795c57df87eca3f8427d65cbe85f09fbb51c82a12b89aa3d7e/androidsource/css/app.css">
<style>
#main {
padding: 48px;
@@ -165,6 +164,99 @@
td {
word-wrap:break-word;
}
+
+/* The following entries are copied from source.android.com's css file. */
+td,td code {
+ color: #202124
+}
+
+th,th code {
+ color: #fff;
+ font: 500 16px/24px Roboto,sans-serif
+}
+
+td,table.responsive tr:not(.alt) td td:first-child,table.responsive td tr:not(.alt) td:first-child {
+ background: rgba(255,255,255,.95);
+ vertical-align: top
+}
+
+td,td code {
+ padding: 7px 8px 8px
+}
+
+tr {
+ border: 0;
+ background: #78909c;
+ border-top: 1px solid #cfd8dc
+}
+
+th,td {
+ border: 0;
+ margin: 0;
+ text-align: left
+}
+
+th {
+ height: 48px;
+ padding: 8px;
+ vertical-align: middle
+}
+
+table {
+ border: 0;
+ border-collapse: collapse;
+ border-spacing: 0;
+ font: 14px/20px Roboto,sans-serif;
+ margin: 16px 0;
+ width: 100%
+}
+
+h1 {
+ color: #80868b;
+ font: 300 34px/40px Roboto,sans-serif;
+ letter-spacing: -0.01em;
+ margin: 40px 0 20px
+}
+
+h1,h2,h3,h4,h5,h6 {
+ overflow: hidden;
+ padding: 0;
+ text-overflow: ellipsis
+}
+
+:link,:visited {
+ color: #039be5;
+ outline: 0;
+ text-decoration: none
+}
+
+body,html {
+ color: #202124;
+ font: 400 16px/24px Roboto,sans-serif;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ height: 100%;
+ margin: 0;
+ -webkit-text-size-adjust: 100%;
+ -moz-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
+ text-size-adjust: 100%
+}
+
+html {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box
+}
+
+*,*::before,*::after {
+ -webkit-box-sizing: inherit;
+ box-sizing: inherit
+}
+
+body,div,dl,dd,form,img,input,figure,menu {
+ margin: 0;
+ padding: 0
+}
</style>
{{template "copyBaseUrl"}}
</head>
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index f1fa0ff..3b77042 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)
@@ -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/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 a993bf6..5e1f88e 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 {
@@ -511,7 +528,7 @@
}
func (a *AARImport) DepsMutator(ctx android.BottomUpMutatorContext) {
- if !ctx.Config().UnbundledBuildPrebuiltSdks() {
+ if !ctx.Config().UnbundledBuildUsePrebuiltSdks() {
sdkDep := decodeSdkDep(ctx, sdkContext(a))
if sdkDep.useModule && sdkDep.frameworkResModule != "" {
ctx.AddVariationDependencies(nil, frameworkResTag, sdkDep.frameworkResModule)
diff --git a/java/android_manifest.go b/java/android_manifest.go
index d72476d..7b378cd 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)
}
@@ -68,34 +69,55 @@
args = append(args, "--use-embedded-dex=true")
}
- // Inject minSdkVersion into the manifest
+ var deps android.Paths
+ targetSdkVersion := sdkVersionOrDefault(ctx, sdkContext.targetSdkVersion())
+ if targetSdkVersion == ctx.Config().PlatformSdkCodename() &&
+ ctx.Config().UnbundledBuild() &&
+ !ctx.Config().UnbundledBuildUsePrebuiltSdks() &&
+ ctx.Config().IsEnvTrue("UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT") {
+ apiFingerprint := ApiFingerprintPath(ctx)
+ targetSdkVersion += fmt.Sprintf(".$$(cat %s)", apiFingerprint.String())
+ deps = append(deps, apiFingerprint)
+ }
+
fixedManifest := android.PathForModuleOut(ctx, "manifest_fixer", "AndroidManifest.xml")
ctx.Build(pctx, android.BuildParams{
- Rule: manifestFixerRule,
- Input: manifest,
- Output: fixedManifest,
+ Rule: manifestFixerRule,
+ Description: "fix manifest",
+ Input: manifest,
+ Implicits: deps,
+ Output: fixedManifest,
Args: map[string]string{
"minSdkVersion": sdkVersionOrDefault(ctx, sdkContext.minSdkVersion()),
- "targetSdkVersion": sdkVersionOrDefault(ctx, sdkContext.targetSdkVersion()),
+ "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 ab623e2..ec021fc 100644
--- a/java/app.go
+++ b/java/app.go
@@ -34,6 +34,7 @@
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)
}
// AndroidManifest.xml merging
@@ -161,14 +162,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 +188,12 @@
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 false
+ return shouldUncompressDex(ctx, &a.dexpreopter)
}
func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
@@ -294,7 +288,7 @@
a.appProperties.AlwaysPackageNativeLibs
if embedJni {
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 +296,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 +341,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 +386,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 +408,6 @@
}
} else {
ctx.ModuleErrorf("jni_libs dependency %q must be a cc library", otherName)
-
}
} else if tag == certificateTag {
if dep, ok := module.(*AndroidAppCertificate); ok {
@@ -438,7 +433,7 @@
func AndroidAppFactory() android.Module {
module := &AndroidApp{}
- module.Module.deviceProperties.Optimize.Enabled = proptools.BoolPtr(true)
+ module.Module.deviceProperties.Optimize.EnabledByDefault = true
module.Module.deviceProperties.Optimize.Shrink = proptools.BoolPtr(true)
module.Module.properties.Instrument = true
@@ -487,6 +482,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)
@@ -508,7 +505,7 @@
func AndroidTestFactory() android.Module {
module := &AndroidTest{}
- module.Module.deviceProperties.Optimize.Enabled = proptools.BoolPtr(true)
+ module.Module.deviceProperties.Optimize.EnabledByDefault = true
module.Module.properties.Instrument = true
module.Module.properties.Installable = proptools.BoolPtr(true)
@@ -550,7 +547,7 @@
func AndroidTestHelperAppFactory() android.Module {
module := &AndroidTestHelperApp{}
- module.Module.deviceProperties.Optimize.Enabled = proptools.BoolPtr(true)
+ module.Module.deviceProperties.Optimize.EnabledByDefault = true
module.Module.properties.Installable = proptools.BoolPtr(true)
module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
@@ -620,3 +617,148 @@
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
+
+ // 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 (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) 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_DPI_VARIANTS
+ // TODO: LOCAL_PACKAGE_SPLITS
+
+ srcApk := a.prebuilt.SingleSourcePath(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)
+
+ // 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.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..e4c6afe 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -968,3 +968,87 @@
}
}
}
+
+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")
+ }
+}
diff --git a/java/builder.go b/java/builder.go
index 338cd52..d257d1d 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -154,6 +154,7 @@
processor string
systemModules classpath
aidlFlags string
+ aidlDeps android.Paths
javaVersion string
errorProneExtraJavacFlags string
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 9f40a6c..9c883e5 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,9 @@
implementationJars android.Paths
implementationAndResourceJars android.Paths
resourceJars android.Paths
+
+ combinedHeaderJar android.Path
+ combinedImplementationJar android.Path
}
type DeviceHostConverterProperties struct {
@@ -98,6 +104,27 @@
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, nil)
+ d.combinedHeaderJar = outputFile
+ } else {
+ d.combinedHeaderJar = d.headerJars[0]
+ }
+
}
var _ Dependency = (*DeviceHostConverter)(nil)
@@ -129,3 +156,18 @@
func (d *DeviceHostConverter) ExportedSdkLibs() []string {
return nil
}
+
+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/dex.go b/java/dex.go
index 987129e..c8a4fa8 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -171,7 +171,7 @@
func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags,
classesJar android.Path, jarName string) android.ModuleOutPath {
- useR8 := Bool(j.deviceProperties.Optimize.Enabled)
+ useR8 := j.deviceProperties.EffectiveOptimizeEnabled()
// Compile classes.jar into classes.dex and then javalib.jar
javalibJar := android.PathForModuleOut(ctx, "dex", jarName)
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 e857fe8..092a133 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -197,8 +197,10 @@
}
for _, target := range targets {
- files := buildBootImageRuleForArch(ctx, image, target.Arch.ArchType, profile, missingDeps)
- allFiles = append(allFiles, files.Paths()...)
+ if target.NativeBridge == android.NativeBridgeDisabled {
+ files := buildBootImageRuleForArch(ctx, image, target.Arch.ArchType, profile, missingDeps)
+ allFiles = append(allFiles, files.Paths()...)
+ }
}
}
@@ -469,7 +471,14 @@
var imageNames []string
for _, current := range append(d.otherImages, image) {
imageNames = append(imageNames, current.name)
+ var arches []android.ArchType
for arch, _ := range current.images {
+ arches = append(arches, arch)
+ }
+
+ sort.Slice(arches, func(i, j int) bool { return arches[i].String() < arches[j].String() })
+
+ for _, arch := range arches {
ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+current.name+"_"+arch.String(), current.vdexInstalls[arch].String())
ctx.Strict("DEXPREOPT_IMAGE_"+current.name+"_"+arch.String(), current.images[arch].String())
ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+current.name+"_"+arch.String(), current.installs[arch].String())
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index b30bd00..a0b1ea5 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -138,21 +138,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"))
}
@@ -167,9 +175,9 @@
return bootImageConfig{
name: "apex",
- modules: runtimeModules,
- dexLocations: runtimeBootLocations,
- dexPaths: runtimeBootDexPaths,
+ modules: imageModules,
+ dexLocations: bootLocations,
+ dexPaths: bootDexPaths,
dir: dir,
symbolsDir: symbolsDir,
images: images,
diff --git a/java/droiddoc.go b/java/droiddoc.go
index e163617..fd7e2a4 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -404,6 +404,7 @@
sourcepathArgs string
dokkaClasspathArgs string
aidlFlags string
+ aidlDeps android.Paths
doclavaStubsFlags string
doclavaDocsFlags string
@@ -574,26 +575,23 @@
func (j *Javadoc) collectAidlFlags(ctx android.ModuleContext, deps deps) droiddocBuilderFlags {
var flags droiddocBuilderFlags
- // aidl flags.
- aidlFlags := j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)
- if len(aidlFlags) > 0 {
- // optimization.
- ctx.Variable(pctx, "aidlFlags", strings.Join(aidlFlags, " "))
- flags.aidlFlags = "$aidlFlags"
- }
+ flags.aidlFlags, flags.aidlDeps = j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)
return flags
}
func (j *Javadoc) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath,
- aidlIncludeDirs android.Paths) []string {
+ aidlIncludeDirs android.Paths) (string, android.Paths) {
aidlIncludes := android.PathsForModuleSrc(ctx, j.properties.Aidl.Local_include_dirs)
aidlIncludes = append(aidlIncludes, android.PathsForSource(ctx, j.properties.Aidl.Include_dirs)...)
var flags []string
+ var deps android.Paths
+
if aidlPreprocess.Valid() {
flags = append(flags, "-p"+aidlPreprocess.String())
+ deps = append(deps, aidlPreprocess.Path())
} else {
flags = append(flags, android.JoinWithPrefix(aidlIncludeDirs.Strings(), "-I"))
}
@@ -604,7 +602,7 @@
flags = append(flags, "-I"+src.String())
}
- return flags
+ return strings.Join(flags, " "), deps
}
func (j *Javadoc) genSources(ctx android.ModuleContext, srcFiles android.Paths,
@@ -615,7 +613,7 @@
for _, srcFile := range srcFiles {
switch srcFile.Ext() {
case ".aidl":
- javaFile := genAidl(ctx, srcFile, flags.aidlFlags)
+ javaFile := genAidl(ctx, srcFile, flags.aidlFlags, flags.aidlDeps)
outSrcFiles = append(outSrcFiles, javaFile)
case ".sysprop":
javaFile := genSysprop(ctx, srcFile)
diff --git a/java/gen.go b/java/gen.go
index 7c57a46..b1c028d 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -60,7 +60,7 @@
})
)
-func genAidl(ctx android.ModuleContext, aidlFile android.Path, aidlFlags string) android.Path {
+func genAidl(ctx android.ModuleContext, aidlFile android.Path, aidlFlags string, deps android.Paths) android.Path {
javaFile := android.GenPathWithExt(ctx, "aidl", aidlFile, "java")
depFile := javaFile.String() + ".d"
@@ -69,6 +69,7 @@
Description: "aidl " + aidlFile.Rel(),
Output: javaFile,
Input: aidlFile,
+ Implicits: deps,
Args: map[string]string{
"depFile": depFile,
"aidlFlags": aidlFlags,
@@ -112,7 +113,7 @@
for _, srcFile := range srcFiles {
switch srcFile.Ext() {
case ".aidl":
- javaFile := genAidl(ctx, srcFile, flags.aidlFlags)
+ javaFile := genAidl(ctx, srcFile, flags.aidlFlags, flags.aidlDeps)
outSrcFiles = append(outSrcFiles, javaFile)
case ".logtags":
j.logtagsSrcs = append(j.logtagsSrcs, srcFile)
diff --git a/java/java.go b/java/java.go
index bf62578..47dd957 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
@@ -228,6 +235,8 @@
// If false, disable all optimization. Defaults to true for android_app and android_test
// modules, false for java_library and java_test modules.
Enabled *bool
+ // True if the module containing this has it set by default.
+ EnabledByDefault bool `blueprint:"mutated"`
// If true, optimize for size by removing unused code. Defaults to true for apps,
// false for libraries and tests.
@@ -257,6 +266,10 @@
IsSDKLibrary bool `blueprint:"mutated"`
}
+func (me *CompilerDeviceProperties) EffectiveOptimizeEnabled() bool {
+ return BoolDefault(me.Optimize.Enabled, me.Optimize.EnabledByDefault)
+}
+
// Module contains the properties and members used by all java module types
type Module struct {
android.ModuleBase
@@ -410,7 +423,7 @@
frameworkResModule string
jars android.Paths
- aidl android.Path
+ aidl android.OptionalPath
}
type jniLib struct {
@@ -460,7 +473,7 @@
} else if sdkDep.useModule {
ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.modules...)
- if Bool(j.deviceProperties.Optimize.Enabled) {
+ if j.deviceProperties.EffectiveOptimizeEnabled() {
ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultBootclasspathLibraries...)
ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultLibraries...)
}
@@ -534,7 +547,7 @@
}
func (j *Module) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath,
- aidlIncludeDirs android.Paths) []string {
+ aidlIncludeDirs android.Paths) (string, android.Paths) {
aidlIncludes := android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Local_include_dirs)
aidlIncludes = append(aidlIncludes,
@@ -542,16 +555,24 @@
aidlIncludes = append(aidlIncludes,
android.PathsForSource(ctx, j.deviceProperties.Aidl.Include_dirs)...)
- flags := []string{}
+ var flags []string
+ var deps android.Paths
if aidlPreprocess.Valid() {
flags = append(flags, "-p"+aidlPreprocess.String())
- } else {
+ deps = append(deps, aidlPreprocess.Path())
+ } else if len(aidlIncludeDirs) > 0 {
flags = append(flags, android.JoinWithPrefix(aidlIncludeDirs.Strings(), "-I"))
}
- flags = append(flags, android.JoinWithPrefix(j.exportAidlIncludeDirs.Strings(), "-I"))
- flags = append(flags, android.JoinWithPrefix(aidlIncludes.Strings(), "-I"))
+ if len(j.exportAidlIncludeDirs) > 0 {
+ flags = append(flags, android.JoinWithPrefix(j.exportAidlIncludeDirs.Strings(), "-I"))
+ }
+
+ if len(aidlIncludes) > 0 {
+ flags = append(flags, android.JoinWithPrefix(aidlIncludes.Strings(), "-I"))
+ }
+
flags = append(flags, "-I"+android.PathForModuleSrc(ctx).String())
if src := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "src"); src.Valid() {
flags = append(flags, "-I"+src.String())
@@ -565,7 +586,7 @@
flags = append(flags, "--transaction_names")
}
- return flags
+ return strings.Join(flags, " "), deps
}
type deps struct {
@@ -683,7 +704,9 @@
} else if sdkDep.useFiles {
// sdkDep.jar is actually equivalent to turbine header.jar.
deps.classpath = append(deps.classpath, sdkDep.jars...)
- deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, sdkDep.aidl)
+ deps.aidlPreprocess = sdkDep.aidl
+ } else {
+ deps.aidlPreprocess = sdkDep.aidl
}
}
@@ -713,7 +736,7 @@
deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
// names of sdk libs that are directly depended are exported
j.exportedSdkLibs = append(j.exportedSdkLibs, otherName)
- default:
+ case staticLibTag:
ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
}
case Dependency:
@@ -724,6 +747,7 @@
deps.classpath = append(deps.classpath, dep.HeaderJars()...)
// sdk lib names from dependencies are re-exported
j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...)
+ deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
case staticLibTag:
deps.classpath = append(deps.classpath, dep.HeaderJars()...)
deps.staticJars = append(deps.staticJars, dep.ImplementationJars()...)
@@ -731,6 +755,7 @@
deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars()...)
// sdk lib names from dependencies are re-exported
j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...)
+ deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
case pluginTag:
if plugin, ok := dep.(*Plugin); ok {
deps.processorPath = append(deps.processorPath, dep.ImplementationAndResourcesJars()...)
@@ -765,7 +790,6 @@
deps.kotlinAnnotations = dep.HeaderJars()
}
- deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
case android.SourceFileProducer:
switch tag {
case libTag:
@@ -806,7 +830,7 @@
v := sdkContext.sdkVersion()
// For PDK builds, use the latest SDK version instead of "current"
if ctx.Config().IsPdkBuild() && (v == "" || v == "current") {
- sdkVersions := ctx.Config().Get(sdkSingletonKey).([]int)
+ sdkVersions := ctx.Config().Get(sdkVersionsKey).([]int)
latestSdkVersion := 0
if len(sdkVersions) > 0 {
latestSdkVersion = sdkVersions[len(sdkVersions)-1]
@@ -919,12 +943,7 @@
}
// aidl flags.
- aidlFlags := j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)
- if len(aidlFlags) > 0 {
- // optimization.
- ctx.Variable(pctx, "aidlFlags", strings.Join(aidlFlags, " "))
- flags.aidlFlags = "$aidlFlags"
- }
+ flags.aidlFlags, flags.aidlDeps = j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)
if len(javacFlags) > 0 {
// optimization.
@@ -1234,9 +1253,9 @@
// 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
}
@@ -1620,6 +1639,9 @@
&module.Module.protoProperties,
&module.testHelperLibraryProperties)
+ module.Module.properties.Installable = proptools.BoolPtr(true)
+ module.Module.dexpreopter.isTest = true
+
InitJavaModule(module, android.HostAndDeviceSupported)
return module
}
diff --git a/java/java_test.go b/java/java_test.go
index 3ae993d..5335d78 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))
@@ -86,6 +87,7 @@
ctx.RegisterModuleType("droiddoc_host", android.ModuleFactoryAdaptor(DroiddocHostFactory))
ctx.RegisterModuleType("droiddoc_template", android.ModuleFactoryAdaptor(ExportedDroiddocDirFactory))
ctx.RegisterModuleType("java_sdk_library", android.ModuleFactoryAdaptor(SdkLibraryFactory))
+ ctx.RegisterModuleType("java_sdk_library_import", android.ModuleFactoryAdaptor(sdkLibraryImportFactory))
ctx.RegisterModuleType("override_android_app", android.ModuleFactoryAdaptor(OverrideAndroidAppModuleFactory))
ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(PrebuiltApisFactory))
ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
@@ -94,10 +96,9 @@
ctx.PreArchMutators(android.RegisterOverridePreArchMutators)
ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
ctx.TopDown("prebuilt_apis", PrebuiltApisMutator).Parallel()
- ctx.TopDown("java_sdk_library", SdkLibraryMutator).Parallel()
})
ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory))
- ctx.RegisterPreSingletonType("sdk", android.SingletonFactoryAdaptor(sdkSingletonFactory))
+ ctx.RegisterPreSingletonType("sdk_versions", android.SingletonFactoryAdaptor(sdkPreSingletonFactory))
// Register module types and mutators from cc needed for JNI testing
ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
@@ -131,6 +132,7 @@
"api/system-removed.txt": nil,
"api/test-current.txt": nil,
"api/test-removed.txt": nil,
+ "framework/aidl/a.aidl": nil,
"prebuilts/sdk/14/public/android.jar": nil,
"prebuilts/sdk/14/public/framework.aidl": nil,
@@ -162,6 +164,8 @@
"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,
+
// For framework-res, which is an implicit dependency for framework
"AndroidManifest.xml": nil,
"build/make/target/product/security/testkey": nil,
@@ -324,7 +328,7 @@
java_library {
name: "foo",
srcs: ["a.java"],
- libs: ["bar"],
+ libs: ["bar", "sdklib"],
static_libs: ["baz"],
}
@@ -342,17 +346,27 @@
name: "qux",
jars: ["b.jar"],
}
+
+ java_sdk_library_import {
+ name: "sdklib",
+ jars: ["b.jar"],
+ }
`)
javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
barJar := ctx.ModuleForTests("bar", "android_common").Rule("combineJar").Output
bazJar := ctx.ModuleForTests("baz", "android_common").Rule("combineJar").Output
+ sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").Rule("combineJar").Output
if !strings.Contains(javac.Args["classpath"], barJar.String()) {
t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barJar.String())
}
+ if !strings.Contains(javac.Args["classpath"], sdklibStubsJar.String()) {
+ t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String())
+ }
+
if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != bazJar.String() {
t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, bazJar.String())
}
@@ -367,6 +381,7 @@
srcs: ["a.java"],
libs: ["bar"],
static_libs: ["baz"],
+ optimize: {enabled: false},
}
java_library {
@@ -383,6 +398,22 @@
name: "baz",
srcs: ["c.java"],
}
+
+ android_test {
+ name: "atestOptimize",
+ defaults: ["defaults"],
+ optimize: {enabled: true},
+ }
+
+ android_test {
+ name: "atestNoOptimize",
+ defaults: ["defaults"],
+ }
+
+ android_test {
+ name: "atestDefault",
+ srcs: ["a.java"],
+ }
`)
javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
@@ -401,6 +432,21 @@
if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
}
+
+ atestOptimize := ctx.ModuleForTests("atestOptimize", "android_common").MaybeRule("r8")
+ if atestOptimize.Output == nil {
+ t.Errorf("atestOptimize should optimize APK")
+ }
+
+ atestNoOptimize := ctx.ModuleForTests("atestNoOptimize", "android_common").MaybeRule("d8")
+ if atestNoOptimize.Output == nil {
+ t.Errorf("atestNoOptimize should not optimize APK")
+ }
+
+ atestDefault := ctx.ModuleForTests("atestDefault", "android_common").MaybeRule("r8")
+ if atestDefault.Output == nil {
+ t.Errorf("atestDefault should optimize APK")
+ }
}
func TestResources(t *testing.T) {
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 48e7746..e93f8fb 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -19,16 +19,23 @@
"android/soong/java/config"
"fmt"
"path/filepath"
+ "runtime"
"sort"
"strconv"
"strings"
+
+ "github.com/google/blueprint/pathtools"
)
func init() {
- android.RegisterPreSingletonType("sdk", sdkSingletonFactory)
+ android.RegisterPreSingletonType("sdk_versions", sdkPreSingletonFactory)
+ android.RegisterSingletonType("sdk", sdkSingletonFactory)
+ android.RegisterMakeVarsProvider(pctx, sdkMakeVars)
}
-var sdkSingletonKey = android.NewOnceKey("sdkSingletonKey")
+var sdkVersionsKey = android.NewOnceKey("sdkVersionsKey")
+var sdkFrameworkAidlPathKey = android.NewOnceKey("sdkFrameworkAidlPathKey")
+var apiFingerprintPathKey = android.NewOnceKey("apiFingerprintPathKey")
type sdkContext interface {
// sdkVersion eturns the sdk_version property of the current module, or an empty string if it is not set.
@@ -76,7 +83,7 @@
v := sdkContext.sdkVersion()
// For PDK builds, use the latest SDK version instead of "current"
if ctx.Config().IsPdkBuild() && (v == "" || v == "current") {
- sdkVersions := ctx.Config().Get(sdkSingletonKey).([]int)
+ sdkVersions := ctx.Config().Get(sdkVersionsKey).([]int)
latestSdkVersion := 0
if len(sdkVersions) > 0 {
latestSdkVersion = sdkVersions[len(sdkVersions)-1]
@@ -130,17 +137,19 @@
return sdkDep{
useFiles: true,
jars: android.Paths{jarPath.Path(), lambdaStubsPath},
- aidl: aidlPath.Path(),
+ aidl: android.OptionalPathForPath(aidlPath.Path()),
}
}
- toModule := func(m, r string) sdkDep {
+ toModule := func(m, r string, aidl android.Path) sdkDep {
ret := sdkDep{
useModule: true,
modules: []string{m, config.DefaultLambdaStubsLibrary},
systemModules: m + "_system_modules",
frameworkResModule: r,
+ aidl: android.OptionalPathForPath(aidl),
}
+
if m == "core.current.stubs" {
ret.systemModules = "core-system-modules"
} else if m == "core.platform.api.stubs" {
@@ -164,7 +173,7 @@
}
}
- if ctx.Config().UnbundledBuildPrebuiltSdks() && v != "" {
+ if ctx.Config().UnbundledBuildUsePrebuiltSdks() && v != "" {
return toPrebuilt(v)
}
@@ -175,25 +184,25 @@
frameworkResModule: "framework-res",
}
case "current":
- return toModule("android_stubs_current", "framework-res")
+ return toModule("android_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
case "system_current":
- return toModule("android_system_stubs_current", "framework-res")
+ return toModule("android_system_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
case "test_current":
- return toModule("android_test_stubs_current", "framework-res")
+ return toModule("android_test_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
case "core_current":
- return toModule("core.current.stubs", "")
+ return toModule("core.current.stubs", "", nil)
default:
return toPrebuilt(v)
}
}
-func sdkSingletonFactory() android.Singleton {
- return sdkSingleton{}
+func sdkPreSingletonFactory() android.Singleton {
+ return sdkPreSingleton{}
}
-type sdkSingleton struct{}
+type sdkPreSingleton struct{}
-func (sdkSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+func (sdkPreSingleton) GenerateBuildActions(ctx android.SingletonContext) {
sdkJars, err := ctx.GlobWithDeps("prebuilts/sdk/*/public/android.jar", nil)
if err != nil {
ctx.Errorf("failed to glob prebuilts/sdk/*/public/android.jar: %s", err.Error())
@@ -213,5 +222,154 @@
sort.Ints(sdkVersions)
- ctx.Config().Once(sdkSingletonKey, func() interface{} { return sdkVersions })
+ ctx.Config().Once(sdkVersionsKey, func() interface{} { return sdkVersions })
+}
+
+func sdkSingletonFactory() android.Singleton {
+ return sdkSingleton{}
+}
+
+type sdkSingleton struct{}
+
+func (sdkSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ if ctx.Config().UnbundledBuildUsePrebuiltSdks() || ctx.Config().IsPdkBuild() {
+ return
+ }
+
+ createSdkFrameworkAidl(ctx)
+ createAPIFingerprint(ctx)
+}
+
+// Create framework.aidl by extracting anything that implements android.os.Parcelable from the SDK stubs modules.
+func createSdkFrameworkAidl(ctx android.SingletonContext) {
+ stubsModules := []string{
+ "android_stubs_current",
+ "android_test_stubs_current",
+ "android_system_stubs_current",
+ }
+
+ stubsJars := make([]android.Paths, len(stubsModules))
+
+ ctx.VisitAllModules(func(module android.Module) {
+ // Collect dex jar paths for the modules listed above.
+ if j, ok := module.(Dependency); ok {
+ name := ctx.ModuleName(module)
+ if i := android.IndexList(name, stubsModules); i != -1 {
+ stubsJars[i] = j.HeaderJars()
+ }
+ }
+ })
+
+ var missingDeps []string
+
+ for i := range stubsJars {
+ if stubsJars[i] == nil {
+ if ctx.Config().AllowMissingDependencies() {
+ missingDeps = append(missingDeps, stubsModules[i])
+ } else {
+ ctx.Errorf("failed to find dex jar path for module %q",
+ stubsModules[i])
+ }
+ }
+ }
+
+ rule := android.NewRuleBuilder()
+ rule.MissingDeps(missingDeps)
+
+ var aidls android.Paths
+ for _, jars := range stubsJars {
+ for _, jar := range jars {
+ aidl := android.PathForOutput(ctx, "aidl", pathtools.ReplaceExtension(jar.Base(), "aidl"))
+
+ rule.Command().
+ Text("rm -f").Output(aidl)
+ rule.Command().
+ Tool(ctx.Config().HostToolPath(ctx, "sdkparcelables")).
+ Input(jar).
+ Output(aidl)
+
+ aidls = append(aidls, aidl)
+ }
+ }
+
+ combinedAidl := sdkFrameworkAidlPath(ctx)
+ tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp")
+
+ rule.Command().
+ Text("rm -f").Output(tempPath)
+ rule.Command().
+ Text("cat").
+ Inputs(aidls).
+ Text("| sort -u >").
+ Output(tempPath)
+
+ commitChangeForRestat(rule, tempPath, combinedAidl)
+
+ rule.Build(pctx, ctx, "framework_aidl", "generate framework.aidl")
+}
+
+func sdkFrameworkAidlPath(ctx android.PathContext) android.OutputPath {
+ return ctx.Config().Once(sdkFrameworkAidlPathKey, func() interface{} {
+ return android.PathForOutput(ctx, "framework.aidl")
+ }).(android.OutputPath)
+}
+
+// Create api_fingerprint.txt
+func createAPIFingerprint(ctx android.SingletonContext) {
+ out := ApiFingerprintPath(ctx)
+
+ rule := android.NewRuleBuilder()
+
+ rule.Command().
+ Text("rm -f").Output(out)
+ cmd := rule.Command()
+
+ if ctx.Config().PlatformSdkCodename() == "REL" {
+ cmd.Text("echo REL >").Output(out)
+ } else if ctx.Config().IsPdkBuild() {
+ // TODO: get this from the PDK artifacts?
+ cmd.Text("echo PDK >").Output(out)
+ } else if !ctx.Config().UnbundledBuildUsePrebuiltSdks() {
+ in, err := ctx.GlobWithDeps("frameworks/base/api/*current.txt", nil)
+ if err != nil {
+ ctx.Errorf("error globbing API files: %s", err)
+ }
+
+ cmd.Text("cat").
+ Inputs(android.PathsForSource(ctx, in)).
+ Text("|")
+
+ if runtime.GOOS == "darwin" {
+ cmd.Text("md5")
+ } else {
+ cmd.Text("md5sum")
+ }
+
+ cmd.Text("| cut -d' ' -f1 >").
+ Output(out)
+ } else {
+ // Unbundled build
+ // TODO: use a prebuilt api_fingerprint.txt from prebuilts/sdk/current.txt once we have one
+ cmd.Text("echo").
+ Flag(ctx.Config().PlatformPreviewSdkVersion()).
+ Text(">").
+ Output(out)
+ }
+
+ rule.Build(pctx, ctx, "api_fingerprint", "generate api_fingerprint.txt")
+}
+
+func ApiFingerprintPath(ctx android.PathContext) android.OutputPath {
+ return ctx.Config().Once(apiFingerprintPathKey, func() interface{} {
+ return android.PathForOutput(ctx, "api_fingerprint.txt")
+ }).(android.OutputPath)
+}
+
+func sdkMakeVars(ctx android.MakeVarsContext) {
+ if ctx.Config().UnbundledBuildUsePrebuiltSdks() || ctx.Config().IsPdkBuild() {
+ return
+ }
+
+ ctx.Strict("FRAMEWORK_AIDL", sdkFrameworkAidlPath(ctx).String())
+ ctx.Strict("API_FINGERPRINT", ApiFingerprintPath(ctx).String())
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 72cce57..72c5cfc 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -42,10 +42,6 @@
name string
}
-type syspropLibraryInterface interface {
- SyspropJavaModule() *SdkLibrary
-}
-
var (
publicApiStubsTag = dependencyTag{name: "public"}
systemApiStubsTag = dependencyTag{name: "system"}
@@ -79,10 +75,7 @@
func init() {
android.RegisterModuleType("java_sdk_library", SdkLibraryFactory)
-
- android.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("java_sdk_library", SdkLibraryMutator).Parallel()
- })
+ android.RegisterModuleType("java_sdk_library_import", sdkLibraryImportFactory)
android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
javaSdkLibraries := javaSdkLibraries(ctx.Config())
@@ -376,7 +369,7 @@
}
// Creates a static java library that has API stubs
-func (module *SdkLibrary) createStubsLibrary(mctx android.TopDownMutatorContext, apiScope apiScope) {
+func (module *SdkLibrary) createStubsLibrary(mctx android.LoadHookContext, apiScope apiScope) {
props := struct {
Name *string
Srcs []string
@@ -409,7 +402,7 @@
props.Sdk_version = proptools.StringPtr(module.sdkVersion(apiScope))
props.Libs = module.sdkLibraryProperties.Stub_only_libs
// Unbundled apps will use the prebult one from /prebuilts/sdk
- if mctx.Config().UnbundledBuildPrebuiltSdks() {
+ if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
props.Product_variables.Unbundled_build.Enabled = proptools.BoolPtr(false)
}
props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false)
@@ -435,7 +428,7 @@
// Creates a droiddoc module that creates stubs source files from the given full source
// files
-func (module *SdkLibrary) createDocs(mctx android.TopDownMutatorContext, apiScope apiScope) {
+func (module *SdkLibrary) createDocs(mctx android.LoadHookContext, apiScope apiScope) {
props := struct {
Name *string
Srcs []string
@@ -534,7 +527,7 @@
}
// Creates the xml file that publicizes the runtime library
-func (module *SdkLibrary) createXmlFile(mctx android.TopDownMutatorContext) {
+func (module *SdkLibrary) createXmlFile(mctx android.LoadHookContext) {
template := `
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 The Android Open Source Project
@@ -619,7 +612,7 @@
// to satisfy SdkLibraryDependency interface
func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseContext, sdkVersion string) android.Paths {
// This module is just a wrapper for the stubs.
- if ctx.Config().UnbundledBuildPrebuiltSdks() {
+ if ctx.Config().UnbundledBuildUsePrebuiltSdks() {
return module.PrebuiltJars(ctx, sdkVersion)
} else {
if strings.HasPrefix(sdkVersion, "system_") {
@@ -635,7 +628,7 @@
// to satisfy SdkLibraryDependency interface
func (module *SdkLibrary) SdkImplementationJars(ctx android.BaseContext, sdkVersion string) android.Paths {
// This module is just a wrapper for the stubs.
- if ctx.Config().UnbundledBuildPrebuiltSdks() {
+ if ctx.Config().UnbundledBuildUsePrebuiltSdks() {
return module.PrebuiltJars(ctx, sdkVersion)
} else {
if strings.HasPrefix(sdkVersion, "system_") {
@@ -659,15 +652,7 @@
// For a java_sdk_library module, create internal modules for stubs, docs,
// runtime libs and xml file. If requested, the stubs and docs are created twice
// once for public API level and once for system API level
-func SdkLibraryMutator(mctx android.TopDownMutatorContext) {
- if module, ok := mctx.Module().(*SdkLibrary); ok {
- module.createInternalModules(mctx)
- } else if module, ok := mctx.Module().(syspropLibraryInterface); ok {
- module.SyspropJavaModule().createInternalModules(mctx)
- }
-}
-
-func (module *SdkLibrary) createInternalModules(mctx android.TopDownMutatorContext) {
+func (module *SdkLibrary) CreateInternalModules(mctx android.LoadHookContext) {
if len(module.Library.Module.properties.Srcs) == 0 {
mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs")
}
@@ -744,5 +729,115 @@
module := &SdkLibrary{}
module.InitSdkLibraryProperties()
InitJavaModule(module, android.HostAndDeviceSupported)
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.CreateInternalModules(ctx) })
return module
}
+
+//
+// SDK library prebuilts
+//
+
+type sdkLibraryImportProperties struct {
+ Jars []string `android:"path"`
+
+ Sdk_version *string
+
+ Installable *bool
+
+ // List of shared java libs that this module has dependencies to
+ Libs []string
+
+ // List of files to remove from the jar file(s)
+ Exclude_files []string
+
+ // List of directories to remove from the jar file(s)
+ Exclude_dirs []string
+}
+
+type sdkLibraryImport struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+ prebuilt android.Prebuilt
+
+ properties sdkLibraryImportProperties
+
+ stubsPath android.Paths
+}
+
+var _ SdkLibraryDependency = (*sdkLibraryImport)(nil)
+
+func sdkLibraryImportFactory() android.Module {
+ module := &sdkLibraryImport{}
+
+ module.AddProperties(&module.properties)
+
+ android.InitPrebuiltModule(module, &module.properties.Jars)
+ InitJavaModule(module, android.HostAndDeviceSupported)
+
+ android.AddLoadHook(module, func(mctx android.LoadHookContext) { module.createInternalModules(mctx) })
+ return module
+}
+
+func (module *sdkLibraryImport) Prebuilt() *android.Prebuilt {
+ return &module.prebuilt
+}
+
+func (module *sdkLibraryImport) Name() string {
+ return module.prebuilt.Name(module.ModuleBase.Name())
+}
+
+func (module *sdkLibraryImport) createInternalModules(mctx android.LoadHookContext) {
+ // Creates a java import for the jar with ".stubs" suffix
+ props := struct {
+ Name *string
+ Soc_specific *bool
+ Device_specific *bool
+ Product_specific *bool
+ }{}
+
+ props.Name = proptools.StringPtr(module.BaseModuleName() + sdkStubsLibrarySuffix)
+
+ if module.SocSpecific() {
+ props.Soc_specific = proptools.BoolPtr(true)
+ } else if module.DeviceSpecific() {
+ props.Device_specific = proptools.BoolPtr(true)
+ } else if module.ProductSpecific() {
+ props.Product_specific = proptools.BoolPtr(true)
+ }
+
+ mctx.CreateModule(android.ModuleFactoryAdaptor(ImportFactory), &props, &module.properties)
+
+ javaSdkLibraries := javaSdkLibraries(mctx.Config())
+ javaSdkLibrariesLock.Lock()
+ defer javaSdkLibrariesLock.Unlock()
+ *javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
+}
+
+func (module *sdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
+ // Add dependencies to the prebuilt stubs library
+ ctx.AddVariationDependencies(nil, publicApiStubsTag, module.BaseModuleName()+sdkStubsLibrarySuffix)
+}
+
+func (module *sdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // Record the paths to the prebuilt stubs library.
+ ctx.VisitDirectDeps(func(to android.Module) {
+ tag := ctx.OtherModuleDependencyTag(to)
+
+ switch tag {
+ case publicApiStubsTag:
+ module.stubsPath = to.(Dependency).HeaderJars()
+ }
+ })
+}
+
+// to satisfy SdkLibraryDependency interface
+func (module *sdkLibraryImport) SdkHeaderJars(ctx android.BaseContext, sdkVersion string) android.Paths {
+ // This module is just a wrapper for the prebuilt stubs.
+ return module.stubsPath
+}
+
+// to satisfy SdkLibraryDependency interface
+func (module *sdkLibraryImport) SdkImplementationJars(ctx android.BaseContext, sdkVersion string) android.Paths {
+ // This module is just a wrapper for the stubs.
+ return module.stubsPath
+}
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 7fa40a3..e446129 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -15,174 +15,189 @@
package java
import (
- "android/soong/android"
"path/filepath"
"reflect"
"strings"
"testing"
"github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+ "android/soong/java/config"
)
-var classpathTestcases = []struct {
- name string
- unbundled bool
- pdk bool
- moduleType string
- host android.OsClass
- properties string
- bootclasspath []string
- system string
- classpath []string
-}{
- {
- name: "default",
- bootclasspath: []string{"core.platform.api.stubs", "core-lambda-stubs"},
- system: "core-platform-api-stubs-system-modules",
- classpath: []string{"ext", "framework"},
- },
- {
- name: "blank sdk version",
- properties: `sdk_version: "",`,
- bootclasspath: []string{"core.platform.api.stubs", "core-lambda-stubs"},
- system: "core-platform-api-stubs-system-modules",
- classpath: []string{"ext", "framework"},
- },
- {
-
- name: "sdk v25",
- properties: `sdk_version: "25",`,
- bootclasspath: []string{`""`},
- system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- classpath: []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- },
- {
-
- name: "current",
- properties: `sdk_version: "current",`,
- bootclasspath: []string{"android_stubs_current", "core-lambda-stubs"},
- system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- },
- {
-
- name: "system_current",
- properties: `sdk_version: "system_current",`,
- bootclasspath: []string{"android_system_stubs_current", "core-lambda-stubs"},
- system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- },
- {
-
- name: "system_25",
- properties: `sdk_version: "system_25",`,
- bootclasspath: []string{`""`},
- system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- classpath: []string{"prebuilts/sdk/25/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- },
- {
-
- name: "test_current",
- properties: `sdk_version: "test_current",`,
- bootclasspath: []string{"android_test_stubs_current", "core-lambda-stubs"},
- system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- },
- {
-
- name: "core_current",
- properties: `sdk_version: "core_current",`,
- bootclasspath: []string{"core.current.stubs", "core-lambda-stubs"},
- system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- },
- {
-
- name: "nostdlib",
- properties: `no_standard_libs: true, system_modules: "none"`,
- system: "none",
- bootclasspath: []string{`""`},
- classpath: []string{},
- },
- {
-
- name: "nostdlib system_modules",
- properties: `no_standard_libs: true, system_modules: "core-platform-api-stubs-system-modules"`,
- system: "core-platform-api-stubs-system-modules",
- bootclasspath: []string{`""`},
- classpath: []string{},
- },
- {
-
- name: "host default",
- moduleType: "java_library_host",
- properties: ``,
- host: android.Host,
- bootclasspath: []string{"jdk8/jre/lib/jce.jar", "jdk8/jre/lib/rt.jar"},
- classpath: []string{},
- },
- {
- name: "host nostdlib",
- moduleType: "java_library_host",
- host: android.Host,
- properties: `no_standard_libs: true`,
- classpath: []string{},
- },
- {
-
- name: "host supported default",
- host: android.Host,
- properties: `host_supported: true,`,
- classpath: []string{},
- bootclasspath: []string{"jdk8/jre/lib/jce.jar", "jdk8/jre/lib/rt.jar"},
- },
- {
- name: "host supported nostdlib",
- host: android.Host,
- properties: `host_supported: true, no_standard_libs: true, system_modules: "none"`,
- classpath: []string{},
- },
- {
-
- name: "unbundled sdk v25",
- unbundled: true,
- properties: `sdk_version: "25",`,
- bootclasspath: []string{`""`},
- system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- classpath: []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- },
- {
-
- name: "unbundled current",
- unbundled: true,
- properties: `sdk_version: "current",`,
- bootclasspath: []string{`""`},
- system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- classpath: []string{"prebuilts/sdk/current/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- },
-
- {
- name: "pdk default",
- pdk: true,
- bootclasspath: []string{`""`},
- system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- classpath: []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- },
- {
- name: "pdk current",
- pdk: true,
- properties: `sdk_version: "current",`,
- bootclasspath: []string{`""`},
- system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- classpath: []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- },
- {
- name: "pdk 25",
- pdk: true,
- properties: `sdk_version: "25",`,
- bootclasspath: []string{`""`},
- system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
- classpath: []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- },
-}
-
func TestClasspath(t *testing.T) {
+ var classpathTestcases = []struct {
+ name string
+ unbundled bool
+ pdk bool
+ moduleType string
+ host android.OsClass
+ properties string
+ bootclasspath []string
+ system string
+ classpath []string
+ aidl string
+ }{
+ {
+ name: "default",
+ bootclasspath: config.DefaultBootclasspathLibraries,
+ system: config.DefaultSystemModules,
+ classpath: config.DefaultLibraries,
+ aidl: "-Iframework/aidl",
+ },
+ {
+ name: "blank sdk version",
+ properties: `sdk_version: "",`,
+ bootclasspath: config.DefaultBootclasspathLibraries,
+ system: config.DefaultSystemModules,
+ classpath: config.DefaultLibraries,
+ aidl: "-Iframework/aidl",
+ },
+ {
+
+ name: "sdk v25",
+ properties: `sdk_version: "25",`,
+ bootclasspath: []string{`""`},
+ system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+ classpath: []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/25/public/framework.aidl",
+ },
+ {
+
+ name: "current",
+ properties: `sdk_version: "current",`,
+ bootclasspath: []string{"android_stubs_current", "core-lambda-stubs"},
+ system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+ aidl: "-p" + buildDir + "/framework.aidl",
+ },
+ {
+
+ name: "system_current",
+ properties: `sdk_version: "system_current",`,
+ bootclasspath: []string{"android_system_stubs_current", "core-lambda-stubs"},
+ system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+ aidl: "-p" + buildDir + "/framework.aidl",
+ },
+ {
+
+ name: "system_25",
+ properties: `sdk_version: "system_25",`,
+ bootclasspath: []string{`""`},
+ system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+ classpath: []string{"prebuilts/sdk/25/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/25/public/framework.aidl",
+ },
+ {
+
+ name: "test_current",
+ properties: `sdk_version: "test_current",`,
+ bootclasspath: []string{"android_test_stubs_current", "core-lambda-stubs"},
+ system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+ aidl: "-p" + buildDir + "/framework.aidl",
+ },
+ {
+
+ name: "core_current",
+ properties: `sdk_version: "core_current",`,
+ bootclasspath: []string{"core.current.stubs", "core-lambda-stubs"},
+ system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+ },
+ {
+
+ name: "nostdlib",
+ properties: `no_standard_libs: true, system_modules: "none"`,
+ system: "none",
+ bootclasspath: []string{`""`},
+ classpath: []string{},
+ },
+ {
+
+ name: "nostdlib system_modules",
+ properties: `no_standard_libs: true, system_modules: "core-platform-api-stubs-system-modules"`,
+ system: "core-platform-api-stubs-system-modules",
+ bootclasspath: []string{`""`},
+ classpath: []string{},
+ },
+ {
+
+ name: "host default",
+ moduleType: "java_library_host",
+ properties: ``,
+ host: android.Host,
+ bootclasspath: []string{"jdk8/jre/lib/jce.jar", "jdk8/jre/lib/rt.jar"},
+ classpath: []string{},
+ },
+ {
+ name: "host nostdlib",
+ moduleType: "java_library_host",
+ host: android.Host,
+ properties: `no_standard_libs: true`,
+ classpath: []string{},
+ },
+ {
+
+ name: "host supported default",
+ host: android.Host,
+ properties: `host_supported: true,`,
+ classpath: []string{},
+ bootclasspath: []string{"jdk8/jre/lib/jce.jar", "jdk8/jre/lib/rt.jar"},
+ },
+ {
+ name: "host supported nostdlib",
+ host: android.Host,
+ properties: `host_supported: true, no_standard_libs: true, system_modules: "none"`,
+ classpath: []string{},
+ },
+ {
+
+ name: "unbundled sdk v25",
+ unbundled: true,
+ properties: `sdk_version: "25",`,
+ bootclasspath: []string{`""`},
+ system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+ classpath: []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/25/public/framework.aidl",
+ },
+ {
+
+ name: "unbundled current",
+ unbundled: true,
+ properties: `sdk_version: "current",`,
+ bootclasspath: []string{`""`},
+ system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+ classpath: []string{"prebuilts/sdk/current/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/current/public/framework.aidl",
+ },
+
+ {
+ name: "pdk default",
+ pdk: true,
+ bootclasspath: []string{`""`},
+ system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+ classpath: []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/25/public/framework.aidl",
+ },
+ {
+ name: "pdk current",
+ pdk: true,
+ properties: `sdk_version: "current",`,
+ bootclasspath: []string{`""`},
+ system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+ classpath: []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/25/public/framework.aidl",
+ },
+ {
+ name: "pdk 25",
+ pdk: true,
+ properties: `sdk_version: "25",`,
+ bootclasspath: []string{`""`},
+ system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+ classpath: []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/25/public/framework.aidl",
+ },
+ }
+
for _, testcase := range classpathTestcases {
t.Run(testcase.name, func(t *testing.T) {
moduleType := "java_library"
@@ -193,6 +208,11 @@
bp := moduleType + ` {
name: "foo",
srcs: ["a.java"],
+ target: {
+ android: {
+ srcs: ["bar-doc/IFoo.aidl"],
+ },
+ },
` + testcase.properties + `
}`
@@ -228,18 +248,7 @@
system = "--system=" + filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system") + "/"
}
- t.Run("1.8", func(t *testing.T) {
- // Test default javac 1.8
- config := testConfig(nil)
- if testcase.unbundled {
- config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
- }
- if testcase.pdk {
- config.TestProductVariables.Pdk = proptools.BoolPtr(true)
- }
- ctx := testContext(config, bp, nil)
- run(t, ctx, config)
-
+ checkClasspath := func(t *testing.T, ctx *android.TestContext) {
javac := ctx.ModuleForTests("foo", variant).Rule("javac")
got := javac.Args["bootClasspath"]
@@ -261,6 +270,33 @@
if !reflect.DeepEqual(javac.Implicits.Strings(), deps) {
t.Errorf("implicits expected %q != got %q", deps, javac.Implicits.Strings())
}
+ }
+
+ t.Run("1.8", func(t *testing.T) {
+ // Test default javac 1.8
+ config := testConfig(nil)
+ if testcase.unbundled {
+ config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
+ }
+ if testcase.pdk {
+ config.TestProductVariables.Pdk = proptools.BoolPtr(true)
+ }
+ ctx := testContext(config, bp, nil)
+ run(t, ctx, config)
+
+ checkClasspath(t, ctx)
+
+ if testcase.host != android.Host {
+ aidl := ctx.ModuleForTests("foo", variant).Rule("aidl")
+
+ aidlFlags := aidl.Args["aidlFlags"]
+ // Trim trailing "-I." to avoid having to specify it in every test
+ aidlFlags = strings.TrimSpace(strings.TrimSuffix(aidlFlags, "-I."))
+
+ if g, w := aidlFlags, testcase.aidl; g != w {
+ t.Errorf("want aidl flags %q, got %q", w, g)
+ }
+ }
})
// Test again with javac 1.9
@@ -301,27 +337,7 @@
ctx := testContext(config, bp, nil)
run(t, ctx, config)
- javac := ctx.ModuleForTests("foo", variant).Rule("javac")
-
- got := javac.Args["bootClasspath"]
- if got != bc {
- t.Errorf("bootclasspath expected %q != got %q", bc, got)
- }
-
- got = javac.Args["classpath"]
- if got != c {
- t.Errorf("classpath expected %q != got %q", c, got)
- }
-
- var deps []string
- if len(bootclasspath) > 0 && bootclasspath[0] != `""` {
- deps = append(deps, bootclasspath...)
- }
- deps = append(deps, classpath...)
-
- if !reflect.DeepEqual(javac.Implicits.Strings(), deps) {
- t.Errorf("implicits expected %q != got %q", deps, javac.Implicits.Strings())
- }
+ checkClasspath(t, ctx)
})
})
}
diff --git a/java/testing.go b/java/testing.go
index 7d23d8f..1be3768 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -37,7 +37,6 @@
extraModules := []string{
"core-lambda-stubs",
- "framework",
"ext",
"android_stubs_current",
"android_system_stubs_current",
@@ -61,6 +60,17 @@
}
bp += `
+ java_library {
+ name: "framework",
+ srcs: ["a.java"],
+ no_standard_libs: true,
+ sdk_version: "core_current",
+ system_modules: "core-platform-api-stubs-system-modules",
+ aidl: {
+ export_include_dirs: ["framework/aidl"],
+ },
+ }
+
android_app {
name: "framework-res",
no_framework_libs: true,
diff --git a/scripts/build_broken_logs.go b/scripts/build_broken_logs.go
index f081f26..4f3e0de 100644
--- a/scripts/build_broken_logs.go
+++ b/scripts/build_broken_logs.go
@@ -60,32 +60,18 @@
warnings []string
}{
{
- name: "BUILD_BROKEN_DUP_COPY_HEADERS",
- behavior: DefaultDeprecated,
- warnings: []string{"Duplicate header copy:"},
- },
- {
name: "BUILD_BROKEN_DUP_RULES",
behavior: DefaultFalse,
warnings: []string{"overriding commands for target"},
},
{
name: "BUILD_BROKEN_ANDROIDMK_EXPORTS",
- behavior: DefaultFalse,
+ behavior: DefaultDeprecated,
warnings: []string{"export_keyword"},
},
{
- name: "BUILD_BROKEN_PHONY_TARGETS",
- behavior: DefaultFalse,
- warnings: []string{
- "depends on PHONY target",
- "looks like a real file",
- "writing to readonly directory",
- },
- },
- {
name: "BUILD_BROKEN_ENG_DEBUG_TAGS",
- behavior: DefaultTrue,
+ behavior: DefaultDeprecated,
warnings: []string{
"Changes.md#LOCAL_MODULE_TAGS",
},
diff --git a/scripts/strip.sh b/scripts/strip.sh
index d536907..0f77da8 100755
--- a/scripts/strip.sh
+++ b/scripts/strip.sh
@@ -24,6 +24,7 @@
# -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
@@ -32,11 +33,11 @@
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
@@ -71,6 +72,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 +139,21 @@
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 ;;
+ 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 +177,11 @@
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,6 +191,8 @@
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
else
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 48078d8..0313ecd 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -18,6 +18,7 @@
"android/soong/android"
"android/soong/cc"
"android/soong/java"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -63,10 +64,6 @@
return "lib" + m.Name()
}
-func (m *syspropLibrary) SyspropJavaModule() *java.SdkLibrary {
- return &m.SdkLibrary
-}
-
func syspropLibraryFactory() android.Module {
m := &syspropLibrary{}
@@ -77,7 +74,7 @@
m.InitSdkLibraryProperties()
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) })
return m
}
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index af89c24..d78238a 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -61,15 +61,11 @@
ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory))
ctx.RegisterModuleType("java_system_modules", android.ModuleFactoryAdaptor(java.SystemModulesFactory))
ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(java.PrebuiltApisFactory))
- ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("load_hooks", android.LoadHookMutator).Parallel()
- })
ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
ctx.TopDown("prebuilt_apis", java.PrebuiltApisMutator).Parallel()
- ctx.TopDown("java_sdk_library", java.SdkLibraryMutator).Parallel()
})
ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
@@ -106,6 +102,7 @@
"api/system-removed.txt": nil,
"api/test-current.txt": nil,
"api/test-removed.txt": nil,
+ "framework/aidl/a.aidl": nil,
"prebuilts/sdk/current/core/android.jar": nil,
"prebuilts/sdk/current/public/android.jar": nil,
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/config.go b/ui/build/config.go
index 7eb3a72..c298f00 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -53,9 +53,8 @@
pdkBuild bool
- brokenDupRules bool
- brokenPhonyTargets bool
- brokenUsesNetwork bool
+ brokenDupRules bool
+ brokenUsesNetwork bool
pathReplaced bool
}
@@ -615,14 +614,6 @@
return c.brokenDupRules
}
-func (c *configImpl) SetBuildBrokenPhonyTargets(val bool) {
- c.brokenPhonyTargets = val
-}
-
-func (c *configImpl) BuildBrokenPhonyTargets() bool {
- return c.brokenPhonyTargets
-}
-
func (c *configImpl) SetBuildBrokenUsesNetwork(val bool) {
c.brokenUsesNetwork = val
}
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 3e387c1..483c273 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -200,17 +200,49 @@
// Whether --werror_overriding_commands will work
"BUILD_BROKEN_DUP_RULES",
- // Used to turn on --werror_ options in Kati
- "BUILD_BROKEN_PHONY_TARGETS",
-
// Whether to enable the network during the build
"BUILD_BROKEN_USES_NETWORK",
// Not used, but useful to be in the soong.log
"BOARD_VNDK_VERSION",
"BUILD_BROKEN_ANDROIDMK_EXPORTS",
- "BUILD_BROKEN_DUP_COPY_HEADERS",
"BUILD_BROKEN_ENG_DEBUG_TAGS",
+
+ "DEFAULT_WARNING_BUILD_MODULE_TYPES",
+ "DEFAULT_ERROR_BUILD_MODULE_TYPES",
+ "BUILD_BROKEN_USES_BUILD_AUX_EXECUTABLE",
+ "BUILD_BROKEN_USES_BUILD_AUX_STATIC_LIBRARY",
+ "BUILD_BROKEN_USES_BUILD_COPY_HEADERS",
+ "BUILD_BROKEN_USES_BUILD_EXECUTABLE",
+ "BUILD_BROKEN_USES_BUILD_FUZZ_TEST",
+ "BUILD_BROKEN_USES_BUILD_HEADER_LIBRARY",
+ "BUILD_BROKEN_USES_BUILD_HOST_DALVIK_JAVA_LIBRARY",
+ "BUILD_BROKEN_USES_BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY",
+ "BUILD_BROKEN_USES_BUILD_HOST_EXECUTABLE",
+ "BUILD_BROKEN_USES_BUILD_HOST_FUZZ_TEST",
+ "BUILD_BROKEN_USES_BUILD_HOST_JAVA_LIBRARY",
+ "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",
+ "BUILD_BROKEN_USES_BUILD_JAVA_LIBRARY",
+ "BUILD_BROKEN_USES_BUILD_MULTI_PREBUILT",
+ "BUILD_BROKEN_USES_BUILD_NATIVE_BENCHMARK",
+ "BUILD_BROKEN_USES_BUILD_NATIVE_TEST",
+ "BUILD_BROKEN_USES_BUILD_NOTICE_FILE",
+ "BUILD_BROKEN_USES_BUILD_PACKAGE",
+ "BUILD_BROKEN_USES_BUILD_PHONY_PACKAGE",
+ "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",
+ "BUILD_BROKEN_USES_BUILD_TARGET_TEST_CONFIG",
}, exportEnvVars...), BannerVars...)
make_vars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true)
@@ -240,6 +272,5 @@
config.SetPdkBuild(make_vars["TARGET_BUILD_PDK"] == "true")
config.SetBuildBrokenDupRules(make_vars["BUILD_BROKEN_DUP_RULES"] == "true")
- config.SetBuildBrokenPhonyTargets(make_vars["BUILD_BROKEN_PHONY_TARGETS"] == "true")
config.SetBuildBrokenUsesNetwork(make_vars["BUILD_BROKEN_USES_NETWORK"] == "true")
}
diff --git a/ui/build/kati.go b/ui/build/kati.go
index 959d0bd..5ad966a 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -81,6 +81,9 @@
"--werror_suffix_rules",
"--warn_real_to_phony",
"--warn_phony_looks_real",
+ "--werror_real_to_phony",
+ "--werror_phony_looks_real",
+ "--werror_writable",
"--top_level_phony",
"--kati_stats",
}, args...)
@@ -138,13 +141,6 @@
args = append(args, "--werror_overriding_commands")
}
- if !config.BuildBrokenPhonyTargets() {
- args = append(args,
- "--werror_real_to_phony",
- "--werror_phony_looks_real",
- "--werror_writable")
- }
-
args = append(args, config.KatiArgs()...)
args = append(args,
@@ -162,11 +158,8 @@
args := []string{
"--writable", config.DistDir() + "/",
- "--werror_writable",
"--werror_implicit_rules",
"--werror_overriding_commands",
- "--werror_real_to_phony",
- "--werror_phony_looks_real",
"-f", "build/make/packaging/main.mk",
"KATI_PACKAGE_MK_DIR=" + config.KatiPackageMkDir(),
}
@@ -202,11 +195,8 @@
defer ctx.EndTrace()
runKati(ctx, config, katiCleanspecSuffix, []string{
- "--werror_writable",
"--werror_implicit_rules",
"--werror_overriding_commands",
- "--werror_real_to_phony",
- "--werror_phony_looks_real",
"-f", "build/make/core/cleanbuild.mk",
"SOONG_MAKEVARS_MK=" + config.SoongMakeVarsMk(),
"TARGET_DEVICE_DIR=" + config.TargetDeviceDir(),
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index ed2d9ca..54006d2 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,
@@ -104,7 +107,6 @@
"timeout": Allowed,
"tr": Allowed,
"unzip": Allowed,
- "xz": Allowed,
"zip": Allowed,
"zipinfo": Allowed,
@@ -134,7 +136,6 @@
"du": LinuxOnlyPrebuilt,
"echo": LinuxOnlyPrebuilt,
"env": LinuxOnlyPrebuilt,
- "expr": LinuxOnlyPrebuilt,
"head": LinuxOnlyPrebuilt,
"getconf": LinuxOnlyPrebuilt,
"hostname": LinuxOnlyPrebuilt,
diff --git a/zip/cmd/main.go b/zip/cmd/main.go
index b4f75f7..6f40a3e 100644
--- a/zip/cmd/main.go
+++ b/zip/cmd/main.go
@@ -105,12 +105,6 @@
nonDeflatedFiles = make(uniqueSet)
)
-func usage() {
- fmt.Fprintf(os.Stderr, "usage: soong_zip -o zipfile [-m manifest] [-C dir] [-f|-l file] [-D dir]...\n")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
func main() {
var expandedArgs []string
for _, arg := range os.Args {
@@ -128,7 +122,11 @@
}
flags := flag.NewFlagSet("flags", flag.ExitOnError)
- flags.Usage = usage
+ flags.Usage = func() {
+ fmt.Fprintf(os.Stderr, "usage: soong_zip -o zipfile [-m manifest] [-C dir] [-f|-l file] [-D dir]...\n")
+ flags.PrintDefaults()
+ os.Exit(2)
+ }
out := flags.String("o", "", "file to write zip file to")
manifest := flags.String("m", "", "input jar manifest file name")