Merge "Print number of converted modules"
diff --git a/android/apex.go b/android/apex.go
index d5fd922..cf1bcfe 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -913,6 +913,7 @@
// ModuleWithMinSdkVersionCheck represents a module that implements min_sdk_version checks
type ModuleWithMinSdkVersionCheck interface {
Module
+ MinSdkVersion(ctx EarlyModuleContext) SdkSpec
CheckMinSdkVersion(ctx ModuleContext)
}
@@ -944,6 +945,14 @@
if am, ok := from.(DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
return false
}
+ if m, ok := to.(ModuleWithMinSdkVersionCheck); ok {
+ // This dependency performs its own min_sdk_version check, just make sure it sets min_sdk_version
+ // to trigger the check.
+ if !m.MinSdkVersion(ctx).Specified() {
+ ctx.OtherModuleErrorf(m, "must set min_sdk_version")
+ }
+ return false
+ }
if err := to.ShouldSupportSdkVersion(ctx, minSdkVersion); err != nil {
toName := ctx.OtherModuleName(to)
if ver, ok := minSdkVersionAllowlist[toName]; !ok || ver.GreaterThan(minSdkVersion) {
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index ca40aaa..a2d6992 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1537,9 +1537,11 @@
},
{
desc: "LOCAL_LICENSE_KINDS, LOCAL_LICENSE_CONDITIONS, LOCAL_NOTICE_FILE",
- // TODO(b/205615944): When valid "android_license_files" exists, the test requires an Android.mk
- // file (and an Android.bp file is required as well if the license files locates outside the current
- // directory). So plan to use a mock file system to mock the Android.mk and Android.bp files.
+ // When "android_license_files" is valid, the test requires an Android.mk file
+ // outside the current (and an Android.bp file is required as well if the license
+ // files locates directory), thus a mock file system is needed. The integration
+ // test cases for these scenarios have been added in
+ // $(ANDROID_BUILD_TOP)/build/soong/tests/androidmk_test.sh.
in: `
include $(CLEAR_VARS)
LOCAL_MODULE := foo
diff --git a/apex/apex.go b/apex/apex.go
index 4ecb104..bb9207d 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2346,6 +2346,8 @@
//
// TODO(jiyong): move these checks to a separate go file.
+var _ android.ModuleWithMinSdkVersionCheck = (*apexBundle)(nil)
+
// Entures that min_sdk_version of the included modules are equal or less than the min_sdk_version
// of this apexBundle.
func (a *apexBundle) CheckMinSdkVersion(ctx android.ModuleContext) {
@@ -2357,7 +2359,15 @@
android.CheckMinSdkVersion(ctx, minSdkVersion, a.WalkPayloadDeps)
}
-func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) android.ApiLevel {
+func (a *apexBundle) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpec{
+ Kind: android.SdkNone,
+ ApiLevel: a.minSdkVersion(ctx),
+ Raw: String(a.properties.Min_sdk_version),
+ }
+}
+
+func (a *apexBundle) minSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
ver := proptools.String(a.properties.Min_sdk_version)
if ver == "" {
return android.NoneApiLevel
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 2f7dce5..3b9b13a 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -8410,6 +8410,184 @@
ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += otherapex")
}
+func TestSdkLibraryCanHaveHigherMinSdkVersion(t *testing.T) {
+ preparer := android.GroupFixturePreparers(
+ PrepareForTestWithApexBuildComponents,
+ prepareForTestWithMyapex,
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.PrepareForTestWithJavaDefaultModules,
+ android.PrepareForTestWithAndroidBuildComponents,
+ dexpreopt.FixtureSetApexBootJars("myapex:mybootclasspathlib"),
+ dexpreopt.FixtureSetApexSystemServerJars("myapex:mysystemserverclasspathlib"),
+ )
+
+ // Test java_sdk_library in bootclasspath_fragment may define higher min_sdk_version than the apex
+ t.Run("bootclasspath_fragment jar has higher min_sdk_version than apex", func(t *testing.T) {
+ preparer.RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ bootclasspath_fragments: ["mybootclasspathfragment"],
+ min_sdk_version: "30",
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ bootclasspath_fragment {
+ name: "mybootclasspathfragment",
+ contents: ["mybootclasspathlib"],
+ apex_available: ["myapex"],
+ }
+
+ java_sdk_library {
+ name: "mybootclasspathlib",
+ srcs: ["mybootclasspathlib.java"],
+ apex_available: ["myapex"],
+ compile_dex: true,
+ unsafe_ignore_missing_latest_api: true,
+ min_sdk_version: "31",
+ static_libs: ["util"],
+ }
+
+ java_library {
+ name: "util",
+ srcs: ["a.java"],
+ apex_available: ["myapex"],
+ min_sdk_version: "31",
+ static_libs: ["another_util"],
+ }
+
+ java_library {
+ name: "another_util",
+ srcs: ["a.java"],
+ min_sdk_version: "31",
+ apex_available: ["myapex"],
+ }
+ `)
+ })
+
+ // Test java_sdk_library in systemserverclasspath_fragment may define higher min_sdk_version than the apex
+ t.Run("systemserverclasspath_fragment jar has higher min_sdk_version than apex", func(t *testing.T) {
+ preparer.RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
+ min_sdk_version: "30",
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ systemserverclasspath_fragment {
+ name: "mysystemserverclasspathfragment",
+ contents: ["mysystemserverclasspathlib"],
+ apex_available: ["myapex"],
+ }
+
+ java_sdk_library {
+ name: "mysystemserverclasspathlib",
+ srcs: ["mysystemserverclasspathlib.java"],
+ apex_available: ["myapex"],
+ compile_dex: true,
+ min_sdk_version: "32",
+ unsafe_ignore_missing_latest_api: true,
+ static_libs: ["util"],
+ }
+
+ java_library {
+ name: "util",
+ srcs: ["a.java"],
+ apex_available: ["myapex"],
+ min_sdk_version: "31",
+ static_libs: ["another_util"],
+ }
+
+ java_library {
+ name: "another_util",
+ srcs: ["a.java"],
+ min_sdk_version: "31",
+ apex_available: ["myapex"],
+ }
+ `)
+ })
+
+ t.Run("bootclasspath_fragment jar must set min_sdk_version", func(t *testing.T) {
+ preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "mybootclasspathlib".*must set min_sdk_version`)).
+ RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ bootclasspath_fragments: ["mybootclasspathfragment"],
+ min_sdk_version: "30",
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ bootclasspath_fragment {
+ name: "mybootclasspathfragment",
+ contents: ["mybootclasspathlib"],
+ apex_available: ["myapex"],
+ }
+
+ java_sdk_library {
+ name: "mybootclasspathlib",
+ srcs: ["mybootclasspathlib.java"],
+ apex_available: ["myapex"],
+ compile_dex: true,
+ unsafe_ignore_missing_latest_api: true,
+ }
+ `)
+ })
+
+ t.Run("systemserverclasspath_fragment jar must set min_sdk_version", func(t *testing.T) {
+ preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "mysystemserverclasspathlib".*must set min_sdk_version`)).
+ RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
+ min_sdk_version: "30",
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ systemserverclasspath_fragment {
+ name: "mysystemserverclasspathfragment",
+ contents: ["mysystemserverclasspathlib"],
+ apex_available: ["myapex"],
+ }
+
+ java_sdk_library {
+ name: "mysystemserverclasspathlib",
+ srcs: ["mysystemserverclasspathlib.java"],
+ apex_available: ["myapex"],
+ compile_dex: true,
+ unsafe_ignore_missing_latest_api: true,
+ }
+ `)
+ })
+}
+
func TestMain(m *testing.M) {
os.Exit(m.Run())
}
diff --git a/bpfix/Android.bp b/bpfix/Android.bp
index 345dbd0..a72d9b4 100644
--- a/bpfix/Android.bp
+++ b/bpfix/Android.bp
@@ -52,5 +52,6 @@
],
deps: [
"blueprint-parser",
+ "blueprint-pathtools",
],
}
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index e1140b8..c0925fe 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -22,6 +22,7 @@
"flag"
"fmt"
"io"
+ "io/ioutil"
"os"
"path/filepath"
"reflect"
@@ -29,6 +30,7 @@
"strings"
"github.com/google/blueprint/parser"
+ "github.com/google/blueprint/pathtools"
)
// Reformat takes a blueprint file as a string and returns a formatted version
@@ -166,7 +168,7 @@
},
{
Name: "rewriteLicenseProperties",
- Fix: runPatchListMod(rewriteLicenseProperties),
+ Fix: runPatchListMod(rewriteLicenseProperty(nil, "")),
},
}
@@ -1452,9 +1454,16 @@
return nil
}
+func rewriteLicenseProperty(fs pathtools.FileSystem, relativePath string) patchListModFunction {
+ return func(mod *parser.Module, buf []byte, patchList *parser.PatchList) error {
+ return rewriteLicenseProperties(mod, patchList, fs, relativePath)
+ }
+}
+
// rewrite the "android_license_kinds" and "android_license_files" properties to a package module
// (and a license module when needed).
-func rewriteLicenseProperties(mod *parser.Module, buf []byte, patchList *parser.PatchList) error {
+func rewriteLicenseProperties(mod *parser.Module, patchList *parser.PatchList, fs pathtools.FileSystem,
+ relativePath string) error {
// if a package module has been added, no more action is needed.
for _, patch := range *patchList {
if strings.Contains(patch.Replacement, "package {") {
@@ -1462,15 +1471,33 @@
}
}
+ // initial the fs
+ if fs == nil {
+ fs = pathtools.NewOsFs(os.Getenv("ANDROID_BUILD_TOP"))
+ }
+
+ // initial the relativePath
+ if len(relativePath) == 0 {
+ relativePath = getModuleRelativePath()
+ }
+ // validate the relativePath
+ ok := hasFile(relativePath+"/Android.mk", fs)
+ // some modules in the existing test cases in the androidmk_test.go do not have a valid path
+ if !ok && len(relativePath) > 0 {
+ return fmt.Errorf("Cannot find an Android.mk file at path %s", relativePath)
+ }
+
licenseKindsPropertyName := "android_license_kinds"
licenseFilesPropertyName := "android_license_files"
- androidBpFileErr := "// Error: No Android.bp file is found at\n" +
+ androidBpFileErr := "// Error: No Android.bp file is found at path\n" +
"// %s\n" +
- "// Please add one there with the needed license module first.\n"
+ "// Please add one there with the needed license module first.\n" +
+ "// Then reset the default_applicable_licenses property below with the license module name.\n"
licenseModuleErr := "// Error: Cannot get the name of the license module in the\n" +
"// %s file.\n" +
- "// If no such license module exists, please add one there first.\n"
+ "// If no such license module exists, please add one there first.\n" +
+ "// Then reset the default_applicable_licenses property below with the license module name.\n"
defaultApplicableLicense := "Android-Apache-2.0"
var licenseModuleName, licensePatch string
@@ -1482,15 +1509,16 @@
// if have LOCAL_NOTICE_FILE outside the current directory, need to find and refer to the license
// module in the LOCAL_NOTICE_FILE location directly and no new license module needs to be created
if hasFileInParentDir {
- bpPath, ok := getPathFromProperty(mod, licenseFilesPropertyName)
+ bpPath, ok := getPathFromProperty(mod, licenseFilesPropertyName, fs, relativePath)
if !ok {
- bpDir, err := getDirFromProperty(mod, licenseFilesPropertyName)
+ bpDir, err := getDirFromProperty(mod, licenseFilesPropertyName, fs, relativePath)
if err != nil {
return err
}
licensePatch += fmt.Sprintf(androidBpFileErr, bpDir)
+ defaultApplicableLicense = ""
} else {
- licenseModuleName, _ = getModuleName(bpPath, "license")
+ licenseModuleName, _ = getModuleName(bpPath, "license", fs)
if len(licenseModuleName) == 0 {
licensePatch += fmt.Sprintf(licenseModuleErr, bpPath)
}
@@ -1498,7 +1526,6 @@
}
} else {
// if have LOCAL_NOTICE_FILE in the current directory, need to create a new license module
- relativePath := getModuleRelativePath()
if len(relativePath) == 0 {
return fmt.Errorf("Cannot obtain the relative path of the Android.mk file")
}
@@ -1617,17 +1644,14 @@
return absPath
}
-// check whether a file exists in a directory
-func hasFile(dir string, fileName string) error {
- _, err := os.Stat(dir + fileName)
- if err != nil {
- return err
- }
- return nil
+// check whether a file exists in a filesystem
+func hasFile(path string, fs pathtools.FileSystem) bool {
+ ok, _, _ := fs.Exists(path)
+ return ok
}
// get the directory where an `Android.bp` file and the property files are expected to locate
-func getDirFromProperty(mod *parser.Module, property string) (string, error) {
+func getDirFromProperty(mod *parser.Module, property string, fs pathtools.FileSystem, relativePath string) (string, error) {
listValue, ok := getLiteralListPropertyValue(mod, property)
if !ok {
// if do not find
@@ -1637,7 +1661,11 @@
// if empty
return "", fmt.Errorf("Cannot find the value of the %s.%s property", mod.Type, property)
}
- path := getModuleAbsolutePath()
+ _, isDir, _ := fs.Exists(relativePath)
+ if !isDir {
+ return "", fmt.Errorf("Cannot find the path %s", relativePath)
+ }
+ path := relativePath
for {
if !strings.HasPrefix(listValue[0], "../") {
break
@@ -1645,25 +1673,29 @@
path = filepath.Dir(path)
listValue[0] = strings.TrimPrefix(listValue[0], "../")
}
+ _, isDir, _ = fs.Exists(path)
+ if !isDir {
+ return "", fmt.Errorf("Cannot find the path %s", path)
+ }
return path, nil
}
// get the path of the `Android.bp` file at the expected location where the property files locate
-func getPathFromProperty(mod *parser.Module, property string) (string, bool) {
- dir, err := getDirFromProperty(mod, property)
+func getPathFromProperty(mod *parser.Module, property string, fs pathtools.FileSystem, relativePath string) (string, bool) {
+ dir, err := getDirFromProperty(mod, property, fs, relativePath)
if err != nil {
return "", false
}
- err = hasFile(dir, "/Android.bp")
- if err != nil {
+ ok := hasFile(dir+"/Android.bp", fs)
+ if !ok {
return "", false
}
return dir + "/Android.bp", true
}
// parse an Android.bp file to get the name of the first module with type of moduleType
-func getModuleName(path string, moduleType string) (string, error) {
- tree, err := parserPath(path)
+func getModuleName(path string, moduleType string, fs pathtools.FileSystem) (string, error) {
+ tree, err := parserPath(path, fs)
if err != nil {
return "", err
}
@@ -1685,8 +1717,13 @@
}
// parse an Android.bp file with the specific path
-func parserPath(path string) (tree *parser.File, err error) {
- fileContent, _ := os.ReadFile(path)
+func parserPath(path string, fs pathtools.FileSystem) (tree *parser.File, err error) {
+ f, err := fs.Open(path)
+ if err != nil {
+ return tree, err
+ }
+ defer f.Close()
+ fileContent, _ := ioutil.ReadAll(f)
tree, err = parse(path, bytes.NewBufferString(string(fileContent)))
if err != nil {
return tree, err
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index e6b6af5..221df45 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -25,6 +25,7 @@
"reflect"
"github.com/google/blueprint/parser"
+ "github.com/google/blueprint/pathtools"
)
// TODO(jeffrygaston) remove this when position is removed from ParseNode (in b/38325146) and we can directly do reflect.DeepEqual
@@ -1678,10 +1679,20 @@
}
}
-func TestRewriteLicenseProperties(t *testing.T) {
+func TestRewriteLicenseProperty(t *testing.T) {
+ mockFs := pathtools.MockFs(map[string][]byte{
+ "a/b/c/d/Android.mk": []byte("this is not important."),
+ "a/b/LicenseFile1": []byte("LicenseFile1"),
+ "a/b/LicenseFile2": []byte("LicenseFile2"),
+ "a/b/Android.bp": []byte("license {\n\tname: \"reuse_a_b_license\",\n}\n"),
+ })
+ relativePath := "a/b/c/d"
+ relativePathErr := "a/b/c"
tests := []struct {
name string
in string
+ fs pathtools.FileSystem
+ path string
out string
}{
{
@@ -1744,13 +1755,194 @@
}
`,
},
- // TODO(b/205615944): When valid "android_license_files" exists, the test requires an Android.mk
- // file (and an Android.bp file is required as well if the license files locates outside the current
- // directory). So plan to use a mock file system to mock the Android.mk and Android.bp files.
+ {
+ name: "license rewriting with license files in the current directory",
+ in: `
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: ["LicenseFile1", "LicenseFile2",],
+ }
+ `,
+ fs: mockFs,
+ path: relativePath,
+ out: `
+ package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "a_b_c_d_license",
+ ],
+ }
+
+ license {
+ name: "a_b_c_d_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "license_kind",
+ ],
+ license_text: [
+ "LicenseFile1",
+ "LicenseFile2",
+ ],
+ }
+
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: [
+ "LicenseFile1",
+ "LicenseFile2",
+ ],
+ }
+ `,
+ },
+ {
+ name: "license rewriting with license files outside the current directory",
+ in: `
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: ["../../LicenseFile1", "../../LicenseFile2",],
+ }
+ `,
+ fs: mockFs,
+ path: relativePath,
+ out: `
+ package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "reuse_a_b_license",
+ ],
+ }
+
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: [
+ "../../LicenseFile1",
+ "../../LicenseFile2",
+ ],
+ }
+ `,
+ },
+ {
+ name: "license rewriting with no Android.bp file in the expected location",
+ in: `
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: ["../../LicenseFile1", "../../LicenseFile2",],
+ }
+ `,
+ fs: pathtools.MockFs(map[string][]byte{
+ "a/b/c/d/Android.mk": []byte("this is not important."),
+ "a/b/LicenseFile1": []byte("LicenseFile1"),
+ "a/b/LicenseFile2": []byte("LicenseFile2"),
+ "a/Android.bp": []byte("license {\n\tname: \"reuse_a_b_license\",\n}\n"),
+ }),
+ path: relativePath,
+ out: `
+ // Error: No Android.bp file is found at path
+ // a/b
+ // Please add one there with the needed license module first.
+ // Then reset the default_applicable_licenses property below with the license module name.
+ package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "",
+ ],
+ }
+
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: [
+ "../../LicenseFile1",
+ "../../LicenseFile2",
+ ],
+ }
+ `,
+ },
+ {
+ name: "license rewriting with an Android.bp file without a license module",
+ in: `
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: ["../../LicenseFile1", "../../LicenseFile2",],
+ }
+ `,
+ fs: pathtools.MockFs(map[string][]byte{
+ "a/b/c/d/Android.mk": []byte("this is not important."),
+ "a/b/LicenseFile1": []byte("LicenseFile1"),
+ "a/b/LicenseFile2": []byte("LicenseFile2"),
+ "a/b/Android.bp": []byte("non_license {\n\tname: \"reuse_a_b_license\",\n}\n"),
+ }),
+ path: relativePath,
+ out: `
+ // Error: Cannot get the name of the license module in the
+ // a/b/Android.bp file.
+ // If no such license module exists, please add one there first.
+ // Then reset the default_applicable_licenses property below with the license module name.
+ package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "",
+ ],
+ }
+
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: [
+ "../../LicenseFile1",
+ "../../LicenseFile2",
+ ],
+ }
+ `,
+ },
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
- runPassOnce(t, test.in, test.out, runPatchListMod(rewriteLicenseProperties))
+ runPassOnce(t, test.in, test.out, runPatchListMod(rewriteLicenseProperty(test.fs, test.path)))
+ })
+ }
+
+ testErrs := []struct {
+ name string
+ in string
+ fs pathtools.FileSystem
+ path string
+ expectedErr string
+ }{
+ {
+ name: "license rewriting with a wrong path",
+ in: `
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: ["../../LicenseFile1", "../../LicenseFile2",],
+ }
+ `,
+ fs: mockFs,
+ path: relativePathErr,
+ expectedErr: `
+ Cannot find an Android.mk file at path a/b/c
+ `,
+ },
+ }
+ for _, test := range testErrs {
+ t.Run(test.name, func(t *testing.T) {
+ checkError(t, test.in, test.expectedErr, runPatchListMod(rewriteLicenseProperty(test.fs, test.path)))
})
}
}
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 3a1f5fc..38065f1 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -16,7 +16,6 @@
import (
"fmt"
- "strconv"
"strings"
"github.com/google/blueprint"
@@ -43,20 +42,6 @@
},
"args", "libs")
-// targetSdkVersion for manifest_fixer
-// When TARGET_BUILD_APPS is not empty, this method returns the unreleased(future) API level
-// This enables release builds (that run with TARGET_BUILD_APPS=[val...]) to target APIs that have not yet been finalized as part of an SDK
-func targetSdkVersionForManifestFixer(ctx android.ModuleContext, sdkContext android.SdkContext) string {
- if ctx.Config().UnbundledBuildApps() {
- return strconv.Itoa(android.FutureApiLevel.FinalOrFutureInt())
- }
- targetSdkVersion, err := sdkContext.TargetSdkVersion(ctx).EffectiveVersionString(ctx)
- if err != nil {
- ctx.ModuleErrorf("invalid targetSdkVersion: %s", err)
- }
- return targetSdkVersion
-}
-
// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext android.SdkContext,
classLoaderContexts dexpreopt.ClassLoaderContextMap, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis,
@@ -104,7 +89,10 @@
args = append(args, "--logging-parent", loggingParent)
}
var deps android.Paths
- targetSdkVersion := targetSdkVersionForManifestFixer(ctx, sdkContext)
+ targetSdkVersion, err := sdkContext.TargetSdkVersion(ctx).EffectiveVersionString(ctx)
+ if err != nil {
+ ctx.ModuleErrorf("invalid targetSdkVersion: %s", err)
+ }
if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
deps = append(deps, ApiFingerprintPath(ctx))
diff --git a/java/base.go b/java/base.go
index 2f90db2..c0da215 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1643,8 +1643,7 @@
}
// Implements android.ApexModule
-func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
- sdkVersion android.ApiLevel) error {
+func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
sdkSpec := j.MinSdkVersion(ctx)
if !sdkSpec.Specified() {
return fmt.Errorf("min_sdk_version is not specified")
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index df1e121..bfe895c 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -594,8 +594,11 @@
if imageConfig != nil {
info.modules = imageConfig.modules
- info.profilePathOnHost = imageConfig.profilePathOnHost
- info.profileInstallPathInApex = imageConfig.profileInstallPathInApex
+ global := dexpreopt.GetGlobalConfig(ctx)
+ if !global.DisableGenerateProfile {
+ info.profilePathOnHost = imageConfig.profilePathOnHost
+ info.profileInstallPathInApex = imageConfig.profileInstallPathInApex
+ }
}
info.bootImageFilesByArch = bootImageFilesByArch
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 3065d57..52ab06e 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1129,6 +1129,22 @@
return generatedScopes
}
+var _ android.ModuleWithMinSdkVersionCheck = (*SdkLibrary)(nil)
+
+func (module *SdkLibrary) CheckMinSdkVersion(ctx android.ModuleContext) {
+ android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx).ApiLevel, func(c android.ModuleContext, do android.PayloadDepsCallback) {
+ ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
+ isExternal := !module.depIsInSameApex(ctx, child)
+ if am, ok := child.(android.ApexModule); ok {
+ if !do(ctx, parent, am, isExternal) {
+ return false
+ }
+ }
+ return !isExternal
+ })
+ })
+}
+
type sdkLibraryComponentTag struct {
blueprint.BaseDependencyTag
name string
@@ -1214,6 +1230,10 @@
}
func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ if proptools.String(module.deviceProperties.Min_sdk_version) != "" {
+ module.CheckMinSdkVersion(ctx)
+ }
+
module.generateCommonBuildActions(ctx)
// Only build an implementation library if required.
@@ -2605,12 +2625,12 @@
func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
if module.hideApexVariantFromMake {
- return []android.AndroidMkEntries{android.AndroidMkEntries{
+ return []android.AndroidMkEntries{{
Disabled: true,
}}
}
- return []android.AndroidMkEntries{android.AndroidMkEntries{
+ return []android.AndroidMkEntries{{
Class: "ETC",
OutputFile: android.OptionalPathForPath(module.outputFilePath),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 2271573..f3a19e9 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -1140,3 +1140,87 @@
})
}
}
+
+func TestSdkLibrary_CheckMinSdkVersion(t *testing.T) {
+ preparer := android.GroupFixturePreparers(
+ PrepareForTestWithJavaBuildComponents,
+ PrepareForTestWithJavaDefaultModules,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ )
+
+ preparer.RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ static_libs: ["util"],
+ min_sdk_version: "30",
+ unsafe_ignore_missing_latest_api: true,
+ }
+
+ java_library {
+ name: "util",
+ srcs: ["a.java"],
+ min_sdk_version: "30",
+ }
+ `)
+
+ preparer.
+ RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ libs: ["util"],
+ impl_only_libs: ["util"],
+ stub_only_libs: ["util"],
+ stub_only_static_libs: ["util"],
+ min_sdk_version: "30",
+ unsafe_ignore_missing_latest_api: true,
+ }
+
+ java_library {
+ name: "util",
+ srcs: ["a.java"],
+ }
+ `)
+
+ preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "util".*should support min_sdk_version\(30\)`)).
+ RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ static_libs: ["util"],
+ min_sdk_version: "30",
+ unsafe_ignore_missing_latest_api: true,
+ }
+
+ java_library {
+ name: "util",
+ srcs: ["a.java"],
+ min_sdk_version: "31",
+ }
+ `)
+
+ preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "another_util".*should support min_sdk_version\(30\)`)).
+ RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ static_libs: ["util"],
+ min_sdk_version: "30",
+ unsafe_ignore_missing_latest_api: true,
+ }
+
+ java_library {
+ name: "util",
+ srcs: ["a.java"],
+ static_libs: ["another_util"],
+ min_sdk_version: "30",
+ }
+
+ java_library {
+ name: "another_util",
+ srcs: ["a.java"],
+ min_sdk_version: "31",
+ }
+ `)
+}
diff --git a/tests/androidmk_test.sh b/tests/androidmk_test.sh
new file mode 100755
index 0000000..331dc77
--- /dev/null
+++ b/tests/androidmk_test.sh
@@ -0,0 +1,135 @@
+#!/bin/bash -eu
+
+set -o pipefail
+
+# How to run: bash path-to-script/androidmk_test.sh
+# Tests of converting license functionality of the androidmk tool
+REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)"
+$REAL_TOP/build/soong/soong_ui.bash --make-mode androidmk
+
+source "$(dirname "$0")/lib.sh"
+
+# Expect to create a new license module
+function test_rewrite_license_property_inside_current_directory {
+ setup
+
+ # Create an Android.mk file
+ mkdir -p a/b
+ cat > a/b/Android.mk <<'EOF'
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_LICENSE_KINDS := license_kind1 license_kind2
+LOCAL_LICENSE_CONDITIONS := license_condition
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/license_notice1 $(LOCAL_PATH)/license_notice2
+include $(BUILD_PACKAGE)
+EOF
+
+ # Create an expected Android.bp file for the module "foo"
+ cat > a/b/Android.bp <<'EOF'
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "a_b_license",
+ ],
+}
+
+license {
+ name: "a_b_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "license_kind1",
+ "license_kind2",
+ ],
+ license_text: [
+ "license_notice1",
+ "license_notice2",
+ ],
+}
+
+android_app {
+ name: "foo",
+}
+EOF
+
+ run_androidmk_test "a/b/Android.mk" "a/b/Android.bp"
+}
+
+# Expect to reference to an existing license module
+function test_rewrite_license_property_outside_current_directory {
+ setup
+
+ # Create an Android.mk file
+ mkdir -p a/b/c/d
+ cat > a/b/c/d/Android.mk <<'EOF'
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_LICENSE_KINDS := license_kind1 license_kind2
+LOCAL_LICENSE_CONDITIONS := license_condition
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../license_notice1 $(LOCAL_PATH)/../../license_notice2
+include $(BUILD_PACKAGE)
+EOF
+
+ # Create an expected (input) Android.bp file at a/b/
+ cat > a/b/Android.bp <<'EOF'
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "a_b_license",
+ ],
+}
+
+license {
+ name: "a_b_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "license_kind1",
+ "license_kind2",
+ ],
+ license_text: [
+ "license_notice1",
+ "license_notice2",
+ ],
+}
+
+android_app {
+ name: "bar",
+}
+EOF
+
+ # Create an expected (output) Android.bp file for the module "foo"
+ cat > a/b/c/d/Android.bp <<'EOF'
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "a_b_license",
+ ],
+}
+
+android_app {
+ name: "foo",
+}
+EOF
+
+ run_androidmk_test "a/b/c/d/Android.mk" "a/b/c/d/Android.bp"
+}
+
+run_androidmk_test () {
+ export ANDROID_BUILD_TOP="$MOCK_TOP"
+
+ local out=$($REAL_TOP/*/host/*/bin/androidmk "$1")
+ local expected=$(<"$2")
+
+ if [[ "$out" != "$expected" ]]; then
+ ANDROID_BUILD_TOP="$REAL_TOP"
+ cleanup_mock_top
+ fail "The output is not the same as the expected"
+ fi
+
+ ANDROID_BUILD_TOP="$REAL_TOP"
+ cleanup_mock_top
+ echo "Succeeded"
+}
+
+test_rewrite_license_property_inside_current_directory
+
+test_rewrite_license_property_outside_current_directory
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index b19949a..76a918b 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -3,6 +3,7 @@
set -o pipefail
TOP="$(readlink -f "$(dirname "$0")"/../../..)"
+"$TOP/build/soong/tests/androidmk_test.sh"
"$TOP/build/soong/tests/bootstrap_test.sh"
"$TOP/build/soong/tests/mixed_mode_test.sh"
"$TOP/build/soong/tests/bp2build_bazel_test.sh"