Merge "Switch to clang-r383902 (11.0.1)." into rvc-dev
diff --git a/Android.bp b/Android.bp
index 352cf80..a81676f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -187,6 +187,7 @@
"cc/rs.go",
"cc/sanitize.go",
"cc/sabi.go",
+ "cc/sdk.go",
"cc/snapshot_utils.go",
"cc/stl.go",
"cc/strip.go",
diff --git a/android/apex.go b/android/apex.go
index c7410a1..19f58d3 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -18,6 +18,7 @@
"fmt"
"sort"
"strconv"
+ "strings"
"sync"
"github.com/google/blueprint"
@@ -395,3 +396,52 @@
m.AddProperties(&base.ApexProperties)
}
+
+// A dependency info for a single ApexModule, either direct or transitive.
+type ApexModuleDepInfo struct {
+ // Name of the dependency
+ To string
+ // List of dependencies To belongs to. Includes APEX itself, if a direct dependency.
+ From []string
+ // Whether the dependency belongs to the final compiled APEX.
+ IsExternal bool
+}
+
+// A map of a dependency name to its ApexModuleDepInfo
+type DepNameToDepInfoMap map[string]ApexModuleDepInfo
+
+type ApexBundleDepsInfo struct {
+ fullListPath OutputPath
+}
+
+type ApexDepsInfoIntf interface {
+ FullListPath() Path
+}
+
+func (d *ApexBundleDepsInfo) FullListPath() Path {
+ return d.fullListPath
+}
+
+var _ ApexDepsInfoIntf = (*ApexBundleDepsInfo)(nil)
+
+func (d *ApexBundleDepsInfo) BuildDepsInfoLists(ctx ModuleContext, depInfos DepNameToDepInfoMap) {
+ var content strings.Builder
+ for _, key := range FirstUniqueStrings(SortedStringKeys(depInfos)) {
+ info := depInfos[key]
+ toName := info.To
+ if info.IsExternal {
+ toName = toName + " (external)"
+ }
+ fmt.Fprintf(&content, "%s <- %s\\n", toName, strings.Join(SortedUniqueStrings(info.From), ", "))
+ }
+
+ d.fullListPath = PathForModuleOut(ctx, "depsinfo", "fulllist.txt").OutputPath
+ ctx.Build(pctx, BuildParams{
+ Rule: WriteFile,
+ Description: "Full Dependency Info",
+ Output: d.fullListPath,
+ Args: map[string]string{
+ "content": content.String(),
+ },
+ })
+}
diff --git a/android/api_levels.go b/android/api_levels.go
index b6296d8..0872066 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -73,6 +73,7 @@
"O-MR1": 27,
"P": 28,
"Q": 29,
+ "R": 30,
}
for i, codename := range config.PlatformVersionActiveCodenames() {
apiLevelsMap[codename] = baseApiLevel + i
diff --git a/android/defaults.go b/android/defaults.go
index fd707a4..6a908ea 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -176,18 +176,18 @@
defaultsVisibility := module.defaultsVisibility()
module.AddProperties(&base.nameProperties, defaultsVisibility)
- // The defaults_visibility property controls the visibility of a defaults module.
- base.primaryVisibilityProperty =
- newVisibilityProperty("defaults_visibility", &defaultsVisibility.Defaults_visibility)
-
// Unlike non-defaults modules the visibility property is not stored in m.base().commonProperties.
- // Instead it is stored in a separate instance of commonProperties created above so use that.
+ // Instead it is stored in a separate instance of commonProperties created above so clear the
+ // existing list of properties.
+ clearVisibilityProperties(module)
+
+ // The defaults_visibility property controls the visibility of a defaults module so it must be
+ // set as the primary property, which also adds it to the list.
+ setPrimaryVisibilityProperty(module, "defaults_visibility", &defaultsVisibility.Defaults_visibility)
+
// The visibility property needs to be checked (but not parsed) by the visibility module during
- // its checking phase and parsing phase.
- base.visibilityPropertyInfo = []visibilityProperty{
- base.primaryVisibilityProperty,
- newVisibilityProperty("visibility", &commonProperties.Visibility),
- }
+ // its checking phase and parsing phase so add it to the list as a normal property.
+ AddVisibilityProperty(module, "visibility", &commonProperties.Visibility)
base.module = module
}
diff --git a/android/module.go b/android/module.go
index d9e655a..1f17eda 100644
--- a/android/module.go
+++ b/android/module.go
@@ -607,10 +607,8 @@
base.customizableProperties = m.GetProperties()
// The default_visibility property needs to be checked and parsed by the visibility module during
- // its checking and parsing phases.
- base.primaryVisibilityProperty =
- newVisibilityProperty("visibility", &base.commonProperties.Visibility)
- base.visibilityPropertyInfo = []visibilityProperty{base.primaryVisibilityProperty}
+ // its checking and parsing phases so make it the primary visibility property.
+ setPrimaryVisibilityProperty(m, "visibility", &base.commonProperties.Visibility)
}
func InitAndroidArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) {
diff --git a/android/neverallow.go b/android/neverallow.go
index 4d3a16f..cf09792 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -54,6 +54,7 @@
AddNeverAllowRules(createLibcoreRules()...)
AddNeverAllowRules(createMediaRules()...)
AddNeverAllowRules(createJavaDeviceForHostRules()...)
+ AddNeverAllowRules(createCcSdkVariantRules()...)
}
// Add a NeverAllow rule to the set of rules to apply.
@@ -177,6 +178,37 @@
}
}
+func createCcSdkVariantRules() []Rule {
+ sdkVersionOnlyWhitelist := []string{
+ // derive_sdk_prefer32 has stem: "derive_sdk" which conflicts with the derive_sdk.
+ // This sometimes works because the APEX modules that contain derive_sdk and
+ // derive_sdk_prefer32 suppress the platform installation rules, but fails when
+ // the APEX modules contain the SDK variant and the platform variant still exists.
+ "frameworks/base/apex/sdkextensions/derive_sdk",
+ }
+
+ platformVariantPropertiesWhitelist := []string{
+ // android_native_app_glue and libRSSupport use native_window.h but target old
+ // sdk versions (minimum and 9 respectively) where libnativewindow didn't exist,
+ // so they can't add libnativewindow to shared_libs to get the header directory
+ // for the platform variant. Allow them to use the platform variant
+ // property to set shared_libs.
+ "prebuilts/ndk",
+ "frameworks/rs",
+ }
+
+ return []Rule{
+ NeverAllow().
+ NotIn(sdkVersionOnlyWhitelist...).
+ WithMatcher("sdk_variant_only", isSetMatcherInstance).
+ Because("sdk_variant_only can only be used in whitelisted projects"),
+ NeverAllow().
+ NotIn(platformVariantPropertiesWhitelist...).
+ WithMatcher("platform.shared_libs", isSetMatcherInstance).
+ Because("platform variant properties can only be used in whitelisted projects"),
+ }
+}
+
func neverallowMutator(ctx BottomUpMutatorContext) {
m, ok := ctx.Module().(Module)
if !ok {
@@ -268,6 +300,18 @@
return ".regexp(" + m.re.String() + ")"
}
+type isSetMatcher struct{}
+
+func (m *isSetMatcher) Test(value string) bool {
+ return value != ""
+}
+
+func (m *isSetMatcher) String() string {
+ return ".is-set"
+}
+
+var isSetMatcherInstance = &isSetMatcher{}
+
type ruleProperty struct {
fields []string // e.x.: Vndk.Enabled
matcher ValueMatcher
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 83b2250..2fc42e3 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -259,6 +259,50 @@
}`),
},
},
+ // CC sdk rule tests
+ {
+ name: `"sdk_variant_only" outside whitelist`,
+ fs: map[string][]byte{
+ "Android.bp": []byte(`
+ cc_library {
+ name: "outside_whitelist",
+ sdk_version: "current",
+ sdk_variant_only: true,
+ }`),
+ },
+ expectedErrors: []string{
+ `module "outside_whitelist": violates neverallow`,
+ },
+ },
+ {
+ name: `"sdk_variant_only: false" outside whitelist`,
+ fs: map[string][]byte{
+ "Android.bp": []byte(`
+ cc_library {
+ name: "outside_whitelist",
+ sdk_version: "current",
+ sdk_variant_only: false,
+ }`),
+ },
+ expectedErrors: []string{
+ `module "outside_whitelist": violates neverallow`,
+ },
+ },
+ {
+ name: `"platform" outside whitelist`,
+ fs: map[string][]byte{
+ "Android.bp": []byte(`
+ cc_library {
+ name: "outside_whitelist",
+ platform: {
+ shared_libs: ["libfoo"],
+ },
+ }`),
+ },
+ expectedErrors: []string{
+ `module "outside_whitelist": violates neverallow`,
+ },
+ },
}
func TestNeverallow(t *testing.T) {
@@ -299,6 +343,8 @@
Include_dirs []string
Vendor_available *bool
Static_libs []string
+ Sdk_version *string
+ Sdk_variant_only *bool
Vndk struct {
Enabled *bool
@@ -315,6 +361,10 @@
Cflags []string
}
}
+
+ Platform struct {
+ Shared_libs []string
+ }
}
type mockCcLibraryModule struct {
diff --git a/android/package.go b/android/package.go
index 077c4a4..bb5f4e7 100644
--- a/android/package.go
+++ b/android/package.go
@@ -101,10 +101,8 @@
module.AddProperties(&module.properties)
// The default_visibility property needs to be checked and parsed by the visibility module during
- // its checking and parsing phases.
- module.primaryVisibilityProperty =
- newVisibilityProperty("default_visibility", &module.properties.Default_visibility)
- module.visibilityPropertyInfo = []visibilityProperty{module.primaryVisibilityProperty}
+ // its checking and parsing phases so make it the primary visibility property.
+ setPrimaryVisibilityProperty(module, "default_visibility", &module.properties.Default_visibility)
return module
}
diff --git a/android/visibility.go b/android/visibility.go
index 3f04123..1e3b91d 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -246,14 +246,8 @@
}
for _, v := range visibility {
- ok, pkg, name := splitRule(v, currentPkg)
+ ok, pkg, name := splitRule(ctx, v, currentPkg, property)
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(property,
- "invalid visibility pattern %q must match"+
- " //<package>:<module>, //<package> or :<module>",
- v)
continue
}
@@ -301,21 +295,24 @@
// Parse the visibility rules that control access to the module and store them by id
// for use when enforcing the rules.
- if visibility := m.visibility(); visibility != nil {
- rule := parseRules(ctx, currentPkg, m.visibility())
- if rule != nil {
- moduleToVisibilityRuleMap(ctx.Config()).Store(qualifiedModuleId, rule)
+ primaryProperty := m.base().primaryVisibilityProperty
+ if primaryProperty != nil {
+ if visibility := primaryProperty.getStrings(); visibility != nil {
+ rule := parseRules(ctx, currentPkg, primaryProperty.getName(), visibility)
+ if rule != nil {
+ moduleToVisibilityRuleMap(ctx.Config()).Store(qualifiedModuleId, rule)
+ }
}
}
}
-func parseRules(ctx BaseModuleContext, currentPkg string, visibility []string) compositeRule {
+func parseRules(ctx BaseModuleContext, currentPkg, property string, visibility []string) compositeRule {
rules := make(compositeRule, 0, len(visibility))
hasPrivateRule := false
hasPublicRule := false
hasNonPrivateRule := false
for _, v := range visibility {
- ok, pkg, name := splitRule(v, currentPkg)
+ ok, pkg, name := splitRule(ctx, v, currentPkg, property)
if !ok {
continue
}
@@ -376,10 +373,16 @@
return !isAncestor("vendor", pkg)
}
-func splitRule(ruleExpression string, currentPkg string) (bool, string, string) {
+func splitRule(ctx BaseModuleContext, ruleExpression string, currentPkg, property string) (bool, string, string) {
// Make sure that the rule is of the correct format.
matches := visibilityRuleRegexp.FindStringSubmatch(ruleExpression)
if ruleExpression == "" || matches == nil {
+ // 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(property,
+ "invalid visibility pattern %q must match"+
+ " //<package>:<module>, //<package> or :<module>",
+ ruleExpression)
return false, "", ""
}
@@ -480,3 +483,28 @@
return rule.Strings()
}
+
+// Clear the default visibility properties so they can be replaced.
+func clearVisibilityProperties(module Module) {
+ module.base().visibilityPropertyInfo = nil
+}
+
+// Add a property that contains visibility rules so that they are checked for
+// correctness.
+func AddVisibilityProperty(module Module, name string, stringsProperty *[]string) {
+ addVisibilityProperty(module, name, stringsProperty)
+}
+
+func addVisibilityProperty(module Module, name string, stringsProperty *[]string) visibilityProperty {
+ base := module.base()
+ property := newVisibilityProperty(name, stringsProperty)
+ base.visibilityPropertyInfo = append(base.visibilityPropertyInfo, property)
+ return property
+}
+
+// Set the primary visibility property.
+//
+// Also adds the property to the list of properties to be validated.
+func setPrimaryVisibilityProperty(module Module, name string, stringsProperty *[]string) {
+ module.base().primaryVisibilityProperty = addVisibilityProperty(module, name, stringsProperty)
+}
diff --git a/apex/apex.go b/apex/apex.go
index 6a0c4c1..45ba908 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1276,12 +1276,6 @@
return false
}
-type depInfo struct {
- to string
- from []string
- isExternal bool
-}
-
type apexBundle struct {
android.ModuleBase
android.DefaultableModuleBase
@@ -1316,7 +1310,7 @@
requiredDeps []string
// list of module names that this APEX is including (to be shown via *-deps-info target)
- depInfos map[string]depInfo
+ android.ApexBundleDepsInfo
testApex bool
vndkApex bool
@@ -1871,38 +1865,11 @@
if String(a.properties.Min_sdk_version) == "" {
ctx.PropertyErrorf("updatable", "updatable APEXes should set min_sdk_version as well")
}
+
+ a.checkJavaStableSdkVersion(ctx)
}
}
-// Collects the list of module names that directly or indirectly contributes to the payload of this APEX
-func (a *apexBundle) collectDepsInfo(ctx android.ModuleContext) {
- a.depInfos = make(map[string]depInfo)
- a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
- if from.Name() == to.Name() {
- // This can happen for cc.reuseObjTag. We are not interested in tracking this.
- // As soon as the dependency graph crosses the APEX boundary, don't go further.
- return !externalDep
- }
-
- if info, exists := a.depInfos[to.Name()]; exists {
- if !android.InList(from.Name(), info.from) {
- info.from = append(info.from, from.Name())
- }
- info.isExternal = info.isExternal && externalDep
- a.depInfos[to.Name()] = info
- } else {
- a.depInfos[to.Name()] = depInfo{
- to: to.Name(),
- from: []string{from.Name()},
- isExternal: externalDep,
- }
- }
-
- // As soon as the dependency graph crosses the APEX boundary, don't go further.
- return !externalDep
- })
-}
-
func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild()
switch a.properties.ApexType {
@@ -1941,8 +1908,6 @@
a.checkApexAvailability(ctx)
a.checkUpdatable(ctx)
- a.collectDepsInfo(ctx)
-
handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
// native lib dependencies
@@ -2247,6 +2212,23 @@
a.buildApexDependencyInfo(ctx)
}
+// Enforce that Java deps of the apex are using stable SDKs to compile
+func (a *apexBundle) checkJavaStableSdkVersion(ctx android.ModuleContext) {
+ // Visit direct deps only. As long as we guarantee top-level deps are using
+ // stable SDKs, java's checkLinkType guarantees correct usage for transitive deps
+ ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
+ tag := ctx.OtherModuleDependencyTag(module)
+ switch tag {
+ case javaLibTag, androidAppTag:
+ if m, ok := module.(interface{ CheckStableSdkVersion() error }); ok {
+ if err := m.CheckStableSdkVersion(); err != nil {
+ ctx.ModuleErrorf("cannot depend on \"%v\": %v", ctx.OtherModuleName(module), err)
+ }
+ }
+ }
+ })
+}
+
func whitelistedApexAvailable(apex, moduleName string) bool {
key := apex
moduleName = normalizeModuleName(moduleName)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 5451fa2..f0e7ff3 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -478,7 +478,7 @@
ensureListContains(t, noticeInputs, "custom_notice")
ensureListContains(t, noticeInputs, "custom_notice_for_static_lib")
- depsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("myapex-deps-info.txt").Args["content"], "\\n")
+ depsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
ensureListContains(t, depsInfo, "myjar <- myapex")
ensureListContains(t, depsInfo, "mylib <- myapex")
ensureListContains(t, depsInfo, "mylib2 <- mylib")
@@ -784,7 +784,7 @@
// Ensure that libfoo stubs is not linking to libbar (since it is a stubs)
ensureNotContains(t, libFooStubsLdFlags, "libbar.so")
- depsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("myapex2-deps-info.txt").Args["content"], "\\n")
+ depsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
ensureListContains(t, depsInfo, "mylib <- myapex2")
ensureListContains(t, depsInfo, "libbaz <- mylib")
@@ -1377,6 +1377,122 @@
`)
}
+func TestJavaStableSdkVersion(t *testing.T) {
+ testCases := []struct {
+ name string
+ expectedError string
+ bp string
+ }{
+ {
+ name: "Non-updatable apex with non-stable dep",
+ bp: `
+ apex {
+ name: "myapex",
+ java_libs: ["myjar"],
+ key: "myapex.key",
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ java_library {
+ name: "myjar",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "core_platform",
+ apex_available: ["myapex"],
+ }
+ `,
+ },
+ {
+ name: "Updatable apex with stable dep",
+ bp: `
+ apex {
+ name: "myapex",
+ java_libs: ["myjar"],
+ key: "myapex.key",
+ updatable: true,
+ min_sdk_version: "29",
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ java_library {
+ name: "myjar",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "current",
+ apex_available: ["myapex"],
+ }
+ `,
+ },
+ {
+ name: "Updatable apex with non-stable dep",
+ expectedError: "cannot depend on \"myjar\"",
+ bp: `
+ apex {
+ name: "myapex",
+ java_libs: ["myjar"],
+ key: "myapex.key",
+ updatable: true,
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ java_library {
+ name: "myjar",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "core_platform",
+ apex_available: ["myapex"],
+ }
+ `,
+ },
+ {
+ name: "Updatable apex with non-stable transitive dep",
+ expectedError: "compiles against Android API, but dependency \"transitive-jar\" is compiling against non-public Android API.",
+ bp: `
+ apex {
+ name: "myapex",
+ java_libs: ["myjar"],
+ key: "myapex.key",
+ updatable: true,
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ java_library {
+ name: "myjar",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "current",
+ apex_available: ["myapex"],
+ static_libs: ["transitive-jar"],
+ }
+ java_library {
+ name: "transitive-jar",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "core_platform",
+ apex_available: ["myapex"],
+ }
+ `,
+ },
+ }
+
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ if test.expectedError == "" {
+ testApex(t, test.bp)
+ } else {
+ testApexError(t, test.expectedError, test.bp)
+ }
+ })
+ }
+}
+
func TestFilesInSubDir(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -3323,18 +3439,20 @@
android_app {
name: "AppFoo",
srcs: ["foo/bar/MyClass.java"],
- sdk_version: "none",
+ sdk_version: "current",
system_modules: "none",
jni_libs: ["libjni"],
+ stl: "none",
apex_available: [ "myapex" ],
}
android_app {
name: "AppFooPriv",
srcs: ["foo/bar/MyClass.java"],
- sdk_version: "none",
+ sdk_version: "current",
system_modules: "none",
privileged: true,
+ stl: "none",
apex_available: [ "myapex" ],
}
@@ -3371,7 +3489,7 @@
}
// JNI libraries including transitive deps are
for _, jni := range []string{"libjni", "libfoo"} {
- jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module).OutputFile()
+ jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_myapex").Module().(*cc.Module).OutputFile()
// ... embedded inside APK (jnilibs.zip)
ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String())
// ... and not directly inside the APEX
@@ -4287,6 +4405,7 @@
java_library {
name: "some-updatable-apex-lib",
srcs: ["a.java"],
+ sdk_version: "current",
apex_available: [
"some-updatable-apex",
],
@@ -4295,12 +4414,14 @@
java_library {
name: "some-platform-lib",
srcs: ["a.java"],
+ sdk_version: "current",
installable: true,
}
java_library {
name: "some-art-lib",
srcs: ["a.java"],
+ sdk_version: "current",
apex_available: [
"com.android.art.something",
],
diff --git a/apex/builder.go b/apex/builder.go
index 0d7e801..a3e6929 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -679,29 +679,37 @@
return
}
- var content strings.Builder
- for _, key := range android.SortedStringKeys(a.depInfos) {
- info := a.depInfos[key]
- toName := info.to
- if info.isExternal {
- toName = toName + " (external)"
+ depInfos := android.DepNameToDepInfoMap{}
+ a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ if from.Name() == to.Name() {
+ // This can happen for cc.reuseObjTag. We are not interested in tracking this.
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
+ return !externalDep
}
- fmt.Fprintf(&content, "%s <- %s\\n", toName, strings.Join(android.SortedUniqueStrings(info.from), ", "))
- }
- depsInfoFile := android.PathForOutput(ctx, a.Name()+"-deps-info.txt")
- ctx.Build(pctx, android.BuildParams{
- Rule: android.WriteFile,
- Description: "Dependency Info",
- Output: depsInfoFile,
- Args: map[string]string{
- "content": content.String(),
- },
+ if info, exists := depInfos[to.Name()]; exists {
+ if !android.InList(from.Name(), info.From) {
+ info.From = append(info.From, from.Name())
+ }
+ info.IsExternal = info.IsExternal && externalDep
+ depInfos[to.Name()] = info
+ } else {
+ depInfos[to.Name()] = android.ApexModuleDepInfo{
+ To: to.Name(),
+ From: []string{from.Name()},
+ IsExternal: externalDep,
+ }
+ }
+
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
+ return !externalDep
})
+ a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, depInfos)
+
ctx.Build(pctx, android.BuildParams{
Rule: android.Phony,
Output: android.PathForPhony(ctx, a.Name()+"-deps-info"),
- Inputs: []android.Path{depsInfoFile},
+ Inputs: []android.Path{a.ApexBundleDepsInfo.FullListPath()},
})
}
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index 54447fa..523ac26 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -143,6 +143,7 @@
system_shared_libs: [],
stl: "none",
notice: "custom_notice",
+ sdk_version: "current",
}
cc_library {
name: "libprofile-clang-extras_ndk",
@@ -151,6 +152,7 @@
system_shared_libs: [],
stl: "none",
notice: "custom_notice",
+ sdk_version: "current",
}
`, func(fs map[string][]byte, config android.Config) {
config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 1c90aaf..5438b14 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -29,6 +29,7 @@
vendorSuffix = ".vendor"
ramdiskSuffix = ".ramdisk"
recoverySuffix = ".recovery"
+ sdkSuffix = ".sdk"
)
type AndroidMkContext interface {
@@ -103,6 +104,28 @@
}
}
}
+ if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake {
+ // Make the SDK variant uninstallable so that there are not two rules to install
+ // to the same location.
+ entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+ // Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite
+ // dependencies to the .sdk suffix when building a module that uses the SDK.
+ entries.SetString("SOONG_SDK_VARIANT_MODULES",
+ "$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))")
+ }
+ },
+ },
+ ExtraFooters: []android.AndroidMkExtraFootersFunc{
+ func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+ if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake &&
+ c.CcLibraryInterface() && c.Shared() {
+ // Using the SDK variant as a JNI library needs a copy of the .so that
+ // is not named .sdk.so so that it can be packaged into the APK with
+ // the right name.
+ fmt.Fprintln(w, "$(eval $(call copy-one-file,",
+ "$(LOCAL_BUILT_MODULE),",
+ "$(patsubst %.sdk.so,%.so,$(LOCAL_BUILT_MODULE))))")
+ }
},
},
}
@@ -397,6 +420,9 @@
}
func (installer *baseInstaller) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ if installer.path == (android.InstallPath{}) {
+ return
+ }
// Soong installation is only supported for host modules. Have Make
// installation trigger Soong installation.
if ctx.Target().Os.Class == android.Host {
diff --git a/cc/cc.go b/cc/cc.go
index a92495c..b237935 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -42,6 +42,7 @@
ctx.RegisterModuleType("cc_defaults", defaultsFactory)
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("sdk", sdkMutator).Parallel()
ctx.BottomUp("vndk", VndkMutator).Parallel()
ctx.BottomUp("link", LinkageMutator).Parallel()
ctx.BottomUp("ndk_api", NdkApiMutator).Parallel()
@@ -208,12 +209,16 @@
// Deprecated. true is the default, false is invalid.
Clang *bool `android:"arch_variant"`
- // Minimum sdk version supported when compiling against the ndk
+ // Minimum sdk version supported when compiling against the ndk. Setting this property causes
+ // two variants to be built, one for the platform and one for apps.
Sdk_version *string
// Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
Min_sdk_version *string
+ // If true, always create an sdk variant and don't create a platform variant.
+ Sdk_variant_only *bool
+
AndroidMkSharedLibs []string `blueprint:"mutated"`
AndroidMkStaticLibs []string `blueprint:"mutated"`
AndroidMkRuntimeLibs []string `blueprint:"mutated"`
@@ -255,6 +260,16 @@
SnapshotRuntimeLibs []string `blueprint:"mutated"`
Installable *bool
+
+ // Set by factories of module types that can only be referenced from variants compiled against
+ // the SDK.
+ AlwaysSdk bool `blueprint:"mutated"`
+
+ // Variant is an SDK variant created by sdkMutator
+ IsSdkVariant bool `blueprint:"mutated"`
+ // Set when both SDK and platform variants are exported to Make to trigger renaming the SDK
+ // variant to have a ".sdk" suffix.
+ SdkAndPlatformVariantVisibleToMake bool `blueprint:"mutated"`
}
type VendorProperties struct {
@@ -534,7 +549,10 @@
}
func (c *Module) SelectedStl() string {
- return c.stl.Properties.SelectedStl
+ if c.stl != nil {
+ return c.stl.Properties.SelectedStl
+ }
+ return ""
}
func (c *Module) ToolchainLibrary() bool {
@@ -562,6 +580,10 @@
return String(c.Properties.Sdk_version)
}
+func (c *Module) AlwaysSdk() bool {
+ return c.Properties.AlwaysSdk || Bool(c.Properties.Sdk_variant_only)
+}
+
func (c *Module) IncludeDirs() android.Paths {
if c.linker != nil {
if library, ok := c.linker.(exportedFlagsProducer); ok {
@@ -821,6 +843,17 @@
return c.Properties.VndkVersion != ""
}
+func (c *Module) canUseSdk() bool {
+ return c.Os() == android.Android && !c.UseVndk() && !c.InRamdisk() && !c.InRecovery()
+}
+
+func (c *Module) UseSdk() bool {
+ if c.canUseSdk() {
+ return String(c.Properties.Sdk_version) != ""
+ }
+ return false
+}
+
func (c *Module) isCoverageVariant() bool {
return c.coverage.Properties.IsCoverageVariant
}
@@ -1078,14 +1111,11 @@
}
func (ctx *moduleContextImpl) canUseSdk() bool {
- return ctx.ctx.Device() && !ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && !ctx.ctx.Fuchsia()
+ return ctx.mod.canUseSdk()
}
func (ctx *moduleContextImpl) useSdk() bool {
- if ctx.canUseSdk() {
- return String(ctx.mod.Properties.Sdk_version) != ""
- }
- return false
+ return ctx.mod.UseSdk()
}
func (ctx *moduleContextImpl) sdkVersion() string {
@@ -1404,6 +1434,8 @@
c.Properties.SubName += ramdiskSuffix
} else if c.InRecovery() && !c.OnlyInRecovery() {
c.Properties.SubName += recoverySuffix
+ } else if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake {
+ c.Properties.SubName += sdkSuffix
}
ctx := &moduleContext{
diff --git a/cc/library.go b/cc/library.go
index c3b20b6..ce814b1 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1224,7 +1224,7 @@
if Bool(library.Properties.Static_ndk_lib) && library.static() &&
!ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && ctx.Device() &&
library.baseLinker.sanitize.isUnsanitizedVariant() &&
- !library.buildStubs() {
+ !library.buildStubs() && ctx.sdkVersion() == "" {
installPath := getNdkSysrootBase(ctx).Join(
ctx, "usr/lib", config.NDKTriple(ctx.toolchain()), file.Base())
diff --git a/cc/linkable.go b/cc/linkable.go
index 9147681..4a70d48 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -47,12 +47,14 @@
InRecovery() bool
OnlyInRecovery() bool
+ UseSdk() bool
UseVndk() bool
MustUseVendorVariant() bool
IsVndk() bool
HasVendorVariant() bool
SdkVersion() string
+ AlwaysSdk() bool
ToolchainLibrary() bool
NdkPrebuiltStl() bool
diff --git a/cc/linker.go b/cc/linker.go
index aa2d0ab..9b2c1e7 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -158,6 +158,13 @@
// the ramdisk variant of the C/C++ module.
Exclude_static_libs []string
}
+ Platform struct {
+ // list of shared libs that should be use to build the platform variant
+ // of a module that sets sdk_version. This should rarely be necessary,
+ // in most cases the same libraries are available for the SDK and platform
+ // variants.
+ Shared_libs []string
+ }
}
// make android::build:GetBuildNumber() available containing the build ID.
@@ -255,6 +262,10 @@
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
}
+ if !ctx.useSdk() {
+ deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Target.Platform.Shared_libs...)
+ }
+
if ctx.toolchain().Bionic() {
// libclang_rt.builtins and libatomic have to be last on the command line
if !Bool(linker.Properties.No_libcrt) {
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index eb8e9d3..119ca40 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -385,6 +385,9 @@
module.linker = stub
module.installer = stub
+ module.Properties.AlwaysSdk = true
+ module.Properties.Sdk_version = StringPtr("current")
+
module.AddProperties(&stub.properties, &library.MutatedProperties)
return module
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index 3a630d2..c4d7708 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -76,6 +76,8 @@
baseLinker: NewBaseLinker(nil),
},
}
+ module.Properties.AlwaysSdk = true
+ module.Properties.Sdk_version = StringPtr("current")
module.Properties.HideFromMake = true
return module.Init()
}
@@ -125,10 +127,9 @@
libraryDecorator: library,
}
module.installer = nil
- minVersionString := "minimum"
- noStlString := "none"
- module.Properties.Sdk_version = &minVersionString
- module.stl.Properties.Stl = &noStlString
+ module.Properties.Sdk_version = StringPtr("minimum")
+ module.Properties.AlwaysSdk = true
+ module.stl.Properties.Stl = StringPtr("none")
return module.Init()
}
@@ -145,6 +146,9 @@
}
module.installer = nil
module.Properties.HideFromMake = true
+ module.Properties.AlwaysSdk = true
+ module.Properties.Sdk_version = StringPtr("current")
+ module.stl.Properties.Stl = StringPtr("none")
module.ModuleBase.EnableNativeBridgeSupportByDefault()
return module.Init()
}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index f12edc6..371f270 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -1041,7 +1041,7 @@
}
// Export the static lib name to make
- if c.static() {
+ if c.static() && c.ExportedToMake() {
if t == cfi {
appendStringSync(c.Name(), cfiStaticLibs(mctx.Config()), &cfiStaticLibsMutex)
} else if t == hwasan {
diff --git a/cc/sdk.go b/cc/sdk.go
new file mode 100644
index 0000000..d05a04a
--- /dev/null
+++ b/cc/sdk.go
@@ -0,0 +1,65 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+ "android/soong/android"
+ "android/soong/genrule"
+)
+
+// sdkMutator sets a creates a platform and an SDK variant for modules
+// that set sdk_version, and ignores sdk_version for the platform
+// variant. The SDK variant will be used for embedding in APKs
+// that may be installed on older platforms. Apexes use their own
+// variants that enforce backwards compatibility.
+func sdkMutator(ctx android.BottomUpMutatorContext) {
+ if ctx.Os() != android.Android {
+ return
+ }
+
+ switch m := ctx.Module().(type) {
+ case LinkableInterface:
+ if m.AlwaysSdk() {
+ if !m.UseSdk() {
+ ctx.ModuleErrorf("UseSdk() must return true when AlwaysSdk is set, did the factory forget to set Sdk_version?")
+ }
+ ctx.CreateVariations("sdk")
+ } else if m.UseSdk() {
+ modules := ctx.CreateVariations("", "sdk")
+ modules[0].(*Module).Properties.Sdk_version = nil
+ modules[1].(*Module).Properties.IsSdkVariant = true
+
+ if ctx.Config().UnbundledBuild() {
+ modules[0].(*Module).Properties.HideFromMake = true
+ } else {
+ modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
+ modules[1].(*Module).Properties.PreventInstall = true
+ }
+ ctx.AliasVariation("")
+ } else {
+ ctx.CreateVariations("")
+ ctx.AliasVariation("")
+ }
+ case *genrule.Module:
+ if p, ok := m.Extra.(*GenruleExtraProperties); ok {
+ if String(p.Sdk_version) != "" {
+ ctx.CreateVariations("", "sdk")
+ } else {
+ ctx.CreateVariations("")
+ }
+ ctx.AliasVariation("")
+ }
+ }
+}
diff --git a/cc/sdk_test.go b/cc/sdk_test.go
new file mode 100644
index 0000000..5a3c181
--- /dev/null
+++ b/cc/sdk_test.go
@@ -0,0 +1,102 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+ "testing"
+
+ "android/soong/android"
+)
+
+func TestSdkMutator(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libsdk",
+ shared_libs: ["libsdkdep"],
+ sdk_version: "current",
+ stl: "c++_shared",
+ }
+
+ cc_library {
+ name: "libsdkdep",
+ sdk_version: "current",
+ stl: "c++_shared",
+ }
+
+ cc_library {
+ name: "libplatform",
+ shared_libs: ["libsdk"],
+ stl: "libc++",
+ }
+
+ cc_binary {
+ name: "platformbinary",
+ shared_libs: ["libplatform"],
+ stl: "libc++",
+ }
+
+ cc_binary {
+ name: "sdkbinary",
+ shared_libs: ["libsdk"],
+ sdk_version: "current",
+ stl: "libc++",
+ }
+ `
+
+ assertDep := func(t *testing.T, from, to android.TestingModule) {
+ t.Helper()
+ found := false
+
+ var toFile android.Path
+ m := to.Module().(*Module)
+ if toc := m.Toc(); toc.Valid() {
+ toFile = toc.Path()
+ } else {
+ toFile = m.outputFile.Path()
+ }
+
+ rule := from.Description("link")
+ for _, dep := range rule.Implicits {
+ if dep.String() == toFile.String() {
+ found = true
+ }
+ }
+ if !found {
+ t.Errorf("expected %q in %q", toFile.String(), rule.Implicits.Strings())
+ }
+ }
+
+ ctx := testCc(t, bp)
+
+ libsdkNDK := ctx.ModuleForTests("libsdk", "android_arm64_armv8-a_sdk_shared")
+ libsdkPlatform := ctx.ModuleForTests("libsdk", "android_arm64_armv8-a_shared")
+ libsdkdepNDK := ctx.ModuleForTests("libsdkdep", "android_arm64_armv8-a_sdk_shared")
+ libsdkdepPlatform := ctx.ModuleForTests("libsdkdep", "android_arm64_armv8-a_shared")
+ libplatform := ctx.ModuleForTests("libplatform", "android_arm64_armv8-a_shared")
+ platformbinary := ctx.ModuleForTests("platformbinary", "android_arm64_armv8-a")
+ sdkbinary := ctx.ModuleForTests("sdkbinary", "android_arm64_armv8-a_sdk")
+
+ libcxxNDK := ctx.ModuleForTests("ndk_libc++_shared", "android_arm64_armv8-a_sdk_shared")
+ libcxxPlatform := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared")
+
+ assertDep(t, libsdkNDK, libsdkdepNDK)
+ assertDep(t, libsdkPlatform, libsdkdepPlatform)
+ assertDep(t, libplatform, libsdkPlatform)
+ assertDep(t, platformbinary, libplatform)
+ assertDep(t, sdkbinary, libsdkNDK)
+
+ assertDep(t, libsdkNDK, libcxxNDK)
+ assertDep(t, libsdkPlatform, libcxxPlatform)
+}
diff --git a/cc/stl.go b/cc/stl.go
index eda8a4f..34ff30c 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -115,9 +115,13 @@
switch s {
case "libc++", "libc++_static":
return s
+ case "c++_shared":
+ return "libc++"
+ case "c++_static":
+ return "libc++_static"
case "none":
return ""
- case "":
+ case "", "system":
if ctx.static() {
return "libc++_static"
} else {
diff --git a/cc/testing.go b/cc/testing.go
index f85795b..53f0995 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -152,6 +152,7 @@
name: "libgcc_stripped",
vendor_available: true,
recovery_available: true,
+ sdk_version: "current",
src: "",
}
@@ -169,6 +170,7 @@
llndk_library {
name: "libc",
symbol_file: "",
+ sdk_version: "current",
}
cc_library {
name: "libm",
@@ -188,6 +190,7 @@
llndk_library {
name: "libm",
symbol_file: "",
+ sdk_version: "current",
}
cc_library {
name: "libdl",
@@ -207,6 +210,7 @@
llndk_library {
name: "libdl",
symbol_file: "",
+ sdk_version: "current",
}
cc_library {
name: "libft2",
@@ -219,6 +223,7 @@
name: "libft2",
symbol_file: "",
vendor_available: false,
+ sdk_version: "current",
}
cc_library {
name: "libc++_static",
@@ -375,6 +380,16 @@
sdk_version: "27",
}
+ ndk_prebuilt_object {
+ name: "ndk_crtbegin_dynamic.27",
+ sdk_version: "27",
+ }
+
+ ndk_prebuilt_object {
+ name: "ndk_crtend_android.27",
+ sdk_version: "27",
+ }
+
ndk_prebuilt_shared_stl {
name: "ndk_libc++_shared",
}
diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go
index dfc6f76..042e012 100644
--- a/cc/toolchain_library.go
+++ b/cc/toolchain_library.go
@@ -67,6 +67,7 @@
module.stl = nil
module.sanitize = nil
module.installer = nil
+ module.Properties.Sdk_version = StringPtr("current")
return module.Init()
}
diff --git a/java/app.go b/java/app.go
index 951ce16..0c94e23 100755
--- a/java/app.go
+++ b/java/app.go
@@ -230,6 +230,13 @@
for _, jniTarget := range ctx.MultiTargets() {
variation := append(jniTarget.Variations(),
blueprint.Variation{Mutator: "link", Variation: "shared"})
+
+ // If the app builds against an Android SDK use the SDK variant of JNI dependencies
+ // unless jni_uses_platform_apis is set.
+ if a.sdkVersion().specified() && a.sdkVersion().kind != sdkCorePlatform &&
+ !Bool(a.appProperties.Jni_uses_platform_apis) {
+ variation = append(variation, blueprint.Variation{Mutator: "sdk", Variation: "sdk"})
+ }
ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
}
@@ -557,7 +564,7 @@
dexJarFile := a.dexBuildActions(ctx)
- jniLibs, certificateDeps := collectAppDeps(ctx, a.shouldEmbedJnis(ctx))
+ jniLibs, certificateDeps := collectAppDeps(ctx, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
jniJarFile := a.jniBuildActions(jniLibs, ctx)
if ctx.Failed() {
@@ -607,7 +614,8 @@
}
}
-func collectAppDeps(ctx android.ModuleContext, shouldCollectRecursiveNativeDeps bool) ([]jniLib, []Certificate) {
+func collectAppDeps(ctx android.ModuleContext, shouldCollectRecursiveNativeDeps bool,
+ checkNativeSdkVersion bool) ([]jniLib, []Certificate) {
var jniLibs []jniLib
var certificates []Certificate
seenModulePaths := make(map[string]bool)
@@ -629,6 +637,18 @@
}
seenModulePaths[path.String()] = true
+ if checkNativeSdkVersion {
+ if app, ok := ctx.Module().(interface{ sdkVersion() sdkSpec }); ok {
+ if app.sdkVersion().specified() &&
+ app.sdkVersion().kind != sdkCorePlatform &&
+ dep.SdkVersion() == "" {
+ ctx.PropertyErrorf("jni_libs",
+ "JNI dependency %q uses platform APIs, but this module does not",
+ otherName)
+ }
+ }
+ }
+
if lib.Valid() {
jniLibs = append(jniLibs, jniLib{
name: ctx.OtherModuleName(module),
@@ -1169,7 +1189,7 @@
ctx.ModuleErrorf("One and only one of certficate, presigned, and default_dev_cert properties must be set")
}
- _, certificates := collectAppDeps(ctx, false)
+ _, certificates := collectAppDeps(ctx, false, false)
// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
// TODO: LOCAL_PACKAGE_SPLITS
@@ -1457,7 +1477,7 @@
r.aapt.buildActions(ctx, r, aaptLinkFlags...)
// Sign the built package
- _, certificates := collectAppDeps(ctx, false)
+ _, certificates := collectAppDeps(ctx, false, false)
certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx)
signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk")
SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil)
diff --git a/java/app_test.go b/java/app_test.go
index 8ec8a7f..f2cbbfb 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -912,6 +912,7 @@
cc_library {
name: "libjni",
system_shared_libs: [],
+ sdk_version: "current",
stl: "none",
}
@@ -1024,6 +1025,7 @@
name: "libjni",
system_shared_libs: [],
stl: "none",
+ sdk_version: "current",
}
android_app {
@@ -1048,26 +1050,26 @@
android_test {
name: "test",
- sdk_version: "core_platform",
+ sdk_version: "current",
jni_libs: ["libjni"],
}
android_test {
name: "test_noembed",
- sdk_version: "core_platform",
+ sdk_version: "current",
jni_libs: ["libjni"],
use_embedded_native_libs: false,
}
android_test_helper_app {
name: "test_helper",
- sdk_version: "core_platform",
+ sdk_version: "current",
jni_libs: ["libjni"],
}
android_test_helper_app {
name: "test_helper_noembed",
- sdk_version: "core_platform",
+ sdk_version: "current",
jni_libs: ["libjni"],
use_embedded_native_libs: false,
}
@@ -1099,6 +1101,10 @@
if g, w := !strings.Contains(jniLibZip.Args["jarArgs"], "-L 0"), test.compressed; g != w {
t.Errorf("expected jni compressed %v, got %v", w, g)
}
+
+ if !strings.Contains(jniLibZip.Implicits[0].String(), "_sdk_") {
+ t.Errorf("expected input %q to use sdk variant", jniLibZip.Implicits[0].String())
+ }
}
})
}
@@ -2293,6 +2299,7 @@
system_shared_libs: [],
stl: "none",
notice: "LIB_NOTICE",
+ sdk_version: "current",
}
java_library {
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 7ac71a4..62675c4 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -1471,6 +1471,15 @@
cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths)
+ // TODO(b/154317059): Clean up this whitelist by baselining and/or checking in last-released.
+ if d.Name() != "android.car-system-stubs-docs" &&
+ d.Name() != "android.car-stubs-docs" &&
+ d.Name() != "system-api-stubs-docs" &&
+ d.Name() != "test-api-stubs-docs" {
+ cmd.Flag("--lints-as-errors")
+ cmd.Flag("--warnings-as-errors") // Most lints are actually warnings.
+ }
+
cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles)
newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since)
@@ -1489,20 +1498,37 @@
updatedBaselineOutput := android.PathForModuleOut(ctx, "api_lint_baseline.txt")
d.apiLintTimestamp = android.PathForModuleOut(ctx, "api_lint.timestamp")
+ msg := `` +
+ `************************************************************\n` +
+ `Your API changes are triggering API Lint warnings or errors.\n` +
+ `To make these errors go away, fix the code according to the\n` +
+ `error and/or warning messages above.\n` +
+ `\n` +
+ `If it's not possible to do so, there are workarounds:\n` +
+ `\n` +
+ `1. You can suppress the errors with @SuppressLint(\"<id>\")\n`
+
if baselineFile.Valid() {
cmd.FlagWithInput("--baseline ", baselineFile.Path())
cmd.FlagWithOutput("--update-baseline ", updatedBaselineOutput)
+
+ msg += fmt.Sprintf(``+
+ `2. You can update the baseline by executing the following\n`+
+ ` command:\n`+
+ ` cp \\ \n`+
+ ` \"$PWD/%s\" \\ \n`+
+ ` \"$PWD/%s\" \n`+
+ ` To submit the revised baseline.txt to the main Android\n`+
+ ` repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path())
+ } else {
+ msg += fmt.Sprintf(``+
+ `2. You can add a baseline file of existing lint failures\n`+
+ ` to the build rule of %s.\n`, d.Name())
}
+ msg += `************************************************************\n`
zipSyncCleanupCmd(rule, srcJarDir)
- msg := fmt.Sprintf(`\n******************************\n`+
- `Your API changes are triggering API Lint warnings or errors.\n\n`+
- `To make these errors go away, you have two choices:\n`+
- ` 1. You can suppress the errors with @SuppressLint(\"<id>\").\n\n`+
- ` 2. You can update the baseline by executing the following command:\n`+
- ` cp \"$PWD/%s\" \"$PWD/%s\"\n\n`+
- `******************************\n`, updatedBaselineOutput, baselineFile.Path())
rule.Command().
Text("touch").Output(d.apiLintTimestamp).
Text(") || (").
diff --git a/java/java.go b/java/java.go
index 5d77807..6589721 100644
--- a/java/java.go
+++ b/java/java.go
@@ -86,6 +86,14 @@
ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
}
+func (j *Module) CheckStableSdkVersion() error {
+ sdkVersion := j.sdkVersion()
+ if sdkVersion.stable() {
+ return nil
+ }
+ return fmt.Errorf("non stable SDK %v", sdkVersion)
+}
+
func (j *Module) checkSdkVersions(ctx android.ModuleContext) {
if j.SocSpecific() || j.DeviceSpecific() ||
(j.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 86eddb1..03bc76b 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -59,7 +59,7 @@
apiver = elements[0]
scope = elements[1]
- if scope != "public" && scope != "system" && scope != "test" {
+ if scope != "public" && scope != "system" && scope != "test" && scope != "module-lib" && scope != "system-server" {
ctx.ModuleErrorf("invalid scope %q found in path: %q", scope, path)
return
}
@@ -100,7 +100,7 @@
mydir := mctx.ModuleDir() + "/"
var files []string
for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs {
- for _, scope := range []string{"public", "system", "test", "core"} {
+ for _, scope := range []string{"public", "system", "test", "core", "module-lib", "system-server"} {
vfiles, err := mctx.GlobWithDeps(mydir+apiver+"/"+scope+"/"+name, nil)
if err != nil {
mctx.ModuleErrorf("failed to glob %s files under %q: %s", name, mydir+apiver+"/"+scope, err)
diff --git a/java/sdk.go b/java/sdk.go
index be5e512..4414600 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -170,9 +170,12 @@
return false
}
switch s.kind {
+ case sdkNone:
+ // there is nothing to manage and version in this case; de facto stable API.
+ return true
case sdkCore, sdkPublic, sdkSystem, sdkModule, sdkSystemServer:
return true
- case sdkNone, sdkCorePlatform, sdkTest, sdkPrivate:
+ case sdkCorePlatform, sdkTest, sdkPrivate:
return false
default:
panic(fmt.Errorf("unknown sdkKind=%v", s.kind))
diff --git a/java/sdk_library.go b/java/sdk_library.go
index fa26795..d9c948f 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -90,6 +90,9 @@
// Extra arguments to pass to droidstubs for this scope.
droidstubsArgs []string
+
+ // Whether the api scope can be treated as unstable, and should skip compat checks.
+ unstable bool
}
// Initialize a scope, creating and adding appropriate dependency tags
@@ -142,6 +145,7 @@
moduleSuffix: sdkTestApiSuffix,
sdkVersion: "test_current",
droidstubsArgs: []string{"-showAnnotation android.annotation.TestApi"},
+ unstable: true,
})
allApiScopes = apiScopes{
apiScopePublic,
@@ -556,12 +560,14 @@
props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
- // check against the latest released API
- props.Check_api.Last_released.Api_file = proptools.StringPtr(
- module.latestApiFilegroupName(apiScope))
- props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
- module.latestRemovedApiFilegroupName(apiScope))
- props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
+ if !apiScope.unstable {
+ // check against the latest released API
+ props.Check_api.Last_released.Api_file = proptools.StringPtr(
+ module.latestApiFilegroupName(apiScope))
+ props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
+ module.latestRemovedApiFilegroupName(apiScope))
+ props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
+ }
// Dist the api txt artifact for sdk builds.
if !Bool(module.sdkLibraryProperties.No_dist) {
diff --git a/rust/rust.go b/rust/rust.go
index 17734f9..5cc8845 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -164,6 +164,10 @@
return false
}
+func (mod *Module) UseSdk() bool {
+ return false
+}
+
func (mod *Module) UseVndk() bool {
return false
}
@@ -184,6 +188,10 @@
return ""
}
+func (mod *Module) AlwaysSdk() bool {
+ return false
+}
+
func (mod *Module) ToolchainLibrary() bool {
return false
}