diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go index f383de90a..8e71a9784 100644 --- a/cmd/merge_zips/merge_zips.go +++ b/cmd/merge_zips/merge_zips.go @@ -173,6 +173,10 @@ func (ze zipEntry) CRC32() uint32 { return ze.content.FileHeader.CRC32 } +func (ze zipEntry) Size() uint64 { + return ze.content.FileHeader.UncompressedSize64 +} + func (ze zipEntry) WriteToZip(dest string, zw *zip.Writer) error { return zw.CopyFrom(ze.content, dest) } @@ -195,6 +199,10 @@ func (be bufferEntry) CRC32() uint32 { return crc32.ChecksumIEEE(be.content) } +func (be bufferEntry) Size() uint64 { + return uint64(len(be.content)) +} + func (be bufferEntry) WriteToZip(dest string, zw *zip.Writer) error { w, err := zw.CreateHeader(be.fh) if err != nil { @@ -215,6 +223,7 @@ type zipSource interface { String() string IsDir() bool CRC32() uint32 + Size() uint64 WriteToZip(dest string, zw *zip.Writer) error } @@ -369,25 +378,27 @@ func mergeZips(readers []namedZipReader, writer *zip.Writer, manifest, entrypoin return fmt.Errorf("Directory/file mismatch at %v from %v and %v\n", dest, existingSource, source) } + if ignoreDuplicates { continue } + if emulateJar && file.Name == jar.ManifestFile || file.Name == jar.ModuleInfoClass { // Skip manifest and module info files that are not from the first input file continue } - if !source.IsDir() { - if emulateJar { - if existingSource.CRC32() != source.CRC32() { - fmt.Fprintf(os.Stdout, "WARNING: Duplicate path %v found in %v and %v\n", - dest, existingSource, source) - } - } else { - return fmt.Errorf("Duplicate path %v found in %v and %v\n", - dest, existingSource, source) - } + + if source.IsDir() { + continue } + + if existingSource.CRC32() == source.CRC32() && existingSource.Size() == source.Size() { + continue + } + + return fmt.Errorf("Duplicate path %v found in %v and %v\n", + dest, existingSource, source) } } } diff --git a/cmd/merge_zips/merge_zips_test.go b/cmd/merge_zips/merge_zips_test.go index f91111f14..19fa5edd3 100644 --- a/cmd/merge_zips/merge_zips_test.go +++ b/cmd/merge_zips/merge_zips_test.go @@ -87,6 +87,14 @@ func TestMergeZips(t *testing.T) { ignoreDuplicates: true, }, + { + name: "duplicates identical", + in: [][]testZipEntry{ + {a}, + {a}, + }, + out: []testZipEntry{a}, + }, { name: "sort", in: [][]testZipEntry{ diff --git a/java/aapt2.go b/java/aapt2.go index 70c750716..5553bfdf8 100644 --- a/java/aapt2.go +++ b/java/aapt2.go @@ -111,7 +111,8 @@ func aapt2CompileDirs(ctx android.ModuleContext, flata android.WritablePath, dir var aapt2LinkRule = pctx.AndroidStaticRule("aapt2Link", blueprint.RuleParams{ - Command: `${config.Aapt2Cmd} link -o $out $flags --java $genDir --proguard $proguardOptions ` + + Command: `rm -rf $genDir && ` + + `${config.Aapt2Cmd} link -o $out $flags --java $genDir --proguard $proguardOptions ` + `--output-text-symbols ${rTxt} $inFlags && ` + `${config.SoongZipCmd} -write_if_changed -jar -o $genJar -C $genDir -D $genDir &&` + `${config.ExtractJarPackagesCmd} -i $genJar -o $extraPackages --prefix '--extra-packages '`, diff --git a/java/aar.go b/java/aar.go index 35fb96f78..a06d19164 100644 --- a/java/aar.go +++ b/java/aar.go @@ -250,6 +250,8 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati } switch ctx.OtherModuleDependencyTag(module) { + case instrumentationForTag: + // Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2. case libTag, frameworkResTag: if exportPackage != nil { sharedLibs = append(sharedLibs, exportPackage) diff --git a/java/app.go b/java/app.go index d21b62aec..5d25dcf17 100644 --- a/java/app.go +++ b/java/app.go @@ -318,12 +318,6 @@ type AndroidTest struct { } func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { - if String(a.appTestProperties.Instrumentation_for) != "" { - a.AndroidApp.extraLinkFlags = append(a.AndroidApp.extraLinkFlags, - "--rename-instrumentation-target-package", - String(a.appTestProperties.Instrumentation_for)) - } - a.generateAndroidBuildActions(ctx) a.testConfig = tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config, a.testProperties.Test_config_template, a.manifestPath) @@ -335,6 +329,12 @@ func (a *AndroidTest) DepsMutator(ctx android.BottomUpMutatorContext) { android.ExtractSourceDeps(ctx, a.testProperties.Test_config_template) android.ExtractSourcesDeps(ctx, a.testProperties.Data) a.AndroidApp.DepsMutator(ctx) + if a.appTestProperties.Instrumentation_for != nil { + // The android_app dependency listed in instrumentation_for needs to be added to the classpath for javac, + // but not added to the aapt2 link includes like a normal android_app or android_library dependency, so + // use instrumentationForTag instead of libTag. + ctx.AddVariationDependencies(nil, instrumentationForTag, String(a.appTestProperties.Instrumentation_for)) + } } func AndroidTestFactory() android.Module { diff --git a/java/builder.go b/java/builder.go index f55a7c796..cefb916df 100644 --- a/java/builder.go +++ b/java/builder.go @@ -399,6 +399,17 @@ func TransformJetifier(ctx android.ModuleContext, outputFile android.WritablePat }) } +func GenerateMainClassManifest(ctx android.ModuleContext, outputFile android.WritablePath, mainClass string) { + ctx.Build(pctx, android.BuildParams{ + Rule: android.WriteFile, + Description: "manifest", + Output: outputFile, + Args: map[string]string{ + "content": "Main-Class: " + mainClass + "\n", + }, + }) +} + type classpath []android.Path func (x *classpath) FormJavaClassPath(optName string) string { diff --git a/java/dex.go b/java/dex.go index ce0c18e66..625fb83cc 100644 --- a/java/dex.go +++ b/java/dex.go @@ -157,6 +157,8 @@ func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8F if !Bool(opt.Obfuscate) { r8Flags = append(r8Flags, "-dontobfuscate") } + // TODO(ccross): if this is an instrumentation test of an obfuscated app, use the + // dictionary of the app and move the app from libraryjars to injars. return r8Flags, r8Deps } @@ -171,8 +173,6 @@ func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, outDir := android.PathForModuleOut(ctx, "dex") if useR8 { - // TODO(ccross): if this is an instrumentation test of an obfuscated app, use the - // dictionary of the app and move the app from libraryjars to injars. proguardDictionary := android.PathForModuleOut(ctx, "proguard_dictionary") j.proguardDictionary = proguardDictionary r8Flags, r8Deps := j.r8Flags(ctx, flags) diff --git a/java/java.go b/java/java.go index e5218bb76..d7068c6d9 100644 --- a/java/java.go +++ b/java/java.go @@ -309,6 +309,9 @@ type Module struct { // list of extra progurad flag files extraProguardFlagFiles android.Paths + // manifest file to use instead of properties.Manifest + overrideManifest android.OptionalPath + // list of SDK lib names that this java moudule is exporting exportedSdkLibs []string @@ -368,16 +371,17 @@ type jniDependencyTag struct { } var ( - staticLibTag = dependencyTag{name: "staticlib"} - libTag = dependencyTag{name: "javalib"} - annoTag = dependencyTag{name: "annotation processor"} - bootClasspathTag = dependencyTag{name: "bootclasspath"} - systemModulesTag = dependencyTag{name: "system modules"} - frameworkResTag = dependencyTag{name: "framework-res"} - frameworkApkTag = dependencyTag{name: "framework-apk"} - kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib"} - proguardRaiseTag = dependencyTag{name: "proguard-raise"} - certificateTag = dependencyTag{name: "certificate"} + staticLibTag = dependencyTag{name: "staticlib"} + libTag = dependencyTag{name: "javalib"} + annoTag = dependencyTag{name: "annotation processor"} + bootClasspathTag = dependencyTag{name: "bootclasspath"} + systemModulesTag = dependencyTag{name: "system modules"} + frameworkResTag = dependencyTag{name: "framework-res"} + frameworkApkTag = dependencyTag{name: "framework-apk"} + kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib"} + proguardRaiseTag = dependencyTag{name: "proguard-raise"} + certificateTag = dependencyTag{name: "certificate"} + instrumentationForTag = dependencyTag{name: "instrumentation_for"} ) type sdkDep struct { @@ -817,7 +821,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { switch tag { case bootClasspathTag: deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars()...) - case libTag: + case libTag, instrumentationForTag: deps.classpath = append(deps.classpath, dep.HeaderJars()...) // sdk lib names from dependencies are re-exported j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...) @@ -1193,8 +1197,8 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars ...android.Path jars = append(jars, deps.staticJars...) jars = append(jars, deps.staticResourceJars...) - var manifest android.OptionalPath - if j.properties.Manifest != nil { + manifest := j.overrideManifest + if !manifest.Valid() && j.properties.Manifest != nil { manifest = android.OptionalPathForPath(ctx.ExpandSource(*j.properties.Manifest, "manifest")) } @@ -1536,6 +1540,9 @@ func TestHostFactory() android.Module { type binaryProperties struct { // installable script to execute the resulting jar Wrapper *string + + // Name of the class containing main to be inserted into the manifest as Main-Class. + Main_class *string } type Binary struct { @@ -1556,6 +1563,15 @@ func (j *Binary) HostToolPath() android.OptionalPath { func (j *Binary) GenerateAndroidBuildActions(ctx android.ModuleContext) { if ctx.Arch().ArchType == android.Common { // Compile the jar + if j.binaryProperties.Main_class != nil { + if j.properties.Manifest != nil { + ctx.PropertyErrorf("main_class", "main_class cannot be used when manifest is set") + } + manifestFile := android.PathForModuleOut(ctx, "manifest.txt") + GenerateMainClassManifest(ctx, manifestFile, String(j.binaryProperties.Main_class)) + j.overrideManifest = android.OptionalPathForPath(manifestFile) + } + j.Library.GenerateAndroidBuildActions(ctx) } else { // Handle the binary wrapper