diff options
-rw-r--r-- | OWNERS | 8 | ||||
-rw-r--r-- | android/neverallow.go | 4 | ||||
-rw-r--r-- | apex/androidmk.go | 30 | ||||
-rw-r--r-- | apex/apex.go | 32 | ||||
-rw-r--r-- | apex/apex_test.go | 100 | ||||
-rw-r--r-- | apex/builder.go | 35 | ||||
-rw-r--r-- | cc/androidmk.go | 19 | ||||
-rw-r--r-- | cc/binary.go | 4 | ||||
-rw-r--r-- | cc/cc.go | 74 | ||||
-rw-r--r-- | cc/cc_test.go | 85 | ||||
-rw-r--r-- | cc/genrule.go | 10 | ||||
-rw-r--r-- | cc/object.go | 4 | ||||
-rw-r--r-- | cc/prebuilt.go | 8 | ||||
-rw-r--r-- | cc/testing.go | 1 | ||||
-rw-r--r-- | cc/vendor_snapshot.go | 177 | ||||
-rw-r--r-- | cc/vndk_prebuilt.go | 4 | ||||
-rw-r--r-- | dexpreopt/config.go | 44 | ||||
-rw-r--r-- | dexpreopt/dexpreopt.go | 32 | ||||
-rw-r--r-- | java/aar.go | 2 | ||||
-rw-r--r-- | java/androidmk.go | 25 | ||||
-rwxr-xr-x | java/app.go | 81 | ||||
-rw-r--r-- | java/app_test.go | 4 | ||||
-rw-r--r-- | java/builder.go | 9 | ||||
-rw-r--r-- | java/device_host_converter.go | 2 | ||||
-rw-r--r-- | java/dexpreopt.go | 2 | ||||
-rw-r--r-- | java/dexpreopt_bootjars.go | 4 | ||||
-rw-r--r-- | java/droiddoc.go | 7 | ||||
-rw-r--r-- | java/hiddenapi_singleton.go | 2 | ||||
-rw-r--r-- | java/java.go | 80 | ||||
-rw-r--r-- | java/sdk.go | 49 | ||||
-rw-r--r-- | java/sdk_library.go | 22 | ||||
-rw-r--r-- | java/sdk_test.go | 2 | ||||
-rw-r--r-- | ui/build/dumpvars.go | 15 | ||||
-rw-r--r-- | ui/build/path.go | 12 |
34 files changed, 738 insertions, 251 deletions
@@ -1,4 +1,10 @@ -per-file * = asmundak@google.com,ccross@android.com,dwillemsen@google.com,jungjw@google.com,paulduffin@google.com +per-file * = asmundak@google.com +per-file * = ccross@android.com +per-file * = dwillemsen@google.com +per-file * = eakammer@google.com +per-file * = jungjw@google.com +per-file * = patricearruda@google.com +per-file * = paulduffin@google.com per-file ndk_*.go, *gen_stub_libs.py = danalbert@google.com per-file clang.go,global.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com diff --git a/android/neverallow.go b/android/neverallow.go index 9e075b719..be3f7123b 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -187,6 +187,10 @@ func createCcSdkVariantRules() []Rule { // 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", + // These are for apps and shouldn't be used by non-SDK variant modules. + "prebuilts/ndk", + "tools/test/graphicsbenchmark/apps/sample_app", + "tools/test/graphicsbenchmark/functional_tests/java", } platformVariantPropertiesWhitelist := []string{ diff --git a/apex/androidmk.go b/apex/androidmk.go index 9321ad261..1b3a4ba10 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -81,7 +81,7 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo seenDataOutPaths := make(map[string]bool) for _, fi := range a.filesInfo { - if cc, ok := fi.module.(*cc.Module); ok && cc.Properties.HideFromMake { + if ccMod, ok := fi.module.(*cc.Module); ok && ccMod.Properties.HideFromMake { continue } @@ -178,7 +178,8 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo if fi.jacocoReportClassesFile != nil { fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", fi.jacocoReportClassesFile.String()) } - if fi.class == javaSharedLib { + switch fi.class { + case javaSharedLib: javaModule := fi.module.(java.Dependency) // soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar Therefore // we need to remove the suffix from LOCAL_MODULE_STEM, otherwise @@ -189,7 +190,7 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", fi.builtFile.String()) fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false") fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk") - } else if fi.class == app { + case app: fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", fi.certificate.AndroidMkString()) // soong_app_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .apk Therefore // we need to remove the suffix from LOCAL_MODULE_STEM, otherwise @@ -199,19 +200,26 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", strings.Join(app.JniCoverageOutputs().Strings(), " ")) } fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_app_prebuilt.mk") - } else if fi.class == nativeSharedLib || fi.class == nativeExecutable || fi.class == nativeTest { + case appSet: + as, ok := fi.module.(*java.AndroidAppSet) + if !ok { + panic(fmt.Sprintf("Expected %s to be AndroidAppSet", fi.module)) + } + fmt.Fprintln(w, "LOCAL_APK_SET_MASTER_FILE :=", as.MasterFile()) + fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_android_app_set.mk") + case nativeSharedLib, nativeExecutable, nativeTest: fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.Stem()) - if cc, ok := fi.module.(*cc.Module); ok { - if cc.UnstrippedOutputFile() != nil { - fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", cc.UnstrippedOutputFile().String()) + if ccMod, ok := fi.module.(*cc.Module); ok { + if ccMod.UnstrippedOutputFile() != nil { + fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", ccMod.UnstrippedOutputFile().String()) } - cc.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w) - if cc.CoverageOutputFile().Valid() { - fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", cc.CoverageOutputFile().String()) + ccMod.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w) + if ccMod.CoverageOutputFile().Valid() { + fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", ccMod.CoverageOutputFile().String()) } } fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_prebuilt.mk") - } else { + default: fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.Stem()) if fi.builtFile == a.manifestPbOut && apexType == flattenedApex { if a.primaryApexType { diff --git a/apex/apex.go b/apex/apex.go index d3c5df005..2f7b2e535 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -1115,6 +1115,7 @@ const ( javaSharedLib nativeTest app + appSet ) func (class apexFileClass) NameInMake() string { @@ -1129,7 +1130,7 @@ func (class apexFileClass) NameInMake() string { return "JAVA_LIBRARIES" case nativeTest: return "NATIVE_TESTS" - case app: + case app, appSet: // b/142537672 Why isn't this APP? We want to have full control over // the paths and file names of the apk file under the flattend APEX. // If this is set to APP, then the paths and file names are modified @@ -1650,13 +1651,14 @@ func apexFileForShBinary(ctx android.BaseModuleContext, sh *sh.ShBinary) apexFil } type javaDependency interface { - java.Dependency + DexJarBuildPath() android.Path + JacocoReportClassesFile() android.Path Stem() string } func apexFileForJavaLibrary(ctx android.BaseModuleContext, lib javaDependency, module android.Module) apexFile { dirInApex := "javalib" - fileToCopy := lib.DexJar() + fileToCopy := lib.DexJarBuildPath() af := newApexFile(ctx, fileToCopy, module.Name(), dirInApex, javaSharedLib, module) af.jacocoReportClassesFile = lib.JacocoReportClassesFile() af.stem = lib.Stem() + ".jar" @@ -1977,23 +1979,16 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.PropertyErrorf("binaries", "%q is neither cc_binary, (embedded) py_binary, (host) blueprint_go_binary, (host) bootstrap_go_binary, nor sh_binary", depName) } case javaLibTag: - if javaLib, ok := child.(*java.Library); ok { - af := apexFileForJavaLibrary(ctx, javaLib, javaLib) - if !af.Ok() { - ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName) - } else { - filesInfo = append(filesInfo, af) - return true // track transitive dependencies - } - } else if sdkLib, ok := child.(*java.SdkLibrary); ok { - af := apexFileForJavaLibrary(ctx, sdkLib, sdkLib) + switch child.(type) { + case *java.Library, *java.SdkLibrary, *java.DexImport: + af := apexFileForJavaLibrary(ctx, child.(javaDependency), child.(android.Module)) if !af.Ok() { ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName) return false } filesInfo = append(filesInfo, af) return true // track transitive dependencies - } else { + default: ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child)) } case androidAppTag: @@ -2004,6 +1999,15 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap)) } else if ap, ok := child.(*java.AndroidTestHelperApp); ok { filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap)) + } else if ap, ok := child.(*java.AndroidAppSet); ok { + appDir := "app" + if ap.Privileged() { + appDir = "priv-app" + } + af := newApexFile(ctx, ap.OutputFile(), ap.Name(), + filepath.Join(appDir, ap.BaseModuleName()), appSet, ap) + af.certificate = java.PresignedCertificate + filesInfo = append(filesInfo, af) } else { ctx.PropertyErrorf("apps", "%q is not an android_app module", depName) } diff --git a/apex/apex_test.go b/apex/apex_test.go index 779119c27..d6a5d0909 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -96,7 +96,7 @@ func withTargets(targets map[android.OsType][]android.Target) testCustomizer { // - X86 (secondary) // - Arm64 on X86_64 (native bridge) // - Arm on X86 (native bridge) -func withNativeBridgeEnabled(fs map[string][]byte, config android.Config) { +func withNativeBridgeEnabled(_ map[string][]byte, config android.Config) { config.Targets[android.Android] = []android.Target{ {Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""}, @@ -115,15 +115,15 @@ func withManifestPackageNameOverrides(specs []string) testCustomizer { } } -func withBinder32bit(fs map[string][]byte, config android.Config) { +func withBinder32bit(_ map[string][]byte, config android.Config) { config.TestProductVariables.Binder32bit = proptools.BoolPtr(true) } -func withUnbundledBuild(fs map[string][]byte, config android.Config) { +func withUnbundledBuild(_ map[string][]byte, config android.Config) { config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true) } -func testApexContext(t *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) { +func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) { android.ClearApexDependency() bp = bp + ` @@ -187,6 +187,7 @@ func testApexContext(t *testing.T, bp string, handlers ...testCustomizer) (*andr "baz": nil, "bar/baz": nil, "testdata/baz": nil, + "AppSet.apks": nil, } cc.GatherRequiredFilesForTest(fs) @@ -258,7 +259,7 @@ func setUp() { } func tearDown() { - os.RemoveAll(buildDir) + _ = os.RemoveAll(buildDir) } // ensure that 'result' equals 'expected' @@ -294,6 +295,17 @@ func ensureNotContains(t *testing.T, result string, notExpected string) { } } +func ensureMatches(t *testing.T, result string, expectedRex string) { + ok, err := regexp.MatchString(expectedRex, result) + if err != nil { + t.Fatalf("regexp failure trying to match %s against `%s` expression: %s", result, expectedRex, err) + return + } + if !ok { + t.Errorf("%s does not match regular expession %s", result, expectedRex) + } +} + func ensureListContains(t *testing.T, result []string, expected string) { t.Helper() if !android.InList(expected, result) { @@ -329,7 +341,10 @@ func TestBasicApex(t *testing.T) { binaries: ["foo",], } }, - java_libs: ["myjar"], + java_libs: [ + "myjar", + "myjar_dex", + ], } apex { @@ -438,6 +453,15 @@ func TestBasicApex(t *testing.T) { ], } + dex_import { + name: "myjar_dex", + jars: ["prebuilt.jar"], + apex_available: [ + "//apex_available:platform", + "myapex", + ], + } + java_library { name: "myotherjar", srcs: ["foo/bar/MyClass.java"], @@ -473,6 +497,7 @@ func TestBasicApex(t *testing.T) { // Ensure that apex variant is created for the direct dep ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex") ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_myapex") // Ensure that apex variant is created for the indirect dep ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex") @@ -482,6 +507,7 @@ func TestBasicApex(t *testing.T) { ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") ensureContains(t, copyCmds, "image.apex/lib64/mylib2.so") ensureContains(t, copyCmds, "image.apex/javalib/myjar_stem.jar") + ensureContains(t, copyCmds, "image.apex/javalib/myjar_dex.jar") // .. but not for java libs ensureNotContains(t, copyCmds, "image.apex/javalib/myotherjar.jar") ensureNotContains(t, copyCmds, "image.apex/javalib/msharedjar.jar") @@ -4758,6 +4784,38 @@ func TestAppBundle(t *testing.T) { ensureContains(t, content, `"apex_config":{"apex_embedded_apk_config":[{"package_name":"com.android.foo","path":"app/AppFoo/AppFoo.apk"}]}`) } +func TestAppSetBundle(t *testing.T) { + ctx, _ := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + apps: ["AppSet"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + android_app_set { + name: "AppSet", + set: "AppSet.apks", + }`) + mod := ctx.ModuleForTests("myapex", "android_common_myapex_image") + bundleConfigRule := mod.Description("Bundle Config") + content := bundleConfigRule.Args["content"] + ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`) + s := mod.Rule("apexRule").Args["copy_commands"] + copyCmds := regexp.MustCompile(" *&& *").Split(s, -1) + if len(copyCmds) != 3 { + t.Fatalf("Expected 3 commands, got %d in:\n%s", len(copyCmds), s) + } + ensureMatches(t, copyCmds[0], "^rm -rf .*/app/AppSet$") + ensureMatches(t, copyCmds[1], "^mkdir -p .*/app/AppSet$") + ensureMatches(t, copyCmds[2], "^unzip .*-d .*/app/AppSet .*/AppSet.zip$") +} + func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) { t.Helper() @@ -4917,7 +4975,7 @@ func TestUpdatable_should_set_min_sdk_version(t *testing.T) { func TestNoUpdatableJarsInBootImage(t *testing.T) { - var error string + var err string var transform func(*dexpreopt.GlobalConfig) t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) { @@ -4928,35 +4986,35 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { }) t.Run("updatable jar from ART apex in the framework boot image => error", func(t *testing.T) { - error = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image" + err = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image" transform = func(config *dexpreopt.GlobalConfig) { config.BootJars = []string{"com.android.art.something:some-art-lib"} } - testNoUpdatableJarsInBootImage(t, error, transform) + testNoUpdatableJarsInBootImage(t, err, transform) }) t.Run("updatable jar from some other apex in the ART boot image => error", func(t *testing.T) { - error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image" + err = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image" transform = func(config *dexpreopt.GlobalConfig) { config.ArtApexJars = []string{"some-updatable-apex:some-updatable-apex-lib"} } - testNoUpdatableJarsInBootImage(t, error, transform) + testNoUpdatableJarsInBootImage(t, err, transform) }) t.Run("non-updatable jar from some other apex in the ART boot image => error", func(t *testing.T) { - error = "module 'some-non-updatable-apex-lib' is not allowed in the ART boot image" + err = "module 'some-non-updatable-apex-lib' is not allowed in the ART boot image" transform = func(config *dexpreopt.GlobalConfig) { config.ArtApexJars = []string{"some-non-updatable-apex:some-non-updatable-apex-lib"} } - testNoUpdatableJarsInBootImage(t, error, transform) + testNoUpdatableJarsInBootImage(t, err, transform) }) t.Run("updatable jar from some other apex in the framework boot image => error", func(t *testing.T) { - error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image" + err = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image" transform = func(config *dexpreopt.GlobalConfig) { config.BootJars = []string{"some-updatable-apex:some-updatable-apex-lib"} } - testNoUpdatableJarsInBootImage(t, error, transform) + testNoUpdatableJarsInBootImage(t, err, transform) }) t.Run("non-updatable jar from some other apex in the framework boot image => ok", func(t *testing.T) { @@ -4967,27 +5025,27 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { }) t.Run("nonexistent jar in the ART boot image => error", func(t *testing.T) { - error = "failed to find a dex jar path for module 'nonexistent'" + err = "failed to find a dex jar path for module 'nonexistent'" transform = func(config *dexpreopt.GlobalConfig) { config.ArtApexJars = []string{"platform:nonexistent"} } - testNoUpdatableJarsInBootImage(t, error, transform) + testNoUpdatableJarsInBootImage(t, err, transform) }) t.Run("nonexistent jar in the framework boot image => error", func(t *testing.T) { - error = "failed to find a dex jar path for module 'nonexistent'" + err = "failed to find a dex jar path for module 'nonexistent'" transform = func(config *dexpreopt.GlobalConfig) { config.BootJars = []string{"platform:nonexistent"} } - testNoUpdatableJarsInBootImage(t, error, transform) + testNoUpdatableJarsInBootImage(t, err, transform) }) t.Run("platform jar in the ART boot image => error", func(t *testing.T) { - error = "module 'some-platform-lib' is not allowed in the ART boot image" + err = "module 'some-platform-lib' is not allowed in the ART boot image" transform = func(config *dexpreopt.GlobalConfig) { config.ArtApexJars = []string{"platform:some-platform-lib"} } - testNoUpdatableJarsInBootImage(t, error, transform) + testNoUpdatableJarsInBootImage(t, err, transform) }) t.Run("platform jar in the framework boot image => ok", func(t *testing.T) { diff --git a/apex/builder.go b/apex/builder.go index 0108d068a..17eac1a39 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -69,11 +69,14 @@ var ( // by default set to (uid/gid/mode) = (1000/1000/0644) // TODO(b/113082813) make this configurable using config.fs syntax generateFsConfig = pctx.StaticRule("generateFsConfig", blueprint.RuleParams{ - Command: `echo '/ 1000 1000 0755' > ${out} && ` + - `echo ${ro_paths} | tr ' ' '\n' | awk '{print "/"$$1 " 1000 1000 0644"}' >> ${out} && ` + - `echo ${exec_paths} | tr ' ' '\n' | awk '{print "/"$$1 " 0 2000 0755"}' >> ${out}`, - Description: "fs_config ${out}", - }, "ro_paths", "exec_paths") + Command: `( echo '/ 1000 1000 0755' ` + + `&& for i in ${ro_paths}; do echo "/$$i 1000 1000 0644"; done ` + + `&& for i in ${exec_paths}; do echo "/$$i 0 2000 0755"; done ` + + `&& ( tr ' ' '\n' <${out}.apklist | for i in ${apk_paths}; do read apk; echo "/$$i 0 2000 0755"; zipinfo -1 $$apk | sed "s:\(.*\):/$$i/\1 1000 1000 0644:"; done ) ) > ${out}`, + Description: "fs_config ${out}", + Rspfile: "$out.apklist", + RspfileContent: "$in", + }, "ro_paths", "exec_paths", "apk_paths") apexManifestRule = pctx.StaticRule("apexManifestRule", blueprint.RuleParams{ Command: `rm -f $out && ${jsonmodify} $in ` + @@ -287,7 +290,7 @@ func (a *apexBundle) buildBundleConfig(ctx android.ModuleContext) android.Output // collect the manifest names and paths of android apps // if their manifest names are overridden for _, fi := range a.filesInfo { - if fi.class != app { + if fi.class != app && fi.class != appSet { continue } packageName := fi.overriddenPackageName @@ -337,13 +340,22 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { var copyCommands []string for _, fi := range a.filesInfo { destPath := android.PathForModuleOut(ctx, "image"+suffix, fi.Path()).String() - copyCommands = append(copyCommands, "mkdir -p "+filepath.Dir(destPath)) + destPathDir := filepath.Dir(destPath) + if fi.class == appSet { + copyCommands = append(copyCommands, "rm -rf "+destPathDir) + } + copyCommands = append(copyCommands, "mkdir -p "+destPathDir) if a.linkToSystemLib && fi.transitiveDep && fi.AvailableToPlatform() { // TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here pathOnDevice := filepath.Join("/system", fi.Path()) copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath) } else { - copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath) + if fi.class == appSet { + copyCommands = append(copyCommands, + fmt.Sprintf("unzip -q -d %s %s", destPathDir, fi.builtFile.String())) + } else { + copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath) + } implicitInputs = append(implicitInputs, fi.builtFile) } // create additional symlinks pointing the file inside the APEX @@ -416,6 +428,8 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { // files and dirs that will be created in APEX var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"} var executablePaths []string // this also includes dirs + var extractedAppSetPaths android.Paths + var extractedAppSetDirs []string for _, f := range a.filesInfo { pathInApex := f.Path() if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") { @@ -426,6 +440,9 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { for _, s := range f.symlinks { executablePaths = append(executablePaths, filepath.Join(f.installDir, s)) } + } else if f.class == appSet { + extractedAppSetPaths = append(extractedAppSetPaths, f.builtFile) + extractedAppSetDirs = append(extractedAppSetDirs, f.installDir) } else { readOnlyPaths = append(readOnlyPaths, pathInApex) } @@ -446,9 +463,11 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { Rule: generateFsConfig, Output: cannedFsConfig, Description: "generate fs config", + Inputs: extractedAppSetPaths, Args: map[string]string{ "ro_paths": strings.Join(readOnlyPaths, " "), "exec_paths": strings.Join(executablePaths, " "), + "apk_paths": strings.Join(extractedAppSetDirs, " "), }, }) diff --git a/cc/androidmk.go b/cc/androidmk.go index 3ce1a8955..52480ea68 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -548,6 +548,25 @@ func (c *vendorSnapshotBinaryDecorator) AndroidMkEntries(ctx AndroidMkContext, e }) } +func (c *vendorSnapshotObjectLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { + entries.Class = "STATIC_LIBRARIES" + + if c.androidMkVendorSuffix { + entries.SubName = vendorSuffix + } else { + entries.SubName = "" + } + + entries.ExtraFooters = append(entries.ExtraFooters, + func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) { + out := entries.OutputFile.Path() + varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, entries.SubName) + + fmt.Fprintf(w, "\n%s := %s\n", varname, out.String()) + fmt.Fprintln(w, ".KATI_READONLY: "+varname) + }) +} + func (c *ndkPrebuiltStlLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { entries.Class = "SHARED_LIBRARIES" } diff --git a/cc/binary.go b/cc/binary.go index 661264eef..251b7f0c4 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -231,6 +231,10 @@ func (binary *binaryDecorator) staticBinary() bool { return binary.static() } +func (binary *binaryDecorator) binary() bool { + return true +} + func (binary *binaryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { flags = binary.baseLinker.linkerFlags(ctx, flags) @@ -316,6 +316,8 @@ type ModuleContextIntf interface { static() bool staticBinary() bool header() bool + binary() bool + object() bool toolchain() config.Toolchain canUseSdk() bool useSdk() bool @@ -1017,14 +1019,8 @@ func (c *Module) nativeCoverage() bool { } func (c *Module) isSnapshotPrebuilt() bool { - if _, ok := c.linker.(*vndkPrebuiltLibraryDecorator); ok { - return true - } - if _, ok := c.linker.(*vendorSnapshotLibraryDecorator); ok { - return true - } - if _, ok := c.linker.(*vendorSnapshotBinaryDecorator); ok { - return true + if p, ok := c.linker.(interface{ isSnapshotPrebuilt() bool }); ok { + return p.isSnapshotPrebuilt() } return false } @@ -1129,6 +1125,14 @@ func (ctx *moduleContextImpl) header() bool { return ctx.mod.header() } +func (ctx *moduleContextImpl) binary() bool { + return ctx.mod.binary() +} + +func (ctx *moduleContextImpl) object() bool { + return ctx.mod.object() +} + func (ctx *moduleContextImpl) canUseSdk() bool { return ctx.mod.canUseSdk() } @@ -1925,7 +1929,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { if deps.StaticUnwinderIfLegacy { actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, - }, staticUnwinderDepTag, staticUnwinder(actx)) + }, staticUnwinderDepTag, rewriteSnapshotLibs(staticUnwinder(actx), vendorSnapshotStaticLibs)) } for _, lib := range deps.LateStaticLibs { @@ -2006,11 +2010,13 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { actx.AddVariationDependencies(nil, objDepTag, deps.ObjFiles...) + vendorSnapshotObjects := vendorSnapshotObjects(actx.Config()) + if deps.CrtBegin != "" { - actx.AddVariationDependencies(nil, CrtBeginDepTag, deps.CrtBegin) + actx.AddVariationDependencies(nil, CrtBeginDepTag, rewriteSnapshotLibs(deps.CrtBegin, vendorSnapshotObjects)) } if deps.CrtEnd != "" { - actx.AddVariationDependencies(nil, CrtEndDepTag, deps.CrtEnd) + actx.AddVariationDependencies(nil, CrtEndDepTag, rewriteSnapshotLibs(deps.CrtEnd, vendorSnapshotObjects)) } if deps.LinkerFlagsFile != "" { actx.AddDependency(c, linkerFlagsDepTag, deps.LinkerFlagsFile) @@ -2752,6 +2758,24 @@ func (c *Module) header() bool { return false } +func (c *Module) binary() bool { + if b, ok := c.linker.(interface { + binary() bool + }); ok { + return b.binary() + } + return false +} + +func (c *Module) object() bool { + if o, ok := c.linker.(interface { + object() bool + }); ok { + return o.object() + } + return false +} + func (c *Module) getMakeLinkType(actx android.ModuleContext) string { if c.UseVndk() { if lib, ok := c.linker.(*llndkStubDecorator); ok { @@ -3064,20 +3088,32 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { // This will be available in /system, /vendor and /product // or a /system directory that is available to vendor and product. coreVariantNeeded = true - vendorVariants = append(vendorVariants, platformVndkVersion) - productVariants = append(productVariants, platformVndkVersion) - // VNDK modules must not create BOARD_VNDK_VERSION variant because its - // code is PLATFORM_VNDK_VERSION. - // On the other hand, vendor_available modules which are not VNDK should - // also build BOARD_VNDK_VERSION because it's installed in /vendor. + + // We assume that modules under proprietary paths are compatible for + // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or + // PLATFORM_VNDK_VERSION. + if isVendorProprietaryPath(mctx.ModuleDir()) { + vendorVariants = append(vendorVariants, boardVndkVersion) + } else { + vendorVariants = append(vendorVariants, platformVndkVersion) + } + // vendor_available modules are also available to /product. + productVariants = append(productVariants, platformVndkVersion) + // VNDK is always PLATFORM_VNDK_VERSION if !m.IsVndk() { - vendorVariants = append(vendorVariants, boardVndkVersion) productVariants = append(productVariants, productVndkVersion) } } else if vendorSpecific && String(m.Properties.Sdk_version) == "" { // This will be available in /vendor (or /odm) only - vendorVariants = append(vendorVariants, boardVndkVersion) + // We assume that modules under proprietary paths are compatible for + // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or + // PLATFORM_VNDK_VERSION. + if isVendorProprietaryPath(mctx.ModuleDir()) { + vendorVariants = append(vendorVariants, boardVndkVersion) + } else { + vendorVariants = append(vendorVariants, platformVndkVersion) + } } else { // This is either in /system (or similar: /data), or is a // modules built with the NDK. Modules built with the NDK diff --git a/cc/cc_test.go b/cc/cc_test.go index 67eb248d2..76b4e38e2 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -258,9 +258,7 @@ func checkVndkModule(t *testing.T, ctx *android.TestContext, name, subDir string } } -func checkSnapshot(t *testing.T, ctx *android.TestContext, singletonName, moduleName, snapshotFilename, subDir, variant string) { - snapshotSingleton := ctx.SingletonForTests(singletonName) - +func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) { mod, ok := ctx.ModuleForTests(moduleName, variant).Module().(android.OutputFileProducer) if !ok { t.Errorf("%q must have output\n", moduleName) @@ -273,7 +271,7 @@ func checkSnapshot(t *testing.T, ctx *android.TestContext, singletonName, module } snapshotPath := filepath.Join(subDir, snapshotFilename) - out := snapshotSingleton.Output(snapshotPath) + out := singleton.Output(snapshotPath) if out.Input.String() != outputFiles[0].String() { t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0]) } @@ -398,16 +396,18 @@ func TestVndk(t *testing.T) { variant := "android_vendor.VER_arm64_armv8-a_shared" variant2nd := "android_vendor.VER_arm_armv7-a-neon_shared" - checkSnapshot(t, ctx, "vndk-snapshot", "libvndk", "libvndk.so", vndkCoreLibPath, variant) - checkSnapshot(t, ctx, "vndk-snapshot", "libvndk", "libvndk.so", vndkCoreLib2ndPath, variant2nd) - checkSnapshot(t, ctx, "vndk-snapshot", "libvndk_sp", "libvndk_sp-x.so", vndkSpLibPath, variant) - checkSnapshot(t, ctx, "vndk-snapshot", "libvndk_sp", "libvndk_sp-x.so", vndkSpLib2ndPath, variant2nd) + snapshotSingleton := ctx.SingletonForTests("vndk-snapshot") + + checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", vndkCoreLibPath, variant) + checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", vndkCoreLib2ndPath, variant2nd) + checkSnapshot(t, ctx, snapshotSingleton, "libvndk_sp", "libvndk_sp-x.so", vndkSpLibPath, variant) + checkSnapshot(t, ctx, snapshotSingleton, "libvndk_sp", "libvndk_sp-x.so", vndkSpLib2ndPath, variant2nd) snapshotConfigsPath := filepath.Join(snapshotVariantPath, "configs") - checkSnapshot(t, ctx, "vndk-snapshot", "llndk.libraries.txt", "llndk.libraries.txt", snapshotConfigsPath, "") - checkSnapshot(t, ctx, "vndk-snapshot", "vndkcore.libraries.txt", "vndkcore.libraries.txt", snapshotConfigsPath, "") - checkSnapshot(t, ctx, "vndk-snapshot", "vndksp.libraries.txt", "vndksp.libraries.txt", snapshotConfigsPath, "") - checkSnapshot(t, ctx, "vndk-snapshot", "vndkprivate.libraries.txt", "vndkprivate.libraries.txt", snapshotConfigsPath, "") + checkSnapshot(t, ctx, snapshotSingleton, "llndk.libraries.txt", "llndk.libraries.txt", snapshotConfigsPath, "") + checkSnapshot(t, ctx, snapshotSingleton, "vndkcore.libraries.txt", "vndkcore.libraries.txt", snapshotConfigsPath, "") + checkSnapshot(t, ctx, snapshotSingleton, "vndksp.libraries.txt", "vndksp.libraries.txt", snapshotConfigsPath, "") + checkSnapshot(t, ctx, snapshotSingleton, "vndkprivate.libraries.txt", "vndkprivate.libraries.txt", snapshotConfigsPath, "") checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{ "LLNDK: libc.so", @@ -839,6 +839,17 @@ func TestVendorSnapshot(t *testing.T) { vendor_available: true, nocrt: true, } + + toolchain_library { + name: "libb", + vendor_available: true, + src: "libb.a", + } + + cc_object { + name: "obj", + vendor_available: true, + } ` config := TestConfig(buildDir, android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") @@ -849,6 +860,9 @@ func TestVendorSnapshot(t *testing.T) { snapshotDir := "vendor-snapshot" snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64") + snapshotSingleton := ctx.SingletonForTests("vendor-snapshot") + + var jsonFiles []string for _, arch := range [][]string{ []string{"arm64", "armv8-a"}, @@ -861,22 +875,51 @@ func TestVendorSnapshot(t *testing.T) { // For shared libraries, only non-VNDK vendor_available modules are captured sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant) sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") - checkSnapshot(t, ctx, "vendor-snapshot", "libvendor", "libvendor.so", sharedDir, sharedVariant) - checkSnapshot(t, ctx, "vendor-snapshot", "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant) + checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant) + checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant) + jsonFiles = append(jsonFiles, + filepath.Join(sharedDir, "libvendor.so.json"), + filepath.Join(sharedDir, "libvendor_available.so.json")) // For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured. staticVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static", archType, archVariant) staticDir := filepath.Join(snapshotVariantPath, archDir, "static") - checkSnapshot(t, ctx, "vendor-snapshot", "libvndk", "libvndk.a", staticDir, staticVariant) - checkSnapshot(t, ctx, "vendor-snapshot", "libvendor", "libvendor.a", staticDir, staticVariant) - checkSnapshot(t, ctx, "vendor-snapshot", "libvendor_available", "libvendor_available.a", staticDir, staticVariant) - - // For binary libraries, all vendor:true and vendor_available modules are captured. + checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant) + checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.a", staticDir, staticVariant) + checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.a", staticDir, staticVariant) + checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.a", staticDir, staticVariant) + jsonFiles = append(jsonFiles, + filepath.Join(staticDir, "libb.a.json"), + filepath.Join(staticDir, "libvndk.a.json"), + filepath.Join(staticDir, "libvendor.a.json"), + filepath.Join(staticDir, "libvendor_available.a.json")) + + // For binary executables, all vendor:true and vendor_available modules are captured. if archType == "arm64" { binaryVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant) binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary") - checkSnapshot(t, ctx, "vendor-snapshot", "vendor_bin", "vendor_bin", binaryDir, binaryVariant) - checkSnapshot(t, ctx, "vendor-snapshot", "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant) + checkSnapshot(t, ctx, snapshotSingleton, "vendor_bin", "vendor_bin", binaryDir, binaryVariant) + checkSnapshot(t, ctx, snapshotSingleton, "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant) + jsonFiles = append(jsonFiles, + filepath.Join(binaryDir, "vendor_bin.json"), + filepath.Join(binaryDir, "vendor_available_bin.json")) + } + + // For header libraries, all vendor:true and vendor_available modules are captured. + headerDir := filepath.Join(snapshotVariantPath, archDir, "header") + jsonFiles = append(jsonFiles, filepath.Join(headerDir, "libvendor_headers.json")) + + // For object modules, all vendor:true and vendor_available modules are captured. + objectVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant) + objectDir := filepath.Join(snapshotVariantPath, archDir, "object") + checkSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant) + jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json")) + } + + for _, jsonFile := range jsonFiles { + // verify all json files exist + if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { + t.Errorf("%q expected but not found", jsonFile) } } } diff --git a/cc/genrule.go b/cc/genrule.go index 9331448b8..66d178456 100644 --- a/cc/genrule.go +++ b/cc/genrule.go @@ -79,8 +79,14 @@ func (g *GenruleExtraProperties) ExtraImageVariations(ctx android.BaseModuleCont var variants []string if Bool(g.Vendor_available) || ctx.SocSpecific() || ctx.DeviceSpecific() { - variants = append(variants, VendorVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion()) - if vndkVersion := ctx.DeviceConfig().VndkVersion(); vndkVersion != "current" { + vndkVersion := ctx.DeviceConfig().VndkVersion() + // If vndkVersion is current, we can always use PlatformVndkVersion. + // If not, we assume modules under proprietary paths are compatible for + // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, that is + // PLATFORM_VNDK_VERSION. + if vndkVersion == "current" || !isVendorProprietaryPath(ctx.ModuleDir()) { + variants = append(variants, VendorVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion()) + } else { variants = append(variants, VendorVariationPrefix+vndkVersion) } } diff --git a/cc/object.go b/cc/object.go index 19decec37..15a529e85 100644 --- a/cc/object.go +++ b/cc/object.go @@ -158,3 +158,7 @@ func (object *objectLinker) nativeCoverage() bool { func (object *objectLinker) coverageOutputFilePath() android.OptionalPath { return android.OptionalPath{} } + +func (object *objectLinker) object() bool { + return true +} diff --git a/cc/prebuilt.go b/cc/prebuilt.go index ac990f35f..0751f1ca6 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -291,6 +291,10 @@ func (p *prebuiltObjectLinker) link(ctx ModuleContext, return nil } +func (p *prebuiltObjectLinker) object() bool { + return true +} + func newPrebuiltObject() *Module { module := newObject() prebuilt := &prebuiltObjectLinker{ @@ -349,6 +353,10 @@ func (p *prebuiltBinaryLinker) link(ctx ModuleContext, return nil } +func (p *prebuiltBinaryLinker) binary() bool { + return true +} + // cc_prebuilt_binary installs a precompiled executable in srcs property in the // device's directory. func prebuiltBinaryFactory() android.Module { diff --git a/cc/testing.go b/cc/testing.go index be020c596..edbb24d13 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -496,6 +496,7 @@ func TestConfig(buildDir string, os android.OsType, env map[string]string, "my_include": nil, "foo.map.txt": nil, "liba.so": nil, + "libb.a": nil, } GatherRequiredFilesForTest(mockFS) diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go index 5801fc76d..ea94544e3 100644 --- a/cc/vendor_snapshot.go +++ b/cc/vendor_snapshot.go @@ -30,6 +30,7 @@ const ( vendorSnapshotSharedSuffix = ".vendor_shared." vendorSnapshotStaticSuffix = ".vendor_static." vendorSnapshotBinarySuffix = ".vendor_binary." + vendorSnapshotObjectSuffix = ".vendor_object." ) var ( @@ -39,6 +40,7 @@ var ( vendorSnapshotStaticLibsKey = android.NewOnceKey("vendorSnapshotStaticLibs") vendorSnapshotSharedLibsKey = android.NewOnceKey("vendorSnapshotSharedLibs") vendorSnapshotBinariesKey = android.NewOnceKey("vendorSnapshotBinaries") + vendorSnapshotObjectsKey = android.NewOnceKey("vendorSnapshotObjects") ) // vendor snapshot maps hold names of vendor snapshot modules per arch @@ -72,6 +74,12 @@ func vendorSnapshotBinaries(config android.Config) *snapshotMap { }).(*snapshotMap) } +func vendorSnapshotObjects(config android.Config) *snapshotMap { + return config.Once(vendorSnapshotObjectsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + type vendorSnapshotLibraryProperties struct { // snapshot version. Version string @@ -185,6 +193,10 @@ func (p *vendorSnapshotLibraryDecorator) nativeCoverage() bool { return false } +func (p *vendorSnapshotLibraryDecorator) isSnapshotPrebuilt() bool { + return true +} + func (p *vendorSnapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) { if p.matchesWithDevice(ctx.DeviceConfig()) && (p.shared() || p.static()) { p.baseInstaller.install(ctx, file) @@ -337,6 +349,10 @@ func (p *vendorSnapshotBinaryDecorator) link(ctx ModuleContext, return outputFile } +func (p *vendorSnapshotBinaryDecorator) isSnapshotPrebuilt() bool { + return true +} + func VendorSnapshotBinaryFactory() android.Module { module, binary := NewBinary(android.DeviceSupported) binary.baseLinker.Properties.No_libcrt = BoolPtr(true) @@ -364,12 +380,98 @@ func VendorSnapshotBinaryFactory() android.Module { return module.Init() } +type vendorSnapshotObjectProperties struct { + // snapshot version. + Version string + + // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64_ab') + Target_arch string + + // Prebuilt file for each arch. + Src *string `android:"arch_variant"` +} + +type vendorSnapshotObjectLinker struct { + objectLinker + properties vendorSnapshotObjectProperties + androidMkVendorSuffix bool +} + +func (p *vendorSnapshotObjectLinker) Name(name string) string { + return name + p.NameSuffix() +} + +func (p *vendorSnapshotObjectLinker) NameSuffix() string { + versionSuffix := p.version() + if p.arch() != "" { + versionSuffix += "." + p.arch() + } + return vendorSnapshotObjectSuffix + versionSuffix +} + +func (p *vendorSnapshotObjectLinker) version() string { + return p.properties.Version +} + +func (p *vendorSnapshotObjectLinker) arch() string { + return p.properties.Target_arch +} + +func (p *vendorSnapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bool { + if config.DeviceArch() != p.arch() { + return false + } + if p.properties.Src == nil { + return false + } + return true +} + +func (p *vendorSnapshotObjectLinker) link(ctx ModuleContext, + flags Flags, deps PathDeps, objs Objects) android.Path { + if !p.matchesWithDevice(ctx.DeviceConfig()) { + return nil + } + + m := ctx.Module().(*Module) + p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()] + + return android.PathForModuleSrc(ctx, *p.properties.Src) +} + +func (p *vendorSnapshotObjectLinker) nativeCoverage() bool { + return false +} + +func (p *vendorSnapshotObjectLinker) isSnapshotPrebuilt() bool { + return true +} + +func VendorSnapshotObjectFactory() android.Module { + module := newObject() + + prebuilt := &vendorSnapshotObjectLinker{ + objectLinker: objectLinker{ + baseLinker: NewBaseLinker(nil), + }, + } + module.linker = prebuilt + + android.AddLoadHook(module, func(ctx android.LoadHookContext) { + vendorSnapshotLoadHook(ctx, prebuilt) + }) + + module.AddProperties(&prebuilt.properties) + return module.Init() +} + func init() { android.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton) android.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory) android.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory) android.RegisterModuleType("vendor_snapshot_header", VendorSnapshotHeaderFactory) android.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory) + android.RegisterModuleType("vendor_snapshot_object", VendorSnapshotObjectFactory) } func VendorSnapshotSingleton() android.Singleton { @@ -429,7 +531,7 @@ func isVendorProprietaryPath(dir string) bool { // depend on newer VNDK) So they are captured as vendor snapshot To build older vendor // image and newer system image altogether. func isVendorSnapshotModule(m *Module, moduleDir string) bool { - if !m.Enabled() { + if !m.Enabled() || m.Properties.HideFromMake { return false } // skip proprietary modules, but include all VNDK (static) @@ -443,37 +545,37 @@ func isVendorSnapshotModule(m *Module, moduleDir string) bool { return false } // the module must be installed in /vendor - if !m.installable() || m.isSnapshotPrebuilt() || !m.inVendor() { - return false - } - // exclude test modules - if _, ok := m.linker.(interface{ gtest() bool }); ok { - return false - } - // TODO(b/65377115): add full support for sanitizer - if m.sanitize != nil && !m.sanitize.isUnsanitizedVariant() { + if !m.IsForPlatform() || m.isSnapshotPrebuilt() || !m.inVendor() { return false } // Libraries if l, ok := m.linker.(snapshotLibraryInterface); ok { + // TODO(b/65377115): add full support for sanitizer + if m.sanitize != nil { + // cfi, scs and hwasan export both sanitized and unsanitized variants for static and header + // Always use unsanitized variants of them. + for _, t := range []sanitizerType{cfi, scs, hwasan} { + if !l.shared() && m.sanitize.isSanitizerEnabled(t) { + return false + } + } + } if l.static() { - return proptools.BoolDefault(m.VendorProperties.Vendor_available, true) + return m.outputFile.Valid() && proptools.BoolDefault(m.VendorProperties.Vendor_available, true) } if l.shared() { - return !m.IsVndk() + return m.outputFile.Valid() && !m.IsVndk() } return true } - // Binaries - _, ok := m.linker.(*binaryDecorator) - if !ok { - if _, ok := m.linker.(*prebuiltBinaryLinker); !ok { - return false - } + // Binaries and Objects + if m.binary() || m.object() { + return m.outputFile.Valid() && proptools.BoolDefault(m.VendorProperties.Vendor_available, true) } - return proptools.BoolDefault(m.VendorProperties.Vendor_available, true) + + return false } func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { @@ -496,6 +598,8 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont (header only libraries) binary/ (executable binaries) + object/ + (.o object files) arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/ shared/ (.so shared libraries) @@ -505,6 +609,8 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont (header only libraries) binary/ (executable binaries) + object/ + (.o object files) NOTICE_FILES/ (notice files, e.g. libbase.txt) configs/ @@ -620,7 +726,7 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont } propOut = filepath.Join(snapshotArchDir, targetArch, libType, stem+".json") - } else { + } else if m.binary() { // binary flags prop.Symlinks = m.Symlinks() prop.SharedLibs = m.Properties.SnapshotSharedLibs @@ -630,6 +736,17 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base()) ret = append(ret, copyFile(ctx, binPath, snapshotBinOut)) propOut = snapshotBinOut + ".json" + } else if m.object() { + // object files aren't installed to the device, so their names can conflict. + // Use module name as stem. + objPath := m.outputFile.Path() + snapshotObjOut := filepath.Join(snapshotArchDir, targetArch, "object", + ctx.ModuleName(m)+filepath.Ext(objPath.Base())) + ret = append(ret, copyFile(ctx, objPath, snapshotObjOut)) + propOut = snapshotObjOut + ".json" + } else { + ctx.Errorf("unknown module %q in vendor snapshot", m.String()) + return nil } j, err := json.Marshal(prop) @@ -716,6 +833,7 @@ type snapshotInterface interface { var _ snapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil) var _ snapshotInterface = (*vendorSnapshotLibraryDecorator)(nil) var _ snapshotInterface = (*vendorSnapshotBinaryDecorator)(nil) +var _ snapshotInterface = (*vendorSnapshotObjectLinker)(nil) // gathers all snapshot modules for vendor, and disable unnecessary snapshots // TODO(b/145966707): remove mutator and utilize android.Prebuilt to override source modules @@ -731,12 +849,12 @@ func VendorSnapshotMutator(ctx android.BottomUpMutatorContext) { return } - snapshot, ok := module.linker.(snapshotInterface) - if !ok { + if !module.isSnapshotPrebuilt() { return } - if !snapshot.matchesWithDevice(ctx.DeviceConfig()) { + // isSnapshotPrebuilt ensures snapshotInterface + if !module.linker.(snapshotInterface).matchesWithDevice(ctx.DeviceConfig()) { // Disable unnecessary snapshot module, but do not disable // vndk_prebuilt_shared because they might be packed into vndk APEX if !module.IsVndk() { @@ -758,6 +876,8 @@ func VendorSnapshotMutator(ctx android.BottomUpMutatorContext) { } } else if _, ok := module.linker.(*vendorSnapshotBinaryDecorator); ok { snapshotMap = vendorSnapshotBinaries(ctx.Config()) + } else if _, ok := module.linker.(*vendorSnapshotObjectLinker); ok { + snapshotMap = vendorSnapshotObjects(ctx.Config()) } else { return } @@ -804,6 +924,11 @@ func VendorSnapshotSourceMutator(ctx android.BottomUpMutatorContext) { return } + // .. and also filter out llndk library + if module.isLlndk(ctx.Config()) { + return + } + var snapshotMap *snapshotMap if lib, ok := module.linker.(libraryInterface); ok { @@ -815,10 +940,10 @@ func VendorSnapshotSourceMutator(ctx android.BottomUpMutatorContext) { // header snapshotMap = vendorSnapshotHeaderLibs(ctx.Config()) } - } else if _, ok := module.linker.(*binaryDecorator); ok { - snapshotMap = vendorSnapshotBinaries(ctx.Config()) - } else if _, ok := module.linker.(*prebuiltBinaryLinker); ok { + } else if module.binary() { snapshotMap = vendorSnapshotBinaries(ctx.Config()) + } else if module.object() { + snapshotMap = vendorSnapshotObjects(ctx.Config()) } else { return } diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go index 53b518186..5a44c4663 100644 --- a/cc/vndk_prebuilt.go +++ b/cc/vndk_prebuilt.go @@ -186,6 +186,10 @@ func (p *vndkPrebuiltLibraryDecorator) nativeCoverage() bool { return false } +func (p *vndkPrebuiltLibraryDecorator) isSnapshotPrebuilt() bool { + return true +} + func (p *vndkPrebuiltLibraryDecorator) install(ctx ModuleContext, file android.Path) { arches := ctx.DeviceConfig().Arches() if len(arches) == 0 || arches[0].ArchType.String() != p.arch() { diff --git a/dexpreopt/config.go b/dexpreopt/config.go index 98850e51a..3440f8ee6 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -50,6 +50,8 @@ type GlobalConfig struct { UpdatableSystemServerJars []string // jars within apex that are loaded into system server SpeedApps []string // apps that should be speed optimized + BrokenSuboptimalOrderOfSystemServerJars bool // if true, sub-optimal order does not cause a build error + PreoptFlags []string // global dex2oat flags that should be used if no module-specific dex2oat flags are specified DefaultCompilerFilter string // default compiler filter to pass to dex2oat, overridden by --compiler-filter= in module-specific dex2oat flags @@ -98,6 +100,15 @@ type GlobalSoongConfig struct { ConstructContext android.Path } +// LibraryPath contains paths to the library DEX jar on host and on device. +type LibraryPath struct { + Host android.Path + Device string +} + +// LibraryPaths is a map from library name to on-host and on-device paths to its DEX jar. +type LibraryPaths map[string]*LibraryPath + type ModuleConfig struct { Name string DexLocation string // dex location on device @@ -115,7 +126,7 @@ type ModuleConfig struct { EnforceUsesLibraries bool PresentOptionalUsesLibraries []string UsesLibraries []string - LibraryPaths map[string]android.Path + LibraryPaths LibraryPaths Archs []android.ArchType DexPreoptImages []android.Path @@ -163,14 +174,6 @@ func constructPaths(ctx android.PathContext, paths []string) android.Paths { return ret } -func constructPathMap(ctx android.PathContext, paths map[string]string) map[string]android.Path { - ret := map[string]android.Path{} - for key, path := range paths { - ret[key] = constructPath(ctx, path) - } - return ret -} - func constructWritablePath(ctx android.PathContext, path string) android.WritablePath { if path == "" { return nil @@ -262,6 +265,13 @@ func SetTestGlobalConfig(config android.Config, globalConfig *GlobalConfig) { // from Make to read the module dexpreopt.config written in the Make config // stage. func ParseModuleConfig(ctx android.PathContext, data []byte) (*ModuleConfig, error) { + type jsonLibraryPath struct { + Host string + Device string + } + + type jsonLibraryPaths map[string]jsonLibraryPath + type ModuleJSONConfig struct { *ModuleConfig @@ -271,12 +281,24 @@ func ParseModuleConfig(ctx android.PathContext, data []byte) (*ModuleConfig, err DexPath string ManifestPath string ProfileClassListing string - LibraryPaths map[string]string + LibraryPaths jsonLibraryPaths DexPreoptImages []string DexPreoptImageLocations []string PreoptBootClassPathDexFiles []string } + // convert JSON map of library paths to LibraryPaths + constructLibraryPaths := func(ctx android.PathContext, paths jsonLibraryPaths) LibraryPaths { + m := LibraryPaths{} + for lib, path := range paths { + m[lib] = &LibraryPath{ + constructPath(ctx, path.Host), + path.Device, + } + } + return m + } + config := ModuleJSONConfig{} err := json.Unmarshal(data, &config) @@ -289,7 +311,7 @@ func ParseModuleConfig(ctx android.PathContext, data []byte) (*ModuleConfig, err config.ModuleConfig.DexPath = constructPath(ctx, config.DexPath) config.ModuleConfig.ManifestPath = constructPath(ctx, config.ManifestPath) config.ModuleConfig.ProfileClassListing = android.OptionalPathForPath(constructPath(ctx, config.ProfileClassListing)) - config.ModuleConfig.LibraryPaths = constructPathMap(ctx, config.LibraryPaths) + config.ModuleConfig.LibraryPaths = constructLibraryPaths(ctx, config.LibraryPaths) config.ModuleConfig.DexPreoptImages = constructPaths(ctx, config.DexPreoptImages) config.ModuleConfig.DexPreoptImageLocations = config.DexPreoptImageLocations config.ModuleConfig.PreoptBootClassPathDexFiles = constructPaths(ctx, config.PreoptBootClassPathDexFiles) diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index 5275e8fd1..57a9250b6 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -229,8 +229,9 @@ func (m classLoaderContextMap) getValue(sdkVer int) *classLoaderContext { func (m classLoaderContextMap) addLibs(sdkVer int, module *ModuleConfig, libs ...string) { clc := m.getValue(sdkVer) for _, lib := range libs { - clc.Host = append(clc.Host, pathForLibrary(module, lib)) - clc.Target = append(clc.Target, filepath.Join("/system/framework", lib+".jar")) + p := pathForLibrary(module, lib) + clc.Host = append(clc.Host, p.Host) + clc.Target = append(clc.Target, p.Device) } } @@ -314,6 +315,8 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g dexPathHost := SystemServerDexJarHostPath(ctx, module.Name) rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String())) rule.Command().Text("cp -f").Input(module.DexPath).Output(dexPathHost) + + checkSystemServerOrder(ctx, jarIndex) } else { // Pass special class loader context to skip the classpath and collision check. // This will get removed once LOCAL_USES_LIBRARIES is enforced. @@ -555,7 +558,7 @@ func PathToLocation(path android.Path, arch android.ArchType) string { return filepath.Join(filepath.Dir(filepath.Dir(path.String())), filepath.Base(path.String())) } -func pathForLibrary(module *ModuleConfig, lib string) android.Path { +func pathForLibrary(module *ModuleConfig, lib string) *LibraryPath { path, ok := module.LibraryPaths[lib] if !ok { panic(fmt.Errorf("unknown library path for %q", lib)) @@ -607,6 +610,29 @@ func SystemServerDexJarHostPath(ctx android.PathContext, jar string) android.Out } } +// Check the order of jars on the system server classpath and give a warning/error if a jar precedes +// one of its dependencies. This is not an error, but a missed optimization, as dexpreopt won't +// have the dependency jar in the class loader context, and it won't be able to resolve any +// references to its classes and methods. +func checkSystemServerOrder(ctx android.PathContext, jarIndex int) { + mctx, isModule := ctx.(android.ModuleContext) + if isModule { + config := GetGlobalConfig(ctx) + jars := NonUpdatableSystemServerJars(ctx, config) + mctx.WalkDeps(func(dep android.Module, parent android.Module) bool { + depIndex := android.IndexList(dep.Name(), jars) + if jarIndex < depIndex && !config.BrokenSuboptimalOrderOfSystemServerJars { + jar := jars[jarIndex] + dep := jars[depIndex] + mctx.ModuleErrorf("non-optimal order of jars on the system server classpath:"+ + " '%s' precedes its dependency '%s', so dexpreopt is unable to resolve any"+ + " references from '%s' to '%s'.\n", jar, dep, jar, dep) + } + return true + }) + } +} + func contains(l []string, s string) bool { for _, e := range l { if e == s { diff --git a/java/aar.go b/java/aar.go index c8daf835b..7413c8082 100644 --- a/java/aar.go +++ b/java/aar.go @@ -730,7 +730,7 @@ func (a *AARImport) ImplementationAndResourcesJars() android.Paths { return android.Paths{a.classpathFile} } -func (a *AARImport) DexJar() android.Path { +func (a *AARImport) DexJarBuildPath() android.Path { return nil } diff --git a/java/androidmk.go b/java/androidmk.go index 6eb22fd93..62cf169fa 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -69,7 +69,26 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { if !library.ApexModuleBase.AvailableFor(android.AvailableToPlatform) { hideFromMake = true } - if !hideFromMake { + if hideFromMake { + // May still need to add some additional dependencies. This will be called + // once for the platform variant (even if it is not being used) and once each + // for the APEX specific variants. In order to avoid adding the dependency + // multiple times only add it for the platform variant. + checkedModulePaths := library.additionalCheckedModules + if library.IsForPlatform() && len(checkedModulePaths) != 0 { + mainEntries = android.AndroidMkEntries{ + Class: "FAKE", + // Need at least one output file in order for this to take effect. + OutputFile: android.OptionalPathForPath(checkedModulePaths[0]), + Include: "$(BUILD_PHONY_PACKAGE)", + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(entries *android.AndroidMkEntries) { + entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", checkedModulePaths.Strings()...) + }, + }, + } + } + } else { mainEntries = android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", DistFile: android.OptionalPathForPath(library.distFile), @@ -104,6 +123,10 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.exportedSdkLibs...) + if len(library.additionalCheckedModules) != 0 { + entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...) + } + if library.proguardDictionary != nil { entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.proguardDictionary) } diff --git a/java/app.go b/java/app.go index a45ab6f99..24dde79f4 100755 --- a/java/app.go +++ b/java/app.go @@ -28,6 +28,7 @@ import ( "android/soong/android" "android/soong/cc" + "android/soong/dexpreopt" "android/soong/tradefed" ) @@ -96,6 +97,14 @@ func (as *AndroidAppSet) Privileged() bool { return Bool(as.properties.Privileged) } +func (as *AndroidAppSet) OutputFile() android.Path { + return as.packedOutput +} + +func (as *AndroidAppSet) MasterFile() string { + return as.masterFile +} + var TargetCpuAbi = map[string]string{ "arm": "ARMEABI_V7A", "arm64": "ARM64_V8A", @@ -120,7 +129,7 @@ func SupportedAbis(ctx android.ModuleContext) []string { } func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { - as.packedOutput = android.PathForModuleOut(ctx, "extracted.zip") + as.packedOutput = android.PathForModuleOut(ctx, ctx.ModuleName()+".zip") // We are assuming here that the master file in the APK // set has `.apk` suffix. If it doesn't the build will fail. // APK sets containing APEX files are handled elsewhere. @@ -145,26 +154,17 @@ func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) "stem": ctx.ModuleName(), }, }) - // TODO(asmundak): add this (it's wrong now, will cause copying extracted.zip) - /* - var installDir android.InstallPath - if Bool(as.properties.Privileged) { - installDir = android.PathForModuleInstall(ctx, "priv-app", as.BaseModuleName()) - } else if ctx.InstallInTestcases() { - installDir = android.PathForModuleInstall(ctx, as.BaseModuleName(), ctx.DeviceConfig().DeviceArch()) - } else { - installDir = android.PathForModuleInstall(ctx, "app", as.BaseModuleName()) - } - ctx.InstallFile(installDir, as.masterFile", as.packedOutput) - */ } // android_app_set extracts a set of APKs based on the target device // configuration and installs this set as "split APKs". -// The set will always contain `base-master.apk` and every APK built -// to the target device. All density-specific APK will be included, too, -// unless PRODUCT_APPT_PREBUILT_DPI is defined (should contain comma-sepearated -// list of density names (LDPI, MDPI, HDPI, etc.) +// The extracted set always contains 'master' APK whose name is +// _module_name_.apk and every split APK matching target device. +// The extraction of the density-specific splits depends on +// PRODUCT_AAPT_PREBUILT_DPI variable. If present (its value should +// be a list density names: LDPI, MDPI, HDPI, etc.), only listed +// splits will be extracted. Otherwise all density-specific splits +// will be extracted. func AndroidApkSetFactory() android.Module { module := &AndroidAppSet{} module.AddProperties(&module.properties) @@ -335,7 +335,7 @@ type Certificate struct { presigned bool } -var presignedCertificate = Certificate{presigned: true} +var PresignedCertificate = Certificate{presigned: true} func (c Certificate) AndroidMkString() string { if c.presigned { @@ -445,8 +445,11 @@ func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVer return } dep, _ := m.(*cc.Module) - jniSdkVersion, err := android.ApiStrToNum(ctx, dep.SdkVersion()) - if err != nil || int(minSdkVersion) < jniSdkVersion { + // The domain of cc.sdk_version is "current" and <number> + // We can rely on sdkSpec to convert it to <number> so that "current" is handled + // properly regardless of sdk finalization. + jniSdkVersion, err := sdkSpecFrom(dep.SdkVersion()).effectiveVersion(ctx) + if err != nil || minSdkVersion < jniSdkVersion { ctx.OtherModuleErrorf(dep, "sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)", dep.SdkVersion(), minSdkVersion, ctx.ModuleName()) return @@ -1186,7 +1189,7 @@ type OverrideAndroidApp struct { android.OverrideModuleBase } -func (i *OverrideAndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { +func (i *OverrideAndroidApp) GenerateAndroidBuildActions(_ android.ModuleContext) { // All the overrides happen in the base module. // TODO(jungjw): Check the base module type. } @@ -1207,7 +1210,7 @@ type OverrideAndroidTest struct { android.OverrideModuleBase } -func (i *OverrideAndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { +func (i *OverrideAndroidTest) GenerateAndroidBuildActions(_ android.ModuleContext) { // All the overrides happen in the base module. // TODO(jungjw): Check the base module type. } @@ -1229,7 +1232,7 @@ type OverrideRuntimeResourceOverlay struct { android.OverrideModuleBase } -func (i *OverrideRuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) { +func (i *OverrideRuntimeResourceOverlay) GenerateAndroidBuildActions(_ android.ModuleContext) { // All the overrides happen in the base module. // TODO(jungjw): Check the base module type. } @@ -1474,7 +1477,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext // Sign or align the package if package has not been preprocessed if a.preprocessed { a.outputFile = srcApk - a.certificate = presignedCertificate + a.certificate = PresignedCertificate } else if !Bool(a.properties.Presigned) { // If the certificate property is empty at this point, default_dev_cert must be set to true. // Which makes processMainCert's behavior for the empty cert string WAI. @@ -1494,7 +1497,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename) TransformZipAlign(ctx, alignedApk, dexOutput) a.outputFile = alignedApk - a.certificate = presignedCertificate + a.certificate = PresignedCertificate } // TODO: Optionally compress the output apk. @@ -1552,7 +1555,7 @@ func (a *AndroidAppImport) Privileged() bool { return Bool(a.properties.Privileged) } -func (a *AndroidAppImport) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { +func (a *AndroidAppImport) DepIsInSameApex(_ android.BaseModuleContext, _ android.Module) bool { // android_app_import might have extra dependencies via uses_libs property. // Don't track the dependency as we don't automatically add those libraries // to the classpath. It should be explicitly added to java_libs property of APEX @@ -1875,24 +1878,30 @@ func (u *usesLibrary) presentOptionalUsesLibs(ctx android.BaseModuleContext) []s return optionalUsesLibs } -// usesLibraryPaths returns a map of module names of shared library dependencies to the paths to their dex jars. -func (u *usesLibrary) usesLibraryPaths(ctx android.ModuleContext) map[string]android.Path { - usesLibPaths := make(map[string]android.Path) +// usesLibraryPaths returns a map of module names of shared library dependencies to the paths +// to their dex jars on host and on device. +func (u *usesLibrary) usesLibraryPaths(ctx android.ModuleContext) dexpreopt.LibraryPaths { + usesLibPaths := make(dexpreopt.LibraryPaths) if !ctx.Config().UnbundledBuild() { ctx.VisitDirectDepsWithTag(usesLibTag, func(m android.Module) { + dep := ctx.OtherModuleName(m) if lib, ok := m.(Dependency); ok { - if dexJar := lib.DexJar(); dexJar != nil { - usesLibPaths[ctx.OtherModuleName(m)] = dexJar + if dexJar := lib.DexJarBuildPath(); dexJar != nil { + usesLibPaths[dep] = &dexpreopt.LibraryPath{ + dexJar, + // TODO(b/132357300): propagate actual install paths here. + filepath.Join("/system/framework", dep+".jar"), + } } else { - ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must produce a dex jar, does it have installable: true?", - ctx.OtherModuleName(m)) + ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must"+ + " produce a dex jar, does it have installable: true?", dep) } } else if ctx.Config().AllowMissingDependencies() { - ctx.AddMissingDependencies([]string{ctx.OtherModuleName(m)}) + ctx.AddMissingDependencies([]string{dep}) } else { - ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be a java library", - ctx.OtherModuleName(m)) + ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be "+ + "a java library", dep) } }) } diff --git a/java/app_test.go b/java/app_test.go index eb583bea6..eeba161b3 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -149,7 +149,7 @@ func TestAndroidAppSet(t *testing.T) { prerelease: true, }`) module := ctx.ModuleForTests("foo", "android_common") - const packedSplitApks = "extracted.zip" + const packedSplitApks = "foo.zip" params := module.Output(packedSplitApks) if params.Rule == nil { t.Errorf("expected output %s is missing", packedSplitApks) @@ -218,7 +218,7 @@ func TestAndroidAppSet_Variants(t *testing.T) { ctx := testContext() run(t, ctx, config) module := ctx.ModuleForTests("foo", "android_common") - const packedSplitApks = "extracted.zip" + const packedSplitApks = "foo.zip" params := module.Output(packedSplitApks) for k, v := range test.expected { if actual := params.Args[k]; actual != v { diff --git a/java/builder.go b/java/builder.go index 640dba93b..a27e5c390 100644 --- a/java/builder.go +++ b/java/builder.go @@ -206,7 +206,7 @@ var ( blueprint.RuleParams{ Command: "rm -f $out && " + "${config.PackageCheckCmd} $in $packages && " + - "cp $in $out", + "touch $out", CommandDeps: []string{"${config.PackageCheckCmd}"}, }, "packages") @@ -547,9 +547,8 @@ func TransformJarJar(ctx android.ModuleContext, outputFile android.WritablePath, }) } -func CheckJarPackages(ctx android.ModuleContext, classesJar android.Path, permittedPackages []string) android.ModuleOutPath { - outputFile := android.PathForModuleOut(ctx, "package-check", classesJar.Base()) - +func CheckJarPackages(ctx android.ModuleContext, outputFile android.WritablePath, + classesJar android.Path, permittedPackages []string) { ctx.Build(pctx, android.BuildParams{ Rule: packageCheck, Description: "packageCheck", @@ -559,8 +558,6 @@ func CheckJarPackages(ctx android.ModuleContext, classesJar android.Path, permit "packages": strings.Join(permittedPackages, " "), }, }) - - return outputFile } func TransformJetifier(ctx android.ModuleContext, outputFile android.WritablePath, diff --git a/java/device_host_converter.go b/java/device_host_converter.go index b40ab9316..1ffb13f94 100644 --- a/java/device_host_converter.go +++ b/java/device_host_converter.go @@ -150,7 +150,7 @@ func (d *DeviceHostConverter) ImplementationAndResourcesJars() android.Paths { return d.implementationAndResourceJars } -func (d *DeviceHostConverter) DexJar() android.Path { +func (d *DeviceHostConverter) DexJarBuildPath() android.Path { return nil } diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 4725b0781..2911fd9b9 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -37,7 +37,7 @@ type dexpreopter struct { usesLibs []string optionalUsesLibs []string enforceUsesLibs bool - libraryPaths map[string]android.Path + libraryPaths dexpreopt.LibraryPaths builtInstalled string } diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index ed61d4bd3..9d9383814 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -255,7 +255,7 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul return -1, nil } - jar, hasJar := module.(interface{ DexJar() android.Path }) + jar, hasJar := module.(interface{ DexJarBuildPath() android.Path }) if !hasJar { return -1, nil } @@ -296,7 +296,7 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul panic("unknown boot image: " + image.name) } - return index, jar.DexJar() + return index, jar.DexJarBuildPath() } // buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image. diff --git a/java/droiddoc.go b/java/droiddoc.go index b16c9cd72..d61c62c60 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -1334,13 +1334,10 @@ func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.Ru d.annotationsZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"_annotations.zip") cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip) - if len(d.properties.Merge_annotations_dirs) == 0 { - ctx.PropertyErrorf("merge_annotations_dirs", - "has to be non-empty if annotations was enabled!") + if len(d.properties.Merge_annotations_dirs) != 0 { + d.mergeAnnoDirFlags(ctx, cmd) } - d.mergeAnnoDirFlags(ctx, cmd) - // TODO(tnorbye): find owners to fix these warnings when annotation was enabled. cmd.FlagWithArg("--hide ", "HiddenTypedefConstant"). FlagWithArg("--hide ", "SuperfluousPrefix"). diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index c7f7cbdfe..2f35798b5 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -147,7 +147,7 @@ func stubFlagsRule(ctx android.SingletonContext) { name := ctx.ModuleName(module) for moduleList, pathList := range moduleListToPathList { if i := android.IndexList(name, *moduleList); i != -1 { - pathList[i] = j.DexJar() + pathList[i] = j.DexJarBuildPath() } } } diff --git a/java/java.go b/java/java.go index 09df2ad43..0ba1f5a7a 100644 --- a/java/java.go +++ b/java/java.go @@ -463,6 +463,9 @@ type Module struct { // expanded Jarjar_rules expandJarjarRules android.Path + // list of additional targets for checkbuild + additionalCheckedModules android.Paths + // Extra files generated by the module type to be added as java resources. extraResources android.Paths @@ -498,7 +501,7 @@ type Dependency interface { ImplementationJars() android.Paths ResourceJars() android.Paths ImplementationAndResourcesJars() android.Paths - DexJar() android.Path + DexJarBuildPath() android.Path AidlIncludeDirs() android.Paths ExportedSdkLibs() []string ExportedPlugins() (android.Paths, []string) @@ -833,41 +836,46 @@ type linkTypeContext interface { } func (m *Module) getLinkType(name string) (ret linkType, stubs bool) { - ver := m.sdkVersion() - switch { - case name == "core.current.stubs" || name == "core.platform.api.stubs" || - name == "stub-annotations" || name == "private-stub-annotations-jar" || - name == "core-lambda-stubs" || name == "core-generated-annotation-stubs": + switch name { + case "core.current.stubs", "core.platform.api.stubs", "stub-annotations", + "private-stub-annotations-jar", "core-lambda-stubs", "core-generated-annotation-stubs": return javaCore, true - case ver.kind == sdkCore: - return javaCore, false - case name == "android_system_stubs_current": + case "android_stubs_current": + return javaSdk, true + case "android_system_stubs_current": return javaSystem, true - case ver.kind == sdkSystem: - return javaSystem, false - case name == "android_test_stubs_current": + case "android_module_lib_stubs_current": + return javaModule, true + case "android_system_server_stubs_current": + return javaSystemServer, true + case "android_test_stubs_current": return javaSystem, true - case ver.kind == sdkTest: - return javaPlatform, false - case name == "android_stubs_current": - return javaSdk, true - case ver.kind == sdkPublic: + } + + if stub, linkType := moduleStubLinkType(name); stub { + return linkType, true + } + + ver := m.sdkVersion() + switch ver.kind { + case sdkCore: + return javaCore, false + case sdkSystem: + return javaSystem, false + case sdkPublic: return javaSdk, false - case name == "android_module_lib_stubs_current": - return javaModule, true - case ver.kind == sdkModule: + case sdkModule: return javaModule, false - case name == "android_system_server_stubs_current": - return javaSystemServer, true - case ver.kind == sdkSystemServer: + case sdkSystemServer: return javaSystemServer, false - case ver.kind == sdkPrivate || ver.kind == sdkNone || ver.kind == sdkCorePlatform: + case sdkPrivate, sdkNone, sdkCorePlatform, sdkTest: return javaPlatform, false - case !ver.valid(): + } + + if !ver.valid() { panic(fmt.Errorf("sdk_version is invalid. got %q", ver.raw)) - default: - return javaSdk, false } + return javaSdk, false } func checkLinkType(ctx android.ModuleContext, from *Module, to linkTypeContext, tag dependencyTag) { @@ -1518,10 +1526,10 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // Check package restrictions if necessary. if len(j.properties.Permitted_packages) > 0 { - // Check packages and copy input to package-checked file. - // Use the file copied after a successful package check as the output file for this - // module so that any dependencies on this module will trigger the package check. - outputFile = CheckJarPackages(ctx, outputFile, j.properties.Permitted_packages) + // Check packages and copy to package-checked file. + pkgckFile := android.PathForModuleOut(ctx, "package-check.stamp") + CheckJarPackages(ctx, pkgckFile, outputFile, j.properties.Permitted_packages) + j.additionalCheckedModules = append(j.additionalCheckedModules, pkgckFile) if ctx.Failed() { return @@ -1736,7 +1744,7 @@ func (j *Module) ImplementationJars() android.Paths { return android.Paths{j.implementationJarFile} } -func (j *Module) DexJar() android.Path { +func (j *Module) DexJarBuildPath() android.Path { return j.dexJarFile } @@ -2562,7 +2570,7 @@ func (j *Import) ImplementationAndResourcesJars() android.Paths { return android.Paths{j.combinedClasspathFile} } -func (j *Import) DexJar() android.Path { +func (j *Import) DexJarBuildPath() android.Path { return nil } @@ -2688,6 +2696,10 @@ func (j *DexImport) Stem() string { return proptools.StringDefault(j.properties.Stem, j.ModuleBase.Name()) } +func (a *DexImport) JacocoReportClassesFile() android.Path { + return nil +} + func (j *DexImport) IsInstallable() bool { return true } @@ -2745,7 +2757,7 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.Stem()+".jar", dexOutputFile) } -func (j *DexImport) DexJar() android.Path { +func (j *DexImport) DexJarBuildPath() android.Path { return j.dexJarFile } diff --git a/java/sdk.go b/java/sdk.go index 9310f7846..2a08f329e 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -35,6 +35,7 @@ func init() { var sdkVersionsKey = android.NewOnceKey("sdkVersionsKey") var sdkFrameworkAidlPathKey = android.NewOnceKey("sdkFrameworkAidlPathKey") +var nonUpdatableFrameworkAidlPathKey = android.NewOnceKey("nonUpdatableFrameworkAidlPathKey") var apiFingerprintPathKey = android.NewOnceKey("apiFingerprintPathKey") type sdkContext interface { @@ -447,7 +448,7 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep return toModule([]string{"core.current.stubs"}, "", nil) case sdkModule: // TODO(146757305): provide .apk and .aidl that have more APIs for modules - return toModule([]string{"android_module_lib_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx)) + return toModule([]string{"android_module_lib_stubs_current"}, "framework-res", nonUpdatableFrameworkAidlPath(ctx)) case sdkSystemServer: // TODO(146757305): provide .apk and .aidl that have more APIs for modules return toModule([]string{"android_system_server_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx)) @@ -506,6 +507,7 @@ func (sdkSingleton) GenerateBuildActions(ctx android.SingletonContext) { } createSdkFrameworkAidl(ctx) + createNonUpdatableFrameworkAidl(ctx) createAPIFingerprint(ctx) } @@ -517,6 +519,31 @@ func createSdkFrameworkAidl(ctx android.SingletonContext) { "android_system_stubs_current", } + combinedAidl := sdkFrameworkAidlPath(ctx) + tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp") + + rule := createFrameworkAidl(stubsModules, tempPath, ctx) + + commitChangeForRestat(rule, tempPath, combinedAidl) + + rule.Build(pctx, ctx, "framework_aidl", "generate framework.aidl") +} + +// Creates a version of framework.aidl for the non-updatable part of the platform. +func createNonUpdatableFrameworkAidl(ctx android.SingletonContext) { + stubsModules := []string{"android_module_lib_stubs_current"} + + combinedAidl := nonUpdatableFrameworkAidlPath(ctx) + tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp") + + rule := createFrameworkAidl(stubsModules, tempPath, ctx) + + commitChangeForRestat(rule, tempPath, combinedAidl) + + rule.Build(pctx, ctx, "framework_non_updatable_aidl", "generate framework_non_updatable.aidl") +} + +func createFrameworkAidl(stubsModules []string, path android.OutputPath, ctx android.SingletonContext) *android.RuleBuilder { stubsJars := make([]android.Paths, len(stubsModules)) ctx.VisitAllModules(func(module android.Module) { @@ -536,8 +563,7 @@ func createSdkFrameworkAidl(ctx android.SingletonContext) { if ctx.Config().AllowMissingDependencies() { missingDeps = append(missingDeps, stubsModules[i]) } else { - ctx.Errorf("failed to find dex jar path for module %q", - stubsModules[i]) + ctx.Errorf("failed to find dex jar path for module %q", stubsModules[i]) } } } @@ -561,20 +587,15 @@ func createSdkFrameworkAidl(ctx android.SingletonContext) { } } - combinedAidl := sdkFrameworkAidlPath(ctx) - tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp") - rule.Command(). - Text("rm -f").Output(tempPath) + Text("rm -f").Output(path) rule.Command(). Text("cat"). Inputs(aidls). Text("| sort -u >"). - Output(tempPath) + Output(path) - commitChangeForRestat(rule, tempPath, combinedAidl) - - rule.Build(pctx, ctx, "framework_aidl", "generate framework.aidl") + return rule } func sdkFrameworkAidlPath(ctx android.PathContext) android.OutputPath { @@ -583,6 +604,12 @@ func sdkFrameworkAidlPath(ctx android.PathContext) android.OutputPath { }).(android.OutputPath) } +func nonUpdatableFrameworkAidlPath(ctx android.PathContext) android.OutputPath { + return ctx.Config().Once(nonUpdatableFrameworkAidlPathKey, func() interface{} { + return android.PathForOutput(ctx, "framework_non_updatable.aidl") + }).(android.OutputPath) +} + // Create api_fingerprint.txt func createAPIFingerprint(ctx android.SingletonContext) { out := ApiFingerprintPath(ctx) diff --git a/java/sdk_library.go b/java/sdk_library.go index 67b0bd603..de5ee03c4 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -1113,7 +1113,9 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false) props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags - props.Java_version = module.properties.Java_version + // We compile the stubs for 1.8 in line with the main android.jar stubs, and potential + // interop with older developer tools that don't support 1.9. + props.Java_version = proptools.StringPtr("1.8") if module.deviceProperties.Compile_dex != nil { props.Compile_dex = module.deviceProperties.Compile_dex } @@ -1575,6 +1577,24 @@ func (s *frameworkModulesNamingScheme) apiModuleName(scope *apiScope, baseName s var _ sdkLibraryComponentNamingScheme = (*frameworkModulesNamingScheme)(nil) +func moduleStubLinkType(name string) (stub bool, ret linkType) { + // This suffix-based approach is fragile and could potentially mis-trigger. + // TODO(b/155164730): Clean this up when modules no longer reference sdk_lib stubs directly. + if strings.HasSuffix(name, ".stubs.public") || strings.HasSuffix(name, "-stubs-publicapi") { + return true, javaSdk + } + if strings.HasSuffix(name, ".stubs.system") || strings.HasSuffix(name, "-stubs-systemapi") { + return true, javaSystem + } + if strings.HasSuffix(name, ".stubs.module_lib") || strings.HasSuffix(name, "-stubs-module_libs_api") { + return true, javaModule + } + if strings.HasSuffix(name, ".stubs.test") { + return true, javaSystem + } + return false, javaPlatform +} + // java_sdk_library is a special Java library that provides optional platform APIs to apps. // In practice, it can be viewed as a combination of several modules: 1) stubs library that clients // are linked against to, 2) droiddoc module that internally generates API stubs source files, diff --git a/java/sdk_test.go b/java/sdk_test.go index fb8646313..52d2df552 100644 --- a/java/sdk_test.go +++ b/java/sdk_test.go @@ -252,7 +252,7 @@ func TestClasspath(t *testing.T) { bootclasspath: []string{"android_module_lib_stubs_current", "core-lambda-stubs"}, system: "core-current-stubs-system-modules", java9classpath: []string{"android_module_lib_stubs_current"}, - aidl: "-p" + buildDir + "/framework.aidl", + aidl: "-p" + buildDir + "/framework_non_updatable.aidl", }, { name: "system_server_current", diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go index a559330cb..7dc4915e2 100644 --- a/ui/build/dumpvars.go +++ b/ui/build/dumpvars.go @@ -54,18 +54,16 @@ func DumpMakeVars(ctx Context, config Config, goals, vars []string) (map[string] var ret map[string]string if len(makeVars) > 0 { + // It's not safe to use the same TMPDIR as the build, as that can be removed. tmpDir, err := ioutil.TempDir("", "dumpvars") if err != nil { return nil, err } defer os.RemoveAll(tmpDir) - // It's not safe to use the same TMPDIR as the build, as that can be removed. - config.Environment().Set("TMPDIR", tmpDir) - - SetupLitePath(ctx, config) + SetupLitePath(ctx, config, tmpDir) - ret, err = dumpMakeVars(ctx, config, goals, makeVars, false) + ret, err = dumpMakeVars(ctx, config, goals, makeVars, false, tmpDir) if err != nil { return ret, err } @@ -82,7 +80,7 @@ func DumpMakeVars(ctx Context, config Config, goals, vars []string) (map[string] return ret, nil } -func dumpMakeVars(ctx Context, config Config, goals, vars []string, write_soong_vars bool) (map[string]string, error) { +func dumpMakeVars(ctx Context, config Config, goals, vars []string, write_soong_vars bool, tmpDir string) (map[string]string, error) { ctx.BeginTrace(metrics.RunKati, "dumpvars") defer ctx.EndTrace() @@ -98,6 +96,9 @@ func dumpMakeVars(ctx Context, config Config, goals, vars []string, write_soong_ cmd.Environment.Set("WRITE_SOONG_VARIABLES", "true") } cmd.Environment.Set("DUMP_MANY_VARS", strings.Join(vars, " ")) + if tmpDir != "" { + cmd.Environment.Set("TMPDIR", tmpDir) + } cmd.Sandbox = dumpvarsSandbox output := bytes.Buffer{} cmd.Stdout = &output @@ -253,7 +254,7 @@ func runMakeProductConfig(ctx Context, config Config) { "BUILD_BROKEN_USES_BUILD_STATIC_LIBRARY", }, exportEnvVars...), BannerVars...) - make_vars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true) + make_vars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true, "") if err != nil { ctx.Fatalln("Error dumping make vars:", err) } diff --git a/ui/build/path.go b/ui/build/path.go index 7122927a6..6f5cf78b1 100644 --- a/ui/build/path.go +++ b/ui/build/path.go @@ -55,8 +55,9 @@ func parsePathDir(dir string) []string { } // A "lite" version of SetupPath used for dumpvars, or other places that need -// minimal overhead (but at the expense of logging). -func SetupLitePath(ctx Context, config Config) { +// minimal overhead (but at the expense of logging). If tmpDir is empty, the +// default TMPDIR is used from config. +func SetupLitePath(ctx Context, config Config, tmpDir string) { if config.pathReplaced { return } @@ -65,8 +66,11 @@ func SetupLitePath(ctx Context, config Config) { defer ctx.EndTrace() origPath, _ := config.Environment().Get("PATH") - myPath, _ := config.Environment().Get("TMPDIR") - myPath = filepath.Join(myPath, "path") + + if tmpDir == "" { + tmpDir, _ = config.Environment().Get("TMPDIR") + } + myPath := filepath.Join(tmpDir, "path") ensureEmptyDirectoriesExist(ctx, myPath) os.Setenv("PATH", origPath) |