Write appcompat_override system properties
Create a second set of system properties, that can be overlaid over the
real ones if necessary, for appcompat purposes.
Bug: 291814949
Ignore-AOSP-First: Aosp -> internal merge conflict
Test: manual, treehugger, system_properties_test
Change-Id: I541d3658cab7753c16970957c6ab4fc8bd68d8f3
Merged-In: I884a78b67679c1f0b90a6c0159b17ab007f8cc60
diff --git a/tests/system_properties_test.cpp b/tests/system_properties_test.cpp
index b1dfe0b..960f689 100644
--- a/tests/system_properties_test.cpp
+++ b/tests/system_properties_test.cpp
@@ -25,6 +25,9 @@
#include <android-base/file.h>
#include <android-base/silent_death_test.h>
+#include <android-base/stringprintf.h>
+
+#include "utils.h"
using namespace std::literals;
@@ -32,24 +35,34 @@
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
+#include <sys/mount.h>
#include <system_properties/system_properties.h>
class SystemPropertiesTest : public SystemProperties {
public:
SystemPropertiesTest() : SystemProperties(false) {
- valid_ = AreaInit(dir_.path, nullptr);
+ appcompat_path = android::base::StringPrintf("%s/appcompat_override", dir_.path);
+ mkdir(appcompat_path.c_str(), S_IRWXU | S_IXGRP | S_IXOTH);
+ valid_ = AreaInit(dir_.path, nullptr, true);
}
~SystemPropertiesTest() {
if (valid_) {
contexts_->FreeAndUnmap();
}
+ umount(dir_.path);
}
bool valid() const {
return valid_;
}
+ const char* get_path() const { return dir_.path; }
+
+ const char* get_appcompat_path() const { return appcompat_path.c_str(); }
+
+ std::string appcompat_path;
+
private:
TemporaryDir dir_;
bool valid_;
@@ -125,6 +138,58 @@
#endif // __BIONIC__
}
+TEST(properties, __system_property_add_appcompat) {
+#if defined(__BIONIC__)
+ if (getuid() != 0) GTEST_SKIP() << "test requires root";
+ SystemPropertiesTest system_properties;
+ ASSERT_TRUE(system_properties.valid());
+
+ char name[] = "ro.property";
+ char override_name[] = "ro.appcompat_override.ro.property";
+ char name_not_written[] = "ro.property_other";
+ char override_with_no_real[] = "ro.appcompat_override.ro.property_other";
+ ASSERT_EQ(0, system_properties.Add(name, strlen(name), "value1", 6));
+ ASSERT_EQ(0, system_properties.Add(override_name, strlen(override_name), "value2", 6));
+ ASSERT_EQ(0, system_properties.Add(override_with_no_real, strlen(override_with_no_real),
+ "value3", 6));
+
+ char propvalue[PROP_VALUE_MAX];
+ ASSERT_EQ(6, system_properties.Get(name, propvalue));
+ ASSERT_STREQ(propvalue, "value1");
+
+ ASSERT_EQ(6, system_properties.Get(override_name, propvalue));
+ ASSERT_STREQ(propvalue, "value2");
+
+ ASSERT_EQ(0, system_properties.Get(name_not_written, propvalue));
+ ASSERT_STREQ(propvalue, "");
+
+ ASSERT_EQ(6, system_properties.Get(override_with_no_real, propvalue));
+ ASSERT_STREQ(propvalue, "value3");
+
+ int ret = mount(system_properties.get_appcompat_path(), system_properties.get_path(), nullptr,
+ MS_BIND | MS_REC, nullptr);
+ if (ret != 0) {
+ ASSERT_ERRNO(0);
+ }
+ system_properties.Reload(true);
+
+ ASSERT_EQ(6, system_properties.Get(name, propvalue));
+ ASSERT_STREQ(propvalue, "value2");
+
+ ASSERT_EQ(0, system_properties.Get(override_name, propvalue));
+ ASSERT_STREQ(propvalue, "");
+
+ ASSERT_EQ(6, system_properties.Get(name_not_written, propvalue));
+ ASSERT_STREQ(propvalue, "value3");
+
+ ASSERT_EQ(0, system_properties.Get(override_with_no_real, propvalue));
+ ASSERT_STREQ(propvalue, "");
+
+#else // __BIONIC__
+ GTEST_SKIP() << "bionic-only test";
+#endif // __BIONIC__
+}
+
TEST(properties, __system_property_update) {
#if defined(__BIONIC__)
SystemPropertiesTest system_properties;
@@ -432,7 +497,7 @@
// This test only makes sense if we're talking to the real system property service.
struct stat sb;
- ASSERT_FALSE(stat(PROP_FILENAME, &sb) == -1 && errno == ENOENT);
+ ASSERT_FALSE(stat(PROP_DIRNAME, &sb) == -1 && errno == ENOENT);
ASSERT_EXIT(__system_property_add("property", 8, "value", 5), KilledByFault(), "");
#else // __BIONIC__