From 11c1e0f94d24d43ab0ac656d10586838e3d81d21 Mon Sep 17 00:00:00 2001 From: Jaewoong Jung Date: Mon, 29 Jun 2020 19:18:44 -0700 Subject: [PATCH] Output apkcerts file for android_app_set. Soong and Make have no ways to figure out what splits will be outputted from a given android_app_set, so it's impossible for them to provide full PACKAGES.$(LOCAL_MODULE).CERTIFICATE entries, which are required to build a final apkcerts.txt. This change makes extract_apks produce apkcerts.txt files for each input modules instead. The Make-side counterpart of this change merges all local apkcerts.txt into a final one. Fixes: 160119159 Test: main_test.go Test: m apkcerts-list Merged-In: I321e80fd636a955213761f56a3ac64bfe7f7f7c0 Change-Id: I321e80fd636a955213761f56a3ac64bfe7f7f7c0 --- cmd/extract_apks/main.go | 39 ++++++++++++++++++++++++++++------- cmd/extract_apks/main_test.go | 38 ++++++++++++++++++++++++---------- java/androidmk.go | 1 + java/app.go | 13 ++++++++---- java/app_test.go | 5 ++++- java/builder.go | 3 ++- 6 files changed, 75 insertions(+), 24 deletions(-) diff --git a/cmd/extract_apks/main.go b/cmd/extract_apks/main.go index e9a850ee8..db54ffbaf 100644 --- a/cmd/extract_apks/main.go +++ b/cmd/extract_apks/main.go @@ -24,6 +24,7 @@ import ( "math" "os" "regexp" + "sort" "strings" "github.com/golang/protobuf/proto" @@ -355,7 +356,7 @@ type Zip2ZipWriter interface { // Writes out selected entries, renaming them as needed func (apkSet *ApkSet) writeApks(selected SelectionResult, config TargetConfig, - writer Zip2ZipWriter) error { + writer Zip2ZipWriter, partition string) ([]string, error) { // Renaming rules: // splits/MODULE-master.apk to STEM.apk // else @@ -389,10 +390,11 @@ func (apkSet *ApkSet) writeApks(selected SelectionResult, config TargetConfig, } entryOrigin := make(map[string]string) // output entry to input entry + var apkcerts []string for _, apk := range selected.entries { apkFile, ok := apkSet.entries[apk] if !ok { - return fmt.Errorf("TOC refers to an entry %s which does not exist", apk) + return nil, fmt.Errorf("TOC refers to an entry %s which does not exist", apk) } inName := apkFile.Name outName, ok := renamer(inName) @@ -405,10 +407,15 @@ func (apkSet *ApkSet) writeApks(selected SelectionResult, config TargetConfig, } entryOrigin[outName] = inName if err := writer.CopyFrom(apkFile, outName); err != nil { - return err + return nil, err + } + if partition != "" { + apkcerts = append(apkcerts, fmt.Sprintf( + `name="%s" certificate="PRESIGNED" private_key="" partition="%s"`, outName, partition)) } } - return nil + sort.Strings(apkcerts) + return apkcerts, nil } func (apkSet *ApkSet) extractAndCopySingle(selected SelectionResult, outFile *os.File) error { @@ -433,6 +440,9 @@ var ( } extractSingle = flag.Bool("extract-single", false, "extract a single target and output it uncompressed. only available for standalone apks and apexes.") + apkcertsOutput = flag.String("apkcerts", "", + "optional apkcerts.txt output file containing signing info of all outputted apks") + partition = flag.String("partition", "", "partition string. required when -apkcerts is used.") ) // Parse abi values @@ -485,7 +495,8 @@ func (s screenDensityFlagValue) Set(densityList string) error { func processArgs() { flag.Usage = func() { fmt.Fprintln(os.Stderr, `usage: extract_apks -o -sdk-version value -abis value `+ - `-screen-densities value {-stem value | -extract-single} [-allow-prereleased] `) + `-screen-densities value {-stem value | -extract-single} [-allow-prereleased] `+ + `[-apkcerts -partition ] `) flag.PrintDefaults() os.Exit(2) } @@ -498,7 +509,8 @@ func processArgs() { "allow prereleased") flag.StringVar(&targetConfig.stem, "stem", "", "output entries base name in the output zip file") flag.Parse() - if (*outputFile == "") || len(flag.Args()) != 1 || *version == 0 || (targetConfig.stem == "" && !*extractSingle) { + if (*outputFile == "") || len(flag.Args()) != 1 || *version == 0 || + (targetConfig.stem == "" && !*extractSingle) || (*apkcertsOutput != "" && *partition == "") { flag.Usage() } targetConfig.sdkVersion = int32(*version) @@ -536,7 +548,20 @@ func main() { log.Fatal(err) } }() - err = apkSet.writeApks(sel, targetConfig, writer) + apkcerts, err := apkSet.writeApks(sel, targetConfig, writer, *partition) + if err == nil && *apkcertsOutput != "" { + apkcertsFile, err := os.Create(*apkcertsOutput) + if err != nil { + log.Fatal(err) + } + defer apkcertsFile.Close() + for _, a := range apkcerts { + _, err = apkcertsFile.WriteString(a + "\n") + if err != nil { + log.Fatal(err) + } + } + } } if err != nil { log.Fatal(err) diff --git a/cmd/extract_apks/main_test.go b/cmd/extract_apks/main_test.go index bdd4becce..c3e6a2def 100644 --- a/cmd/extract_apks/main_test.go +++ b/cmd/extract_apks/main_test.go @@ -16,10 +16,11 @@ package main import ( "fmt" - "github.com/golang/protobuf/proto" "reflect" "testing" + "github.com/golang/protobuf/proto" + bp "android/soong/cmd/extract_apks/bundle_proto" "android/soong/third_party/zip" ) @@ -430,48 +431,63 @@ func (w testZip2ZipWriter) CopyFrom(file *zip.File, out string) error { return nil } -type testCaseWriteZip struct { +type testCaseWriteApks struct { name string moduleName string stem string + partition string // what we write from what - expected map[string]string + expectedZipEntries map[string]string + expectedApkcerts []string } -func TestWriteZip(t *testing.T) { - testCases := []testCaseWriteZip{ +func TestWriteApks(t *testing.T) { + testCases := []testCaseWriteApks{ { name: "splits", moduleName: "mybase", stem: "Foo", - expected: map[string]string{ + partition: "system", + expectedZipEntries: map[string]string{ "Foo.apk": "splits/mybase-master.apk", "Foo-xhdpi.apk": "splits/mybase-xhdpi.apk", }, + expectedApkcerts: []string{ + `name="Foo-xhdpi.apk" certificate="PRESIGNED" private_key="" partition="system"`, + `name="Foo.apk" certificate="PRESIGNED" private_key="" partition="system"`, + }, }, { name: "universal", moduleName: "base", stem: "Bar", - expected: map[string]string{ + partition: "product", + expectedZipEntries: map[string]string{ "Bar.apk": "universal.apk", }, + expectedApkcerts: []string{ + `name="Bar.apk" certificate="PRESIGNED" private_key="" partition="product"`, + }, }, } for _, testCase := range testCases { apkSet := ApkSet{entries: make(map[string]*zip.File)} sel := SelectionResult{moduleName: testCase.moduleName} - for _, in := range testCase.expected { + for _, in := range testCase.expectedZipEntries { apkSet.entries[in] = &zip.File{FileHeader: zip.FileHeader{Name: in}} sel.entries = append(sel.entries, in) } writer := testZip2ZipWriter{make(map[string]string)} config := TargetConfig{stem: testCase.stem} - if err := apkSet.writeApks(sel, config, writer); err != nil { + apkcerts, err := apkSet.writeApks(sel, config, writer, testCase.partition) + if err != nil { t.Error(err) } - if !reflect.DeepEqual(testCase.expected, writer.entries) { - t.Errorf("expected %v, got %v", testCase.expected, writer.entries) + if !reflect.DeepEqual(testCase.expectedZipEntries, writer.entries) { + t.Errorf("expected zip entries %v, got %v", testCase.expectedZipEntries, writer.entries) + } + if !reflect.DeepEqual(testCase.expectedApkcerts, apkcerts) { + t.Errorf("expected apkcerts %v, got %v", testCase.expectedApkcerts, apkcerts) } } } diff --git a/java/androidmk.go b/java/androidmk.go index e73b03058..618e15d9a 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -719,6 +719,7 @@ func (apkSet *AndroidAppSet) AndroidMkEntries() []android.AndroidMkEntries { func(entries *android.AndroidMkEntries) { entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", apkSet.Privileged()) entries.SetString("LOCAL_APK_SET_MASTER_FILE", apkSet.masterFile) + entries.SetPath("LOCAL_APKCERTS_FILE", apkSet.apkcertsFile) entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", apkSet.properties.Overrides...) }, }, diff --git a/java/app.go b/java/app.go index 37a6453cd..44164e83f 100755 --- a/java/app.go +++ b/java/app.go @@ -79,6 +79,7 @@ type AndroidAppSet struct { properties AndroidAppSetProperties packedOutput android.WritablePath masterFile string + apkcertsFile android.ModuleOutPath } func (as *AndroidAppSet) Name() string { @@ -130,6 +131,7 @@ func SupportedAbis(ctx android.ModuleContext) []string { func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { as.packedOutput = android.PathForModuleOut(ctx, ctx.ModuleName()+".zip") + as.apkcertsFile = android.PathForModuleOut(ctx, "apkcerts.txt") // 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. @@ -142,16 +144,19 @@ func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) // TODO(asmundak): do we support device features ctx.Build(pctx, android.BuildParams{ - Rule: extractMatchingApks, - Description: "Extract APKs from APK set", - Output: as.packedOutput, - Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)}, + Rule: extractMatchingApks, + Description: "Extract APKs from APK set", + Output: as.packedOutput, + ImplicitOutput: as.apkcertsFile, + Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)}, Args: map[string]string{ "abis": strings.Join(SupportedAbis(ctx), ","), "allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)), "screen-densities": screenDensities, "sdk-version": ctx.Config().PlatformSdkVersion(), "stem": as.BaseModuleName(), + "apkcerts": as.apkcertsFile.String(), + "partition": as.PartitionTag(ctx.DeviceConfig()), }, }) } diff --git a/java/app_test.go b/java/app_test.go index 120dc00a6..beb29a78c 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -147,7 +147,7 @@ func TestAndroidAppSet(t *testing.T) { name: "foo", set: "prebuilts/apks/app.apks", prerelease: true, - }`) + }`) module := ctx.ModuleForTests("foo", "android_common") const packedSplitApks = "foo.zip" params := module.Output(packedSplitApks) @@ -157,6 +157,9 @@ func TestAndroidAppSet(t *testing.T) { if s := params.Args["allow-prereleased"]; s != "true" { t.Errorf("wrong allow-prereleased value: '%s', expected 'true'", s) } + if s := params.Args["partition"]; s != "system" { + t.Errorf("wrong partition value: '%s', expected 'system'", s) + } mkEntries := android.AndroidMkEntriesForTest(t, config, "", module.Module())[0] actualMaster := mkEntries.EntryMap["LOCAL_APK_SET_MASTER_FILE"] expectedMaster := []string{"foo.apk"} diff --git a/java/builder.go b/java/builder.go index a27e5c390..7318fcbad 100644 --- a/java/builder.go +++ b/java/builder.go @@ -120,10 +120,11 @@ var ( `${config.ExtractApksCmd} -o "${out}" -allow-prereleased=${allow-prereleased} ` + `-sdk-version=${sdk-version} -abis=${abis} ` + `--screen-densities=${screen-densities} --stem=${stem} ` + + `-apkcerts=${apkcerts} -partition=${partition} ` + `${in}`, CommandDeps: []string{"${config.ExtractApksCmd}"}, }, - "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem") + "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem", "apkcerts", "partition") turbine, turbineRE = remoteexec.StaticRules(pctx, "turbine", blueprint.RuleParams{