Share version settings with product config makefile.

Generate version settings from build/make/core/version_defaults.mk.
The generated settings are then loaded into the launcher code and passed
to the environment setup code.

Bug: 198995713
Test: internal
Change-Id: I66131d2c5b232784a9ff0bba9fbd5db62302aaba
diff --git a/mk2rbc/Android.bp b/mk2rbc/Android.bp
index 4fa3eb6..b18bfc7 100644
--- a/mk2rbc/Android.bp
+++ b/mk2rbc/Android.bp
@@ -38,6 +38,7 @@
         "soong_variables.go",
         "types.go",
         "variable.go",
+        "version_defaults.go",
     ],
     deps: ["androidmk-parser"],
 }
diff --git a/mk2rbc/cmd/mk2rbc.go b/mk2rbc/cmd/mk2rbc.go
index 209e82b..7b5f298 100644
--- a/mk2rbc/cmd/mk2rbc.go
+++ b/mk2rbc/cmd/mk2rbc.go
@@ -81,6 +81,7 @@
 var tracedVariables []string
 var errorLogger = errorsByType{data: make(map[string]datum)}
 var makefileFinder = &LinuxMakefileFinder{}
+var versionDefaultsMk = filepath.Join("build", "make", "core", "version_defaults.mk")
 
 func main() {
 	flag.Usage = func() {
@@ -165,13 +166,24 @@
 			quit(fmt.Errorf("cannot generate configuration launcher for %s, it is not a known product",
 				product))
 		}
+		versionDefaults, err := generateVersionDefaults()
+		if err != nil {
+			quit(err)
+		}
 		ok = convertOne(path) && ok
-		err := writeGenerated(*launcher, mk2rbc.Launcher(outputFilePath(path), mk2rbc.MakePath2ModuleName(path)))
+		versionDefaultsPath := outputFilePath(versionDefaultsMk)
+		err = writeGenerated(versionDefaultsPath, versionDefaults)
 		if err != nil {
 			fmt.Fprintf(os.Stderr, "%s:%s", path, err)
 			ok = false
 		}
 
+		err = writeGenerated(*launcher, mk2rbc.Launcher(outputFilePath(path), versionDefaultsPath,
+			mk2rbc.MakePath2ModuleName(path)))
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "%s:%s", path, err)
+			ok = false
+		}
 	} else {
 		files := flag.Args()
 		if *allInSource {
@@ -194,6 +206,15 @@
 	}
 }
 
+func generateVersionDefaults() (string, error) {
+	versionSettings, err := mk2rbc.ParseVersionDefaults(filepath.Join(*rootDir, versionDefaultsMk))
+	if err != nil {
+		return "", err
+	}
+	return mk2rbc.VersionDefaults(versionSettings), nil
+
+}
+
 func quit(s interface{}) {
 	fmt.Fprintln(os.Stderr, s)
 	os.Exit(2)
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index b05d340..b9b7e2c 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -1618,12 +1618,12 @@
 	return starScript, nil
 }
 
-func Launcher(path, name string) string {
+func Launcher(mainModuleUri, versionDefaultsUri, mainModuleName string) string {
 	var buf bytes.Buffer
 	fmt.Fprintf(&buf, "load(%q, %q)\n", baseUri, baseName)
-	fmt.Fprintf(&buf, "load(%q, \"init\")\n", path)
-	fmt.Fprintf(&buf, "g, config = %s(%q, init)\n", cfnMain, name)
-	fmt.Fprintf(&buf, "%s(g, config)\n", cfnPrintVars)
+	fmt.Fprintf(&buf, "load(%q, \"version_defaults\")\n", versionDefaultsUri)
+	fmt.Fprintf(&buf, "load(%q, \"init\")\n", mainModuleUri)
+	fmt.Fprintf(&buf, "%s(%s(%q, init, version_defaults))\n", cfnPrintVars, cfnMain, mainModuleName)
 	return buf.String()
 }
 
diff --git a/mk2rbc/test/version_defaults.mk.test b/mk2rbc/test/version_defaults.mk.test
new file mode 100644
index 0000000..1666392
--- /dev/null
+++ b/mk2rbc/test/version_defaults.mk.test
@@ -0,0 +1,22 @@
+INTERNAL_BUILD_ID_MAKEFILE := $(wildcard $(BUILD_SYSTEM)/build_id.mk)
+ifdef INTERNAL_BUILD_ID_MAKEFILE
+  include $(INTERNAL_BUILD_ID_MAKEFILE)
+endif
+
+DEFAULT_PLATFORM_VERSION := TP1A
+.KATI_READONLY := DEFAULT_PLATFORM_VERSION
+MIN_PLATFORM_VERSION := TP1A
+MAX_PLATFORM_VERSION := TP1A
+PLATFORM_VERSION_LAST_STABLE := 12
+PLATFORM_VERSION_CODENAME.SP2A := Sv2
+PLATFORM_VERSION_CODENAME.TP1A := Tiramisu
+ifndef PLATFORM_SDK_VERSION
+  PLATFORM_SDK_VERSION := 31
+endif
+.KATI_READONLY := PLATFORM_SDK_VERSION
+PLATFORM_SDK_EXTENSION_VERSION := 1
+PLATFORM_BASE_SDK_EXTENSION_VERSION := 0
+ifndef PLATFORM_SECURITY_PATCH
+    PLATFORM_SECURITY_PATCH := 2021-10-05
+endif
+include $(BUILD_SYSTEM)/version_util.mk
diff --git a/mk2rbc/version_defaults.go b/mk2rbc/version_defaults.go
new file mode 100644
index 0000000..27e8198
--- /dev/null
+++ b/mk2rbc/version_defaults.go
@@ -0,0 +1,109 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package mk2rbc
+
+import (
+	mkparser "android/soong/androidmk/parser"
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+const codenamePrefix = "PLATFORM_VERSION_CODENAME."
+
+// ParseVersionDefaults extracts version settings from the given file
+// and returns the map.
+func ParseVersionDefaults(path string) (map[string]string, error) {
+	contents, err := ioutil.ReadFile(path)
+	if err != nil {
+		return nil, err
+	}
+	parser := mkparser.NewParser(path, bytes.NewBuffer(contents))
+	nodes, errs := parser.Parse()
+	if len(errs) > 0 {
+		for _, e := range errs {
+			fmt.Fprintln(os.Stderr, "ERROR:", e)
+		}
+		return nil, fmt.Errorf("cannot parse %s", path)
+	}
+
+	result := map[string]string{
+		"DEFAULT_PLATFORM_VERSION":            "",
+		"MAX_PLATFORM_VERSION":                "",
+		"MIN_PLATFORM_VERSION":                "A",
+		"PLATFORM_BASE_SDK_EXTENSION_VERSION": "",
+		"PLATFORM_SDK_EXTENSION_VERSION":      "",
+		"PLATFORM_SDK_VERSION":                "",
+		"PLATFORM_SECURITY_PATCH":             "",
+		"PLATFORM_VERSION_LAST_STABLE":        "",
+	}
+	for _, node := range nodes {
+		asgn, ok := node.(*mkparser.Assignment)
+		if !(ok && asgn.Name.Const()) {
+			continue
+		}
+		s := asgn.Name.Strings[0]
+		_, ok = result[s]
+		if !ok {
+			ok = strings.HasPrefix(s, codenamePrefix)
+		}
+		if !ok {
+			continue
+		}
+		v := asgn.Value
+		if !v.Const() {
+			return nil, fmt.Errorf("the value of %s should be constant", s)
+		}
+		result[s] = strings.TrimSpace(v.Strings[0])
+	}
+	return result, nil
+}
+
+func genericValue(s string) interface{} {
+	if ival, err := strconv.ParseInt(s, 0, 0); err == nil {
+		return ival
+	}
+	return s
+}
+
+// VersionDefaults generates the contents of the version_defaults.rbc file
+func VersionDefaults(values map[string]string) string {
+	var sink bytes.Buffer
+	var lines []string
+	var codenames []string
+	for name, value := range values {
+		if strings.HasPrefix(name, codenamePrefix) {
+			codenames = append(codenames,
+				fmt.Sprintf("%q: %q", strings.TrimPrefix(name, codenamePrefix), value))
+		} else {
+			// Print numbers as such
+			lines = append(lines, fmt.Sprintf("    %s = %#v,\n",
+				strings.ToLower(name), genericValue(value)))
+		}
+	}
+	sort.Strings(lines)
+	sink.WriteString("version_defaults = struct(\n")
+	for _, l := range lines {
+		sink.WriteString(l)
+	}
+	sink.WriteString("    codenames = { ")
+	sink.WriteString(strings.Join(codenames, ", "))
+	sink.WriteString(" }\n)\n")
+	return sink.String()
+}
diff --git a/mk2rbc/version_defaults_test.go b/mk2rbc/version_defaults_test.go
new file mode 100644
index 0000000..c78fa32
--- /dev/null
+++ b/mk2rbc/version_defaults_test.go
@@ -0,0 +1,60 @@
+package mk2rbc
+
+import (
+	"path/filepath"
+	"reflect"
+	"strings"
+	"testing"
+)
+
+func TestParseVersionDefaults(t *testing.T) {
+	testDir := getTestDirectory()
+	abspath := func(relPath string) string { return filepath.Join(testDir, relPath) }
+	actualProducts, err := ParseVersionDefaults(abspath("version_defaults.mk.test"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	expectedProducts := map[string]string{
+		"DEFAULT_PLATFORM_VERSION":            "TP1A",
+		"MAX_PLATFORM_VERSION":                "TP1A",
+		"MIN_PLATFORM_VERSION":                "TP1A",
+		"PLATFORM_BASE_SDK_EXTENSION_VERSION": "0",
+		"PLATFORM_SDK_EXTENSION_VERSION":      "1",
+		"PLATFORM_SDK_VERSION":                "31",
+		"PLATFORM_SECURITY_PATCH":             "2021-10-05",
+		"PLATFORM_VERSION_LAST_STABLE":        "12",
+		"PLATFORM_VERSION_CODENAME.SP2A":      "Sv2",
+		"PLATFORM_VERSION_CODENAME.TP1A":      "Tiramisu",
+	}
+	if !reflect.DeepEqual(actualProducts, expectedProducts) {
+		t.Errorf("\nExpected: %v\n  Actual: %v", expectedProducts, actualProducts)
+	}
+}
+
+func TestVersionDefaults(t *testing.T) {
+	testDir := getTestDirectory()
+	abspath := func(relPath string) string { return filepath.Join(testDir, relPath) }
+	actualProducts, err := ParseVersionDefaults(abspath("version_defaults.mk.test"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	expectedString := `version_defaults = struct(
+    default_platform_version = "TP1A",
+    max_platform_version = "TP1A",
+    min_platform_version = "TP1A",
+    platform_base_sdk_extension_version = 0,
+    platform_sdk_extension_version = 1,
+    platform_sdk_version = 31,
+    platform_security_patch = "2021-10-05",
+    platform_version_last_stable = 12,
+    codenames = { "SP2A": "Sv2", "TP1A": "Tiramisu" }
+)
+`
+	actualString := VersionDefaults(actualProducts)
+	if !reflect.DeepEqual(actualString, expectedString) {
+		t.Errorf("\nExpected: %v\nActual:\n%v",
+			strings.ReplaceAll(expectedString, "\n", "␤\n"),
+			strings.ReplaceAll(actualString, "\n", "␤\n"))
+	}
+
+}