Merge changes If068597b,Icbadbe6d into main

* changes:
  release_config: make the code more sharable
  release_config: add namespace to proto
diff --git a/cmd/release_config/Android.bp b/cmd/release_config/Android.bp
deleted file mode 100644
index 7f627ff..0000000
--- a/cmd/release_config/Android.bp
+++ /dev/null
@@ -1,30 +0,0 @@
-package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-bootstrap_go_package {
-    name: "release-config",
-    pkgPath: "android/soong/cmd/release_config",
-    deps: [
-        "golang-protobuf-encoding-prototext",
-        "golang-protobuf-reflect-protoreflect",
-        "golang-protobuf-runtime-protoimpl",
-        "soong-cmd-release-config-proto",
-    ],
-    srcs: [
-        "main.go",
-    ],
-}
-
-bootstrap_go_package {
-    name: "soong-cmd-release-config-proto",
-    pkgPath: "android/soong/cmd/release_config/release_config_proto",
-    deps: [
-        "golang-protobuf-reflect-protoreflect",
-        "golang-protobuf-runtime-protoimpl",
-    ],
-    srcs: [
-        "release_config_proto/build_flags_out.pb.go",
-        "release_config_proto/build_flags_src.pb.go",
-    ],
-}
diff --git a/cmd/release_config/main.go b/cmd/release_config/main.go
deleted file mode 100644
index 3bb6b3d..0000000
--- a/cmd/release_config/main.go
+++ /dev/null
@@ -1,691 +0,0 @@
-// Copyright 2024 Google Inc. All rights reserved.
-//
-// 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 main
-
-import (
-	"cmp"
-	"encoding/json"
-	"flag"
-	"fmt"
-	"io/fs"
-	"os"
-	"path/filepath"
-	"slices"
-	"strings"
-
-	"android/soong/cmd/release_config/release_config_proto"
-
-	"google.golang.org/protobuf/encoding/prototext"
-	"google.golang.org/protobuf/proto"
-)
-
-var verboseFlag bool
-
-type StringList []string
-
-func (l *StringList) Set(v string) error {
-	*l = append(*l, v)
-	return nil
-}
-
-func (l *StringList) String() string {
-	return fmt.Sprintf("%v", *l)
-}
-
-var releaseConfigMapPaths StringList
-
-func DumpProtos(outDir string, message proto.Message) error {
-	basePath := filepath.Join(outDir, "all_release_configs")
-	writer := func(suffix string, marshal func() ([]byte, error)) error {
-		data, err := marshal()
-		if err != nil {
-			return err
-		}
-		return os.WriteFile(fmt.Sprintf("%s.%s", basePath, suffix), data, 0644)
-	}
-	err := writer("textproto", func() ([]byte, error) { return prototext.MarshalOptions{Multiline: true}.Marshal(message) })
-	if err != nil {
-		return err
-	}
-
-	err = writer("pb", func() ([]byte, error) { return proto.Marshal(message) })
-	if err != nil {
-		return err
-	}
-
-	return writer("json", func() ([]byte, error) { return json.MarshalIndent(message, "", "  ") })
-}
-
-func LoadTextproto(path string, message proto.Message) error {
-	data, err := os.ReadFile(path)
-	if err != nil {
-		return err
-	}
-	ret := prototext.Unmarshal(data, message)
-	if verboseFlag {
-		debug, _ := prototext.Marshal(message)
-		fmt.Printf("%s: %s\n", path, debug)
-	}
-	return ret
-}
-
-func WalkTextprotoFiles(root string, subdir string, Func fs.WalkDirFunc) error {
-	path := filepath.Join(root, subdir)
-	if _, err := os.Stat(path); err != nil {
-		// Missing subdirs are not an error.
-		return nil
-	}
-	return filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
-		if err != nil {
-			return err
-		}
-		if strings.HasSuffix(d.Name(), ".textproto") && d.Type().IsRegular() {
-			return Func(path, d, err)
-		}
-		return nil
-	})
-}
-
-type FlagValue struct {
-	// The path providing this value.
-	path string
-
-	// Protobuf
-	proto release_config_proto.FlagValue
-}
-
-func FlagValueFactory(protoPath string) (fv *FlagValue) {
-	fv = &FlagValue{path: protoPath}
-	if protoPath != "" {
-		LoadTextproto(protoPath, &fv.proto)
-	}
-	return fv
-}
-
-// One directory's contribution to the a release config.
-type ReleaseConfigContribution struct {
-	// Paths to files providing this config.
-	path string
-
-	// The index of the config directory where this release config
-	// contribution was declared.
-	// Flag values cannot be set in a location with a lower index.
-	DeclarationIndex int
-
-	// Protobufs relevant to the config.
-	proto release_config_proto.ReleaseConfig
-
-	FlagValues []*FlagValue
-}
-
-// A single release_config_map.textproto and its associated data.
-// Used primarily for debugging.
-type ReleaseConfigMap struct {
-	// The path to this release_config_map file.
-	path string
-
-	// Data received
-	proto release_config_proto.ReleaseConfigMap
-
-	ReleaseConfigContributions map[string]*ReleaseConfigContribution
-	FlagDeclarations           []release_config_proto.FlagDeclaration
-}
-
-// A generated release config.
-type ReleaseConfig struct {
-	// the Name of the release config
-	Name string
-
-	// The index of the config directory where this release config was
-	// first declared.
-	// Flag values cannot be set in a location with a lower index.
-	DeclarationIndex int
-
-	// What contributes to this config.
-	Contributions []*ReleaseConfigContribution
-
-	// Aliases for this release
-	OtherNames []string
-
-	// The names of release configs that we inherit
-	InheritNames []string
-
-	// Unmarshalled flag artifacts
-	FlagArtifacts FlagArtifacts
-
-	// Generated release config
-	ReleaseConfigArtifact *release_config_proto.ReleaseConfigArtifact
-
-	// We have begun compiling this release config.
-	compileInProgress bool
-}
-
-type FlagArtifact struct {
-	FlagDeclaration *release_config_proto.FlagDeclaration
-
-	// The index of the config directory where this flag was declared.
-	// Flag values cannot be set in a location with a lower index.
-	DeclarationIndex int
-
-	Traces []*release_config_proto.Tracepoint
-
-	// Assigned value
-	Value *release_config_proto.Value
-}
-
-// Key is flag name.
-type FlagArtifacts map[string]*FlagArtifact
-
-type ReleaseConfigDirMap map[string]int
-
-// The generated release configs.
-type ReleaseConfigs struct {
-	// Ordered list of release config maps processed.
-	ReleaseConfigMaps []*ReleaseConfigMap
-
-	// Aliases
-	Aliases map[string]*string
-
-	// Dictionary of flag_name:FlagDeclaration, with no overrides applied.
-	FlagArtifacts FlagArtifacts
-
-	// Dictionary of name:ReleaseConfig
-	ReleaseConfigs map[string]*ReleaseConfig
-
-	// Generated release configs
-	Artifact release_config_proto.ReleaseConfigsArtifact
-
-	// The list of config directories used.
-	ConfigDirs []string
-
-	// A map from the config directory to its order in the list of config
-	// directories.
-	ConfigDirIndexes ReleaseConfigDirMap
-}
-
-func (src *FlagArtifact) Clone() *FlagArtifact {
-	value := &release_config_proto.Value{}
-	proto.Merge(value, src.Value)
-	return &FlagArtifact{
-		FlagDeclaration: src.FlagDeclaration,
-		Traces:          src.Traces,
-		Value:           value,
-	}
-}
-
-func (src FlagArtifacts) Clone() (dst FlagArtifacts) {
-	if dst == nil {
-		dst = make(FlagArtifacts)
-	}
-	for k, v := range src {
-		dst[k] = v.Clone()
-	}
-	return
-}
-
-func ReleaseConfigFactory(name string, index int) (c *ReleaseConfig) {
-	return &ReleaseConfig{Name: name, DeclarationIndex: index}
-}
-
-func ReleaseConfigsFactory() (c *ReleaseConfigs) {
-	return &ReleaseConfigs{
-		Aliases:          make(map[string]*string),
-		FlagArtifacts:    make(map[string]*FlagArtifact),
-		ReleaseConfigs:   make(map[string]*ReleaseConfig),
-		ConfigDirs:       []string{},
-		ConfigDirIndexes: make(ReleaseConfigDirMap),
-	}
-}
-
-func ReleaseConfigMapFactory(protoPath string) (m *ReleaseConfigMap) {
-	m = &ReleaseConfigMap{
-		path:                       protoPath,
-		ReleaseConfigContributions: make(map[string]*ReleaseConfigContribution),
-	}
-	if protoPath != "" {
-		LoadTextproto(protoPath, &m.proto)
-	}
-	return m
-}
-
-func FlagDeclarationFactory(protoPath string) (fd *release_config_proto.FlagDeclaration) {
-	fd = &release_config_proto.FlagDeclaration{}
-	if protoPath != "" {
-		LoadTextproto(protoPath, fd)
-	}
-	return fd
-}
-
-func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex int) error {
-	m := ReleaseConfigMapFactory(path)
-	if m.proto.Origin == nil || *m.proto.Origin == "" {
-		return fmt.Errorf("Release config map %s lacks origin", path)
-	}
-	if m.proto.DefaultContainer == nil {
-		return fmt.Errorf("Release config map %s lacks default_container", path)
-	}
-	dir := filepath.Dir(path)
-	// Record any aliases, checking for duplicates.
-	for _, alias := range m.proto.Aliases {
-		name := *alias.Name
-		oldTarget, ok := configs.Aliases[name]
-		if ok {
-			if *oldTarget != *alias.Target {
-				return fmt.Errorf("Conflicting alias declarations: %s vs %s",
-					*oldTarget, *alias.Target)
-			}
-		}
-		configs.Aliases[name] = alias.Target
-	}
-	var err error
-	err = WalkTextprotoFiles(dir, "flag_declarations", func(path string, d fs.DirEntry, err error) error {
-		flagDeclaration := FlagDeclarationFactory(path)
-		// Container must be specified.
-		if flagDeclaration.Container == nil {
-			flagDeclaration.Container = m.proto.DefaultContainer
-		}
-		// TODO: drop flag_declaration.origin from the proto.
-		if flagDeclaration.Origin == nil {
-			flagDeclaration.Origin = m.proto.Origin
-		}
-		// There is always a default value.
-		if flagDeclaration.Value == nil {
-			flagDeclaration.Value = &release_config_proto.Value{Val: &release_config_proto.Value_UnspecifiedValue{true}}
-		}
-		m.FlagDeclarations = append(m.FlagDeclarations, *flagDeclaration)
-		name := *flagDeclaration.Name
-		if def, ok := configs.FlagArtifacts[name]; !ok {
-			configs.FlagArtifacts[name] = &FlagArtifact{FlagDeclaration: flagDeclaration, DeclarationIndex: ConfigDirIndex}
-		} else if !proto.Equal(def.FlagDeclaration, flagDeclaration) {
-			return fmt.Errorf("Duplicate definition of %s", *flagDeclaration.Name)
-		}
-		// Set the initial value in the flag artifact.
-		configs.FlagArtifacts[name].UpdateValue(
-			FlagValue{path: path, proto: release_config_proto.FlagValue{
-				Name: proto.String(name), Value: flagDeclaration.Value}})
-		return nil
-	})
-	if err != nil {
-		return err
-	}
-
-	err = WalkTextprotoFiles(dir, "release_configs", func(path string, d fs.DirEntry, err error) error {
-		releaseConfigContribution := &ReleaseConfigContribution{path: path, DeclarationIndex: ConfigDirIndex}
-		LoadTextproto(path, &releaseConfigContribution.proto)
-		name := *releaseConfigContribution.proto.Name
-		if fmt.Sprintf("%s.textproto", name) != filepath.Base(path) {
-			return fmt.Errorf("%s incorrectly declares release config %s", path, name)
-		}
-		if _, ok := configs.ReleaseConfigs[name]; !ok {
-			configs.ReleaseConfigs[name] = ReleaseConfigFactory(name, ConfigDirIndex)
-		}
-		config := configs.ReleaseConfigs[name]
-		config.InheritNames = append(config.InheritNames, releaseConfigContribution.proto.Inherits...)
-
-		// Only walk flag_values/{RELEASE} for defined releases.
-		err2 := WalkTextprotoFiles(dir, filepath.Join("flag_values", name), func(path string, d fs.DirEntry, err error) error {
-			flagValue := FlagValueFactory(path)
-			if fmt.Sprintf("%s.textproto", *flagValue.proto.Name) != filepath.Base(path) {
-				return fmt.Errorf("%s incorrectly sets value for flag %s", path, *flagValue.proto.Name)
-			}
-			releaseConfigContribution.FlagValues = append(releaseConfigContribution.FlagValues, flagValue)
-			return nil
-		})
-		if err2 != nil {
-			return err2
-		}
-		m.ReleaseConfigContributions[name] = releaseConfigContribution
-		config.Contributions = append(config.Contributions, releaseConfigContribution)
-		return nil
-	})
-	if err != nil {
-		return err
-	}
-	configs.ReleaseConfigMaps = append(configs.ReleaseConfigMaps, m)
-	return nil
-}
-
-func (configs *ReleaseConfigs) GetReleaseConfig(name string) (*ReleaseConfig, error) {
-	trace := []string{name}
-	for target, ok := configs.Aliases[name]; ok; target, ok = configs.Aliases[name] {
-		name = *target
-		trace = append(trace, name)
-	}
-	if config, ok := configs.ReleaseConfigs[name]; ok {
-		return config, nil
-	}
-	return nil, fmt.Errorf("Missing config %s.  Trace=%v", name, trace)
-}
-
-func (configs *ReleaseConfigs) DumpMakefile(outDir, targetRelease string) error {
-	outFile := filepath.Join(outDir, "release_config.mk")
-	makeVars := make(map[string]string)
-	config, err := configs.GetReleaseConfig(targetRelease)
-	if err != nil {
-		return err
-	}
-	// Sort the flags by name first.
-	names := []string{}
-	for k, _ := range config.FlagArtifacts {
-		names = append(names, k)
-	}
-	slices.SortFunc(names, func(a, b string) int {
-		return cmp.Compare(a, b)
-	})
-	partitions := make(map[string][]string)
-
-	vNames := []string{}
-	addVar := func(name, suffix, value string) {
-		fullName := fmt.Sprintf("_ALL_RELEASE_FLAGS.%s.%s", name, suffix)
-		vNames = append(vNames, fullName)
-		makeVars[fullName] = value
-	}
-
-	for _, name := range names {
-		flag := config.FlagArtifacts[name]
-		decl := flag.FlagDeclaration
-
-		// cName := strings.ToLower(release_config_proto.Container_name[decl.GetContainer()])
-		cName := strings.ToLower(decl.Container.String())
-		if cName == strings.ToLower(release_config_proto.Container_ALL.String()) {
-			partitions["product"] = append(partitions["product"], name)
-			partitions["system"] = append(partitions["system"], name)
-			partitions["system_ext"] = append(partitions["system_ext"], name)
-			partitions["vendor"] = append(partitions["vendor"], name)
-		} else {
-			partitions[cName] = append(partitions[cName], name)
-		}
-		value := MarshalValue(flag.Value)
-		makeVars[name] = value
-		addVar(name, "PARTITIONS", cName)
-		addVar(name, "DEFAULT", MarshalValue(decl.Value))
-		addVar(name, "VALUE", value)
-		addVar(name, "DECLARED_IN", *flag.Traces[0].Source)
-		addVar(name, "SET_IN", *flag.Traces[len(flag.Traces)-1].Source)
-		addVar(name, "ORIGIN", *decl.Origin)
-	}
-	pNames := []string{}
-	for k, _ := range partitions {
-		pNames = append(pNames, k)
-	}
-	slices.SortFunc(pNames, func(a, b string) int {
-		return cmp.Compare(a, b)
-	})
-
-	// Now sort the make variables, and output them.
-	slices.SortFunc(vNames, func(a, b string) int {
-		return cmp.Compare(a, b)
-	})
-
-	// Write the flags as:
-	//   _ALL_RELELASE_FLAGS
-	//   _ALL_RELEASE_FLAGS.PARTITIONS.*
-	//   all _ALL_RELEASE_FLAGS.*, sorted by name
-	//   Final flag values, sorted by name.
-	data := fmt.Sprintf("_ALL_RELEASE_FLAGS :=$= %s\n", strings.Join(names, " "))
-	for _, pName := range pNames {
-		data += fmt.Sprintf("_ALL_RELEASE_FLAGS.PARTITIONS.%s :=$= %s\n", pName, strings.Join(partitions[pName], " "))
-	}
-	for _, vName := range vNames {
-		data += fmt.Sprintf("%s :=$= %s\n", vName, makeVars[vName])
-	}
-	data += "\n\n# Values for all build flags\n"
-	data += fmt.Sprintf("RELEASE_ACONFIG_VALUE_SETS :=$= %s\n",
-		strings.Join(config.ReleaseConfigArtifact.AconfigValueSets, " "))
-	for _, name := range names {
-		data += fmt.Sprintf("%s :=$= %s\n", name, makeVars[name])
-	}
-	return os.WriteFile(outFile, []byte(data), 0644)
-}
-
-func (configs *ReleaseConfigs) GenerateReleaseConfigs(targetRelease string) error {
-	otherNames := make(map[string][]string)
-	for aliasName, aliasTarget := range configs.Aliases {
-		if _, ok := configs.ReleaseConfigs[aliasName]; ok {
-			return fmt.Errorf("Alias %s is a declared release config", aliasName)
-		}
-		if _, ok := configs.ReleaseConfigs[*aliasTarget]; !ok {
-			if _, ok2 := configs.Aliases[*aliasTarget]; !ok2 {
-				return fmt.Errorf("Alias %s points to non-existing config %s", aliasName, *aliasTarget)
-			}
-		}
-		otherNames[*aliasTarget] = append(otherNames[*aliasTarget], aliasName)
-	}
-	for name, aliases := range otherNames {
-		configs.ReleaseConfigs[name].OtherNames = aliases
-	}
-
-	for _, config := range configs.ReleaseConfigs {
-		err := config.GenerateReleaseConfig(configs)
-		if err != nil {
-			return err
-		}
-	}
-
-	releaseConfig, err := configs.GetReleaseConfig(targetRelease)
-	if err != nil {
-		return err
-	}
-	configs.Artifact = release_config_proto.ReleaseConfigsArtifact{
-		ReleaseConfig: releaseConfig.ReleaseConfigArtifact,
-		OtherReleaseConfigs: func() []*release_config_proto.ReleaseConfigArtifact {
-			orc := []*release_config_proto.ReleaseConfigArtifact{}
-			for name, config := range configs.ReleaseConfigs {
-				if name != releaseConfig.Name {
-					orc = append(orc, config.ReleaseConfigArtifact)
-				}
-			}
-			return orc
-		}(),
-	}
-	return nil
-}
-
-func MarshalValue(value *release_config_proto.Value) string {
-	switch val := value.Val.(type) {
-	case *release_config_proto.Value_UnspecifiedValue:
-		// Value was never set.
-		return ""
-	case *release_config_proto.Value_StringValue:
-		return val.StringValue
-	case *release_config_proto.Value_BoolValue:
-		if val.BoolValue {
-			return "true"
-		}
-		// False ==> empty string
-		return ""
-	case *release_config_proto.Value_Obsolete:
-		return " #OBSOLETE"
-	default:
-		// Flagged as error elsewhere, so return empty string here.
-		return ""
-	}
-}
-
-func (fa *FlagArtifact) UpdateValue(flagValue FlagValue) error {
-	name := *flagValue.proto.Name
-	fa.Traces = append(fa.Traces, &release_config_proto.Tracepoint{Source: proto.String(flagValue.path), Value: flagValue.proto.Value})
-	if fa.Value.GetObsolete() {
-		return fmt.Errorf("Attempting to set obsolete flag %s. Trace=%v", name, fa.Traces)
-	}
-	switch val := flagValue.proto.Value.Val.(type) {
-	case *release_config_proto.Value_StringValue:
-		fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_StringValue{val.StringValue}}
-	case *release_config_proto.Value_BoolValue:
-		fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_BoolValue{val.BoolValue}}
-	case *release_config_proto.Value_Obsolete:
-		if !val.Obsolete {
-			return fmt.Errorf("%s: Cannot set obsolete=false.  Trace=%v", name, fa.Traces)
-		}
-		fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_Obsolete{true}}
-	default:
-		return fmt.Errorf("Invalid type for flag_value: %T.  Trace=%v", val, fa.Traces)
-	}
-	return nil
-}
-
-func (fa *FlagArtifact) Marshal() (*release_config_proto.FlagArtifact, error) {
-	return &release_config_proto.FlagArtifact{
-		FlagDeclaration: fa.FlagDeclaration,
-		Value:           fa.Value,
-		Traces:          fa.Traces,
-	}, nil
-}
-
-func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) error {
-	if config.ReleaseConfigArtifact != nil {
-		return nil
-	}
-	if config.compileInProgress {
-		return fmt.Errorf("Loop detected for release config %s", config.Name)
-	}
-	config.compileInProgress = true
-
-	// Generate any configs we need to inherit.  This will detect loops in
-	// the config.
-	contributionsToApply := []*ReleaseConfigContribution{}
-	myInherits := []string{}
-	myInheritsSet := make(map[string]bool)
-	for _, inherit := range config.InheritNames {
-		if _, ok := myInheritsSet[inherit]; ok {
-			continue
-		}
-		myInherits = append(myInherits, inherit)
-		myInheritsSet[inherit] = true
-		iConfig, err := configs.GetReleaseConfig(inherit)
-		if err != nil {
-			return err
-		}
-		iConfig.GenerateReleaseConfig(configs)
-		contributionsToApply = append(contributionsToApply, iConfig.Contributions...)
-	}
-	contributionsToApply = append(contributionsToApply, config.Contributions...)
-
-	myAconfigValueSets := []string{}
-	myFlags := configs.FlagArtifacts.Clone()
-	myDirsMap := make(map[int]bool)
-	for _, contrib := range contributionsToApply {
-		myAconfigValueSets = append(myAconfigValueSets, contrib.proto.AconfigValueSets...)
-		myDirsMap[contrib.DeclarationIndex] = true
-		for _, value := range contrib.FlagValues {
-			fa, ok := myFlags[*value.proto.Name]
-			if !ok {
-				return fmt.Errorf("Setting value for undefined flag %s in %s\n", *value.proto.Name, value.path)
-			}
-			myDirsMap[fa.DeclarationIndex] = true
-			if fa.DeclarationIndex > contrib.DeclarationIndex {
-				// Setting location is to the left of declaration.
-				return fmt.Errorf("Setting value for flag %s not allowed in %s\n", *value.proto.Name, value.path)
-			}
-			if err := fa.UpdateValue(*value); err != nil {
-				return err
-			}
-		}
-	}
-
-	directories := []string{}
-	for idx, confDir := range configs.ConfigDirs {
-		if _, ok := myDirsMap[idx]; ok {
-			directories = append(directories, confDir)
-		}
-	}
-
-	config.FlagArtifacts = myFlags
-	config.ReleaseConfigArtifact = &release_config_proto.ReleaseConfigArtifact{
-		Name:       proto.String(config.Name),
-		OtherNames: config.OtherNames,
-		FlagArtifacts: func() []*release_config_proto.FlagArtifact {
-			ret := []*release_config_proto.FlagArtifact{}
-			for _, flag := range myFlags {
-				ret = append(ret, &release_config_proto.FlagArtifact{
-					FlagDeclaration: flag.FlagDeclaration,
-					Traces:          flag.Traces,
-					Value:           flag.Value,
-				})
-			}
-			return ret
-		}(),
-		AconfigValueSets: myAconfigValueSets,
-		Inherits:         myInherits,
-		Directories:      directories,
-	}
-
-	config.compileInProgress = false
-	return nil
-}
-
-func main() {
-	var targetRelease string
-	var outputDir string
-
-	outEnv := os.Getenv("OUT_DIR")
-	if outEnv == "" {
-		outEnv = "out"
-	}
-	defaultOutputDir := filepath.Join(outEnv, "soong", "release-config")
-	var defaultMapPaths StringList
-	defaultLocations := StringList{
-		"build/release/release_config_map.textproto",
-		"vendor/google_shared/build/release/release_config_map.textproto",
-		"vendor/google/release/release_config_map.textproto",
-	}
-	for _, path := range defaultLocations {
-		if _, err := os.Stat(path); err == nil {
-			defaultMapPaths = append(defaultMapPaths, path)
-		}
-	}
-	prodMaps := os.Getenv("PRODUCT_RELEASE_CONFIG_MAPS")
-	if prodMaps != "" {
-		defaultMapPaths = append(defaultMapPaths, strings.Split(prodMaps, " ")...)
-	}
-
-	flag.BoolVar(&verboseFlag, "debug", false, "print debugging information")
-	flag.Var(&releaseConfigMapPaths, "map", "path to a release_config_map.textproto. may be repeated")
-	flag.StringVar(&targetRelease, "release", "trunk_staging", "TARGET_RELEASE for this build")
-	flag.StringVar(&outputDir, "out_dir", defaultOutputDir, "basepath for the output. Multiple formats are created")
-	flag.Parse()
-
-	if len(releaseConfigMapPaths) == 0 {
-		releaseConfigMapPaths = defaultMapPaths
-		fmt.Printf("No --map argument provided.  Using: --map %s\n", strings.Join(releaseConfigMapPaths, " --map "))
-	}
-
-	configs := ReleaseConfigsFactory()
-	for idx, releaseConfigMapPath := range releaseConfigMapPaths {
-		// Maintain an ordered list of release config directories.
-		configDir := filepath.Dir(releaseConfigMapPath)
-		configs.ConfigDirIndexes[configDir] = idx
-		configs.ConfigDirs = append(configs.ConfigDirs, configDir)
-		err := configs.LoadReleaseConfigMap(releaseConfigMapPath, idx)
-		if err != nil {
-			panic(err)
-		}
-	}
-
-	// Now that we have all of the release config maps, can meld them and generate the artifacts.
-	err := configs.GenerateReleaseConfigs(targetRelease)
-	if err != nil {
-		panic(err)
-	}
-	err = os.MkdirAll(outputDir, 0775)
-	if err != nil {
-		panic(err)
-	}
-	err = configs.DumpMakefile(outputDir, targetRelease)
-	if err != nil {
-		panic(err)
-	}
-	DumpProtos(outputDir, &configs.Artifact)
-}
diff --git a/cmd/release_config/release_config/Android.bp b/cmd/release_config/release_config/Android.bp
new file mode 100644
index 0000000..3c73826
--- /dev/null
+++ b/cmd/release_config/release_config/Android.bp
@@ -0,0 +1,18 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-cmd-release_config-release_config",
+    pkgPath: "android/soong/cmd/release_config/release_config",
+    deps: [
+        "golang-protobuf-encoding-prototext",
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+        "soong-cmd-release_config-proto",
+        "soong-cmd-release_config-lib",
+    ],
+    srcs: [
+        "main.go",
+    ],
+}
diff --git a/cmd/release_config/release_config/main.go b/cmd/release_config/release_config/main.go
new file mode 100644
index 0000000..076abfa
--- /dev/null
+++ b/cmd/release_config/release_config/main.go
@@ -0,0 +1,57 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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 main
+
+import (
+	"flag"
+	"os"
+
+	rc_lib "android/soong/cmd/release_config/release_config_lib"
+)
+
+func main() {
+	var top string
+	var releaseConfigMapPaths rc_lib.StringList
+	var targetRelease string
+	var outputDir string
+	var err error
+	var configs *rc_lib.ReleaseConfigs
+
+	flag.StringVar(&top, "top", ".", "path to top of workspace")
+	flag.Var(&releaseConfigMapPaths, "map", "path to a release_config_map.textproto. may be repeated")
+	flag.StringVar(&targetRelease, "release", "trunk_staging", "TARGET_RELEASE for this build")
+	flag.StringVar(&outputDir, "out_dir", rc_lib.GetDefaultOutDir(), "basepath for the output. Multiple formats are created")
+	flag.Parse()
+
+	if err = os.Chdir(top); err != nil {
+		panic(err)
+	}
+	configs, err = rc_lib.ReadReleaseConfigMaps(releaseConfigMapPaths, targetRelease)
+	if err != nil {
+		panic(err)
+	}
+	err = os.MkdirAll(outputDir, 0775)
+	if err != nil {
+		panic(err)
+	}
+	err = configs.DumpMakefile(outputDir, targetRelease)
+	if err != nil {
+		panic(err)
+	}
+	err = configs.DumpArtifact(outputDir)
+	if err != nil {
+		panic(err)
+	}
+}
diff --git a/cmd/release_config/release_config_lib/Android.bp b/cmd/release_config/release_config_lib/Android.bp
new file mode 100644
index 0000000..601194c
--- /dev/null
+++ b/cmd/release_config/release_config_lib/Android.bp
@@ -0,0 +1,36 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-cmd-release_config-lib",
+    pkgPath: "android/soong/release_config/release_config_lib",
+    deps: [
+        "golang-protobuf-encoding-prototext",
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+        "soong-cmd-release_config-proto",
+    ],
+    srcs: [
+        "flag_artifact.go",
+        "flag_declaration.go",
+        "flag_value.go",
+        "release_config.go",
+        "release_configs.go",
+        "util.go",
+    ],
+}
diff --git a/cmd/release_config/release_config_lib/flag_artifact.go b/cmd/release_config/release_config_lib/flag_artifact.go
new file mode 100644
index 0000000..51673a5
--- /dev/null
+++ b/cmd/release_config/release_config_lib/flag_artifact.go
@@ -0,0 +1,89 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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 release_config_lib
+
+import (
+	"fmt"
+
+	"android/soong/cmd/release_config/release_config_proto"
+
+	"google.golang.org/protobuf/proto"
+)
+
+type FlagArtifact struct {
+	FlagDeclaration *release_config_proto.FlagDeclaration
+
+	// The index of the config directory where this flag was declared.
+	// Flag values cannot be set in a location with a lower index.
+	DeclarationIndex int
+
+	Traces []*release_config_proto.Tracepoint
+
+	// Assigned value
+	Value *release_config_proto.Value
+}
+
+// Key is flag name.
+type FlagArtifacts map[string]*FlagArtifact
+
+func (src *FlagArtifact) Clone() *FlagArtifact {
+	value := &release_config_proto.Value{}
+	proto.Merge(value, src.Value)
+	return &FlagArtifact{
+		FlagDeclaration: src.FlagDeclaration,
+		Traces:          src.Traces,
+		Value:           value,
+	}
+}
+
+func (src FlagArtifacts) Clone() (dst FlagArtifacts) {
+	if dst == nil {
+		dst = make(FlagArtifacts)
+	}
+	for k, v := range src {
+		dst[k] = v.Clone()
+	}
+	return
+}
+
+func (fa *FlagArtifact) UpdateValue(flagValue FlagValue) error {
+	name := *flagValue.proto.Name
+	fa.Traces = append(fa.Traces, &release_config_proto.Tracepoint{Source: proto.String(flagValue.path), Value: flagValue.proto.Value})
+	if fa.Value.GetObsolete() {
+		return fmt.Errorf("Attempting to set obsolete flag %s. Trace=%v", name, fa.Traces)
+	}
+	switch val := flagValue.proto.Value.Val.(type) {
+	case *release_config_proto.Value_StringValue:
+		fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_StringValue{val.StringValue}}
+	case *release_config_proto.Value_BoolValue:
+		fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_BoolValue{val.BoolValue}}
+	case *release_config_proto.Value_Obsolete:
+		if !val.Obsolete {
+			return fmt.Errorf("%s: Cannot set obsolete=false.  Trace=%v", name, fa.Traces)
+		}
+		fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_Obsolete{true}}
+	default:
+		return fmt.Errorf("Invalid type for flag_value: %T.  Trace=%v", val, fa.Traces)
+	}
+	return nil
+}
+
+func (fa *FlagArtifact) Marshal() (*release_config_proto.FlagArtifact, error) {
+	return &release_config_proto.FlagArtifact{
+		FlagDeclaration: fa.FlagDeclaration,
+		Value:           fa.Value,
+		Traces:          fa.Traces,
+	}, nil
+}
diff --git a/cmd/release_config/release_config_lib/flag_declaration.go b/cmd/release_config/release_config_lib/flag_declaration.go
new file mode 100644
index 0000000..d5cc418
--- /dev/null
+++ b/cmd/release_config/release_config_lib/flag_declaration.go
@@ -0,0 +1,27 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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 release_config_lib
+
+import (
+	"android/soong/cmd/release_config/release_config_proto"
+)
+
+func FlagDeclarationFactory(protoPath string) (fd *release_config_proto.FlagDeclaration) {
+	fd = &release_config_proto.FlagDeclaration{}
+	if protoPath != "" {
+		LoadTextproto(protoPath, fd)
+	}
+	return fd
+}
diff --git a/cmd/release_config/release_config_lib/flag_value.go b/cmd/release_config/release_config_lib/flag_value.go
new file mode 100644
index 0000000..138e8f8
--- /dev/null
+++ b/cmd/release_config/release_config_lib/flag_value.go
@@ -0,0 +1,56 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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 release_config_lib
+
+import (
+	"android/soong/cmd/release_config/release_config_proto"
+)
+
+type FlagValue struct {
+	// The path providing this value.
+	path string
+
+	// Protobuf
+	proto release_config_proto.FlagValue
+}
+
+func FlagValueFactory(protoPath string) (fv *FlagValue) {
+	fv = &FlagValue{path: protoPath}
+	if protoPath != "" {
+		LoadTextproto(protoPath, &fv.proto)
+	}
+	return fv
+}
+
+func MarshalValue(value *release_config_proto.Value) string {
+	switch val := value.Val.(type) {
+	case *release_config_proto.Value_UnspecifiedValue:
+		// Value was never set.
+		return ""
+	case *release_config_proto.Value_StringValue:
+		return val.StringValue
+	case *release_config_proto.Value_BoolValue:
+		if val.BoolValue {
+			return "true"
+		}
+		// False ==> empty string
+		return ""
+	case *release_config_proto.Value_Obsolete:
+		return " #OBSOLETE"
+	default:
+		// Flagged as error elsewhere, so return empty string here.
+		return ""
+	}
+}
diff --git a/cmd/release_config/release_config_lib/flag_value_test.go b/cmd/release_config/release_config_lib/flag_value_test.go
new file mode 100644
index 0000000..aaa4caf
--- /dev/null
+++ b/cmd/release_config/release_config_lib/flag_value_test.go
@@ -0,0 +1,67 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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 release_config_lib
+
+import (
+	"os"
+	"path/filepath"
+	"testing"
+
+	rc_proto "android/soong/cmd/release_config/release_config_proto"
+
+	"google.golang.org/protobuf/proto"
+)
+
+type testCaseFlagValue struct {
+	protoPath string
+	name      string
+	data      []byte
+	expected  rc_proto.FlagValue
+	err       error
+}
+
+func (tc testCaseFlagValue) assertProtoEqual(t *testing.T, expected, actual proto.Message) {
+	if !proto.Equal(expected, actual) {
+		t.Errorf("Expected %q found %q", expected, actual)
+	}
+}
+
+func TestFlagValue(t *testing.T) {
+	testCases := []testCaseFlagValue{
+		{
+			name:      "stringVal",
+			protoPath: "build/release/flag_values/test/RELEASE_FOO.textproto",
+			data:      []byte(`name: "RELEASE_FOO" value {string_value: "BAR"}`),
+			expected: rc_proto.FlagValue{
+				Name:  proto.String("RELEASE_FOO"),
+				Value: &rc_proto.Value{Val: &rc_proto.Value_StringValue{"BAR"}},
+			},
+			err: nil,
+		},
+	}
+	for _, tc := range testCases {
+		var err error
+		tempdir := t.TempDir()
+		path := filepath.Join(tempdir, tc.protoPath)
+		if err = os.MkdirAll(filepath.Dir(path), 0755); err != nil {
+			t.Fatal(err)
+		}
+		if err = os.WriteFile(path, tc.data, 0644); err != nil {
+			t.Fatal(err)
+		}
+		actual := FlagValueFactory(path)
+		tc.assertProtoEqual(t, &tc.expected, &actual.proto)
+	}
+}
diff --git a/cmd/release_config/release_config_lib/release_config.go b/cmd/release_config/release_config_lib/release_config.go
new file mode 100644
index 0000000..3110dae
--- /dev/null
+++ b/cmd/release_config/release_config_lib/release_config.go
@@ -0,0 +1,154 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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 release_config_lib
+
+import (
+	"fmt"
+
+	"android/soong/cmd/release_config/release_config_proto"
+
+	"google.golang.org/protobuf/proto"
+)
+
+// One directory's contribution to the a release config.
+type ReleaseConfigContribution struct {
+	// Paths to files providing this config.
+	path string
+
+	// The index of the config directory where this release config
+	// contribution was declared.
+	// Flag values cannot be set in a location with a lower index.
+	DeclarationIndex int
+
+	// Protobufs relevant to the config.
+	proto release_config_proto.ReleaseConfig
+
+	FlagValues []*FlagValue
+}
+
+// A generated release config.
+type ReleaseConfig struct {
+	// the Name of the release config
+	Name string
+
+	// The index of the config directory where this release config was
+	// first declared.
+	// Flag values cannot be set in a location with a lower index.
+	DeclarationIndex int
+
+	// What contributes to this config.
+	Contributions []*ReleaseConfigContribution
+
+	// Aliases for this release
+	OtherNames []string
+
+	// The names of release configs that we inherit
+	InheritNames []string
+
+	// Unmarshalled flag artifacts
+	FlagArtifacts FlagArtifacts
+
+	// Generated release config
+	ReleaseConfigArtifact *release_config_proto.ReleaseConfigArtifact
+
+	// We have begun compiling this release config.
+	compileInProgress bool
+}
+
+func ReleaseConfigFactory(name string, index int) (c *ReleaseConfig) {
+	return &ReleaseConfig{Name: name, DeclarationIndex: index}
+}
+
+func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) error {
+	if config.ReleaseConfigArtifact != nil {
+		return nil
+	}
+	if config.compileInProgress {
+		return fmt.Errorf("Loop detected for release config %s", config.Name)
+	}
+	config.compileInProgress = true
+
+	// Generate any configs we need to inherit.  This will detect loops in
+	// the config.
+	contributionsToApply := []*ReleaseConfigContribution{}
+	myInherits := []string{}
+	myInheritsSet := make(map[string]bool)
+	for _, inherit := range config.InheritNames {
+		if _, ok := myInheritsSet[inherit]; ok {
+			continue
+		}
+		myInherits = append(myInherits, inherit)
+		myInheritsSet[inherit] = true
+		iConfig, err := configs.GetReleaseConfig(inherit)
+		if err != nil {
+			return err
+		}
+		iConfig.GenerateReleaseConfig(configs)
+		contributionsToApply = append(contributionsToApply, iConfig.Contributions...)
+	}
+	contributionsToApply = append(contributionsToApply, config.Contributions...)
+
+	myAconfigValueSets := []string{}
+	myFlags := configs.FlagArtifacts.Clone()
+	myDirsMap := make(map[int]bool)
+	for _, contrib := range contributionsToApply {
+		myAconfigValueSets = append(myAconfigValueSets, contrib.proto.AconfigValueSets...)
+		myDirsMap[contrib.DeclarationIndex] = true
+		for _, value := range contrib.FlagValues {
+			fa, ok := myFlags[*value.proto.Name]
+			if !ok {
+				return fmt.Errorf("Setting value for undefined flag %s in %s\n", *value.proto.Name, value.path)
+			}
+			myDirsMap[fa.DeclarationIndex] = true
+			if fa.DeclarationIndex > contrib.DeclarationIndex {
+				// Setting location is to the left of declaration.
+				return fmt.Errorf("Setting value for flag %s not allowed in %s\n", *value.proto.Name, value.path)
+			}
+			if err := fa.UpdateValue(*value); err != nil {
+				return err
+			}
+		}
+	}
+
+	directories := []string{}
+	for idx, confDir := range configs.ConfigDirs {
+		if _, ok := myDirsMap[idx]; ok {
+			directories = append(directories, confDir)
+		}
+	}
+
+	config.FlagArtifacts = myFlags
+	config.ReleaseConfigArtifact = &release_config_proto.ReleaseConfigArtifact{
+		Name:       proto.String(config.Name),
+		OtherNames: config.OtherNames,
+		FlagArtifacts: func() []*release_config_proto.FlagArtifact {
+			ret := []*release_config_proto.FlagArtifact{}
+			for _, flag := range myFlags {
+				ret = append(ret, &release_config_proto.FlagArtifact{
+					FlagDeclaration: flag.FlagDeclaration,
+					Traces:          flag.Traces,
+					Value:           flag.Value,
+				})
+			}
+			return ret
+		}(),
+		AconfigValueSets: myAconfigValueSets,
+		Inherits:         myInherits,
+		Directories:      directories,
+	}
+
+	config.compileInProgress = false
+	return nil
+}
diff --git a/cmd/release_config/release_config_lib/release_configs.go b/cmd/release_config/release_config_lib/release_configs.go
new file mode 100644
index 0000000..74fdc00
--- /dev/null
+++ b/cmd/release_config/release_config_lib/release_configs.go
@@ -0,0 +1,365 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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 release_config_lib
+
+import (
+	"cmp"
+	"encoding/json"
+	"fmt"
+	"io/fs"
+	"os"
+	"path/filepath"
+	"slices"
+	"strings"
+
+	"android/soong/cmd/release_config/release_config_proto"
+
+	"google.golang.org/protobuf/encoding/prototext"
+	"google.golang.org/protobuf/proto"
+)
+
+// A single release_config_map.textproto and its associated data.
+// Used primarily for debugging.
+type ReleaseConfigMap struct {
+	// The path to this release_config_map file.
+	path string
+
+	// Data received
+	proto release_config_proto.ReleaseConfigMap
+
+	ReleaseConfigContributions map[string]*ReleaseConfigContribution
+	FlagDeclarations           []release_config_proto.FlagDeclaration
+}
+
+type ReleaseConfigDirMap map[string]int
+
+// The generated release configs.
+type ReleaseConfigs struct {
+	// Ordered list of release config maps processed.
+	ReleaseConfigMaps []*ReleaseConfigMap
+
+	// Aliases
+	Aliases map[string]*string
+
+	// Dictionary of flag_name:FlagDeclaration, with no overrides applied.
+	FlagArtifacts FlagArtifacts
+
+	// Dictionary of name:ReleaseConfig
+	ReleaseConfigs map[string]*ReleaseConfig
+
+	// Generated release configs
+	Artifact release_config_proto.ReleaseConfigsArtifact
+
+	// The list of config directories used.
+	ConfigDirs []string
+
+	// A map from the config directory to its order in the list of config
+	// directories.
+	ConfigDirIndexes ReleaseConfigDirMap
+}
+
+func (configs *ReleaseConfigs) DumpArtifact(outDir string) error {
+	message := &configs.Artifact
+	basePath := filepath.Join(outDir, "all_release_configs")
+	writer := func(suffix string, marshal func() ([]byte, error)) error {
+		data, err := marshal()
+		if err != nil {
+			return err
+		}
+		return os.WriteFile(fmt.Sprintf("%s.%s", basePath, suffix), data, 0644)
+	}
+	err := writer("textproto", func() ([]byte, error) { return prototext.MarshalOptions{Multiline: true}.Marshal(message) })
+	if err != nil {
+		return err
+	}
+
+	err = writer("pb", func() ([]byte, error) { return proto.Marshal(message) })
+	if err != nil {
+		return err
+	}
+
+	return writer("json", func() ([]byte, error) { return json.MarshalIndent(message, "", "  ") })
+}
+
+func ReleaseConfigsFactory() (c *ReleaseConfigs) {
+	return &ReleaseConfigs{
+		Aliases:          make(map[string]*string),
+		FlagArtifacts:    make(map[string]*FlagArtifact),
+		ReleaseConfigs:   make(map[string]*ReleaseConfig),
+		ConfigDirs:       []string{},
+		ConfigDirIndexes: make(ReleaseConfigDirMap),
+	}
+}
+
+func ReleaseConfigMapFactory(protoPath string) (m *ReleaseConfigMap) {
+	m = &ReleaseConfigMap{
+		path:                       protoPath,
+		ReleaseConfigContributions: make(map[string]*ReleaseConfigContribution),
+	}
+	if protoPath != "" {
+		LoadTextproto(protoPath, &m.proto)
+	}
+	return m
+}
+
+func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex int) error {
+	m := ReleaseConfigMapFactory(path)
+	if m.proto.DefaultContainer == nil {
+		return fmt.Errorf("Release config map %s lacks default_container", path)
+	}
+	dir := filepath.Dir(path)
+	// Record any aliases, checking for duplicates.
+	for _, alias := range m.proto.Aliases {
+		name := *alias.Name
+		oldTarget, ok := configs.Aliases[name]
+		if ok {
+			if *oldTarget != *alias.Target {
+				return fmt.Errorf("Conflicting alias declarations: %s vs %s",
+					*oldTarget, *alias.Target)
+			}
+		}
+		configs.Aliases[name] = alias.Target
+	}
+	var err error
+	err = WalkTextprotoFiles(dir, "flag_declarations", func(path string, d fs.DirEntry, err error) error {
+		flagDeclaration := FlagDeclarationFactory(path)
+		// Container must be specified.
+		if flagDeclaration.Container == nil {
+			flagDeclaration.Container = m.proto.DefaultContainer
+		}
+		// TODO: once we have namespaces initialized, we can throw an error here.
+		if flagDeclaration.Namespace == nil {
+			flagDeclaration.Namespace = proto.String("android_UNKNOWN")
+		}
+		// If the input didn't specify a value, create one (== UnspecifiedValue).
+		if flagDeclaration.Value == nil {
+			flagDeclaration.Value = &release_config_proto.Value{Val: &release_config_proto.Value_UnspecifiedValue{false}}
+		}
+		m.FlagDeclarations = append(m.FlagDeclarations, *flagDeclaration)
+		name := *flagDeclaration.Name
+		if def, ok := configs.FlagArtifacts[name]; !ok {
+			configs.FlagArtifacts[name] = &FlagArtifact{FlagDeclaration: flagDeclaration, DeclarationIndex: ConfigDirIndex}
+		} else if !proto.Equal(def.FlagDeclaration, flagDeclaration) {
+			return fmt.Errorf("Duplicate definition of %s", *flagDeclaration.Name)
+		}
+		// Set the initial value in the flag artifact.
+		configs.FlagArtifacts[name].UpdateValue(
+			FlagValue{path: path, proto: release_config_proto.FlagValue{
+				Name: proto.String(name), Value: flagDeclaration.Value}})
+		return nil
+	})
+	if err != nil {
+		return err
+	}
+
+	err = WalkTextprotoFiles(dir, "release_configs", func(path string, d fs.DirEntry, err error) error {
+		releaseConfigContribution := &ReleaseConfigContribution{path: path, DeclarationIndex: ConfigDirIndex}
+		LoadTextproto(path, &releaseConfigContribution.proto)
+		name := *releaseConfigContribution.proto.Name
+		if fmt.Sprintf("%s.textproto", name) != filepath.Base(path) {
+			return fmt.Errorf("%s incorrectly declares release config %s", path, name)
+		}
+		if _, ok := configs.ReleaseConfigs[name]; !ok {
+			configs.ReleaseConfigs[name] = ReleaseConfigFactory(name, ConfigDirIndex)
+		}
+		config := configs.ReleaseConfigs[name]
+		config.InheritNames = append(config.InheritNames, releaseConfigContribution.proto.Inherits...)
+
+		// Only walk flag_values/{RELEASE} for defined releases.
+		err2 := WalkTextprotoFiles(dir, filepath.Join("flag_values", name), func(path string, d fs.DirEntry, err error) error {
+			flagValue := FlagValueFactory(path)
+			if fmt.Sprintf("%s.textproto", *flagValue.proto.Name) != filepath.Base(path) {
+				return fmt.Errorf("%s incorrectly sets value for flag %s", path, *flagValue.proto.Name)
+			}
+			releaseConfigContribution.FlagValues = append(releaseConfigContribution.FlagValues, flagValue)
+			return nil
+		})
+		if err2 != nil {
+			return err2
+		}
+		m.ReleaseConfigContributions[name] = releaseConfigContribution
+		config.Contributions = append(config.Contributions, releaseConfigContribution)
+		return nil
+	})
+	if err != nil {
+		return err
+	}
+	configs.ReleaseConfigMaps = append(configs.ReleaseConfigMaps, m)
+	return nil
+}
+
+func (configs *ReleaseConfigs) GetReleaseConfig(name string) (*ReleaseConfig, error) {
+	trace := []string{name}
+	for target, ok := configs.Aliases[name]; ok; target, ok = configs.Aliases[name] {
+		name = *target
+		trace = append(trace, name)
+	}
+	if config, ok := configs.ReleaseConfigs[name]; ok {
+		return config, nil
+	}
+	return nil, fmt.Errorf("Missing config %s.  Trace=%v", name, trace)
+}
+
+func (configs *ReleaseConfigs) DumpMakefile(outDir, targetRelease string) error {
+	outFile := filepath.Join(outDir, "release_config.mk")
+	makeVars := make(map[string]string)
+	config, err := configs.GetReleaseConfig(targetRelease)
+	if err != nil {
+		return err
+	}
+	// Sort the flags by name first.
+	names := []string{}
+	for k, _ := range config.FlagArtifacts {
+		names = append(names, k)
+	}
+	slices.SortFunc(names, func(a, b string) int {
+		return cmp.Compare(a, b)
+	})
+	partitions := make(map[string][]string)
+
+	vNames := []string{}
+	addVar := func(name, suffix, value string) {
+		fullName := fmt.Sprintf("_ALL_RELEASE_FLAGS.%s.%s", name, suffix)
+		vNames = append(vNames, fullName)
+		makeVars[fullName] = value
+	}
+
+	for _, name := range names {
+		flag := config.FlagArtifacts[name]
+		decl := flag.FlagDeclaration
+
+		// cName := strings.ToLower(release_config_proto.Container_name[decl.GetContainer()])
+		cName := strings.ToLower(decl.Container.String())
+		if cName == strings.ToLower(release_config_proto.Container_ALL.String()) {
+			partitions["product"] = append(partitions["product"], name)
+			partitions["system"] = append(partitions["system"], name)
+			partitions["system_ext"] = append(partitions["system_ext"], name)
+			partitions["vendor"] = append(partitions["vendor"], name)
+		} else {
+			partitions[cName] = append(partitions[cName], name)
+		}
+		value := MarshalValue(flag.Value)
+		makeVars[name] = value
+		addVar(name, "PARTITIONS", cName)
+		addVar(name, "DEFAULT", MarshalValue(decl.Value))
+		addVar(name, "VALUE", value)
+		addVar(name, "DECLARED_IN", *flag.Traces[0].Source)
+		addVar(name, "SET_IN", *flag.Traces[len(flag.Traces)-1].Source)
+		addVar(name, "NAMESPACE", *decl.Namespace)
+	}
+	pNames := []string{}
+	for k, _ := range partitions {
+		pNames = append(pNames, k)
+	}
+	slices.SortFunc(pNames, func(a, b string) int {
+		return cmp.Compare(a, b)
+	})
+
+	// Now sort the make variables, and output them.
+	slices.SortFunc(vNames, func(a, b string) int {
+		return cmp.Compare(a, b)
+	})
+
+	// Write the flags as:
+	//   _ALL_RELELASE_FLAGS
+	//   _ALL_RELEASE_FLAGS.PARTITIONS.*
+	//   all _ALL_RELEASE_FLAGS.*, sorted by name
+	//   Final flag values, sorted by name.
+	data := fmt.Sprintf("_ALL_RELEASE_FLAGS :=$= %s\n", strings.Join(names, " "))
+	for _, pName := range pNames {
+		data += fmt.Sprintf("_ALL_RELEASE_FLAGS.PARTITIONS.%s :=$= %s\n", pName, strings.Join(partitions[pName], " "))
+	}
+	for _, vName := range vNames {
+		data += fmt.Sprintf("%s :=$= %s\n", vName, makeVars[vName])
+	}
+	data += "\n\n# Values for all build flags\n"
+	data += fmt.Sprintf("RELEASE_ACONFIG_VALUE_SETS :=$= %s\n",
+		strings.Join(config.ReleaseConfigArtifact.AconfigValueSets, " "))
+	for _, name := range names {
+		data += fmt.Sprintf("%s :=$= %s\n", name, makeVars[name])
+	}
+	return os.WriteFile(outFile, []byte(data), 0644)
+}
+
+func (configs *ReleaseConfigs) GenerateReleaseConfigs(targetRelease string) error {
+	otherNames := make(map[string][]string)
+	for aliasName, aliasTarget := range configs.Aliases {
+		if _, ok := configs.ReleaseConfigs[aliasName]; ok {
+			return fmt.Errorf("Alias %s is a declared release config", aliasName)
+		}
+		if _, ok := configs.ReleaseConfigs[*aliasTarget]; !ok {
+			if _, ok2 := configs.Aliases[*aliasTarget]; !ok2 {
+				return fmt.Errorf("Alias %s points to non-existing config %s", aliasName, *aliasTarget)
+			}
+		}
+		otherNames[*aliasTarget] = append(otherNames[*aliasTarget], aliasName)
+	}
+	for name, aliases := range otherNames {
+		configs.ReleaseConfigs[name].OtherNames = aliases
+	}
+
+	for _, config := range configs.ReleaseConfigs {
+		err := config.GenerateReleaseConfig(configs)
+		if err != nil {
+			return err
+		}
+	}
+
+	releaseConfig, err := configs.GetReleaseConfig(targetRelease)
+	if err != nil {
+		return err
+	}
+	configs.Artifact = release_config_proto.ReleaseConfigsArtifact{
+		ReleaseConfig: releaseConfig.ReleaseConfigArtifact,
+		OtherReleaseConfigs: func() []*release_config_proto.ReleaseConfigArtifact {
+			orc := []*release_config_proto.ReleaseConfigArtifact{}
+			for name, config := range configs.ReleaseConfigs {
+				if name != releaseConfig.Name {
+					orc = append(orc, config.ReleaseConfigArtifact)
+				}
+			}
+			return orc
+		}(),
+	}
+	return nil
+}
+
+func ReadReleaseConfigMaps(releaseConfigMapPaths StringList, targetRelease string) (*ReleaseConfigs, error) {
+	var err error
+
+	if len(releaseConfigMapPaths) == 0 {
+		releaseConfigMapPaths = GetDefaultMapPaths()
+		if len(releaseConfigMapPaths) == 0 {
+			return nil, fmt.Errorf("No maps found")
+		}
+		fmt.Printf("No --map argument provided.  Using: --map %s\n", strings.Join(releaseConfigMapPaths, " --map "))
+	}
+
+	configs := ReleaseConfigsFactory()
+	for idx, releaseConfigMapPath := range releaseConfigMapPaths {
+		// Maintain an ordered list of release config directories.
+		configDir := filepath.Dir(releaseConfigMapPath)
+		configs.ConfigDirIndexes[configDir] = idx
+		configs.ConfigDirs = append(configs.ConfigDirs, configDir)
+		err = configs.LoadReleaseConfigMap(releaseConfigMapPath, idx)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	// Now that we have all of the release config maps, can meld them and generate the artifacts.
+	err = configs.GenerateReleaseConfigs(targetRelease)
+	return configs, err
+}
diff --git a/cmd/release_config/release_config_lib/util.go b/cmd/release_config/release_config_lib/util.go
new file mode 100644
index 0000000..c59deb3
--- /dev/null
+++ b/cmd/release_config/release_config_lib/util.go
@@ -0,0 +1,90 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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 release_config_lib
+
+import (
+	"fmt"
+	"io/fs"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"google.golang.org/protobuf/encoding/prototext"
+	"google.golang.org/protobuf/proto"
+)
+
+type StringList []string
+
+func (l *StringList) Set(v string) error {
+	*l = append(*l, v)
+	return nil
+}
+
+func (l *StringList) String() string {
+	return fmt.Sprintf("%v", *l)
+}
+
+func LoadTextproto(path string, message proto.Message) error {
+	data, err := os.ReadFile(path)
+	if err != nil {
+		return err
+	}
+	ret := prototext.Unmarshal(data, message)
+	return ret
+}
+
+func WalkTextprotoFiles(root string, subdir string, Func fs.WalkDirFunc) error {
+	path := filepath.Join(root, subdir)
+	if _, err := os.Stat(path); err != nil {
+		// Missing subdirs are not an error.
+		return nil
+	}
+	return filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
+		if err != nil {
+			return err
+		}
+		if strings.HasSuffix(d.Name(), ".textproto") && d.Type().IsRegular() {
+			return Func(path, d, err)
+		}
+		return nil
+	})
+}
+
+func GetDefaultOutDir() string {
+	outEnv := os.Getenv("OUT_DIR")
+	if outEnv == "" {
+		outEnv = "out"
+	}
+	return filepath.Join(outEnv, "soong", "release-config")
+}
+
+func GetDefaultMapPaths() StringList {
+	var defaultMapPaths StringList
+	defaultLocations := StringList{
+		"build/release/release_config_map.textproto",
+		"vendor/google_shared/build/release/release_config_map.textproto",
+		"vendor/google/release/release_config_map.textproto",
+	}
+	for _, path := range defaultLocations {
+		if _, err := os.Stat(path); err == nil {
+			defaultMapPaths = append(defaultMapPaths, path)
+		}
+	}
+	prodMaps := os.Getenv("PRODUCT_RELEASE_CONFIG_MAPS")
+	if prodMaps != "" {
+		defaultMapPaths = append(defaultMapPaths, strings.Split(prodMaps, " ")...)
+	}
+	return defaultMapPaths
+}
diff --git a/cmd/release_config/release_config_proto/Android.bp b/cmd/release_config/release_config_proto/Android.bp
index a8660c7..5a6aeab 100644
--- a/cmd/release_config/release_config_proto/Android.bp
+++ b/cmd/release_config/release_config_proto/Android.bp
@@ -17,7 +17,7 @@
 }
 
 bootstrap_go_package {
-    name: "soong-release_config_proto",
+    name: "soong-cmd-release_config-proto",
     pkgPath: "android/soong/release_config/release_config_proto",
     deps: [
         "golang-protobuf-reflect-protoreflect",
diff --git a/cmd/release_config/release_config_proto/build_flags_src.pb.go b/cmd/release_config/release_config_proto/build_flags_src.pb.go
index 0f2c30b..ccf3b3f 100644
--- a/cmd/release_config/release_config_proto/build_flags_src.pb.go
+++ b/cmd/release_config/release_config_proto/build_flags_src.pb.go
@@ -287,6 +287,9 @@
 	// The name of the flag.
 	// See # name for format detail
 	Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+	// Namespace the flag belongs to (required)
+	// See # namespace for format detail
+	Namespace *string `protobuf:"bytes,2,opt,name=namespace" json:"namespace,omitempty"`
 	// Text description of the flag's purpose.
 	Description *string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"`
 	// Value for the flag
@@ -296,9 +299,6 @@
 	// The container for this flag.  This overrides any default container given
 	// in the release_config_map message.
 	Container *Container `protobuf:"varint,206,opt,name=container,enum=android.release_config_proto.Container" json:"container,omitempty"`
-	// Temporarily allow origin at the flag declaration level while we
-	// move flags to their own locations.
-	Origin *string `protobuf:"bytes,208,opt,name=origin" json:"origin,omitempty"`
 }
 
 func (x *FlagDeclaration) Reset() {
@@ -340,6 +340,13 @@
 	return ""
 }
 
+func (x *FlagDeclaration) GetNamespace() string {
+	if x != nil && x.Namespace != nil {
+		return *x.Namespace
+	}
+	return ""
+}
+
 func (x *FlagDeclaration) GetDescription() string {
 	if x != nil && x.Description != nil {
 		return *x.Description
@@ -368,13 +375,6 @@
 	return Container_UNSPECIFIED_container
 }
 
-func (x *FlagDeclaration) GetOrigin() string {
-	if x != nil && x.Origin != nil {
-		return *x.Origin
-	}
-	return ""
-}
-
 type FlagValue struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -568,8 +568,6 @@
 
 	// Any aliases.
 	Aliases []*ReleaseAlias `protobuf:"bytes,1,rep,name=aliases" json:"aliases,omitempty"`
-	// The origin for flags declared here.
-	Origin *string `protobuf:"bytes,2,opt,name=origin" json:"origin,omitempty"`
 	// The default container for flags declared here.
 	DefaultContainer *Container `protobuf:"varint,3,opt,name=default_container,json=defaultContainer,enum=android.release_config_proto.Container" json:"default_container,omitempty"`
 }
@@ -613,13 +611,6 @@
 	return nil
 }
 
-func (x *ReleaseConfigMap) GetOrigin() string {
-	if x != nil && x.Origin != nil {
-		return *x.Origin
-	}
-	return ""
-}
-
 func (x *ReleaseConfigMap) GetDefaultContainer() Container {
 	if x != nil && x.DefaultContainer != nil {
 		return *x.DefaultContainer
@@ -643,71 +634,70 @@
 	0x6c, 0x75, 0x65, 0x18, 0xca, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f,
 	0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1d, 0x0a, 0x08, 0x6f, 0x62, 0x73, 0x6f, 0x6c,
 	0x65, 0x74, 0x65, 0x18, 0xcb, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x08, 0x6f, 0x62,
-	0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x76, 0x61, 0x6c, 0x22, 0xb8, 0x02,
+	0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x76, 0x61, 0x6c, 0x22, 0xbd, 0x02,
 	0x0a, 0x10, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69,
 	0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
-	0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73,
-	0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
-	0x65, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f,
-	0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
-	0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76,
-	0x61, 0x6c, 0x75, 0x65, 0x12, 0x43, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
-	0x18, 0xcd, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
-	0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
-	0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52,
-	0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x46, 0x0a, 0x09, 0x63, 0x6f, 0x6e,
-	0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0xce, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e,
-	0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f,
-	0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6e,
-	0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
-	0x72, 0x12, 0x17, 0x0a, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x18, 0xd0, 0x01, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05,
-	0x4a, 0x06, 0x08, 0xcf, 0x01, 0x10, 0xd0, 0x01, 0x22, 0x5c, 0x0a, 0x0a, 0x66, 0x6c, 0x61, 0x67,
-	0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61,
-	0x6c, 0x75, 0x65, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64,
-	0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e,
-	0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x52,
-	0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x6e, 0x0a, 0x0e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73,
-	0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08,
-	0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08,
-	0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x61, 0x63, 0x6f, 0x6e,
-	0x66, 0x69, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x73, 0x18, 0x03,
-	0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x61, 0x6c,
-	0x75, 0x65, 0x53, 0x65, 0x74, 0x73, 0x22, 0x3b, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73,
-	0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74,
-	0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72,
-	0x67, 0x65, 0x74, 0x22, 0xc9, 0x01, 0x0a, 0x12, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f,
-	0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70, 0x12, 0x45, 0x0a, 0x07, 0x61, 0x6c,
-	0x69, 0x61, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x6e,
+	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70,
+	0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73,
+	0x70, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
+	0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
+	0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
+	0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c,
+	0x75, 0x65, 0x12, 0x43, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0xcd,
+	0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e,
+	0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x08, 0x77,
+	0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x46, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61,
+	0x69, 0x6e, 0x65, 0x72, 0x18, 0xce, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x61, 0x6e,
 	0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f,
-	0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61,
-	0x73, 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65,
-	0x73, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x12, 0x54, 0x0a, 0x11, 0x64, 0x65, 0x66,
-	0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x03,
-	0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72,
+	0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61,
+	0x69, 0x6e, 0x65, 0x72, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4a,
+	0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x06, 0x08, 0xcf, 0x01, 0x10, 0xd0, 0x01, 0x22, 0x5c, 0x0a,
+	0x0a, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e,
+	0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
+	0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73,
+	0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x6e, 0x0a, 0x0e, 0x72,
+	0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a,
+	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
+	0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20,
+	0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x12, 0x2c, 0x0a,
+	0x12, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x73,
+	0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x61, 0x63, 0x6f, 0x6e, 0x66,
+	0x69, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x65, 0x74, 0x73, 0x22, 0x3b, 0x0a, 0x0d, 0x72,
+	0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x12, 0x0a, 0x04,
+	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+	0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0xb1, 0x01, 0x0a, 0x12, 0x72, 0x65, 0x6c,
+	0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70, 0x12,
+	0x45, 0x0a, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x2b, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61,
+	0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
+	0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x07, 0x61,
+	0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x54, 0x0a, 0x11, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c,
+	0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x0e, 0x32, 0x27, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65,
+	0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x10, 0x64, 0x65, 0x66, 0x61,
+	0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2a, 0x4a, 0x0a, 0x08,
+	0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x18, 0x0a, 0x14, 0x55, 0x4e, 0x53, 0x50,
+	0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
+	0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x41, 0x55, 0x4e, 0x43, 0x48, 0x10, 0x01, 0x12, 0x0c,
+	0x0a, 0x08, 0x50, 0x52, 0x45, 0x42, 0x55, 0x49, 0x4c, 0x54, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06,
+	0x4d, 0x41, 0x4e, 0x55, 0x41, 0x4c, 0x10, 0x03, 0x2a, 0x64, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x74,
+	0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x19, 0x0a, 0x15, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49,
+	0x46, 0x49, 0x45, 0x44, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x10, 0x00,
+	0x12, 0x07, 0x0a, 0x03, 0x41, 0x4c, 0x4c, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x52, 0x4f,
+	0x44, 0x55, 0x43, 0x54, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d,
+	0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, 0x5f, 0x45, 0x58, 0x54,
+	0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x56, 0x45, 0x4e, 0x44, 0x4f, 0x52, 0x10, 0x05, 0x42, 0x33,
+	0x5a, 0x31, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f,
+	0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72,
 	0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72,
-	0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x10, 0x64,
-	0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2a,
-	0x4a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x18, 0x0a, 0x14, 0x55,
-	0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x66,
-	0x6c, 0x6f, 0x77, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x41, 0x55, 0x4e, 0x43, 0x48, 0x10,
-	0x01, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x52, 0x45, 0x42, 0x55, 0x49, 0x4c, 0x54, 0x10, 0x02, 0x12,
-	0x0a, 0x0a, 0x06, 0x4d, 0x41, 0x4e, 0x55, 0x41, 0x4c, 0x10, 0x03, 0x2a, 0x64, 0x0a, 0x09, 0x63,
-	0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x19, 0x0a, 0x15, 0x55, 0x4e, 0x53, 0x50,
-	0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
-	0x72, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x4c, 0x4c, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07,
-	0x50, 0x52, 0x4f, 0x44, 0x55, 0x43, 0x54, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x59, 0x53,
-	0x54, 0x45, 0x4d, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, 0x5f,
-	0x45, 0x58, 0x54, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x56, 0x45, 0x4e, 0x44, 0x4f, 0x52, 0x10,
-	0x05, 0x42, 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f,
-	0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
-	0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
-	0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x6f, 0x74, 0x6f,
 }
 
 var (
diff --git a/cmd/release_config/release_config_proto/build_flags_src.proto b/cmd/release_config/release_config_proto/build_flags_src.proto
index 0662716..8501524 100644
--- a/cmd/release_config/release_config_proto/build_flags_src.proto
+++ b/cmd/release_config/release_config_proto/build_flags_src.proto
@@ -26,6 +26,11 @@
 //      RELEASE_MY_PACKAGE_FLAG is a valid name, while MY_PACKAGE_FLAG, and
 //      RELEASE_MY_PACKAGE__FLAG are invalid.
 //
+// # namespace: namespace the flag belongs to
+//
+//    format: a lowercase string in snake_case format, no consecutive underscores, and no leading
+//      digit. For example android_bar_system
+//
 // # package: package to which the flag belongs
 //
 //    format: lowercase strings in snake_case format, delimited by dots, no
@@ -77,6 +82,10 @@
   // See # name for format detail
   optional string name = 1;
 
+  // Namespace the flag belongs to (required)
+  // See # namespace for format detail
+  optional string namespace = 2;
+
   // Text description of the flag's purpose.
   optional string description = 3;
 
@@ -96,12 +105,6 @@
   // The package associated with this flag.
   // (when Gantry is ready for it) optional string package = 207;
   reserved 207;
-
-  // Temporarily allow origin at the flag declaration level while we
-  // move flags to their own locations.
-  optional string origin = 208;
-
-  // TODO: do we want to include "first used in" (= ap2a)?
 }
 
 message flag_value {
@@ -141,9 +144,6 @@
   // Any aliases.
   repeated release_alias aliases = 1;
 
-  // The origin for flags declared here.
-  optional string origin = 2;
-
   // The default container for flags declared here.
   optional container default_container = 3;