arc: Add native_bridge_64bit_support_experiment
Add an experiment flag to enable 64-bit native bridge for ARC on
systems that have 64-bit native bridge support available but not
enabled.
Note that due to the nature of the timing of starting ARC mini-
container - which can be affected by the properties controlled by
this experiment - and user login, the experiment is treated as a one
way off->on transition for all users on a given device.
The experiment flag will have no effect on systems that do not have
64-bit native support available, nor will it affect systems that
have 64-bit native support enabled generally.
Bug: b:62095998
Change-Id: If2a5dc96ba36f8aba31405122a6de20764af30b9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2252956
Commit-Queue: Josh Horwich <[email protected]>
Reviewed-by: Yusuke Sato <[email protected]>
Cr-Commit-Position: refs/heads/master@{#786022}
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 2b0459bf..cc6920f 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3226,6 +3226,11 @@
{"arc-native-bridge-toggle", flag_descriptions::kArcNativeBridgeToggleName,
flag_descriptions::kArcNativeBridgeToggleDescription, kOsCrOS,
FEATURE_VALUE_TYPE(arc::kNativeBridgeToggleFeature)},
+ {"arc-native-bridge-64bit-support-experiment",
+ flag_descriptions::kArcNativeBridge64BitSupportExperimentName,
+ flag_descriptions::kArcNativeBridge64BitSupportExperimentDescription,
+ kOsCrOS,
+ FEATURE_VALUE_TYPE(arc::kNativeBridge64BitSupportExperimentFeature)},
{"arc-usb-host", flag_descriptions::kArcUsbHostName,
flag_descriptions::kArcUsbHostDescription, kOsCrOS,
FEATURE_VALUE_TYPE(arc::kUsbHostFeature)},
diff --git a/chrome/browser/chromeos/arc/session/arc_session_manager.cc b/chrome/browser/chromeos/arc/session/arc_session_manager.cc
index 908926b..906f2bb 100644
--- a/chrome/browser/chromeos/arc/session/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/session/arc_session_manager.cc
@@ -22,6 +22,7 @@
#include "base/task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
+#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/arc/arc_migration_guide_notification.h"
#include "chrome/browser/chromeos/arc/arc_optin_uma.h"
#include "chrome/browser/chromeos/arc/arc_support_host.h"
@@ -214,8 +215,10 @@
bool ExpandPropertyFilesInternal(const base::FilePath& source_path,
const base::FilePath& dest_path,
- bool single_file) {
- if (!arc::ExpandPropertyFiles(source_path, dest_path, single_file))
+ bool single_file,
+ bool add_native_bridge_64bit_support) {
+ if (!arc::ExpandPropertyFiles(source_path, dest_path, single_file,
+ add_native_bridge_64bit_support))
return false;
if (!arc::IsArcVmEnabled())
return true;
@@ -1333,12 +1336,29 @@
// For ARCVM, generate <dest_path>/{combined.prop,fstab}. For ARC, generate
// <dest_path>/{default,build,vendor_build}.prop.
const bool is_arcvm = arc::IsArcVmEnabled();
+ bool add_native_bridge_64bit_support = false;
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ chromeos::switches::kArcEnableNativeBridge64BitSupportExperiment)) {
+ PrefService* local_pref_service = g_browser_process->local_state();
+ if (base::FeatureList::IsEnabled(
+ arc::kNativeBridge64BitSupportExperimentFeature)) {
+ // Note that we treat this experiment as a one-way off->on switch, across
+ // all users of the device, as the lifetime of ARC mini-container and user
+ // sessions are different in different scenarios, and removing the
+ // experiment after it has been in effect for a user's ARC instance can
+ // lead to unexpected, and unsupported, results.
+ local_pref_service->SetBoolean(
+ prefs::kNativeBridge64BitSupportExperimentEnabled, true);
+ }
+ add_native_bridge_64bit_support = local_pref_service->GetBoolean(
+ prefs::kNativeBridge64BitSupportExperimentEnabled);
+ }
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::BindOnce(&ExpandPropertyFilesInternal, property_files_source_dir_,
is_arcvm ? property_files_dest_dir_.Append("combined.prop")
: property_files_dest_dir_,
- /*single_file=*/is_arcvm),
+ /*single_file=*/is_arcvm, add_native_bridge_64bit_support),
base::BindOnce(&ArcSessionManager::OnExpandPropertyFiles,
weak_ptr_factory_.GetWeakPtr()));
}
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 1cce9b4..ae371b7 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -184,6 +184,13 @@
"expiry_milestone": 76
},
{
+ "name": "arc-native-bridge-64bit-support-experiment",
+ "owners": [ "jhorwich" ],
+ // Used on ChromeOS to experimentally enable 64-bit ARC native-bridge
+ // support before promoting it to enabled on a specific device class.
+ "expiry_milestone": 93
+ },
+ {
"name": "arc-native-bridge-toggle",
"owners": [ "[email protected]" ],
// Used on ChromeOS to compare and debug different ARC native-bridge
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 262554a55..4eec203 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3325,6 +3325,11 @@
const char kArcNativeBridgeToggleDescription[] =
"Toggle between native bridge implementations for ARC.";
+const char kArcNativeBridge64BitSupportExperimentName[] =
+ "Enable experimental 64-bit native bridge support for ARC";
+const char kArcNativeBridge64BitSupportExperimentDescription[] =
+ "Enable experimental 64-bit native bridge support for ARC where available.";
+
const char kArcUsbHostName[] = "Enable ARC USB host integration";
const char kArcUsbHostDescription[] =
"Allow Android apps to use USB host feature on ChromeOS devices.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index bfe4dff..6616f270 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1921,6 +1921,9 @@
extern const char kArcNativeBridgeToggleName[];
extern const char kArcNativeBridgeToggleDescription[];
+extern const char kArcNativeBridge64BitSupportExperimentName[];
+extern const char kArcNativeBridge64BitSupportExperimentDescription[];
+
extern const char kArcUsbHostName[];
extern const char kArcUsbHostDescription[];
diff --git a/chromeos/constants/chromeos_switches.cc b/chromeos/constants/chromeos_switches.cc
index 62ecd83..25a486b23 100644
--- a/chromeos/constants/chromeos_switches.cc
+++ b/chromeos/constants/chromeos_switches.cc
@@ -83,6 +83,12 @@
// in autotests to resolve racy conditions.
const char kArcDisableAppSync[] = "arc-disable-app-sync";
+// Flag to enables an experiment to allow users to turn on 64-bit support in
+// native bridge on systems that have such support available but not yet enabled
+// by default.
+const char kArcEnableNativeBridge64BitSupportExperiment[] =
+ "arc-enable-native-bridge-64bit-support-experiment";
+
// Used in autotest to disable GMS-core caches which is on by default.
const char kArcDisableGmsCoreCache[] = "arc-disable-gms-core-cache";
diff --git a/chromeos/constants/chromeos_switches.h b/chromeos/constants/chromeos_switches.h
index 3b1b27fc..4da209e2 100644
--- a/chromeos/constants/chromeos_switches.h
+++ b/chromeos/constants/chromeos_switches.h
@@ -45,6 +45,8 @@
extern const char kArcDisableSystemDefaultApps[];
COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
extern const char kArcDisablePlayAutoInstall[];
+COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
+extern const char kArcEnableNativeBridge64BitSupportExperiment[];
COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kArcForceCacheAppIcons[];
COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kArcForceShowOptInUi[];
COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kArcPackagesCacheMode[];
diff --git a/components/arc/arc_features.cc b/components/arc/arc_features.cc
index d1bbe371..ad16607f 100644
--- a/components/arc/arc_features.cc
+++ b/components/arc/arc_features.cc
@@ -57,6 +57,11 @@
const base::Feature kFilePickerExperimentFeature{
"ArcFilePickerExperiment", base::FEATURE_ENABLED_BY_DEFAULT};
+// Controls experimental 64-bit native bridge support for ARC on boards that
+// have 64-bit native bridge support available but not yet enabled.
+const base::Feature kNativeBridge64BitSupportExperimentFeature{
+ "ArcNativeBridge64BitSupportExperiment", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Toggles between native bridge implementations for ARC.
// Note, that we keep the original feature name to preserve
// corresponding metrics.
diff --git a/components/arc/arc_features.h b/components/arc/arc_features.h
index b03563cb..4416785 100644
--- a/components/arc/arc_features.h
+++ b/components/arc/arc_features.h
@@ -23,6 +23,7 @@
extern const base::Feature kEnableSecondaryAccountsForChildExperiment;
extern const base::Feature kEnableUnifiedAudioFocusFeature;
extern const base::Feature kFilePickerExperimentFeature;
+extern const base::Feature kNativeBridge64BitSupportExperimentFeature;
extern const base::Feature kNativeBridgeToggleFeature;
extern const base::Feature kPictureInPictureFeature;
extern const base::Feature kSmartTextSelectionFeature;
diff --git a/components/arc/arc_prefs.cc b/components/arc/arc_prefs.cc
index 8cba86c..dfa9701a6 100644
--- a/components/arc/arc_prefs.cc
+++ b/components/arc/arc_prefs.cc
@@ -115,6 +115,13 @@
// ======== LOCAL STATE PREFS ========
+// A boolean preference that indicates whether this device has run with the
+// native bridge 64 bit support experiment enabled. Persisting value in local
+// state, rather than in a user profile, is required as it needs to be read
+// whenever ARC mini-container is started.
+const char kNativeBridge64BitSupportExperimentEnabled[] =
+ "arc.native_bridge_64bit_support_experiment";
+
// A dictionary preference that keeps track of stability metric values, which is
// maintained by StabilityMetricsManager. Persisting values in local state is
// required to include these metrics in the initial stability log in case of a
@@ -122,6 +129,8 @@
const char kStabilityMetrics[] = "arc.metrics.stability";
void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
+ registry->RegisterBooleanPref(kNativeBridge64BitSupportExperimentEnabled,
+ false);
registry->RegisterDictionaryPref(kStabilityMetrics);
}
diff --git a/components/arc/arc_prefs.h b/components/arc/arc_prefs.h
index 010604a..0734094 100644
--- a/components/arc/arc_prefs.h
+++ b/components/arc/arc_prefs.h
@@ -45,6 +45,7 @@
ARC_EXPORT extern const char kEngagementPrefsPrefix[];
// Local state prefs in lexicographical order.
+ARC_EXPORT extern const char kNativeBridge64BitSupportExperimentEnabled[];
ARC_EXPORT extern const char kStabilityMetrics[];
void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
diff --git a/components/arc/session/arc_property_util.cc b/components/arc/session/arc_property_util.cc
index 0a4ca1a4..e4066f5 100644
--- a/components/arc/session/arc_property_util.cc
+++ b/components/arc/session/arc_property_util.cc
@@ -5,6 +5,7 @@
#include "components/arc/session/arc_property_util.h"
#include <algorithm>
+#include <tuple>
#include <vector>
#include "base/command_line.h"
@@ -38,6 +39,16 @@
// separated list of regions to include in the OEM key property.
constexpr char kPAIRegionsPropertyName[] = "pai-regions";
+// Properties related to dynamically adding native bridge 64 bit support.
+constexpr char kAbilistPropertyPrefix[] = "ro.product.cpu.abilist=";
+constexpr char kAbilistPropertyExpected[] = "x86_64,x86,armeabi-v7a,armeabi";
+constexpr char kAbilistPropertyReplacement[] =
+ "x86_64,x86,arm64-v8a,armeabi-v7a,armeabi";
+constexpr char kAbilist64PropertyPrefix[] = "ro.product.cpu.abilist64=";
+constexpr char kAbilist64PropertyExpected[] = "x86_64";
+constexpr char kAbilist64PropertyReplacement[] = "x86_64,arm64-v8a";
+constexpr char kDalvikVmIsaArm64[] = "ro.dalvik.vm.isa.arm64=x86_64";
+
// Maximum length of an Android property value.
constexpr int kAndroidMaxPropertyLength = 91;
@@ -146,7 +157,8 @@
bool ExpandPropertyContents(const std::string& content,
brillo::CrosConfigInterface* config,
- std::string* expanded_content) {
+ std::string* expanded_content,
+ bool add_native_bridge_64bit_support) {
const std::vector<std::string> lines = base::SplitString(
content, "\n", base::WhitespaceHandling::KEEP_WHITESPACE,
base::SplitResult::SPLIT_WANT_ALL);
@@ -192,12 +204,38 @@
expanded += line.substr(prev_match);
line = expanded;
} while (inserted);
+ if (add_native_bridge_64bit_support) {
+ // Special-case ro.product.cpu.abilist / ro.product.cpu.abilist64 to add
+ // ARM64.
+ std::string value;
+ if (FindProperty(kAbilistPropertyPrefix, &value, line)) {
+ if (value == kAbilistPropertyExpected) {
+ line = std::string(kAbilistPropertyPrefix) +
+ std::string(kAbilistPropertyReplacement);
+ } else {
+ LOG(ERROR) << "Found unexpected value for " << kAbilistPropertyPrefix
+ << ", value " << value;
+ return false;
+ }
+ }
+ if (FindProperty(kAbilist64PropertyPrefix, &value, line)) {
+ if (value == kAbilist64PropertyExpected) {
+ line = std::string(kAbilist64PropertyPrefix) +
+ std::string(kAbilist64PropertyReplacement);
+ } else {
+ LOG(ERROR) << "Found unexpected value for "
+ << kAbilist64PropertyPrefix << ", value " << value;
+ return false;
+ }
+ }
+ }
std::string truncated;
if (!TruncateAndroidProperty(line, &truncated)) {
LOG(ERROR) << "Unable to truncate property: " << line;
return false;
}
+
new_properties += truncated + "\n";
// Special-case ro.product.board to compute ro.oem.key1 at runtime, as it
@@ -210,6 +248,11 @@
}
}
+ if (add_native_bridge_64bit_support) {
+ // Special-case to add ro.dalvik.vm.isa.arm64.
+ new_properties += std::string(kDalvikVmIsaArm64) + "\n";
+ }
+
*expanded_content = new_properties;
return true;
}
@@ -217,14 +260,16 @@
bool ExpandPropertyFile(const base::FilePath& input,
const base::FilePath& output,
CrosConfig* config,
- bool append) {
+ bool append,
+ bool add_native_bridge_64bit_support) {
std::string content;
std::string expanded;
if (!base::ReadFileToString(input, &content)) {
PLOG(ERROR) << "Failed to read " << input;
return false;
}
- if (!ExpandPropertyContents(content, config, &expanded))
+ if (!ExpandPropertyContents(content, config, &expanded,
+ add_native_bridge_64bit_support))
return false;
if (append && base::PathExists(output)) {
if (!base::AppendToFile(output, expanded.data(), expanded.size())) {
@@ -284,7 +329,8 @@
bool ExpandPropertyContentsForTesting(const std::string& content,
brillo::CrosConfigInterface* config,
std::string* expanded_content) {
- return ExpandPropertyContents(content, config, expanded_content);
+ return ExpandPropertyContents(content, config, expanded_content,
+ /*add_native_bridge_64bit_support=*/false);
}
bool TruncateAndroidPropertyForTesting(const std::string& line,
@@ -295,30 +341,35 @@
bool ExpandPropertyFileForTesting(const base::FilePath& input,
const base::FilePath& output,
CrosConfig* config) {
- return ExpandPropertyFile(input, output, config, /*append=*/false);
+ return ExpandPropertyFile(input, output, config, /*append=*/false,
+ /*add_native_bridge_64bit_support=*/false);
}
bool ExpandPropertyFiles(const base::FilePath& source_path,
const base::FilePath& dest_path,
- bool single_file) {
+ bool single_file,
+ bool add_native_bridge_64bit_support) {
CrosConfig config;
if (single_file)
base::DeleteFile(dest_path, /*recursive=*/false);
// default.prop may not exist. Silently skip it if not found.
- for (const auto& pair : {std::pair<const char*, bool>{"default.prop", true},
- {"build.prop", false},
- {"vendor_build.prop", false}}) {
- const char* file = pair.first;
- const bool is_optional = pair.second;
+ for (const auto& tuple :
+ {std::tuple<const char*, bool, bool>{"default.prop", true, false},
+ {"build.prop", false, true},
+ {"vendor_build.prop", false, false}}) {
+ const char* file = std::get<0>(tuple);
+ const bool is_optional = std::get<1>(tuple);
+ const bool add_native_bridge_properties =
+ std::get<2>(tuple) && add_native_bridge_64bit_support;
if (is_optional && !base::PathExists(source_path.Append(file)))
continue;
- if (!ExpandPropertyFile(source_path.Append(file),
- single_file ? dest_path : dest_path.Append(file),
- &config,
- /*append=*/single_file)) {
+ if (!ExpandPropertyFile(
+ source_path.Append(file),
+ single_file ? dest_path : dest_path.Append(file), &config,
+ /*append=*/single_file, add_native_bridge_properties)) {
LOG(ERROR) << "Failed to expand " << source_path.Append(file);
return false;
}
diff --git a/components/arc/session/arc_property_util.h b/components/arc/session/arc_property_util.h
index 4748e56..8073ee45 100644
--- a/components/arc/session/arc_property_util.h
+++ b/components/arc/session/arc_property_util.h
@@ -61,9 +61,12 @@
// |source_path|. Expanded files are written in |dest_path|. Returns true on
// success. When |single_file| is true, only one file (|dest_path| itself) is
// written. All expanded properties are included in the single file.
+// When |add_native_bridge_64_bit_support| is true, add / modify some properties
+// related to supported CPU ABIs.
bool ExpandPropertyFiles(const base::FilePath& source_path,
const base::FilePath& dest_path,
- bool single_file);
+ bool single_file,
+ bool add_native_bridge_64bit_support);
} // namespace arc
diff --git a/components/arc/session/arc_property_util_unittest.cc b/components/arc/session/arc_property_util_unittest.cc
index 1583bc1..7f60f7c 100644
--- a/components/arc/session/arc_property_util_unittest.cc
+++ b/components/arc/session/arc_property_util_unittest.cc
@@ -291,33 +291,34 @@
// Both source and dest are not found.
EXPECT_FALSE(ExpandPropertyFiles(base::FilePath("/nonexistent1"),
base::FilePath("/nonexistent2"),
- /*single_file=*/false));
+ /*single_file=*/false,
+ /*add_native_bridge...=*/false));
// Both source and dest exist, but the source directory is empty.
base::FilePath source_dir;
ASSERT_TRUE(base::CreateTemporaryDirInDir(GetTempDir(), "test", &source_dir));
base::FilePath dest_dir;
ASSERT_TRUE(base::CreateTemporaryDirInDir(GetTempDir(), "test", &dest_dir));
- EXPECT_FALSE(ExpandPropertyFiles(source_dir, dest_dir, false));
+ EXPECT_FALSE(ExpandPropertyFiles(source_dir, dest_dir, false, false));
// Add default.prop to the source, but not build.prop.
base::FilePath default_prop = source_dir.Append("default.prop");
constexpr const char kDefaultProp[] = "ro.foo=bar\n";
base::WriteFile(default_prop, kDefaultProp, strlen(kDefaultProp));
- EXPECT_FALSE(ExpandPropertyFiles(source_dir, dest_dir, false));
+ EXPECT_FALSE(ExpandPropertyFiles(source_dir, dest_dir, false, false));
// Add build.prop too. The call should not succeed still.
base::FilePath build_prop = source_dir.Append("build.prop");
constexpr const char kBuildProp[] = "ro.baz=boo\n";
base::WriteFile(build_prop, kBuildProp, strlen(kBuildProp));
- EXPECT_FALSE(ExpandPropertyFiles(source_dir, dest_dir, false));
+ EXPECT_FALSE(ExpandPropertyFiles(source_dir, dest_dir, false, false));
// Add vendor_build.prop too. Then the call should succeed.
base::FilePath vendor_build_prop = source_dir.Append("vendor_build.prop");
constexpr const char kVendorBuildProp[] = "ro.a=b\n";
base::WriteFile(vendor_build_prop, kVendorBuildProp,
strlen(kVendorBuildProp));
- EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_dir, false));
+ EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_dir, false, false));
// Verify all dest files are there.
EXPECT_TRUE(base::PathExists(dest_dir.Append("default.prop")));
@@ -337,7 +338,7 @@
EXPECT_EQ(std::string(kVendorBuildProp) + "\n", content);
// Expand it again, verify the previous result is cleared.
- EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_dir, false));
+ EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_dir, false, false));
EXPECT_TRUE(
base::ReadFileToString(dest_dir.Append("default.prop"), &content));
EXPECT_EQ(std::string(kDefaultProp) + "\n", content);
@@ -347,7 +348,7 @@
// destination path.
base::DeleteFile(dest_dir.Append("default.prop"), /*recursive=*/false);
- EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_dir, false));
+ EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_dir, false, false));
EXPECT_TRUE(base::ReadFileToString(dest_dir.Append("build.prop"), &content));
EXPECT_EQ(std::string(kBuildProp) + "\n", content);
@@ -356,8 +357,8 @@
EXPECT_EQ(std::string(kVendorBuildProp) + "\n", content);
// Finally, test the case where source is valid but the dest is not.
- EXPECT_FALSE(
- ExpandPropertyFiles(source_dir, base::FilePath("/nonexistent"), false));
+ EXPECT_FALSE(ExpandPropertyFiles(source_dir, base::FilePath("/nonexistent"),
+ false, false));
}
// Do the same as the previous test, but with |single_file| == true.
@@ -365,7 +366,8 @@
// Both source and dest are not found.
EXPECT_FALSE(ExpandPropertyFiles(base::FilePath("/nonexistent1"),
base::FilePath("/nonexistent2"),
- /*single_file=*/true));
+ /*single_file=*/true,
+ /*add_native_bridge...=*/false));
// Both source and dest exist, but the source directory is empty.
base::FilePath source_dir;
@@ -374,26 +376,26 @@
ASSERT_TRUE(
base::CreateTemporaryDirInDir(GetTempDir(), "test", &dest_prop_file));
dest_prop_file = dest_prop_file.Append("combined.prop");
- EXPECT_FALSE(ExpandPropertyFiles(source_dir, dest_prop_file, true));
+ EXPECT_FALSE(ExpandPropertyFiles(source_dir, dest_prop_file, true, false));
// Add default.prop to the source, but not build.prop.
base::FilePath default_prop = source_dir.Append("default.prop");
constexpr const char kDefaultProp[] = "ro.foo=bar\n";
base::WriteFile(default_prop, kDefaultProp, strlen(kDefaultProp));
- EXPECT_FALSE(ExpandPropertyFiles(source_dir, dest_prop_file, true));
+ EXPECT_FALSE(ExpandPropertyFiles(source_dir, dest_prop_file, true, false));
// Add build.prop too. The call should not succeed still.
base::FilePath build_prop = source_dir.Append("build.prop");
constexpr const char kBuildProp[] = "ro.baz=boo\n";
base::WriteFile(build_prop, kBuildProp, strlen(kBuildProp));
- EXPECT_FALSE(ExpandPropertyFiles(source_dir, dest_prop_file, true));
+ EXPECT_FALSE(ExpandPropertyFiles(source_dir, dest_prop_file, true, false));
// Add vendor_build.prop too. Then the call should succeed.
base::FilePath vendor_build_prop = source_dir.Append("vendor_build.prop");
constexpr const char kVendorBuildProp[] = "ro.a=b\n";
base::WriteFile(vendor_build_prop, kVendorBuildProp,
strlen(kVendorBuildProp));
- EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_prop_file, true));
+ EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_prop_file, true, false));
// Verify only one dest file exists.
EXPECT_FALSE(
@@ -412,7 +414,7 @@
content);
// Expand it again, verify the previous result is cleared.
- EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_prop_file, true));
+ EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_prop_file, true, false));
EXPECT_TRUE(base::ReadFileToString(dest_prop_file, &content));
EXPECT_EQ(base::StringPrintf("%s\n%s\n%s\n", kDefaultProp, kBuildProp,
kVendorBuildProp),
@@ -422,14 +424,99 @@
// the other files.
base::DeleteFile(source_dir.Append("default.prop"),
/*recursive=*/false);
- EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_prop_file, true));
+ EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_prop_file, true, false));
EXPECT_TRUE(base::ReadFileToString(dest_prop_file, &content));
EXPECT_EQ(base::StringPrintf("%s\n%s\n", kBuildProp, kVendorBuildProp),
content);
// Finally, test the case where source is valid but the dest is not.
- EXPECT_FALSE(
- ExpandPropertyFiles(source_dir, base::FilePath("/nonexistent"), true));
+ EXPECT_FALSE(ExpandPropertyFiles(source_dir, base::FilePath("/nonexistent"),
+ true, false));
+}
+
+// Test that ExpandPropertyFiles handles properties related to native bridge
+// 64-bit support properly.
+TEST_F(ArcPropertyUtilTest, TestNativeBridge64Support) {
+ // Set up some properties files.
+ base::FilePath source_dir;
+ ASSERT_TRUE(base::CreateTemporaryDirInDir(GetTempDir(), "test", &source_dir));
+ base::FilePath dest_dir;
+ ASSERT_TRUE(base::CreateTemporaryDirInDir(GetTempDir(), "test", &dest_dir));
+
+ base::FilePath default_prop = source_dir.Append("default.prop");
+ constexpr const char kDefaultProp[] = "ro.foo=bar\n";
+ base::WriteFile(default_prop, kDefaultProp, strlen(kDefaultProp));
+
+ base::FilePath build_prop = source_dir.Append("build.prop");
+ constexpr const char kBuildProp[] =
+ "ro.baz=boo\n"
+ "ro.product.cpu.abilist=x86_64,x86,armeabi-v7a,armeabi\n"
+ "ro.product.cpu.abilist64=x86_64\n";
+ base::WriteFile(build_prop, kBuildProp, strlen(kBuildProp));
+
+ base::FilePath vendor_build_prop = source_dir.Append("vendor_build.prop");
+ constexpr const char kVendorBuildProp[] = "ro.a=b\n";
+ base::WriteFile(vendor_build_prop, kVendorBuildProp,
+ strlen(kVendorBuildProp));
+
+ // Expand with experiment off, verify properties are untouched.
+ std::string content;
+ EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_dir, false, false));
+ EXPECT_TRUE(
+ base::ReadFileToString(dest_dir.Append("default.prop"), &content));
+ EXPECT_EQ(std::string(kDefaultProp) + "\n", content);
+ EXPECT_TRUE(base::ReadFileToString(dest_dir.Append("build.prop"), &content));
+ EXPECT_EQ(std::string(kBuildProp) + "\n", content);
+ EXPECT_TRUE(
+ base::ReadFileToString(dest_dir.Append("vendor_build.prop"), &content));
+ EXPECT_EQ(std::string(kVendorBuildProp) + "\n", content);
+
+ // Expand with experiment on, verify properties are added / modified in
+ // build.prop but not other files.
+ EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_dir, false, true));
+ EXPECT_TRUE(
+ base::ReadFileToString(dest_dir.Append("default.prop"), &content));
+ EXPECT_EQ(std::string(kDefaultProp) + "\n", content);
+ EXPECT_TRUE(base::ReadFileToString(dest_dir.Append("build.prop"), &content));
+ constexpr const char kBuildPropModified[] =
+ "ro.baz=boo\n"
+ "ro.product.cpu.abilist=x86_64,x86,arm64-v8a,armeabi-v7a,armeabi\n"
+ "ro.product.cpu.abilist64=x86_64,arm64-v8a\n\n"
+ "ro.dalvik.vm.isa.arm64=x86_64";
+ EXPECT_EQ(std::string(kBuildPropModified) + "\n", content);
+ EXPECT_TRUE(
+ base::ReadFileToString(dest_dir.Append("vendor_build.prop"), &content));
+ EXPECT_EQ(std::string(kVendorBuildProp) + "\n", content);
+
+ // Expand to a single file with experiment on, verify properties are added /
+ // modified as expected.
+ base::FilePath dest_prop_file;
+ ASSERT_TRUE(
+ base::CreateTemporaryDirInDir(GetTempDir(), "test", &dest_prop_file));
+ dest_prop_file = dest_prop_file.Append("combined.prop");
+ EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_prop_file, true, true));
+
+ // Verify the contents.
+ EXPECT_TRUE(base::ReadFileToString(dest_prop_file, &content));
+ EXPECT_EQ(base::StringPrintf("%s\n%s\n%s\n", kDefaultProp, kBuildPropModified,
+ kVendorBuildProp),
+ content);
+
+ // Verify that unexpected property values generate an error.
+ constexpr const char kBuildPropUnexpected[] =
+ "ro.baz=boo\n"
+ "ro.product.cpu.abilist=x86_64,armeabi-v7a,armeabi,unexpected-abi\n"
+ "ro.product.cpu.abilist64=x86_64\n";
+ base::WriteFile(build_prop, kBuildPropUnexpected,
+ strlen(kBuildPropUnexpected));
+ EXPECT_FALSE(ExpandPropertyFiles(source_dir, dest_dir, false, true));
+ constexpr const char kBuildPropUnexpected2[] =
+ "ro.baz=boo\n"
+ "ro.product.cpu.abilist=x86_64,x86,armeabi-v7a,armeabi\n"
+ "ro.product.cpu.abilist64=x86_64,unexpected-abi_64\n";
+ base::WriteFile(build_prop, kBuildPropUnexpected2,
+ strlen(kBuildPropUnexpected2));
+ EXPECT_FALSE(ExpandPropertyFiles(source_dir, dest_dir, false, true));
}
} // namespace
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 86bd084..15027ea 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -39863,6 +39863,8 @@
<int value="-1670137340"
label="OptimizeLoadingIPCForSmallResources:disabled"/>
<int value="-1669486359" label="ImportantSitesInCBD:enabled"/>
+ <int value="-1665720309"
+ label="ArcNativeBridge64BitSupportExperiment:disabled"/>
<int value="-1664795930" label="StorageAccessAPI:disabled"/>
<int value="-1663410466" label="top-document-isolation"/>
<int value="-1663125441" label="OptInImeMenu:enabled"/>
@@ -40379,6 +40381,8 @@
<int value="-1153892430"
label="AlignFontDisplayAutoTimeoutWithLCPGoal:enabled"/>
<int value="-1151766565" label="enable-fullscreen-tab-detaching"/>
+ <int value="-1150881704"
+ label="ArcNativeBridge64BitSupportExperiment:enabled"/>
<int value="-1145905507" label="SendTabToSelfWhenSignedIn:disabled"/>
<int value="-1145702446" label="ChromeHomeInactivitySheetExpansion:enabled"/>
<int value="-1145246849" label="ThirdPartyDoodles:enabled"/>