Commit f2e1adff authored by Yusuke Sato's avatar Yusuke Sato Committed by Chromium LUCI CQ

arc: Remove arc_property_util* and fake_cros_config.*

The former has been moved to platform2/arc/setup. The latter
is not used anymore.

BUG=chromium:1163122
TEST=try

Change-Id: I104a468668b7e56087740818ef5cdf93a370f761
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2613398
Commit-Queue: Yusuke Sato <yusukes@chromium.org>
Reviewed-by: default avatarYury Khmel <khmel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#846270}
parent f92b961c
......@@ -233,8 +233,6 @@ static_library("arc_base") {
"session/arc_container_client_adapter.h",
"session/arc_data_remover.cc",
"session/arc_data_remover.h",
"session/arc_property_util.cc",
"session/arc_property_util.h",
"session/arc_session.cc",
"session/arc_session.h",
"session/arc_session_impl.cc",
......@@ -340,8 +338,6 @@ static_library("arc_test_support") {
"test/fake_bluetooth_instance.h",
"test/fake_clipboard_instance.cc",
"test/fake_clipboard_instance.h",
"test/fake_cros_config.cc",
"test/fake_cros_config.h",
"test/fake_file_system_instance.cc",
"test/fake_file_system_instance.h",
"test/fake_intent_helper_instance.cc",
......@@ -416,7 +412,6 @@ source_set("unit_tests") {
"property/arc_property_bridge_unittest.cc",
"session/arc_container_client_adapter_unittest.cc",
"session/arc_data_remover_unittest.cc",
"session/arc_property_util_unittest.cc",
"session/arc_session_impl_unittest.cc",
"session/arc_session_runner_unittest.cc",
"session/arc_vm_client_adapter_unittest.cc",
......@@ -476,12 +471,3 @@ source_set("unit_tests") {
"//url:url",
]
}
fuzzer_test("arc_property_util_expand_property_contents_fuzzer") {
sources = [ "session/arc_property_util_expand_property_contents_fuzzer.cc" ]
deps = [
":arc",
":arc_test_support",
"//base",
]
}
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/arc/session/arc_property_util.h"
#include <algorithm>
#include <tuple>
#include <vector>
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/process/launch.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
#include "chromeos/constants/chromeos_switches.h"
namespace brillo {
// This is to use the platform2 code without any modifications.
using CrosConfigInterface = arc::CrosConfig;
} // namespace brillo
namespace arc {
namespace {
// The path in the chromeos-config database where Android properties will be
// looked up.
constexpr char kCrosConfigPropertiesPath[] = "/arc/build-properties";
// Android property name used to store the board name.
constexpr char kBoardPropertyPrefix[] = "ro.product.board=";
// Android property name for custom key used for Play Auto Install selection.
constexpr char kOEMKey1PropertyPrefix[] = "ro.oem.key1=";
// Configuration property name of an optional string that contains a comma-
// 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.
// Note that "%s" is lated replaced with a partition name which is either an
// empty string or a string that ends with '.' e.g. "system_ext.".
constexpr char kAbilistPropertyPrefixTemplate[] = "ro.%sproduct.cpu.abilist=";
constexpr char kAbilistPropertyExpected[] = "x86_64,x86,armeabi-v7a,armeabi";
constexpr char kAbilistPropertyReplacement[] =
"x86_64,x86,arm64-v8a,armeabi-v7a,armeabi";
constexpr char kAbilist64PropertyPrefixTemplate[] =
"ro.%sproduct.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;
bool FindProperty(const std::string& line_prefix_to_find,
std::string* out_prop,
const std::string& line) {
if (base::StartsWith(line, line_prefix_to_find,
base::CompareCase::SENSITIVE)) {
*out_prop = line.substr(line_prefix_to_find.length());
return true;
}
return false;
}
bool TruncateAndroidProperty(const std::string& line, std::string* truncated) {
// If line looks like key=value, cut value down to the max length of an
// Android property. Build fingerprint needs special handling to preserve the
// trailing dev-keys indicator, but other properties can just be truncated.
size_t eq_pos = line.find('=');
if (eq_pos == std::string::npos) {
*truncated = line;
return true;
}
std::string val = line.substr(eq_pos + 1);
base::TrimWhitespaceASCII(val, base::TRIM_ALL, &val);
if (val.length() <= kAndroidMaxPropertyLength) {
*truncated = line;
return true;
}
const std::string key = line.substr(0, eq_pos);
LOG(WARNING) << "Truncating property " << key << " value: " << val;
if (key == "ro.bootimage.build.fingerprint" &&
base::EndsWith(val, "/dev-keys", base::CompareCase::SENSITIVE)) {
// Typical format is brand/product/device/.../dev-keys. We want to remove
// characters from product and device to get below the length limit.
// Assume device has the format {product}_cheets.
std::vector<std::string> fields =
base::SplitString(val, "/", base::WhitespaceHandling::KEEP_WHITESPACE,
base::SplitResult::SPLIT_WANT_ALL);
if (fields.size() < 5) {
LOG(ERROR) << "Invalid build fingerprint: " << val;
return false;
}
size_t remove_chars = (val.length() - kAndroidMaxPropertyLength + 1) / 2;
if (fields[1].length() <= remove_chars) {
LOG(ERROR) << "Unable to remove " << remove_chars << " characters from "
<< fields[1];
return false;
}
fields[1] = fields[1].substr(0, fields[1].length() - remove_chars);
fields[2] = fields[1] + "_cheets";
val = base::JoinString(fields, "/");
} else {
val = val.substr(0, kAndroidMaxPropertyLength);
}
*truncated = key + "=" + val;
return true;
}
// Computes the value of ro.oem.key1 based on the build-time ro.product.board
// value and the device's region of origin.
std::string ComputeOEMKey(brillo::CrosConfigInterface* config,
const std::string& board) {
std::string regions;
if (!config->GetString(kCrosConfigPropertiesPath, kPAIRegionsPropertyName,
&regions)) {
// No region list found, just use the board name as before.
return board;
}
std::string region_code;
if (!base::GetAppOutput({"cros_region_data", "region_code"}, &region_code)) {
LOG(WARNING) << "Failed to get region code";
return board;
}
// Remove trailing newline.
region_code.erase(std::remove(region_code.begin(), region_code.end(), '\n'),
region_code.end());
// Allow wildcard configuration to indicate that all regions should be
// included.
if (regions.compare("*") == 0 && region_code.length() >= 2)
return board + "_" + region_code;
// Check to see if region code is in the list of regions that should be
// included in the property.
std::vector<std::string> region_vector =
base::SplitString(regions, ",", base::WhitespaceHandling::TRIM_WHITESPACE,
base::SplitResult::SPLIT_WANT_NONEMPTY);
for (const auto& region : region_vector) {
if (region_code.compare(region) == 0)
return board + "_" + region_code;
}
return board;
}
bool IsComment(const std::string& line) {
return base::StartsWith(
base::TrimWhitespaceASCII(line, base::TrimPositions::TRIM_LEADING), "#",
base::CompareCase::SENSITIVE);
}
bool ExpandPropertyContents(const std::string& content,
brillo::CrosConfigInterface* config,
std::string* expanded_content,
bool filter_non_ro_props,
bool add_native_bridge_64bit_support,
bool append_dalvik_isa,
const std::string& partition_name) {
const std::vector<std::string> lines = base::SplitString(
content, "\n", base::WhitespaceHandling::KEEP_WHITESPACE,
base::SplitResult::SPLIT_WANT_ALL);
std::string new_properties;
for (std::string line : lines) {
// Since Chrome only expands ro. properties at runtime, skip processing
// non-ro lines here for R+. For P, we cannot do that because the
// expanded property files will directly replace the original ones via
// bind mounts.
if (filter_non_ro_props &&
!base::StartsWith(line, "ro.", base::CompareCase::SENSITIVE)) {
if (!IsComment(line) && line.find('{') != std::string::npos) {
// The non-ro property has substitution(s).
LOG(ERROR) << "Found substitution(s) in a non-ro property: " << line;
return false;
}
continue;
}
// First expand {property} substitutions in the string. The insertions
// may contain substitutions of their own, so we need to repeat until
// nothing more is found.
bool inserted;
do {
inserted = false;
size_t match_start = line.find('{');
size_t prev_match = 0; // 1 char past the end of the previous {} match.
std::string expanded;
// Find all of the {} matches on the line.
while (match_start != std::string::npos) {
expanded += line.substr(prev_match, match_start - prev_match);
size_t match_end = line.find('}', match_start);
if (match_end == std::string::npos) {
LOG(ERROR) << "Unmatched { found in line: " << line;
return false;
}
const std::string keyword =
line.substr(match_start + 1, match_end - match_start - 1);
std::string replacement;
if (config->GetString(kCrosConfigPropertiesPath, keyword,
&replacement)) {
expanded += replacement;
inserted = true;
} else {
LOG(ERROR) << "Did not find a value for " << keyword
<< " while expanding " << line;
return false;
}
prev_match = match_end + 1;
match_start = line.find('{', match_end);
}
if (prev_match != std::string::npos)
expanded += line.substr(prev_match);
line = expanded;
} while (inserted);
if (add_native_bridge_64bit_support) {
// Special-case ro.<partition>product.cpu.abilist and
// ro.<partition>product.cpu.abilist64 to add ARM64.
// Note that <partition> is either an empty string or a string that ends
// with '.' e.g. "system_ext.".
std::string prefix = base::StringPrintf(kAbilistPropertyPrefixTemplate,
partition_name.c_str());
std::string value;
if (FindProperty(prefix, &value, line)) {
if (value == kAbilistPropertyExpected) {
line = prefix + std::string(kAbilistPropertyReplacement);
} else {
LOG(ERROR) << "Found unexpected value for " << prefix << ", value "
<< value;
return false;
}
}
prefix = base::StringPrintf(kAbilist64PropertyPrefixTemplate,
partition_name.c_str());
if (FindProperty(prefix, &value, line)) {
if (value == kAbilist64PropertyExpected) {
line = prefix + std::string(kAbilist64PropertyReplacement);
} else {
LOG(ERROR) << "Found unexpected value for " << prefix << ", 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
// can depend upon the device region.
std::string property;
if (FindProperty(kBoardPropertyPrefix, &property, line)) {
std::string oem_key_property = ComputeOEMKey(config, property);
new_properties +=
std::string(kOEMKey1PropertyPrefix) + oem_key_property + "\n";
}
}
if (append_dalvik_isa) {
// Special-case to add ro.dalvik.vm.isa.arm64.
new_properties += std::string(kDalvikVmIsaArm64) + "\n";
}
*expanded_content = new_properties;
return true;
}
bool ExpandPropertyFile(const base::FilePath& input,
const base::FilePath& output,
CrosConfig* config,
bool append,
bool add_native_bridge_64bit_support,
bool append_dalvik_isa,
const std::string& partition_name) {
std::string content;
std::string expanded;
if (!base::ReadFileToString(input, &content)) {
if (base::SysInfo::IsRunningOnChromeOS())
PLOG(ERROR) << "Failed to read " << input;
return false;
}
if (!ExpandPropertyContents(content, config, &expanded,
/*filter_non_ro_props=*/append,
add_native_bridge_64bit_support,
append_dalvik_isa, partition_name))
return false;
if (append && base::PathExists(output)) {
if (!base::AppendToFile(output, expanded.data(), expanded.size())) {
PLOG(ERROR) << "Failed to append to " << output;
return false;
}
} else {
if (base::WriteFile(output, expanded.data(), expanded.size()) !=
static_cast<int>(expanded.size())) {
PLOG(ERROR) << "Failed to write to " << output;
return false;
}
}
return true;
}
} // namespace
CrosConfig::CrosConfig() {
const base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
if (!cl->HasSwitch(chromeos::switches::kArcBuildProperties)) {
if (base::SysInfo::IsRunningOnChromeOS())
LOG(ERROR) << chromeos::switches::kArcBuildProperties << " is not found";
return;
}
std::string command_line_value =
cl->GetSwitchValueASCII(chromeos::switches::kArcBuildProperties);
info_ = base::JSONReader::Read(command_line_value);
if (!info_) {
LOG(ERROR) << "JSONReader failed reading ARC build properties: "
<< command_line_value;
return;
}
if (!info_->is_dict()) {
LOG(ERROR) << chromeos::switches::kArcBuildProperties
<< " is not a dictionary";
info_.reset();
return;
}
}
CrosConfig::~CrosConfig() = default;
bool CrosConfig::GetString(const std::string& path,
const std::string& property,
std::string* val_out) {
if (path != kCrosConfigPropertiesPath)
return false;
if (!info_)
return false;
const std::string* value = info_->FindStringKey(property);
if (!value)
return false;
*val_out = *value;
return true;
}
bool ExpandPropertyContentsForTesting(const std::string& content,
brillo::CrosConfigInterface* config,
std::string* expanded_content) {
return ExpandPropertyContents(content, config, expanded_content,
/*filter_non_ro_props=*/true,
/*add_native_bridge_64bit_support=*/false,
false, std::string());
}
bool TruncateAndroidPropertyForTesting(const std::string& line,
std::string* truncated) {
return TruncateAndroidProperty(line, truncated);
}
bool ExpandPropertyFileForTesting(const base::FilePath& input,
const base::FilePath& output,
CrosConfig* config) {
return ExpandPropertyFile(input, output, config, /*append=*/false,
/*add_native_bridge_64bit_support=*/false, false,
std::string());
}
bool ExpandPropertyFiles(const base::FilePath& source_path,
const base::FilePath& dest_path,
bool single_file,
bool add_native_bridge_64bit_support) {
CrosConfig config;
if (single_file)
base::DeleteFile(dest_path);
// default.prop may not exist. Silently skip it if not found.
for (const auto& tuple :
// The order has to match the one in PropertyLoadBootDefaults() in
// system/core/init/property_service.cpp.
// Note: Our vendor image doesn't have /vendor/default.prop although
// PropertyLoadBootDefaults() tries to open it.
{std::tuple<const char*, bool, bool, const char*>{"default.prop", true,
false, ""},
{"build.prop", false, true, ""},
{"system_ext_build.prop", true, false, "system_ext."},
{"vendor_build.prop", false, false, "vendor."},
{"odm_build.prop", true, false, "odm."},
{"product_build.prop", true, false, "product."}}) {
const char* file = std::get<0>(tuple);
const bool is_optional = std::get<1>(tuple);
// When true, unconditionally add |kDalvikVmIsaArm64| property.
const bool append_dalvik_isa =
std::get<2>(tuple) && add_native_bridge_64bit_support;
// Search for ro.<partition_name>product.cpu.abilist* properties.
const char* partition_name = std::get<3>(tuple);
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, add_native_bridge_64bit_support,
append_dalvik_isa, partition_name)) {
if (base::SysInfo::IsRunningOnChromeOS())
LOG(ERROR) << "Failed to expand " << source_path.Append(file);
return false;
}
}
return true;
}
} // namespace arc
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_ARC_SESSION_ARC_PROPERTY_UTIL_H_
#define COMPONENTS_ARC_SESSION_ARC_PROPERTY_UTIL_H_
#include <string>
#include "base/optional.h"
#include "base/values.h"
namespace base {
class FilePath;
} // namespace base
namespace arc {
// A class that reads and parses |kArcBuildProperties| command line flags and
// holds the result as a dictionary. This is a drop-in replacement of the
// brillo::CrosConfigInterface classes (which are not available in Chromium).
class CrosConfig {
public:
CrosConfig();
virtual ~CrosConfig();
CrosConfig(const CrosConfig&) = delete;
CrosConfig& operator=(const CrosConfig&) = delete;
// Find the |property| in the dictionary and assigns the result to |val_out|.
// Returns true when the property is found. The function always returns false
// when |path| is not |kCrosConfigPropertiesPath|.
virtual bool GetString(const std::string& path,
const std::string& property,
std::string* val_out);
private:
base::Optional<base::Value> info_;
};
// Expands the contents of a template Android property file. Strings like
// {property} will be looked up in |config| and replaced with their values.
// Returns true if all {} strings were successfully expanded, or false if any
// properties were not found.
bool ExpandPropertyContentsForTesting(const std::string& content,
CrosConfig* config,
std::string* expanded_content);
// Truncates the value side of an Android key=val property line, including
// handling the special case of build fingerprint.
bool TruncateAndroidPropertyForTesting(const std::string& line,
std::string* truncated);
// Expands properties (i.e. {property-name}) in |input| with the dictionary
// |config| provides, and writes the results to |output|. Returns true if the
// output file is successfully written.
bool ExpandPropertyFileForTesting(const base::FilePath& input,
const base::FilePath& output,
CrosConfig* config);
// Calls ExpandPropertyFile for {build,default,vendor_build}.prop files in
// |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 add_native_bridge_64bit_support);
} // namespace arc
#endif // COMPONENTS_ARC_SESSION_ARC_PROPERTY_UTIL_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/arc/session/arc_property_util.h"
#include <stddef.h>
#include <stdint.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <map>
#include <string>
#include "base/command_line.h"
#include "components/arc/test/fake_cros_config.h"
#include "testing/libfuzzer/libfuzzer_exports.h"
namespace {
constexpr size_t kMaxInputSize = 64 * 1024;
}
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
base::CommandLine::Init(*argc, *argv);
return 0;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Limit the input size to avoid timing out on ClusterFuzz.
if (size > kMaxInputSize)
return 0;
FuzzedDataProvider data_provider(data, size);
std::string content = data_provider.ConsumeRandomLengthString(size);
arc::FakeCrosConfig config;
while (data_provider.remaining_bytes()) {
// Cannot use |ConsumeRandomLengthString| in a loop because it can enter an
// infinite loop by always returning an empty string.
size_t path_size = data_provider.ConsumeIntegralInRange<size_t>(
0, data_provider.remaining_bytes());
std::string path =
std::string("/") + data_provider.ConsumeBytesAsString(path_size);
if (data_provider.remaining_bytes() == 0)
break;
size_t property_size = data_provider.ConsumeIntegralInRange<size_t>(
1, data_provider.remaining_bytes());
std::string property = data_provider.ConsumeBytesAsString(property_size);
if (data_provider.remaining_bytes() == 0)
break;
size_t val_size = data_provider.ConsumeIntegralInRange<size_t>(
1, data_provider.remaining_bytes());
std::string val = data_provider.ConsumeBytesAsString(val_size);
config.SetString(path, property, val);
}
std::string expanded_content;
arc::ExpandPropertyContentsForTesting(content, &config, &expanded_content);
return 0;
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/arc/session/arc_property_util.h"
#include <memory>
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/strings/stringprintf.h"
#include "chromeos/constants/chromeos_switches.h"
#include "components/arc/test/fake_cros_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace arc {
namespace {
constexpr char kCrosConfigPropertiesPath[] = "/arc/build-properties";
class ArcPropertyUtilTest : public testing::Test {
public:
ArcPropertyUtilTest() = default;
~ArcPropertyUtilTest() override = default;
ArcPropertyUtilTest(const ArcPropertyUtilTest&) = delete;
ArcPropertyUtilTest& operator=(const ArcPropertyUtilTest&) = delete;
void SetUp() override { ASSERT_TRUE(dir_.CreateUniqueTempDir()); }
protected:
const base::FilePath& GetTempDir() const { return dir_.GetPath(); }
CrosConfig* config() {
if (!config_)
config_ = std::make_unique<CrosConfig>();
return config_.get();
}
private:
std::unique_ptr<CrosConfig> config_;
base::ScopedTempDir dir_;
};
TEST_F(ArcPropertyUtilTest, TestPropertyExpansions) {
FakeCrosConfig config;
config.SetString("/arc/build-properties", "brand", "alphabet");
std::string expanded;
EXPECT_TRUE(ExpandPropertyContentsForTesting(
"ro.a=line1\nro.b={brand}\nro.c=line3\nro.d={brand} {brand}", &config,
&expanded));
EXPECT_EQ("ro.a=line1\nro.b=alphabet\nro.c=line3\nro.d=alphabet alphabet\n",
expanded);
}
TEST_F(ArcPropertyUtilTest, TestPropertyExpansionsUnmatchedBrace) {
FakeCrosConfig config;
config.SetString("/arc/build-properties", "brand", "alphabet");
std::string expanded;
EXPECT_FALSE(ExpandPropertyContentsForTesting(
"ro.a=line{1\nro.b=line}2\nro.c=line3", &config, &expanded));
}
TEST_F(ArcPropertyUtilTest, TestPropertyExpansionsRecursive) {
FakeCrosConfig config;
config.SetString("/arc/build-properties", "brand", "alphabet");
config.SetString("/arc/build-properties", "model", "{brand} soup");
std::string expanded;
EXPECT_TRUE(
ExpandPropertyContentsForTesting("ro.a={model}", &config, &expanded));
EXPECT_EQ("ro.a=alphabet soup\n", expanded);
}
TEST_F(ArcPropertyUtilTest, TestPropertyExpansionsMissingProperty) {
FakeCrosConfig config;
config.SetString("/arc/build-properties", "model", "{brand} soup");
std::string expanded;
EXPECT_FALSE(ExpandPropertyContentsForTesting("ro.a={missing-property}",
&config, &expanded));
EXPECT_FALSE(
ExpandPropertyContentsForTesting("ro.a={model}", &config, &expanded));
}
// Verify that ro.product.board gets copied to ro.oem.key1 as well.
TEST_F(ArcPropertyUtilTest, TestPropertyExpansionBoard) {
FakeCrosConfig config;
config.SetString("/arc/build-properties", "board", "testboard");
std::string expanded;
EXPECT_TRUE(ExpandPropertyContentsForTesting("ro.product.board={board}",
&config, &expanded));
EXPECT_EQ("ro.product.board=testboard\nro.oem.key1=testboard\n", expanded);
}
// Non-fingerprint property should do simple truncation.
TEST_F(ArcPropertyUtilTest, TestPropertyTruncation) {
std::string truncated;
EXPECT_TRUE(TruncateAndroidPropertyForTesting(
"property.name="
"012345678901234567890123456789012345678901234567890123456789"
"01234567890123456789012345678901",
&truncated));
EXPECT_EQ(
"property.name=0123456789012345678901234567890123456789"
"012345678901234567890123456789012345678901234567890",
truncated);
}
// Fingerprint truncation with /release-keys should do simple truncation.
TEST_F(ArcPropertyUtilTest, TestPropertyTruncationFingerprintRelease) {
std::string truncated;
EXPECT_TRUE(TruncateAndroidPropertyForTesting(
"ro.bootimage.build.fingerprint=google/toolongdevicename/"
"toolongdevicename_cheets:7.1.1/R65-10299.0.9999/4538390:user/"
"release-keys",
&truncated));
EXPECT_EQ(
"ro.bootimage.build.fingerprint=google/toolongdevicename/"
"toolongdevicename_cheets:7.1.1/R65-10299.0.9999/4538390:user/relea",
truncated);
}
// Fingerprint truncation with /dev-keys needs to preserve the /dev-keys.
TEST_F(ArcPropertyUtilTest, TestPropertyTruncationFingerprintDev) {
std::string truncated;
EXPECT_TRUE(TruncateAndroidPropertyForTesting(
"ro.bootimage.build.fingerprint=google/toolongdevicename/"
"toolongdevicename_cheets:7.1.1/R65-10299.0.9999/4538390:user/dev-keys",
&truncated));
EXPECT_EQ(
"ro.bootimage.build.fingerprint=google/toolongdevicena/"
"toolongdevicena_cheets/R65-10299.0.9999/4538390:user/dev-keys",
truncated);
}
// Fingerprint truncation with the wrong format should fail.
TEST_F(ArcPropertyUtilTest, TestPropertyTruncationBadFingerprint) {
std::string truncated;
EXPECT_FALSE(TruncateAndroidPropertyForTesting(
"ro.bootimage.build.fingerprint=google/toolongdevicename/"
"toolongdevicename_cheets:7.1.1:123456789012345678901234567890/dev-keys",
&truncated));
}
// Fingerprint truncation without enough room should fail.
TEST_F(ArcPropertyUtilTest, TestPropertyTruncationFingerprintShortDevice) {
std::string truncated;
EXPECT_FALSE(TruncateAndroidPropertyForTesting(
"ro.bootimage.build.fingerprint=google/dev/"
"dev_cheets:7.1.1/R65-10299.0.9999/453839012345678901234567890"
"12345678901234567890:user/dev-keys",
&truncated));
}
// Tests that the GetString method works as intended.
TEST_F(ArcPropertyUtilTest, CrosConfig_GetString) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
command_line->AppendSwitchASCII(chromeos::switches::kArcBuildProperties,
"{\"k1\":\"v1\",\"k2\":\"v2\",\"k3\":3}");
std::string str;
EXPECT_TRUE(config()->GetString(kCrosConfigPropertiesPath, "k1", &str));
EXPECT_EQ("v1", str);
EXPECT_TRUE(config()->GetString(kCrosConfigPropertiesPath, "k2", &str));
EXPECT_EQ("v2", str);
// The value is not a string.
EXPECT_FALSE(config()->GetString(kCrosConfigPropertiesPath, "k3", &str));
// The property path is invalid.
EXPECT_FALSE(config()->GetString("/unknown/path", "k1", &str));
}
// Tests that CrosConfig can handle the case where the command line is not
// passed.
TEST_F(ArcPropertyUtilTest, CrosConfig_NoCommandline) {
std::string str;
EXPECT_FALSE(config()->GetString(kCrosConfigPropertiesPath, "k1", &str));
}
// Tests that CrosConfig can handle an empty command line.
TEST_F(ArcPropertyUtilTest, CrosConfig_EmptyCommandline) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
command_line->AppendSwitchASCII(chromeos::switches::kArcBuildProperties, "");
std::string str;
EXPECT_FALSE(config()->GetString(kCrosConfigPropertiesPath, "k1", &str));
}
// Tests that CrosConfig can handle JSON whose top-level is not a dict.
TEST_F(ArcPropertyUtilTest, CrosConfig_NoDict) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
command_line->AppendSwitchASCII(chromeos::switches::kArcBuildProperties,
"[\"k1\"]");
std::string str;
EXPECT_FALSE(config()->GetString(kCrosConfigPropertiesPath, "k1", &str));
}
// Tests that CrosConfig can handle an invalid JSON.
TEST_F(ArcPropertyUtilTest, CrosConfig_InvalidJson) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
command_line->AppendSwitchASCII(chromeos::switches::kArcBuildProperties,
"{\"k1\":}"); // parse error: no value
std::string str;
EXPECT_FALSE(config()->GetString(kCrosConfigPropertiesPath, "k1", &str));
}
// Tests that ExpandPropertyFile works as intended when no property expantion
// is needed.
TEST_F(ArcPropertyUtilTest, ExpandPropertyFile_NoExpansion) {
constexpr const char kValidProp[] = "ro.foo=bar\nro.baz=boo";
base::FilePath path;
ASSERT_TRUE(CreateTemporaryFileInDir(GetTempDir(), &path));
base::WriteFile(path, kValidProp, strlen(kValidProp));
const base::FilePath dest = GetTempDir().Append("new.prop");
EXPECT_TRUE(ExpandPropertyFileForTesting(path, dest, config()));
std::string content;
EXPECT_TRUE(base::ReadFileToString(dest, &content));
EXPECT_EQ(std::string(kValidProp) + "\n", content);
}
// Tests that ExpandPropertyFile works as intended when property expantion
// is needed.
TEST_F(ArcPropertyUtilTest, ExpandPropertyFile_Expansion) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
command_line->AppendSwitchASCII(chromeos::switches::kArcBuildProperties,
"{\"k1\":\"v1\",\"k2\":\"v2\"}");
constexpr const char kValidProp[] = "ro.foo={k1}\nro.baz={k2}";
base::FilePath path;
ASSERT_TRUE(CreateTemporaryFileInDir(GetTempDir(), &path));
base::WriteFile(path, kValidProp, strlen(kValidProp));
const base::FilePath dest = GetTempDir().Append("new.prop");
EXPECT_TRUE(ExpandPropertyFileForTesting(path, dest, config()));
std::string content;
EXPECT_TRUE(base::ReadFileToString(dest, &content));
EXPECT_EQ("ro.foo=v1\nro.baz=v2\n", content);
}
// Tests that ExpandPropertyFile works as intended when nested property
// expantion is needed.
TEST_F(ArcPropertyUtilTest, ExpandPropertyFile_NestedExpansion) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
command_line->AppendSwitchASCII(chromeos::switches::kArcBuildProperties,
"{\"k1\":\"{k2}\",\"k2\":\"v2\"}");
constexpr const char kValidProp[] = "ro.foo={k1}\nro.baz={k2}";
base::FilePath path;
ASSERT_TRUE(CreateTemporaryFileInDir(GetTempDir(), &path));
base::WriteFile(path, kValidProp, strlen(kValidProp));
const base::FilePath dest = GetTempDir().Append("new.prop");
EXPECT_TRUE(ExpandPropertyFileForTesting(path, dest, config()));
std::string content;
EXPECT_TRUE(base::ReadFileToString(dest, &content));
EXPECT_EQ("ro.foo=v2\nro.baz=v2\n", content);
}
// Test that ExpandPropertyFile handles the case where a property is not found.
TEST_F(ArcPropertyUtilTest, ExpandPropertyFile_CannotExpand) {
constexpr const char kValidProp[] =
"ro.foo={nonexistent-property}\nro.baz=boo\n";
base::FilePath path;
ASSERT_TRUE(CreateTemporaryFileInDir(GetTempDir(), &path));
base::WriteFile(path, kValidProp, strlen(kValidProp));
const base::FilePath dest = GetTempDir().Append("new.prop");
EXPECT_FALSE(ExpandPropertyFileForTesting(path, dest, config()));
}
// Test that ExpandPropertyFile handles the case where the input file is not
// found.
TEST_F(ArcPropertyUtilTest, ExpandPropertyFile_NoSourceFile) {
EXPECT_FALSE(ExpandPropertyFileForTesting(base::FilePath("/nonexistent"),
base::FilePath("/nonexistent2"),
config()));
}
// Test that ExpandPropertyFile handles the case where the output file cannot
// be written.
TEST_F(ArcPropertyUtilTest, ExpandPropertyFile_CannotWrite) {
constexpr const char kValidProp[] = "ro.foo=bar\nro.baz=boo\n";
base::FilePath path;
ASSERT_TRUE(CreateTemporaryFileInDir(GetTempDir(), &path));
base::WriteFile(path, kValidProp, strlen(kValidProp));
EXPECT_FALSE(ExpandPropertyFileForTesting(
path, base::FilePath("/nonexistent2"), config()));
}
TEST_F(ArcPropertyUtilTest, ExpandPropertyFiles) {
// Both source and dest are not found.
EXPECT_FALSE(ExpandPropertyFiles(base::FilePath("/nonexistent1"),
base::FilePath("/nonexistent2"),
/*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, false));
// Add default.prop to the source, but not build.prop.
base::FilePath default_prop = source_dir.Append("default.prop");
// Add a non-ro property to make sure that the property is NOT filetered out
// when not in the "append" mode.
constexpr const char kDefaultProp[] = "dalvik.a=b\nro.foo=bar\n";
base::WriteFile(default_prop, kDefaultProp, strlen(kDefaultProp));
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, 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, false));
// Verify all dest files are there.
EXPECT_TRUE(base::PathExists(dest_dir.Append("default.prop")));
EXPECT_TRUE(base::PathExists(dest_dir.Append("build.prop")));
EXPECT_TRUE(base::PathExists(dest_dir.Append("vendor_build.prop")));
// Verify their content.
std::string content;
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 it again, verify the previous result is cleared.
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);
// If default.prop does not exist in the source path, it should still process
// the other files, while also ensuring that default.prop is removed from the
// destination path.
base::DeleteFile(dest_dir.Append("default.prop"));
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);
EXPECT_TRUE(
base::ReadFileToString(dest_dir.Append("vendor_build.prop"), &content));
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, false));
}
// Do the same as the previous test, but with |single_file| == true.
TEST_F(ArcPropertyUtilTest, ExpandPropertyFiles_SingleFile) {
// Both source and dest are not found.
EXPECT_FALSE(ExpandPropertyFiles(base::FilePath("/nonexistent1"),
base::FilePath("/nonexistent2"),
/*single_file=*/true,
/*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_prop_file;
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, false));
// Add default.prop to the source, but not build.prop.
const base::FilePath default_prop = source_dir.Append("default.prop");
// Add a non-ro property to make sure that the property is filetered out when
// in the "append" mode.
constexpr const char kDefaultPropNonRo[] = "dalvik.a=b\n";
constexpr const char kDefaultProp[] = "ro.foo=bar\n";
base::WriteFile(default_prop,
base::StringPrintf("%s%s", kDefaultPropNonRo, kDefaultProp));
EXPECT_FALSE(ExpandPropertyFiles(source_dir, dest_prop_file, true, false));
// Add build.prop too. The call should not succeed still.
const 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, false));
// Add vendor_build.prop too. Then the call should succeed.
const 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, false));
// Add other optional files too. Then the call should succeed.
const base::FilePath system_ext_build_prop =
source_dir.Append("system_ext_build.prop");
constexpr const char kSystemExtBuildProp[] = "ro.c=d\n";
base::WriteFile(system_ext_build_prop, kSystemExtBuildProp,
strlen(kSystemExtBuildProp));
EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_prop_file, true, false));
const base::FilePath odm_build_prop = source_dir.Append("odm_build.prop");
constexpr const char kOdmBuildProp[] = "ro.e=f\n";
base::WriteFile(odm_build_prop, kOdmBuildProp, strlen(kOdmBuildProp));
EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_prop_file, true, false));
const base::FilePath product_build_prop =
source_dir.Append("product_build.prop");
constexpr const char kProductBuildProp[] = "ro.g=h\n";
base::WriteFile(product_build_prop, kProductBuildProp,
strlen(kProductBuildProp));
EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_prop_file, true, false));
// Verify only one dest file exists.
EXPECT_FALSE(
base::PathExists(dest_prop_file.DirName().Append("default.prop")));
EXPECT_FALSE(base::PathExists(dest_prop_file.DirName().Append("build.prop")));
EXPECT_FALSE(
base::PathExists(dest_prop_file.DirName().Append("vendor_build.prop")));
EXPECT_FALSE(base::PathExists(
dest_prop_file.DirName().Append("system_ext_build.prop")));
EXPECT_FALSE(
base::PathExists(dest_prop_file.DirName().Append("odm_build.prop")));
EXPECT_FALSE(
base::PathExists(dest_prop_file.DirName().Append("product_build.prop")));
EXPECT_TRUE(base::PathExists(dest_prop_file));
// Verify the content.
std::string content;
EXPECT_TRUE(base::ReadFileToString(dest_prop_file, &content));
// Don't include kDefaultPropNonRo since that one should be filtered out.
EXPECT_EQ(base::StringPrintf("%s%s%s%s%s%s", kDefaultProp, kBuildProp,
kSystemExtBuildProp, kVendorBuildProp,
kOdmBuildProp, kProductBuildProp),
content);
// Expand it again, verify the previous result is cleared.
EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_prop_file, true, false));
EXPECT_TRUE(base::ReadFileToString(dest_prop_file, &content));
EXPECT_EQ(base::StringPrintf("%s%s%s%s%s%s", kDefaultProp, kBuildProp,
kSystemExtBuildProp, kVendorBuildProp,
kOdmBuildProp, kProductBuildProp),
content);
// If optional ones e.g. default.prop does not exist in the source path, it
// should still process the other files.
base::DeleteFile(source_dir.Append("default.prop"));
base::DeleteFile(source_dir.Append("odm_build.prop"));
EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_prop_file, true, false));
EXPECT_TRUE(base::ReadFileToString(dest_prop_file, &content));
EXPECT_EQ(base::StringPrintf("%s%s%s%s", kBuildProp, kSystemExtBuildProp,
kVendorBuildProp, kProductBuildProp),
content);
// Finally, test the case where source is valid but the dest is not.
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"
"ro.vendor.product.cpu.abilist=x86_64,x86,armeabi-v7a,armeabi\n"
"ro.vendor.product.cpu.abilist64=x86_64\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 kBuildPropModifiedFirst[] =
"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";
constexpr const char kBuildPropModifiedSecond[] =
"ro.dalvik.vm.isa.arm64=x86_64\n";
EXPECT_EQ(base::StringPrintf("%s\n%s", kBuildPropModifiedFirst,
kBuildPropModifiedSecond),
content);
EXPECT_TRUE(
base::ReadFileToString(dest_dir.Append("vendor_build.prop"), &content));
constexpr const char kVendorBuildPropModified[] =
"ro.a=b\n"
"ro.vendor.product.cpu.abilist=x86_64,x86,arm64-v8a,armeabi-v7a,armeabi\n"
"ro.vendor.product.cpu.abilist64=x86_64,arm64-v8a\n";
EXPECT_EQ(std::string(kVendorBuildPropModified) + "\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%s%s%s", kDefaultProp, kBuildPropModifiedFirst,
kBuildPropModifiedSecond, kVendorBuildPropModified),
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));
}
// Verify that comments and non ro. properties are not written.
TEST_F(ArcPropertyUtilTest, ExpandPropertyFiles_SingleFile_NonRo) {
base::FilePath source_dir;
ASSERT_TRUE(base::CreateTemporaryDirInDir(GetTempDir(), "test", &source_dir));
base::FilePath dest_dir;
ASSERT_TRUE(base::CreateTemporaryDirInDir(GetTempDir(), "test", &dest_dir));
const base::FilePath default_prop = source_dir.Append("default.prop");
constexpr const char kDefaultProp[] = "###\ndalvik.foo=bar\nro.foo=bar\n";
base::WriteFile(default_prop, kDefaultProp, strlen(kDefaultProp));
const base::FilePath build_prop = source_dir.Append("build.prop");
constexpr const char kBuildProp[] = "###\ndalvik.baz=boo\nro.baz=boo\n";
base::WriteFile(build_prop, kBuildProp, strlen(kBuildProp));
const base::FilePath vendor_build_prop =
source_dir.Append("vendor_build.prop");
constexpr const char kVendorBuildProp[] = "###\ndalvik.a=b\nro.a=b\n";
base::WriteFile(vendor_build_prop, kVendorBuildProp,
strlen(kVendorBuildProp));
const base::FilePath dest_prop_file = dest_dir.Append("combined.prop");
EXPECT_TRUE(ExpandPropertyFiles(source_dir, dest_prop_file, true, false));
// Verify the content.
std::string content;
EXPECT_TRUE(base::ReadFileToString(dest_prop_file, &content));
EXPECT_EQ("ro.foo=bar\nro.baz=boo\nro.a=b\n", content);
}
} // namespace
} // namespace arc
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/arc/test/fake_cros_config.h"
namespace arc {
FakeCrosConfig::FakeCrosConfig() = default;
FakeCrosConfig::~FakeCrosConfig() = default;
bool FakeCrosConfig::GetString(const std::string& path,
const std::string& property,
std::string* val_out) {
auto it = overrides_.find(property);
if (it != overrides_.end()) {
*val_out = it->second;
return true;
}
return arc::CrosConfig::GetString(path, property, val_out);
}
void FakeCrosConfig::SetString(const std::string& path,
const std::string& property,
const std::string& value) {
overrides_.emplace(property, value);
}
} // namespace arc
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_ARC_TEST_FAKE_CROS_CONFIG_H_
#define COMPONENTS_ARC_TEST_FAKE_CROS_CONFIG_H_
#include <map>
#include <string>
#include "components/arc/session/arc_property_util.h"
namespace arc {
// A fake arc::CrosConfig used for testing.
class FakeCrosConfig : public arc::CrosConfig {
public:
FakeCrosConfig();
~FakeCrosConfig() override;
FakeCrosConfig(const FakeCrosConfig&) = delete;
FakeCrosConfig& operator=(const FakeCrosConfig&) = delete;
// arc::CrosConfig:
bool GetString(const std::string& path,
const std::string& property,
std::string* val_out) override;
// Sets the value of a property specified by |path| and |property| to |value|.
void SetString(const std::string& path,
const std::string& property,
const std::string& value);
private:
// A map of overridden properties to their values.
std::map<std::string, std::string> overrides_;
};
} // namespace arc
#endif // COMPONENTS_ARC_TEST_FAKE_CROS_CONFIG_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment