Merge changes from topic "aconfig-part-5"
* changes:
aconfig: follow Java conventions for Java file paths
aconfig: separate flag declarations and flag values
diff --git a/core/Makefile b/core/Makefile
index e9340f7..accb05a 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -17,6 +17,52 @@
SYSTEM_DLKM_NOTICE_DEPS :=
# -----------------------------------------------------------------
+# Release Config Flags
+
+# Create a summary file of build flags for each partition
+# $(1): build flags json file
+# $(2): flag names
+define generate-partition-build-flag-file
+$(eval $(strip $(1)): PRIVATE_OUT := $(strip $(1)))
+$(eval $(strip $(1)): PRIVATE_FLAG_NAMES := $(strip $(2)))
+$(strip $(1)):
+ mkdir -p $$(dir $$(PRIVATE_OUT))
+ ( \
+ echo '{' ; \
+ echo 'flags: [' ; \
+ $$(foreach flag, $$(PRIVATE_FLAG_NAMES), \
+ printf ' { "name": "%s", "value": "%s", ' \
+ '$$(flag)' \
+ '$$(_ALL_RELEASE_FLAGS.$$(flag).VALUE)' \
+ ; \
+ printf '"set": "%s", "default": "%s", "declared": "%s", }' \
+ '$$(_ALL_RELEASE_FLAGS.$$(flag).SET_IN)' \
+ '$$(_ALL_RELEASE_FLAGS.$$(flag).DEFAULT)' \
+ '$$(_ALL_RELEASE_FLAGS.$$(flag).DECLARED_IN)' \
+ ; \
+ printf '$$(if $$(filter $$(lastword $$(PRIVATE_FLAG_NAMES)),$$(flag)),,$$(comma))\n' ; \
+ ) \
+ echo "]" ; \
+ echo "}" \
+ ) >> $$(PRIVATE_OUT)
+endef
+
+$(foreach partition, $(_FLAG_PARTITIONS), \
+ $(eval BUILD_FLAG_SUMMARIES.$(partition) \
+ := $(TARGET_OUT_FLAGS)/$(partition)/etc/build_flags.json) \
+ $(eval $(call generate-partition-build-flag-file, \
+ $(BUILD_FLAG_SUMMARIES.$(partition)), \
+ $(_ALL_RELEASE_FLAGS.PARTITIONS.$(partition)) \
+ ) \
+ ) \
+)
+
+# TODO: Remove
+.PHONY: flag-files
+flag-files: $(foreach partition, $(_FLAG_PARTITIONS), \
+ $(TARGET_OUT_FLAGS)/$(partition)/etc/build_flags.json)
+
+# -----------------------------------------------------------------
# Define rules to copy PRODUCT_COPY_FILES defined by the product.
# PRODUCT_COPY_FILES contains words like <source file>:<dest file>[:<owner>].
# <dest file> is relative to $(PRODUCT_OUT), so it should look like,
@@ -5589,6 +5635,8 @@
.PHONY: fastboot_info
fastboot_info: $(INSTALLED_FASTBOOT_INFO_TARGET)
+droidcore-unbundled: $(INSTALLED_FASTBOOT_INFO_TARGET)
+
$(call declare-0p-target,$(INSTALLED_MISC_INFO_TARGET))
.PHONY: misc_info
@@ -5910,6 +5958,7 @@
$(LPMAKE) \
$(SELINUX_FC) \
$(INSTALLED_MISC_INFO_TARGET) \
+ $(INSTALLED_FASTBOOT_INFO_TARGET) \
$(APKCERTS_FILE) \
$(SOONG_APEX_KEYS_FILE) \
$(SOONG_ZIP) \
@@ -6128,6 +6177,9 @@
$(hide) echo "$(PRODUCT_OTA_PUBLIC_KEYS)" > $(zip_root)/META/otakeys.txt
$(hide) cp $(SELINUX_FC) $(zip_root)/META/file_contexts.bin
$(hide) cp $(INSTALLED_MISC_INFO_TARGET) $(zip_root)/META/misc_info.txt
+ifneq ($(INSTALLED_FASTBOOT_INFO_TARGET),)
+ $(hide) cp $(INSTALLED_FASTBOOT_INFO_TARGET) $(zip_root)/META/fastboot-info.txt
+endif
ifneq ($(PRODUCT_SYSTEM_BASE_FS_PATH),)
$(hide) cp $(PRODUCT_SYSTEM_BASE_FS_PATH) \
$(zip_root)/META/$(notdir $(PRODUCT_SYSTEM_BASE_FS_PATH))
diff --git a/core/all_versions.bzl b/core/all_versions.bzl
new file mode 100644
index 0000000..33da673
--- /dev/null
+++ b/core/all_versions.bzl
@@ -0,0 +1,23 @@
+# Copyright (C) 2023 The Android Open Source Project
+#
+# 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.
+
+_all_versions = ["OPR1", "OPD1", "OPD2", "OPM1", "OPM2", "PPR1", "PPD1", "PPD2", "PPM1", "PPM2", "QPR1"] + [
+ version + subversion
+ for version in ["Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
+ for subversion in ["P1A", "P1B", "P2A", "P2B", "D1A", "D1B", "D2A", "D2B", "Q1A", "Q1B", "Q2A", "Q2B", "Q3A", "Q3B"]
+]
+
+variables_to_export_to_make = {
+ "ALL_VERSIONS": _all_versions,
+}
diff --git a/core/board_config.mk b/core/board_config.mk
index 7969b25..bdfb279 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -256,7 +256,7 @@
endif
$(shell build/soong/scripts/update_out $(OUT_DIR)/rbc/rbc_board_config_results.mk \
- $(OUT_DIR)/rbcrun $(OUT_DIR)/rbc/boardlauncher.rbc)
+ $(OUT_DIR)/rbcrun --mode=rbc $(OUT_DIR)/rbc/boardlauncher.rbc)
ifneq ($(.SHELLSTATUS),0)
$(error board configuration runner failed: $(.SHELLSTATUS))
endif
diff --git a/core/dex_preopt_odex_install.mk b/core/dex_preopt_odex_install.mk
index cb16321..7165bea 100644
--- a/core/dex_preopt_odex_install.mk
+++ b/core/dex_preopt_odex_install.mk
@@ -84,12 +84,13 @@
ifndef LOCAL_DEX_PREOPT_GENERATE_PROFILE
# If LOCAL_DEX_PREOPT_GENERATE_PROFILE is not defined, default it based on the existence of the
# profile class listing. TODO: Use product specific directory here.
- my_classes_directory := $(PRODUCT_DEX_PREOPT_PROFILE_DIR)
- LOCAL_DEX_PREOPT_PROFILE := $(my_classes_directory)/$(LOCAL_MODULE).prof
+ ifdef PRODUCT_DEX_PREOPT_PROFILE_DIR
+ LOCAL_DEX_PREOPT_PROFILE := $(PRODUCT_DEX_PREOPT_PROFILE_DIR)/$(LOCAL_MODULE).prof
- ifneq (,$(wildcard $(LOCAL_DEX_PREOPT_PROFILE)))
- my_process_profile := true
- my_profile_is_text_listing :=
+ ifneq (,$(wildcard $(LOCAL_DEX_PREOPT_PROFILE)))
+ my_process_profile := true
+ my_profile_is_text_listing :=
+ endif
endif
else
my_process_profile := $(LOCAL_DEX_PREOPT_GENERATE_PROFILE)
diff --git a/core/envsetup.mk b/core/envsetup.mk
index 7dd9b12..8887ddc 100644
--- a/core/envsetup.mk
+++ b/core/envsetup.mk
@@ -24,14 +24,30 @@
#$(warning $(call find_and_earlier,A B C,C))
#$(warning $(call find_and_earlier,A B C,D))
-define version-list
-$(1)P1A $(1)P1B $(1)P2A $(1)P2B $(1)D1A $(1)D1B $(1)D2A $(1)D2B $(1)Q1A $(1)Q1B $(1)Q2A $(1)Q2B $(1)Q3A $(1)Q3B
+# Runs the starlark file given in $(1), and sets all the variables in its top-level
+# variables_to_export_to_make variable as make variables.
+#
+# In order to avoid running starlark every time the stamp file is checked, we use
+# $(KATI_shell_no_rerun). Then, to make sure that we actually do rerun kati when
+# modifying the starlark files, we add the starlark files to the kati stamp file with
+# $(KATI_extra_file_deps).
+define run-starlark
+$(eval _starlark_results := $(OUT_DIR)/starlark_results/$(subst /,_,$(1)).mk)
+$(KATI_shell_no_rerun mkdir -p $(OUT_DIR)/starlark_results && $(OUT_DIR)/rbcrun --mode=make $(1) >$(_starlark_results) && touch -t 200001010000 $(_starlark_results))
+$(if $(filter-out 0,$(.SHELLSTATUS)),$(error Starlark failed to run))
+$(eval include $(_starlark_results))
+$(KATI_extra_file_deps $(LOADED_STARLARK_FILES))
+$(eval LOADED_STARLARK_FILES :=)
+$(eval _starlark_results :=)
endef
-PREV_VERSIONS := OPR1 OPD1 OPD2 OPM1 OPM2 PPR1 PPD1 PPD2 PPM1 PPM2 QPR1
-ALL_VERSIONS := Q R S T U V W X Y Z
-ALL_VERSIONS := $(PREV_VERSIONS) $(foreach v,$(ALL_VERSIONS),$(call version-list,$(v)))
-PREV_VERSIONS :=
+# ---------------------------------------------------------------
+# Release config
+include $(BUILD_SYSTEM)/release_config.mk
+
+# ---------------------------------------------------------------
+# defines ALL_VERSIONS
+$(call run-starlark,build/make/core/all_versions.bzl)
# Filters ALL_VERSIONS down to the range [$1, $2], and errors if $1 > $2 or $3 is
# not in [$1, $2]
@@ -339,6 +355,7 @@
RBC_PRODUCT_CONFIG \
RBC_BOARD_CONFIG \
SOONG_% \
+ TARGET_RELEASE \
TOPDIR \
TRACE_BEGIN_SOONG \
USER)
@@ -553,6 +570,8 @@
TARGET_OUT_NOTICE_FILES := $(TARGET_OUT_INTERMEDIATES)/NOTICE_FILES
TARGET_OUT_FAKE := $(PRODUCT_OUT)/fake_packages
TARGET_OUT_TESTCASES := $(PRODUCT_OUT)/testcases
+TARGET_OUT_FLAGS := $(TARGET_OUT_INTERMEDIATES)/FLAGS
+
.KATI_READONLY := \
TARGET_OUT_EXECUTABLES \
TARGET_OUT_OPTIONAL_EXECUTABLES \
@@ -566,7 +585,8 @@
TARGET_OUT_ETC \
TARGET_OUT_NOTICE_FILES \
TARGET_OUT_FAKE \
- TARGET_OUT_TESTCASES
+ TARGET_OUT_TESTCASES \
+ TARGET_OUT_FLAGS
ifeq ($(SANITIZE_LITE),true)
# When using SANITIZE_LITE, APKs must not be packaged with sanitized libraries, as they will not
diff --git a/core/product_config.mk b/core/product_config.mk
index 6a27613..01ad030 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -247,7 +247,7 @@
endif
$(shell build/soong/scripts/update_out $(OUT_DIR)/rbc/rbc_product_config_results.mk \
- $(OUT_DIR)/rbcrun $(OUT_DIR)/rbc/launcher.rbc)
+ $(OUT_DIR)/rbcrun --mode=rbc $(OUT_DIR)/rbc/launcher.rbc)
ifneq ($(.SHELLSTATUS),0)
$(error product configuration runner failed: $(.SHELLSTATUS))
endif
diff --git a/core/release_config.mk b/core/release_config.mk
new file mode 100644
index 0000000..0ad87fc
--- /dev/null
+++ b/core/release_config.mk
@@ -0,0 +1,198 @@
+# Copyright (C) 2023 The Android Open Source Project
+#
+# 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.
+
+# Partitions that get build system flag summaries
+_FLAG_PARTITIONS := system vendor system_ext product
+
+# All possible release flags. Defined in the flags.mk files
+# throughout the tree
+_ALL_RELEASE_FLAGS :=
+
+# -----------------------------------------------------------------
+# Choose the flag files
+# Do this first, because we're going to unset TARGET_RELEASE before
+# including anyone, so they don't start making conditionals based on it.
+
+# If this is a google source tree, restrict it to only the one file
+# which has OWNERS control. If it isn't let others define their own.
+config_map_files := build/make/release/release_config_map.mk \
+ $(if $(wildcard vendor/google/release/release_config_map.mk), \
+ vendor/google/release/release_config_map.mk, \
+ $(sort \
+ $(wildcard device/*/release/release_config_map.mk) \
+ $(wildcard device/*/*/release/release_config_map.mk) \
+ $(wildcard vendor/*/release/release_config_map.mk) \
+ $(wildcard vendor/*/*/release/release_config_map.mk) \
+ ) \
+ )
+
+# $1 config name
+# $2 release config files
+define declare-release-config
+ $(eval # No duplicates)
+ $(if $(filter $(_all_release_configs), $(strip $(1))), \
+ $(error declare-release-config: config $(strip $(1)) declared in: $(_included) Previously declared here: $(_all_release_configs.$(strip $(1)).DECLARED_IN)) \
+ )
+ $(eval # Must have release config files)
+ $(if $(strip $(2)),, \
+ $(error declare-release-config: config $(strip $(1)) must have release config files) \
+ )
+ $(eval _all_release_configs := $(sort $(_all_release_configs) $(strip $(1))))
+ $(eval _all_release_configs.$(strip $(1)).DECLARED_IN := $(_included))
+ $(eval _all_release_configs.$(strip $(1)).FILES := $(strip $(2)))
+endef
+
+# Include the config map files
+$(foreach f, $(config_map_files), \
+ $(eval _included := $(f)) \
+ $(eval include $(f)) \
+)
+
+# If TARGET_RELEASE is set, fail if there is no matching release config
+# If it isn't set, no release config files will be included and all flags
+# will get their default values.
+ifneq ($(TARGET_RELEASE),)
+ifeq ($(filter $(_all_release_configs), $(TARGET_RELEASE)),)
+ $(error No release config found for TARGET_RELEASE: $(TARGET_RELEASE))
+else
+ # Choose flag files
+ # Don't sort this, use it in the order they gave us.
+ _release_config_files := $(_all_release_configs.$(TARGET_RELEASE).FILES)
+endif
+else
+# Useful for finding scripts etc that aren't passing or setting TARGET_RELEASE
+ifneq ($(FAIL_IF_NO_RELEASE_CONFIG),)
+ $(error FAIL_IF_NO_RELEASE_CONFIG was set and TARGET_RELEASE was not)
+endif
+_release_config_files :=
+endif
+
+# Unset variables so they can't use it
+define declare-release-config
+$(error declare-release-config can only be called from inside release_config_map.mk files)
+endef
+
+# TODO: Remove this check after enough people have sourced lunch that we don't
+# need to worry about it trying to do get_build_vars TARGET_RELEASE. Maybe after ~9/2023
+ifneq ($(CALLED_FROM_SETUP),true)
+define TARGET_RELEASE
+$(error TARGET_RELEASE may not be accessed directly. Use individual flags.)
+endef
+else
+TARGET_RELEASE:=
+endif
+.KATI_READONLY := TARGET_RELEASE
+
+$(foreach config, $(_all_release_configs), \
+ $(eval _all_release_configs.$(config).DECLARED_IN:= ) \
+ $(eval _all_release_configs.$(config).FILES:= ) \
+)
+_all_release_configs:=
+config_map_files:=
+
+# -----------------------------------------------------------------
+# Declare the flags
+
+# $1 partition(s)
+# $2 flag name. Must start with RELEASE_
+# $3 default. True or false
+define declare-build-flag
+ $(if $(filter-out all $(_FLAG_PARTITIONS), $(strip $(1))), \
+ $(error declare-build-flag: invalid partitions: $(strip $(1))) \
+ )
+ $(if $(and $(filter all,$(strip $(1))),$(filter-out all, $(strip $(1)))), \
+ $(error declare-build-flag: "all" can't be combined with other partitions: $(strip $(1))), \
+ $(eval declare-build-flag.partition := $(_FLAG_PARTITIONS)) \
+ )
+ $(if $(filter-out RELEASE_%, $(strip $(2))), \
+ $(error declare-build-flag: Release flag names must start with RELEASE_: $(strip $(2))) \
+ )
+ $(eval _ALL_RELEASE_FLAGS += $(strip $(2)))
+ $(foreach partition, $(declare-build-flag.partition), \
+ $(eval _ALL_RELEASE_FLAGS.PARTITIONS.$(partition) := $(sort \
+ $(_ALL_RELEASE_FLAGS.PARTITIONS.$(partition)) $(strip $(2)))) \
+ )
+ $(eval _ALL_RELEASE_FLAGS.$(strip $(2)).PARTITIONS := $(declare-build-flag.partition))
+ $(eval _ALL_RELEASE_FLAGS.$(strip $(2)).DEFAULT := $(strip $(3)))
+ $(eval _ALL_RELEASE_FLAGS.$(strip $(2)).DECLARED_IN := $(_included))
+ $(eval _ALL_RELEASE_FLAGS.$(strip $(2)).VALUE := $(strip $(3)))
+ $(eval _ALL_RELEASE_FLAGS.$(strip $(2)).SET_IN := $(_included))
+ $(eval declare-build-flag.partition:=)
+endef
+
+
+# Choose the files
+# If this is a google source tree, restrict it to only the one file
+# which has OWNERS control. If it isn't let others define their own.
+flag_declaration_files := build/make/release/flags.mk \
+ $(if $(wildcard vendor/google/release/flags.mk), \
+ vendor/google/release/flags.mk, \
+ $(sort \
+ $(wildcard device/*/release/flags.mk) \
+ $(wildcard device/*/*/release/flags.mk) \
+ $(wildcard vendor/*/release/flags.mk) \
+ $(wildcard vendor/*/*/release/flags.mk) \
+ ) \
+ )
+
+# Include the files
+$(foreach f, $(flag_declaration_files), \
+ $(eval _included := $(f)) \
+ $(eval include $(f)) \
+)
+
+# Don't let anyone declare build flags after here
+define declare-build-flag
+$(error declare-build-flag can only be called from inside flag definition files.)
+endef
+
+# No more flags from here on
+.KATI_READONLY := _ALL_RELEASE_FLAGS
+
+# -----------------------------------------------------------------
+# Set the flags
+
+# $(1): Flag name. Must start with RELEASE_ and have been defined by declare-build-flag
+# $(2): Value. True or false
+define set-build-flag
+ $(if $(filter-out $(_ALL_RELEASE_FLAGS), $(strip $(1))), \
+ $(error set-build-flag: Undeclared build flag: $(strip $(1))) \
+ )
+ $(eval _ALL_RELEASE_FLAGS.$(strip $(1)).VALUE := $(strip $(2)))
+ $(eval _ALL_RELEASE_FLAGS.$(strip $(1)).SET_IN := $(_included))
+endef
+
+# Include the files (if there are any)
+$(foreach f, $(_release_config_files), \
+ $(eval _included := $(f)) \
+ $(eval include $(f)) \
+)
+
+# Don't let anyone declare build flags after here
+define set-build-flag
+$(error set-build-flag can only be called from inside release config files.)
+endef
+
+# Set the flag values, and don't allow any one to modify them.
+$(foreach flag, $(_ALL_RELEASE_FLAGS), \
+ $(eval $(flag) := $(_ALL_RELEASE_FLAGS.$(flag).VALUE)) \
+ $(eval .KATI_READONLY := $(flag)) \
+)
+
+# -----------------------------------------------------------------
+# Clear out vars
+flag_declaration_files:=
+flag_files:=
+_included:=
+_release_config_files:=
diff --git a/core/tasks/tools/compatibility.mk b/core/tasks/tools/compatibility.mk
index c770b34..8ae2a9a 100644
--- a/core/tasks/tools/compatibility.mk
+++ b/core/tasks/tools/compatibility.mk
@@ -44,10 +44,16 @@
# The JDK to package into the test suite zip file. Always package the linux JDK.
test_suite_jdk_dir := $(ANDROID_JAVA_HOME)/../linux-x86
+ifndef test_suite_jdk_files
+ # This file gets included many times, so make sure we only run the $(shell) once.
+ # Otherwise it will slow down every build due to all copies of it being rerun when kati
+ # checks the stamp file.
+ test_suite_jdk_files :=$= $(shell find $(test_suite_jdk_dir) -type f | sort)
+endif
test_suite_jdk := $(call intermediates-dir-for,PACKAGING,$(test_suite_name)_jdk,HOST)/jdk.zip
$(test_suite_jdk): PRIVATE_JDK_DIR := $(test_suite_jdk_dir)
$(test_suite_jdk): PRIVATE_SUBDIR := $(test_suite_subdir)
-$(test_suite_jdk): $(shell find $(test_suite_jdk_dir) -type f | sort)
+$(test_suite_jdk): $(test_suite_jdk_files)
$(test_suite_jdk): $(SOONG_ZIP)
$(SOONG_ZIP) -o $@ -P $(PRIVATE_SUBDIR)/jdk -C $(PRIVATE_JDK_DIR) -D $(PRIVATE_JDK_DIR) -sha256
diff --git a/envsetup.sh b/envsetup.sh
index 916344c..ef48249 100644
--- a/envsetup.sh
+++ b/envsetup.sh
@@ -842,7 +842,7 @@
export TARGET_PRODUCT=$(get_build_var TARGET_PRODUCT)
export TARGET_BUILD_VARIANT=$(get_build_var TARGET_BUILD_VARIANT)
if [ -n "$release" ]; then
- export TARGET_RELEASE=$(get_build_var TARGET_RELEASE)
+ export TARGET_RELEASE=$release
else
unset TARGET_RELEASE
fi
diff --git a/release/flags.mk b/release/flags.mk
new file mode 100644
index 0000000..eb97dc1
--- /dev/null
+++ b/release/flags.mk
@@ -0,0 +1,23 @@
+# Copyright (C) 2023 The Android Open Source Project
+#
+# 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.
+
+# This file defines the build system flags that can be set based on the
+# release configuration. If at all possible, use aconfig flags instead.
+# This is for things that must be decided at compile time.
+
+# Flag names should be alphabetical by flag name.
+
+$(call declare-build-flag, system, RELEASE_THE_FIRST_FLAG, true)
+$(call declare-build-flag, system, RELEASE_THE_SECOND_FLAG, true)
+
diff --git a/release/release_config_map.mk b/release/release_config_map.mk
new file mode 100644
index 0000000..190cb89
--- /dev/null
+++ b/release/release_config_map.mk
@@ -0,0 +1,16 @@
+# Copyright (C) 2023 The Android Open Source Project
+#
+# 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.
+
+# AOSP doesn't define any release configs yet.
+
diff --git a/tools/rbcrun/Android.bp b/tools/rbcrun/Android.bp
index fcc33ef..4fab858 100644
--- a/tools/rbcrun/Android.bp
+++ b/tools/rbcrun/Android.bp
@@ -34,6 +34,7 @@
pkgPath: "rbcrun",
deps: [
"go-starlark-starlark",
+ "go-starlark-starlarkjson",
"go-starlark-starlarkstruct",
"go-starlark-starlarktest",
],
diff --git a/tools/rbcrun/host.go b/tools/rbcrun/host.go
index f2fda4e..a0fb9e1 100644
--- a/tools/rbcrun/host.go
+++ b/tools/rbcrun/host.go
@@ -24,13 +24,19 @@
"strings"
"go.starlark.net/starlark"
+ "go.starlark.net/starlarkjson"
"go.starlark.net/starlarkstruct"
)
-const callerDirKey = "callerDir"
+type ExecutionMode int
+const (
+ ExecutionModeRbc ExecutionMode = iota
+ ExecutionModeMake ExecutionMode = iota
+)
-var LoadPathRoot = "."
-var shellPath string
+const callerDirKey = "callerDir"
+const shellKey = "shell"
+const executionModeKey = "executionMode"
type modentry struct {
globals starlark.StringDict
@@ -39,20 +45,66 @@
var moduleCache = make(map[string]*modentry)
-var builtins starlark.StringDict
+var rbcBuiltins starlark.StringDict = starlark.StringDict{
+ "struct": starlark.NewBuiltin("struct", starlarkstruct.Make),
+ // To convert find-copy-subdir and product-copy-files-by pattern
+ "rblf_find_files": starlark.NewBuiltin("rblf_find_files", find),
+ // To convert makefile's $(shell cmd)
+ "rblf_shell": starlark.NewBuiltin("rblf_shell", shell),
+ // Output to stderr
+ "rblf_log": starlark.NewBuiltin("rblf_log", log),
+ // To convert makefile's $(wildcard foo*)
+ "rblf_wildcard": starlark.NewBuiltin("rblf_wildcard", wildcard),
+}
-func moduleName2AbsPath(moduleName string, callerDir string) (string, error) {
- path := moduleName
- if ix := strings.LastIndex(path, ":"); ix >= 0 {
- path = path[0:ix] + string(os.PathSeparator) + path[ix+1:]
+var makeBuiltins starlark.StringDict = starlark.StringDict{
+ "struct": starlark.NewBuiltin("struct", starlarkstruct.Make),
+ "json": starlarkjson.Module,
+}
+
+// Takes a module name (the first argument to the load() function) and returns the path
+// it's trying to load, stripping out leading //, and handling leading :s.
+func cleanModuleName(moduleName string, callerDir string) (string, error) {
+ if strings.Count(moduleName, ":") > 1 {
+ return "", fmt.Errorf("at most 1 colon must be present in starlark path: %s", moduleName)
}
- if strings.HasPrefix(path, "//") {
- return filepath.Abs(filepath.Join(LoadPathRoot, path[2:]))
+
+ // We don't have full support for external repositories, but at least support skylib's dicts.
+ if moduleName == "@bazel_skylib//lib:dicts.bzl" {
+ return "external/bazel-skylib/lib/dicts.bzl", nil
+ }
+
+ localLoad := false
+ if strings.HasPrefix(moduleName, "@//") {
+ moduleName = moduleName[3:]
+ } else if strings.HasPrefix(moduleName, "//") {
+ moduleName = moduleName[2:]
} else if strings.HasPrefix(moduleName, ":") {
- return filepath.Abs(filepath.Join(callerDir, path[1:]))
+ moduleName = moduleName[1:]
+ localLoad = true
} else {
- return filepath.Abs(path)
+ return "", fmt.Errorf("load path must start with // or :")
}
+
+ if ix := strings.LastIndex(moduleName, ":"); ix >= 0 {
+ moduleName = moduleName[:ix] + string(os.PathSeparator) + moduleName[ix+1:]
+ }
+
+ if filepath.Clean(moduleName) != moduleName {
+ return "", fmt.Errorf("load path must be clean, found: %s, expected: %s", moduleName, filepath.Clean(moduleName))
+ }
+ if strings.HasPrefix(moduleName, "../") {
+ return "", fmt.Errorf("load path must not start with ../: %s", moduleName)
+ }
+ if strings.HasPrefix(moduleName, "/") {
+ return "", fmt.Errorf("load path starts with /, use // for a absolute path: %s", moduleName)
+ }
+
+ if localLoad {
+ return filepath.Join(callerDir, moduleName), nil
+ }
+
+ return moduleName, nil
}
// loader implements load statement. The format of the loaded module URI is
@@ -61,14 +113,18 @@
// The presence of `|symbol` indicates that the loader should return a single 'symbol'
// bound to None if file is missing.
func loader(thread *starlark.Thread, module string) (starlark.StringDict, error) {
- pipePos := strings.LastIndex(module, "|")
- mustLoad := pipePos < 0
+ mode := thread.Local(executionModeKey).(ExecutionMode)
var defaultSymbol string
- if !mustLoad {
- defaultSymbol = module[pipePos+1:]
- module = module[:pipePos]
+ mustLoad := true
+ if mode == ExecutionModeRbc {
+ pipePos := strings.LastIndex(module, "|")
+ mustLoad = pipePos < 0
+ if !mustLoad {
+ defaultSymbol = module[pipePos+1:]
+ module = module[:pipePos]
+ }
}
- modulePath, err := moduleName2AbsPath(module, thread.Local(callerDirKey).(string))
+ modulePath, err := cleanModuleName(module, thread.Local(callerDirKey).(string))
if err != nil {
return nil, err
}
@@ -100,8 +156,17 @@
}
childThread.SetLocal(callerDirKey, filepath.Dir(modulePath))
- globals, err := starlark.ExecFile(childThread, modulePath, nil, builtins)
- e = &modentry{globals, err}
+ childThread.SetLocal(shellKey, thread.Local(shellKey))
+ childThread.SetLocal(executionModeKey, mode)
+ if mode == ExecutionModeRbc {
+ globals, err := starlark.ExecFile(childThread, modulePath, nil, rbcBuiltins)
+ e = &modentry{globals, err}
+ } else if mode == ExecutionModeMake {
+ globals, err := starlark.ExecFile(childThread, modulePath, nil, makeBuiltins)
+ e = &modentry{globals, err}
+ } else {
+ return nil, fmt.Errorf("unknown executionMode %d", mode)
+ }
} else {
e = &modentry{starlark.StringDict{defaultSymbol: starlark.None}, nil}
}
@@ -189,12 +254,13 @@
// its output the same way as Make's $(shell ) function. The end-of-lines
// ("\n" or "\r\n") are replaced with " " in the result, and the trailing
// end-of-line is removed.
-func shell(_ *starlark.Thread, b *starlark.Builtin, args starlark.Tuple,
+func shell(thread *starlark.Thread, b *starlark.Builtin, args starlark.Tuple,
kwargs []starlark.Tuple) (starlark.Value, error) {
var command string
if err := starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 1, &command); err != nil {
return starlark.None, err
}
+ shellPath := thread.Local(shellKey).(string)
if shellPath == "" {
return starlark.None,
fmt.Errorf("cannot run shell, /bin/sh is missing (running on Windows?)")
@@ -245,45 +311,68 @@
return starlark.None, nil
}
-func setup() {
- // Create the symbols that aid makefile conversion. See README.md
- builtins = starlark.StringDict{
- "struct": starlark.NewBuiltin("struct", starlarkstruct.Make),
- // To convert find-copy-subdir and product-copy-files-by pattern
- "rblf_find_files": starlark.NewBuiltin("rblf_find_files", find),
- // To convert makefile's $(shell cmd)
- "rblf_shell": starlark.NewBuiltin("rblf_shell", shell),
- // Output to stderr
- "rblf_log": starlark.NewBuiltin("rblf_log", log),
- // To convert makefile's $(wildcard foo*)
- "rblf_wildcard": starlark.NewBuiltin("rblf_wildcard", wildcard),
- }
-
- // NOTE(asmundak): OS-specific. Behave similar to Linux `system` call,
- // which always uses /bin/sh to run the command
- shellPath = "/bin/sh"
- if _, err := os.Stat(shellPath); err != nil {
- shellPath = ""
- }
-}
-
// Parses, resolves, and executes a Starlark file.
// filename and src parameters are as for starlark.ExecFile:
// * filename is the name of the file to execute,
// and the name that appears in error messages;
// * src is an optional source of bytes to use instead of filename
// (it can be a string, or a byte array, or an io.Reader instance)
-func Run(filename string, src interface{}) error {
- setup()
+// Returns the top-level starlark variables, the list of starlark files loaded, and an error
+func Run(filename string, src interface{}, mode ExecutionMode) (starlark.StringDict, []string, error) {
+ // NOTE(asmundak): OS-specific. Behave similar to Linux `system` call,
+ // which always uses /bin/sh to run the command
+ shellPath := "/bin/sh"
+ if _, err := os.Stat(shellPath); err != nil {
+ shellPath = ""
+ }
+
mainThread := &starlark.Thread{
Name: "main",
- Print: func(_ *starlark.Thread, msg string) { fmt.Println(msg) },
+ Print: func(_ *starlark.Thread, msg string) {
+ if mode == ExecutionModeRbc {
+ // In rbc mode, rblf_log is used to print to stderr
+ fmt.Println(msg)
+ } else if mode == ExecutionModeMake {
+ fmt.Fprintln(os.Stderr, msg)
+ }
+ },
Load: loader,
}
- absPath, err := filepath.Abs(filename)
- if err == nil {
- mainThread.SetLocal(callerDirKey, filepath.Dir(absPath))
- _, err = starlark.ExecFile(mainThread, absPath, src, builtins)
+ filename, err := filepath.Abs(filename)
+ if err != nil {
+ return nil, nil, err
}
- return err
+ if wd, err := os.Getwd(); err == nil {
+ filename, err = filepath.Rel(wd, filename)
+ if err != nil {
+ return nil, nil, err
+ }
+ if strings.HasPrefix(filename, "../") {
+ return nil, nil, fmt.Errorf("path could not be made relative to workspace root: %s", filename)
+ }
+ } else {
+ return nil, nil, err
+ }
+
+ // Add top-level file to cache for cycle detection purposes
+ moduleCache[filename] = nil
+
+ var results starlark.StringDict
+ mainThread.SetLocal(callerDirKey, filepath.Dir(filename))
+ mainThread.SetLocal(shellKey, shellPath)
+ mainThread.SetLocal(executionModeKey, mode)
+ if mode == ExecutionModeRbc {
+ results, err = starlark.ExecFile(mainThread, filename, src, rbcBuiltins)
+ } else if mode == ExecutionModeMake {
+ results, err = starlark.ExecFile(mainThread, filename, src, makeBuiltins)
+ } else {
+ return results, nil, fmt.Errorf("unknown executionMode %d", mode)
+ }
+ loadedStarlarkFiles := make([]string, 0, len(moduleCache))
+ for file := range moduleCache {
+ loadedStarlarkFiles = append(loadedStarlarkFiles, file)
+ }
+ sort.Strings(loadedStarlarkFiles)
+
+ return results, loadedStarlarkFiles, err
}
diff --git a/tools/rbcrun/host_test.go b/tools/rbcrun/host_test.go
index e109c02..10cac62 100644
--- a/tools/rbcrun/host_test.go
+++ b/tools/rbcrun/host_test.go
@@ -54,7 +54,6 @@
// Common setup for the tests: create thread, change to the test directory
func testSetup(t *testing.T) *starlark.Thread {
- setup()
thread := &starlark.Thread{
Load: func(thread *starlark.Thread, module string) (starlark.StringDict, error) {
if module == "assert.star" {
@@ -78,7 +77,6 @@
// In order to use "assert.star" from go/starlark.net/starlarktest in the tests, provide:
// * load function that handles "assert.star"
// * starlarktest.DataFile function that finds its location
- setup()
if err := os.Chdir(dataDir()); err != nil {
t.Fatal(err)
}
@@ -92,7 +90,9 @@
starlarktest.SetReporter(thread, t)
_, thisSrcFile, _, _ := runtime.Caller(0)
filename := filepath.Join(filepath.Dir(thisSrcFile), starFile)
- if _, err := starlark.ExecFile(thread, filename, nil, builtins); err != nil {
+ thread.SetLocal(executionModeKey, ExecutionModeRbc)
+ thread.SetLocal(shellKey, "/bin/sh")
+ if _, err := starlark.ExecFile(thread, filename, nil, rbcBuiltins); err != nil {
if err, ok := err.(*starlark.EvalError); ok {
t.Fatal(err.Backtrace())
}
@@ -103,7 +103,7 @@
func TestFileOps(t *testing.T) {
// TODO(asmundak): convert this to use exerciseStarlarkTestFile
thread := testSetup(t)
- if _, err := starlark.ExecFile(thread, "file_ops.star", nil, builtins); err != nil {
+ if _, err := starlark.ExecFile(thread, "file_ops.star", nil, rbcBuiltins); err != nil {
if err, ok := err.(*starlark.EvalError); ok {
t.Fatal(err.Backtrace())
}
@@ -122,9 +122,12 @@
}
}
dir := dataDir()
+ if err := os.Chdir(filepath.Dir(dir)); err != nil {
+ t.Fatal(err)
+ }
thread.SetLocal(callerDirKey, dir)
- LoadPathRoot = filepath.Dir(dir)
- if _, err := starlark.ExecFile(thread, "load.star", nil, builtins); err != nil {
+ thread.SetLocal(executionModeKey, ExecutionModeRbc)
+ if _, err := starlark.ExecFile(thread, "testdata/load.star", nil, rbcBuiltins); err != nil {
if err, ok := err.(*starlark.EvalError); ok {
t.Fatal(err.Backtrace())
}
diff --git a/tools/rbcrun/rbcrun/rbcrun.go b/tools/rbcrun/rbcrun/rbcrun.go
index 8dd0f46..b5182f0 100644
--- a/tools/rbcrun/rbcrun/rbcrun.go
+++ b/tools/rbcrun/rbcrun/rbcrun.go
@@ -17,18 +17,22 @@
import (
"flag"
"fmt"
- "go.starlark.net/starlark"
"os"
"rbcrun"
+ "regexp"
+ "strings"
+
+ "go.starlark.net/starlark"
)
var (
+ modeFlag = flag.String("mode", "", "the general behavior of rbcrun. Can be \"rbc\" or \"make\". Required.")
rootdir = flag.String("d", ".", "the value of // for load paths")
perfFile = flag.String("perf", "", "save performance data")
+ identifierRe = regexp.MustCompile("[a-zA-Z_][a-zA-Z0-9_]*")
)
-func main() {
- flag.Parse()
+func getEntrypointStarlarkFile() string {
filename := ""
for _, arg := range flag.Args() {
@@ -42,8 +46,108 @@
flag.Usage()
os.Exit(1)
}
- if stat, err := os.Stat(*rootdir); os.IsNotExist(err) || !stat.IsDir() {
- quit("%s is not a directory\n", *rootdir)
+ return filename
+}
+
+func getMode() rbcrun.ExecutionMode {
+ switch *modeFlag {
+ case "rbc":
+ return rbcrun.ExecutionModeRbc
+ case "make":
+ return rbcrun.ExecutionModeMake
+ case "":
+ quit("-mode flag is required.")
+ default:
+ quit("Unknown -mode value %q, expected 1 of \"rbc\", \"make\"", *modeFlag)
+ }
+ return rbcrun.ExecutionModeMake
+}
+
+var makeStringReplacer = strings.NewReplacer("#", "\\#", "$", "$$")
+
+func cleanStringForMake(s string) (string, error) {
+ if strings.ContainsAny(s, "\\\n") {
+ // \\ in make is literally \\, not a single \, so we can't allow them.
+ // \<newline> in make will produce a space, not a newline.
+ return "", fmt.Errorf("starlark strings exported to make cannot contain backslashes or newlines")
+ }
+ return makeStringReplacer.Replace(s), nil
+}
+
+func getValueInMakeFormat(value starlark.Value, allowLists bool) (string, error) {
+ switch v := value.(type) {
+ case starlark.String:
+ if cleanedValue, err := cleanStringForMake(v.GoString()); err == nil {
+ return cleanedValue, nil
+ } else {
+ return "", err
+ }
+ case starlark.Int:
+ return v.String(), nil
+ case *starlark.List:
+ if !allowLists {
+ return "", fmt.Errorf("nested lists are not allowed to be exported from starlark to make, flatten the list in starlark first")
+ }
+ result := ""
+ for i := 0; i < v.Len(); i++ {
+ value, err := getValueInMakeFormat(v.Index(i), false)
+ if err != nil {
+ return "", err
+ }
+ if i > 0 {
+ result += " "
+ }
+ result += value
+ }
+ return result, nil
+ default:
+ return "", fmt.Errorf("only starlark strings, ints, and lists of strings/ints can be exported to make. Please convert all other types in starlark first. Found type: %s", value.Type())
+ }
+}
+
+func printVarsInMakeFormat(globals starlark.StringDict) error {
+ // We could just directly export top level variables by name instead of going through
+ // a variables_to_export_to_make dictionary, but that wouldn't allow for exporting a
+ // runtime-defined number of variables to make. This can be important because dictionaries
+ // in make are often represented by a unique variable for every key in the dictionary.
+ variablesValue, ok := globals["variables_to_export_to_make"]
+ if !ok {
+ return fmt.Errorf("expected top-level starlark file to have a \"variables_to_export_to_make\" variable")
+ }
+ variables, ok := variablesValue.(*starlark.Dict)
+ if !ok {
+ return fmt.Errorf("expected variables_to_export_to_make to be a dict, got %s", variablesValue.Type())
+ }
+
+ for _, varTuple := range variables.Items() {
+ varNameStarlark, ok := varTuple.Index(0).(starlark.String)
+ if !ok {
+ return fmt.Errorf("all keys in variables_to_export_to_make must be strings, but got %q", varTuple.Index(0).Type())
+ }
+ varName := varNameStarlark.GoString()
+ if !identifierRe.MatchString(varName) {
+ return fmt.Errorf("all variables at the top level starlark file must be valid c identifiers, but got %q", varName)
+ }
+ if varName == "LOADED_STARLARK_FILES" {
+ return fmt.Errorf("the name LOADED_STARLARK_FILES is reserved for use by the starlark interpreter")
+ }
+ valueMake, err := getValueInMakeFormat(varTuple.Index(1), true)
+ if err != nil {
+ return err
+ }
+ // The :=$= is special Kati syntax that means "set and make readonly"
+ fmt.Printf("%s :=$= %s\n", varName, valueMake)
+ }
+ return nil
+}
+
+func main() {
+ flag.Parse()
+ filename := getEntrypointStarlarkFile()
+ mode := getMode()
+
+ if os.Chdir(*rootdir) != nil {
+ quit("could not chdir to %s\n", *rootdir)
}
if *perfFile != "" {
pprof, err := os.Create(*perfFile)
@@ -55,8 +159,7 @@
quit("%s\n", err)
}
}
- rbcrun.LoadPathRoot = *rootdir
- err := rbcrun.Run(filename, nil)
+ variables, loadedStarlarkFiles, err := rbcrun.Run(filename, nil, mode)
rc := 0
if *perfFile != "" {
if err2 := starlark.StopProfile(); err2 != nil {
@@ -71,6 +174,12 @@
quit("%s\n", err)
}
}
+ if mode == rbcrun.ExecutionModeMake {
+ if err := printVarsInMakeFormat(variables); err != nil {
+ quit("%s\n", err)
+ }
+ fmt.Printf("LOADED_STARLARK_FILES := %s\n", strings.Join(loadedStarlarkFiles, " "))
+ }
os.Exit(rc)
}
diff --git a/tools/rbcrun/testdata/module1.star b/tools/rbcrun/testdata/module1.star
index be04f75..02919a0 100644
--- a/tools/rbcrun/testdata/module1.star
+++ b/tools/rbcrun/testdata/module1.star
@@ -2,6 +2,6 @@
load("assert.star", "assert")
# Make sure that builtins are defined for the loaded module, too
-assert.true(rblf_wildcard("module1.star"))
-assert.true(not rblf_wildcard("no_such file"))
+assert.true(rblf_wildcard("testdata/module1.star"))
+assert.true(not rblf_wildcard("testdata/no_such file"))
test = "module1"
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index ac3271b..8d660f8 100644
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -65,7 +65,7 @@
import ota_metadata_pb2
import rangelib
import sparse_img
-
+from concurrent.futures import ThreadPoolExecutor
from apex_utils import GetApexInfoFromTargetFiles
from common import ZipDelete, PARTITIONS_WITH_CARE_MAP, ExternalError, RunAndCheckOutput, IsSparseImage, MakeTempFile, ZipWrite
@@ -1083,8 +1083,15 @@
("system_dlkm", has_system_dlkm, AddSystemDlkm, []),
("system_other", has_system_other, AddSystemOther, []),
)
- for call in add_partition_calls:
- add_partition(*call)
+ # If output_zip exists, each add_partition_calls writes bytes to the same output_zip,
+ # which is not thread-safe. So, run them in serial if output_zip exists.
+ if output_zip:
+ for call in add_partition_calls:
+ add_partition(*call)
+ else:
+ with ThreadPoolExecutor(max_workers=len(add_partition_calls)) as executor:
+ for future in [executor.submit(add_partition, *call) for call in add_partition_calls]:
+ future.result()
AddApexInfo(output_zip)
diff --git a/tools/releasetools/img_from_target_files.py b/tools/releasetools/img_from_target_files.py
index f8bdd81..7c27ef7 100755
--- a/tools/releasetools/img_from_target_files.py
+++ b/tools/releasetools/img_from_target_files.py
@@ -118,6 +118,7 @@
entries = [
'OTA/android-info.txt:android-info.txt',
+ 'META/fastboot-info.txt:fastboot-info.txt',
]
with zipfile.ZipFile(input_file) as input_zip:
namelist = input_zip.namelist()