Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ffbcd1d8 authored by Colin Cross's avatar Colin Cross
Browse files

Extract primary apk from apk set zip

Extract and install the primary apk normally, and then unzip the rest
of them as a post install command.

Bug: 204136549
Test: app_set_test.go
Change-Id: I17437ff27f49df6bc91bdbbea6173b46c7d3ec4e
parent 6cfb37af
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -263,7 +263,7 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo
			if !ok {
				panic(fmt.Sprintf("Expected %s to be AndroidAppSet", fi.module))
			}
			fmt.Fprintln(w, "LOCAL_APK_SET_INSTALL_FILE :=", as.InstallFile())
			fmt.Fprintln(w, "LOCAL_APK_SET_INSTALL_FILE :=", as.PackedAdditionalOutputs().String())
			fmt.Fprintln(w, "LOCAL_APKCERTS_FILE :=", as.APKCertsFile().String())
			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_android_app_set.mk")
		case nativeSharedLib, nativeExecutable, nativeTest:
+2 −1
Original line number Diff line number Diff line
@@ -442,7 +442,8 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
		} else {
			if fi.class == appSet {
				copyCommands = append(copyCommands,
					fmt.Sprintf("unzip -qDD -d %s %s", destPathDir, fi.builtFile.String()))
					fmt.Sprintf("unzip -qDD -d %s %s", destPathDir,
						fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs().String()))
			} else {
				copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
			}
+36 −12
Original line number Diff line number Diff line
@@ -356,7 +356,7 @@ type Zip2ZipWriter interface {

// Writes out selected entries, renaming them as needed
func (apkSet *ApkSet) writeApks(selected SelectionResult, config TargetConfig,
	writer Zip2ZipWriter, partition string) ([]string, error) {
	outFile io.Writer, zipWriter Zip2ZipWriter, partition string) ([]string, error) {
	// Renaming rules:
	//  splits/MODULE-master.apk to STEM.apk
	// else
@@ -406,9 +406,15 @@ func (apkSet *ApkSet) writeApks(selected SelectionResult, config TargetConfig,
				origin, inName, outName)
		}
		entryOrigin[outName] = inName
		if err := writer.CopyFrom(apkFile, outName); err != nil {
		if outName == config.stem+".apk" {
			if err := writeZipEntryToFile(outFile, apkFile); err != nil {
				return nil, err
			}
		} else {
			if err := zipWriter.CopyFrom(apkFile, outName); err != nil {
				return nil, err
			}
		}
		if partition != "" {
			apkcerts = append(apkcerts, fmt.Sprintf(
				`name="%s" certificate="PRESIGNED" private_key="" partition="%s"`, outName, partition))
@@ -426,14 +432,13 @@ func (apkSet *ApkSet) extractAndCopySingle(selected SelectionResult, outFile *os
	if !ok {
		return fmt.Errorf("Couldn't find apk path %s", selected.entries[0])
	}
	inputReader, _ := apk.Open()
	_, err := io.Copy(outFile, inputReader)
	return err
	return writeZipEntryToFile(outFile, apk)
}

// Arguments parsing
var (
	outputFile   = flag.String("o", "", "output file containing extracted entries")
	outputFile   = flag.String("o", "", "output file for primary entry")
	zipFile      = flag.String("zip", "", "output file containing additional extracted entries")
	targetConfig = TargetConfig{
		screenDpi: map[android_bundle_proto.ScreenDensity_DensityAlias]bool{},
		abis:      map[android_bundle_proto.Abi_AbiAlias]int{},
@@ -494,7 +499,8 @@ func (s screenDensityFlagValue) Set(densityList string) error {

func processArgs() {
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, `usage: extract_apks -o <output-file> -sdk-version value -abis value `+
		fmt.Fprintln(os.Stderr, `usage: extract_apks -o <output-file> [-zip <output-zip-file>] `+
			`-sdk-version value -abis value `+
			`-screen-densities value {-stem value | -extract-single} [-allow-prereleased] `+
			`[-apkcerts <apkcerts output file> -partition <partition>] <APK set>`)
		flag.PrintDefaults()
@@ -510,7 +516,8 @@ func processArgs() {
	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) || (*apkcertsOutput != "" && *partition == "") {
		((targetConfig.stem == "" || *zipFile == "") && !*extractSingle) ||
		(*apkcertsOutput != "" && *partition == "") {
		flag.Usage()
	}
	targetConfig.sdkVersion = int32(*version)
@@ -542,13 +549,20 @@ func main() {
	if *extractSingle {
		err = apkSet.extractAndCopySingle(sel, outFile)
	} else {
		writer := zip.NewWriter(outFile)
		zipOutputFile, err := os.Create(*zipFile)
		if err != nil {
			log.Fatal(err)
		}
		defer zipOutputFile.Close()

		zipWriter := zip.NewWriter(zipOutputFile)
		defer func() {
			if err := writer.Close(); err != nil {
			if err := zipWriter.Close(); err != nil {
				log.Fatal(err)
			}
		}()
		apkcerts, err := apkSet.writeApks(sel, targetConfig, writer, *partition)

		apkcerts, err := apkSet.writeApks(sel, targetConfig, outFile, zipWriter, *partition)
		if err == nil && *apkcertsOutput != "" {
			apkcertsFile, err := os.Create(*apkcertsOutput)
			if err != nil {
@@ -567,3 +581,13 @@ func main() {
		log.Fatal(err)
	}
}

func writeZipEntryToFile(outFile io.Writer, zipEntry *zip.File) error {
	reader, err := zipEntry.Open()
	if err != nil {
		return err
	}
	defer reader.Close()
	_, err = io.Copy(outFile, reader)
	return err
}
+46 −22
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
package main

import (
	"bytes"
	"fmt"
	"reflect"
	"testing"
@@ -437,7 +438,7 @@ type testCaseWriteApks struct {
	stem       string
	partition  string
	// what we write from what
	expectedZipEntries map[string]string
	zipEntries       map[string]string
	expectedApkcerts []string
}

@@ -448,7 +449,7 @@ func TestWriteApks(t *testing.T) {
			moduleName: "mybase",
			stem:       "Foo",
			partition:  "system",
			expectedZipEntries: map[string]string{
			zipEntries: map[string]string{
				"Foo.apk":       "splits/mybase-master.apk",
				"Foo-xhdpi.apk": "splits/mybase-xhdpi.apk",
			},
@@ -462,7 +463,7 @@ func TestWriteApks(t *testing.T) {
			moduleName: "base",
			stem:       "Bar",
			partition:  "product",
			expectedZipEntries: map[string]string{
			zipEntries: map[string]string{
				"Bar.apk": "universal.apk",
			},
			expectedApkcerts: []string{
@@ -471,23 +472,46 @@ func TestWriteApks(t *testing.T) {
		},
	}
	for _, testCase := range testCases {
		t.Run(testCase.name, func(t *testing.T) {
			testZipBuf := &bytes.Buffer{}
			testZip := zip.NewWriter(testZipBuf)
			for _, in := range testCase.zipEntries {
				f, _ := testZip.Create(in)
				f.Write([]byte(in))
			}
			testZip.Close()

			zipReader, _ := zip.NewReader(bytes.NewReader(testZipBuf.Bytes()), int64(testZipBuf.Len()))

			apkSet := ApkSet{entries: make(map[string]*zip.File)}
			sel := SelectionResult{moduleName: testCase.moduleName}
		for _, in := range testCase.expectedZipEntries {
			apkSet.entries[in] = &zip.File{FileHeader: zip.FileHeader{Name: in}}
			sel.entries = append(sel.entries, in)
			for _, f := range zipReader.File {
				apkSet.entries[f.Name] = f
				sel.entries = append(sel.entries, f.Name)
			}
		writer := testZip2ZipWriter{make(map[string]string)}

			zipWriter := testZip2ZipWriter{make(map[string]string)}
			outWriter := &bytes.Buffer{}
			config := TargetConfig{stem: testCase.stem}
		apkcerts, err := apkSet.writeApks(sel, config, writer, testCase.partition)
			apkcerts, err := apkSet.writeApks(sel, config, outWriter, zipWriter, testCase.partition)
			if err != nil {
				t.Error(err)
			}
		if !reflect.DeepEqual(testCase.expectedZipEntries, writer.entries) {
			t.Errorf("expected zip entries %v, got %v", testCase.expectedZipEntries, writer.entries)
			expectedZipEntries := make(map[string]string)
			for k, v := range testCase.zipEntries {
				if k != testCase.stem+".apk" {
					expectedZipEntries[k] = v
				}
			}
			if !reflect.DeepEqual(expectedZipEntries, zipWriter.entries) {
				t.Errorf("expected zip entries %v, got %v", testCase.zipEntries, zipWriter.entries)
			}
			if !reflect.DeepEqual(testCase.expectedApkcerts, apkcerts) {
				t.Errorf("expected apkcerts %v, got %v", testCase.expectedApkcerts, apkcerts)
			}
			if g, w := outWriter.String(), testCase.zipEntries[testCase.stem+".apk"]; !reflect.DeepEqual(g, w) {
				t.Errorf("expected output file contents %q, got %q", testCase.stem+".apk", outWriter.String())
			}
		})
	}
}
+2 −2
Original line number Diff line number Diff line
@@ -696,12 +696,12 @@ func (apkSet *AndroidAppSet) AndroidMkEntries() []android.AndroidMkEntries {
	return []android.AndroidMkEntries{
		android.AndroidMkEntries{
			Class:      "APPS",
			OutputFile: android.OptionalPathForPath(apkSet.packedOutput),
			OutputFile: android.OptionalPathForPath(apkSet.primaryOutput),
			Include:    "$(BUILD_SYSTEM)/soong_android_app_set.mk",
			ExtraEntries: []android.AndroidMkExtraEntriesFunc{
				func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
					entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", apkSet.Privileged())
					entries.SetString("LOCAL_APK_SET_INSTALL_FILE", apkSet.InstallFile())
					entries.SetPath("LOCAL_APK_SET_INSTALL_FILE", apkSet.PackedAdditionalOutputs())
					entries.SetPath("LOCAL_APKCERTS_FILE", apkSet.apkcertsFile)
					entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", apkSet.properties.Overrides...)
				},
Loading