Rearrange manifest file handling in merge_zips and soong_zip

Jar always puts default MANIFEST.MF files in if none was specified.
Copying that behavior in soong_zip causes problems with merge_zips,
because it ends up taking the default manifest from the classes.jar
instead of the user's manifest from res.jar.  We don't want the
user's manifest in the classes.jar, otherwise a change to the
manifest will cause all the class files to rebuild.  Instead,
move the manifest insertion to the final merge_zips stage.

Test: m -j checkbuild
Change-Id: Id6376961dbaf743c2fb92843f9bdf2e44b963be0
diff --git a/jar/jar.go b/jar/jar.go
index 5960bf0..f17bc98 100644
--- a/jar/jar.go
+++ b/jar/jar.go
@@ -15,8 +15,14 @@
 package jar
 
 import (
+	"bytes"
 	"fmt"
+	"io/ioutil"
+	"os"
 	"strings"
+	"time"
+
+	"android/soong/third_party/zip"
 )
 
 const (
@@ -25,6 +31,10 @@
 	ModuleInfoClass = "module-info.class"
 )
 
+var DefaultTime = time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC)
+
+var MetaDirExtra = [2]byte{0xca, 0xfe}
+
 // EntryNamesLess tells whether <filepathA> should precede <filepathB> in
 // the order of files with a .jar
 func EntryNamesLess(filepathA string, filepathB string) (less bool) {
@@ -59,3 +69,56 @@
 	}
 	panic(fmt.Errorf("file %q did not match any pattern", name))
 }
+
+func MetaDirFileHeader() *zip.FileHeader {
+	dirHeader := &zip.FileHeader{
+		Name:  MetaDir,
+		Extra: []byte{MetaDirExtra[1], MetaDirExtra[0], 0, 0},
+	}
+	dirHeader.SetMode(0700 | os.ModeDir)
+	dirHeader.SetModTime(DefaultTime)
+
+	return dirHeader
+}
+
+// Convert manifest source path to zip header and contents.  If path is empty uses a default
+// manifest.
+func ManifestFileContents(src string) (*zip.FileHeader, []byte, error) {
+	b, err := manifestContents(src)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	fh := &zip.FileHeader{
+		Name:               ManifestFile,
+		Method:             zip.Store,
+		UncompressedSize64: uint64(len(b)),
+	}
+
+	return fh, b, nil
+}
+
+// Convert manifest source path to contents.  If path is empty uses a default manifest.
+func manifestContents(src string) ([]byte, error) {
+	var givenBytes []byte
+	var err error
+
+	if src != "" {
+		givenBytes, err = ioutil.ReadFile(src)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	manifestMarker := []byte("Manifest-Version:")
+	header := append(manifestMarker, []byte(" 1.0\nCreated-By: soong_zip\n")...)
+
+	var finalBytes []byte
+	if !bytes.Contains(givenBytes, manifestMarker) {
+		finalBytes = append(append(header, givenBytes...), byte('\n'))
+	} else {
+		finalBytes = givenBytes
+	}
+
+	return finalBytes, nil
+}