8a311631ed
We need to be able to store build fingerprints that are over 92 characters long, which is the current restriction for system property value length. Increasing the value maximum across the board has plenty of caveats, particularly that an allocator would be required to handle deallocation when replacing long property values with short values. There is also no compelling reasons to do this. But, increasing the length of simply read-only properties, such as the build fingerprint, has less caveats as there will never be a deallocation of these strings. This change uses spare bits in the top of serial (only spare for read-only properties) to indicate if a property is 'long' or not. The information required to access these 'long' properties is stored in a union where the legacy property value is located. An error message is retained for legacy callers. The new property is readable via __system_property_read_callback() and most importantly android::base::GetProperty and higher level (Java, `getprop`) callers. All code should move to these higher level functions as much as possible. Bug: 23102347 Bug: 34954705 Test: bionic unit tests Change-Id: Ia85e0d979b92afff601cc52b39114379617a0c64
542 lines
18 KiB
C++
542 lines
18 KiB
C++
/*
|
|
* Copyright (C) 2013 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.
|
|
*/
|
|
|
|
#include <gtest/gtest.h>
|
|
#include "BionicDeathTest.h"
|
|
|
|
#include <errno.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
|
|
#include <string>
|
|
#include <thread>
|
|
|
|
using namespace std::literals;
|
|
|
|
#if defined(__BIONIC__)
|
|
|
|
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
|
|
#include <sys/_system_properties.h>
|
|
|
|
struct LocalPropertyTestState {
|
|
LocalPropertyTestState() : valid(false) {
|
|
const char* ANDROID_DATA = getenv("ANDROID_DATA");
|
|
char dir_template[PATH_MAX];
|
|
snprintf(dir_template, sizeof(dir_template), "%s/local/tmp/prop-XXXXXX", ANDROID_DATA);
|
|
char* dirname = mkdtemp(dir_template);
|
|
if (!dirname) {
|
|
fprintf(stderr, "making temp file for test state failed (is %s writable?): %s",
|
|
dir_template, strerror(errno));
|
|
return;
|
|
}
|
|
|
|
pa_dirname = dirname;
|
|
pa_filename = pa_dirname + "/__properties__";
|
|
|
|
__system_property_set_filename(pa_filename.c_str());
|
|
__system_property_area_init();
|
|
valid = true;
|
|
}
|
|
|
|
~LocalPropertyTestState() {
|
|
if (!valid) {
|
|
return;
|
|
}
|
|
|
|
__system_property_set_filename(PROP_FILENAME);
|
|
__system_properties_init();
|
|
unlink(pa_filename.c_str());
|
|
rmdir(pa_dirname.c_str());
|
|
}
|
|
public:
|
|
bool valid;
|
|
private:
|
|
std::string pa_dirname;
|
|
std::string pa_filename;
|
|
};
|
|
|
|
static void foreach_test_callback(const prop_info *pi, void* cookie) {
|
|
size_t *count = static_cast<size_t *>(cookie);
|
|
|
|
ASSERT_TRUE(pi != nullptr);
|
|
(*count)++;
|
|
}
|
|
|
|
static void hierarchical_test_callback(const prop_info *pi, void *cookie) {
|
|
bool (*ok)[8][8] = static_cast<bool (*)[8][8]>(cookie);
|
|
|
|
char name[PROP_NAME_MAX];
|
|
char value[PROP_VALUE_MAX];
|
|
|
|
__system_property_read(pi, name, value);
|
|
|
|
int name_i, name_j, name_k;
|
|
int value_i, value_j, value_k;
|
|
ASSERT_EQ(3, sscanf(name, "property_%d.%d.%d", &name_i, &name_j, &name_k));
|
|
ASSERT_EQ(3, sscanf(value, "value_%d.%d.%d", &value_i, &value_j, &value_k));
|
|
ASSERT_EQ(name_i, value_i);
|
|
ASSERT_GE(name_i, 0);
|
|
ASSERT_LT(name_i, 8);
|
|
ASSERT_EQ(name_j, value_j);
|
|
ASSERT_GE(name_j, 0);
|
|
ASSERT_LT(name_j, 8);
|
|
ASSERT_EQ(name_k, value_k);
|
|
ASSERT_GE(name_k, 0);
|
|
ASSERT_LT(name_k, 8);
|
|
|
|
ok[name_i][name_j][name_k] = true;
|
|
}
|
|
|
|
static void* PropertyWaitHelperFn(void* arg) {
|
|
int* flag = static_cast<int*>(arg);
|
|
prop_info* pi = const_cast<prop_info*>(__system_property_find("property"));
|
|
usleep(100000);
|
|
|
|
*flag = 1;
|
|
__system_property_update(pi, "value3", 6);
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
#endif // __BIONIC__
|
|
|
|
TEST(properties, __system_property_add) {
|
|
#if defined(__BIONIC__)
|
|
LocalPropertyTestState pa;
|
|
ASSERT_TRUE(pa.valid);
|
|
|
|
ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6));
|
|
ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6));
|
|
ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6));
|
|
|
|
// check that there is no limit on property name length
|
|
char name[PROP_NAME_MAX + 11];
|
|
name[0] = 'p';
|
|
for (size_t i = 1; i < sizeof(name); i++) {
|
|
name[i] = 'x';
|
|
}
|
|
|
|
name[sizeof(name)-1] = '\0';
|
|
ASSERT_EQ(0, __system_property_add(name, strlen(name), "value", 5));
|
|
|
|
char propvalue[PROP_VALUE_MAX];
|
|
ASSERT_EQ(6, __system_property_get("property", propvalue));
|
|
ASSERT_STREQ(propvalue, "value1");
|
|
|
|
ASSERT_EQ(6, __system_property_get("other_property", propvalue));
|
|
ASSERT_STREQ(propvalue, "value2");
|
|
|
|
ASSERT_EQ(6, __system_property_get("property_other", propvalue));
|
|
ASSERT_STREQ(propvalue, "value3");
|
|
|
|
ASSERT_EQ(5, __system_property_get(name, propvalue));
|
|
ASSERT_STREQ(propvalue, "value");
|
|
#else // __BIONIC__
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif // __BIONIC__
|
|
}
|
|
|
|
TEST(properties, __system_property_update) {
|
|
#if defined(__BIONIC__)
|
|
LocalPropertyTestState pa;
|
|
ASSERT_TRUE(pa.valid);
|
|
|
|
ASSERT_EQ(0, __system_property_add("property", 8, "oldvalue1", 9));
|
|
ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6));
|
|
ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6));
|
|
|
|
const prop_info* pi = __system_property_find("property");
|
|
ASSERT_TRUE(pi != nullptr);
|
|
__system_property_update(const_cast<prop_info*>(pi), "value4", 6);
|
|
|
|
pi = __system_property_find("other_property");
|
|
ASSERT_TRUE(pi != nullptr);
|
|
__system_property_update(const_cast<prop_info*>(pi), "newvalue5", 9);
|
|
|
|
pi = __system_property_find("property_other");
|
|
ASSERT_TRUE(pi != nullptr);
|
|
__system_property_update(const_cast<prop_info*>(pi), "value6", 6);
|
|
|
|
char propvalue[PROP_VALUE_MAX];
|
|
ASSERT_EQ(6, __system_property_get("property", propvalue));
|
|
ASSERT_STREQ(propvalue, "value4");
|
|
|
|
ASSERT_EQ(9, __system_property_get("other_property", propvalue));
|
|
ASSERT_STREQ(propvalue, "newvalue5");
|
|
|
|
ASSERT_EQ(6, __system_property_get("property_other", propvalue));
|
|
ASSERT_STREQ(propvalue, "value6");
|
|
#else // __BIONIC__
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif // __BIONIC__
|
|
}
|
|
|
|
TEST(properties, fill) {
|
|
#if defined(__BIONIC__)
|
|
LocalPropertyTestState pa;
|
|
ASSERT_TRUE(pa.valid);
|
|
char prop_name[PROP_NAME_MAX];
|
|
char prop_value[PROP_VALUE_MAX];
|
|
char prop_value_ret[PROP_VALUE_MAX];
|
|
int count = 0;
|
|
int ret;
|
|
|
|
while (true) {
|
|
ret = snprintf(prop_name, PROP_NAME_MAX - 1, "property_%d", count);
|
|
memset(prop_name + ret, 'a', PROP_NAME_MAX - 1 - ret);
|
|
ret = snprintf(prop_value, PROP_VALUE_MAX - 1, "value_%d", count);
|
|
memset(prop_value + ret, 'b', PROP_VALUE_MAX - 1 - ret);
|
|
prop_name[PROP_NAME_MAX - 1] = 0;
|
|
prop_value[PROP_VALUE_MAX - 1] = 0;
|
|
|
|
ret = __system_property_add(prop_name, PROP_NAME_MAX - 1, prop_value, PROP_VALUE_MAX - 1);
|
|
if (ret < 0)
|
|
break;
|
|
|
|
count++;
|
|
}
|
|
|
|
// For historical reasons at least 247 properties must be supported
|
|
ASSERT_GE(count, 247);
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
ret = snprintf(prop_name, PROP_NAME_MAX - 1, "property_%d", i);
|
|
memset(prop_name + ret, 'a', PROP_NAME_MAX - 1 - ret);
|
|
ret = snprintf(prop_value, PROP_VALUE_MAX - 1, "value_%d", i);
|
|
memset(prop_value + ret, 'b', PROP_VALUE_MAX - 1 - ret);
|
|
prop_name[PROP_NAME_MAX - 1] = 0;
|
|
prop_value[PROP_VALUE_MAX - 1] = 0;
|
|
memset(prop_value_ret, '\0', PROP_VALUE_MAX);
|
|
|
|
ASSERT_EQ(PROP_VALUE_MAX - 1, __system_property_get(prop_name, prop_value_ret));
|
|
ASSERT_EQ(0, memcmp(prop_value, prop_value_ret, PROP_VALUE_MAX));
|
|
}
|
|
#else // __BIONIC__
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif // __BIONIC__
|
|
}
|
|
|
|
TEST(properties, __system_property_foreach) {
|
|
#if defined(__BIONIC__)
|
|
LocalPropertyTestState pa;
|
|
ASSERT_TRUE(pa.valid);
|
|
|
|
ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6));
|
|
ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6));
|
|
ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6));
|
|
|
|
size_t count = 0;
|
|
ASSERT_EQ(0, __system_property_foreach(foreach_test_callback, &count));
|
|
ASSERT_EQ(3U, count);
|
|
#else // __BIONIC__
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif // __BIONIC__
|
|
}
|
|
|
|
TEST(properties, __system_property_find_nth) {
|
|
#if defined(__BIONIC__)
|
|
LocalPropertyTestState pa;
|
|
ASSERT_TRUE(pa.valid);
|
|
|
|
ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6));
|
|
ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6));
|
|
ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6));
|
|
|
|
char name[PROP_NAME_MAX];
|
|
char value[PROP_VALUE_MAX];
|
|
EXPECT_EQ(6, __system_property_read(__system_property_find_nth(0), name, value));
|
|
EXPECT_STREQ("property", name);
|
|
EXPECT_STREQ("value1", value);
|
|
EXPECT_EQ(6, __system_property_read(__system_property_find_nth(1), name, value));
|
|
EXPECT_STREQ("other_property", name);
|
|
EXPECT_STREQ("value2", value);
|
|
EXPECT_EQ(6, __system_property_read(__system_property_find_nth(2), name, value));
|
|
EXPECT_STREQ("property_other", name);
|
|
EXPECT_STREQ("value3", value);
|
|
|
|
for (unsigned i = 3; i < 1024; ++i) {
|
|
ASSERT_TRUE(__system_property_find_nth(i) == nullptr);
|
|
}
|
|
#else // __BIONIC__
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif // __BIONIC__
|
|
}
|
|
|
|
TEST(properties, fill_hierarchical) {
|
|
#if defined(__BIONIC__)
|
|
LocalPropertyTestState pa;
|
|
ASSERT_TRUE(pa.valid);
|
|
char prop_name[PROP_NAME_MAX];
|
|
char prop_value[PROP_VALUE_MAX];
|
|
char prop_value_ret[PROP_VALUE_MAX];
|
|
int ret;
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
for (int j = 0; j < 8; j++) {
|
|
for (int k = 0; k < 8; k++) {
|
|
ret = snprintf(prop_name, PROP_NAME_MAX - 1, "property_%d.%d.%d", i, j, k);
|
|
memset(prop_name + ret, 'a', PROP_NAME_MAX - 1 - ret);
|
|
ret = snprintf(prop_value, PROP_VALUE_MAX - 1, "value_%d.%d.%d", i, j, k);
|
|
memset(prop_value + ret, 'b', PROP_VALUE_MAX - 1 - ret);
|
|
prop_name[PROP_NAME_MAX - 1] = 0;
|
|
prop_value[PROP_VALUE_MAX - 1] = 0;
|
|
|
|
ASSERT_EQ(0, __system_property_add(prop_name, PROP_NAME_MAX - 1, prop_value, PROP_VALUE_MAX - 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
for (int j = 0; j < 8; j++) {
|
|
for (int k = 0; k < 8; k++) {
|
|
ret = snprintf(prop_name, PROP_NAME_MAX - 1, "property_%d.%d.%d", i, j, k);
|
|
memset(prop_name + ret, 'a', PROP_NAME_MAX - 1 - ret);
|
|
ret = snprintf(prop_value, PROP_VALUE_MAX - 1, "value_%d.%d.%d", i, j, k);
|
|
memset(prop_value + ret, 'b', PROP_VALUE_MAX - 1 - ret);
|
|
prop_name[PROP_NAME_MAX - 1] = 0;
|
|
prop_value[PROP_VALUE_MAX - 1] = 0;
|
|
memset(prop_value_ret, '\0', PROP_VALUE_MAX);
|
|
|
|
ASSERT_EQ(PROP_VALUE_MAX - 1, __system_property_get(prop_name, prop_value_ret));
|
|
ASSERT_EQ(0, memcmp(prop_value, prop_value_ret, PROP_VALUE_MAX));
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ok[8][8][8];
|
|
memset(ok, 0, sizeof(ok));
|
|
__system_property_foreach(hierarchical_test_callback, ok);
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
for (int j = 0; j < 8; j++) {
|
|
for (int k = 0; k < 8; k++) {
|
|
ASSERT_TRUE(ok[i][j][k]);
|
|
}
|
|
}
|
|
}
|
|
#else // __BIONIC__
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif // __BIONIC__
|
|
}
|
|
|
|
TEST(properties, errors) {
|
|
#if defined(__BIONIC__)
|
|
LocalPropertyTestState pa;
|
|
ASSERT_TRUE(pa.valid);
|
|
char prop_value[PROP_NAME_MAX];
|
|
|
|
ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6));
|
|
ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6));
|
|
ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6));
|
|
|
|
ASSERT_EQ(0, __system_property_find("property1"));
|
|
ASSERT_EQ(0, __system_property_get("property1", prop_value));
|
|
|
|
ASSERT_EQ(-1, __system_property_add("name", 4, "value", PROP_VALUE_MAX));
|
|
ASSERT_EQ(-1, __system_property_update(NULL, "value", PROP_VALUE_MAX));
|
|
#else // __BIONIC__
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif // __BIONIC__
|
|
}
|
|
|
|
TEST(properties, __system_property_serial) {
|
|
#if defined(__BIONIC__)
|
|
LocalPropertyTestState pa;
|
|
ASSERT_TRUE(pa.valid);
|
|
|
|
ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6));
|
|
const prop_info* pi = __system_property_find("property");
|
|
ASSERT_TRUE(pi != nullptr);
|
|
unsigned serial = __system_property_serial(pi);
|
|
ASSERT_EQ(0, __system_property_update(const_cast<prop_info*>(pi), "value2", 6));
|
|
ASSERT_NE(serial, __system_property_serial(pi));
|
|
#else // __BIONIC__
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif // __BIONIC__
|
|
}
|
|
|
|
TEST(properties, __system_property_wait_any) {
|
|
#if defined(__BIONIC__)
|
|
LocalPropertyTestState pa;
|
|
ASSERT_TRUE(pa.valid);
|
|
|
|
ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6));
|
|
unsigned serial = __system_property_wait_any(0);
|
|
|
|
prop_info* pi = const_cast<prop_info*>(__system_property_find("property"));
|
|
ASSERT_TRUE(pi != nullptr);
|
|
__system_property_update(pi, "value2", 6);
|
|
serial = __system_property_wait_any(serial);
|
|
|
|
int flag = 0;
|
|
pthread_t t;
|
|
ASSERT_EQ(0, pthread_create(&t, nullptr, PropertyWaitHelperFn, &flag));
|
|
ASSERT_EQ(flag, 0);
|
|
serial = __system_property_wait_any(serial);
|
|
ASSERT_EQ(flag, 1);
|
|
|
|
ASSERT_EQ(0, pthread_join(t, nullptr));
|
|
#else // __BIONIC__
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif // __BIONIC__
|
|
}
|
|
|
|
TEST(properties, __system_property_wait) {
|
|
#if defined(__BIONIC__)
|
|
LocalPropertyTestState pa;
|
|
ASSERT_TRUE(pa.valid);
|
|
|
|
ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6));
|
|
|
|
prop_info* pi = const_cast<prop_info*>(__system_property_find("property"));
|
|
ASSERT_TRUE(pi != nullptr);
|
|
|
|
unsigned serial = __system_property_serial(pi);
|
|
|
|
std::thread thread([]() {
|
|
prop_info* pi = const_cast<prop_info*>(__system_property_find("property"));
|
|
ASSERT_TRUE(pi != nullptr);
|
|
|
|
__system_property_update(pi, "value2", 6);
|
|
});
|
|
|
|
uint32_t new_serial;
|
|
__system_property_wait(pi, serial, &new_serial, nullptr);
|
|
ASSERT_GT(new_serial, serial);
|
|
|
|
char value[PROP_VALUE_MAX];
|
|
ASSERT_EQ(6, __system_property_get("property", value));
|
|
ASSERT_STREQ("value2", value);
|
|
|
|
thread.join();
|
|
#else // __BIONIC__
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif // __BIONIC__
|
|
}
|
|
|
|
class KilledByFault {
|
|
public:
|
|
explicit KilledByFault() {};
|
|
bool operator()(int exit_status) const;
|
|
};
|
|
|
|
bool KilledByFault::operator()(int exit_status) const {
|
|
return WIFSIGNALED(exit_status) &&
|
|
(WTERMSIG(exit_status) == SIGSEGV ||
|
|
WTERMSIG(exit_status) == SIGBUS ||
|
|
WTERMSIG(exit_status) == SIGABRT);
|
|
}
|
|
|
|
class properties_DeathTest : public BionicDeathTest {};
|
|
|
|
TEST_F(properties_DeathTest, read_only) {
|
|
#if defined(__BIONIC__)
|
|
|
|
// 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_EXIT(__system_property_add("property", 8, "value", 5), KilledByFault(), "");
|
|
#else // __BIONIC__
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif // __BIONIC__
|
|
}
|
|
|
|
TEST(properties, __system_property_extra_long_read_only) {
|
|
#if defined(__BIONIC__)
|
|
LocalPropertyTestState pa;
|
|
ASSERT_TRUE(pa.valid);
|
|
|
|
std::vector<std::pair<std::string, std::string>> short_properties = {
|
|
{ "ro.0char", std::string() },
|
|
{ "ro.50char", std::string(50, 'x') },
|
|
{ "ro.91char", std::string(91, 'x') },
|
|
};
|
|
|
|
std::vector<std::pair<std::string, std::string>> long_properties = {
|
|
{ "ro.92char", std::string(92, 'x') },
|
|
{ "ro.93char", std::string(93, 'x') },
|
|
{ "ro.1000char", std::string(1000, 'x') },
|
|
};
|
|
|
|
for (const auto& property : short_properties) {
|
|
const std::string& name = property.first;
|
|
const std::string& value = property.second;
|
|
ASSERT_EQ(0, __system_property_add(name.c_str(), name.size(), value.c_str(), value.size()));
|
|
}
|
|
|
|
for (const auto& property : long_properties) {
|
|
const std::string& name = property.first;
|
|
const std::string& value = property.second;
|
|
ASSERT_EQ(0, __system_property_add(name.c_str(), name.size(), value.c_str(), value.size()));
|
|
}
|
|
|
|
auto check_with_legacy_read = [](const std::string& name, const std::string& expected_value) {
|
|
char value[PROP_VALUE_MAX];
|
|
EXPECT_EQ(static_cast<int>(expected_value.size()), __system_property_get(name.c_str(), value))
|
|
<< name;
|
|
EXPECT_EQ(expected_value, value) << name;
|
|
};
|
|
|
|
auto check_with_read_callback = [](const std::string& name, const std::string& expected_value) {
|
|
const prop_info* pi = __system_property_find(name.c_str());
|
|
ASSERT_NE(nullptr, pi);
|
|
std::string value;
|
|
__system_property_read_callback(pi,
|
|
[](void* cookie, const char*, const char* value, uint32_t) {
|
|
std::string* out_value =
|
|
reinterpret_cast<std::string*>(cookie);
|
|
*out_value = value;
|
|
},
|
|
&value);
|
|
EXPECT_EQ(expected_value, value) << name;
|
|
};
|
|
|
|
for (const auto& property : short_properties) {
|
|
const std::string& name = property.first;
|
|
const std::string& value = property.second;
|
|
check_with_legacy_read(name, value);
|
|
check_with_read_callback(name, value);
|
|
}
|
|
|
|
constexpr static const char* kExtraLongLegacyError =
|
|
"Must use __system_property_read_callback() to read";
|
|
for (const auto& property : long_properties) {
|
|
const std::string& name = property.first;
|
|
const std::string& value = property.second;
|
|
check_with_legacy_read(name, kExtraLongLegacyError);
|
|
check_with_read_callback(name, value);
|
|
}
|
|
|
|
#else // __BIONIC__
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif // __BIONIC__
|
|
}
|
|
|
|
// pa_size is 128 * 1024 currently, if a property is longer then we expect it to fail gracefully.
|
|
TEST(properties, __system_property_extra_long_read_only_too_long) {
|
|
#if defined(__BIONIC__)
|
|
LocalPropertyTestState pa;
|
|
ASSERT_TRUE(pa.valid);
|
|
|
|
auto name = "ro.super_long_property"s;
|
|
auto value = std::string(128 * 1024 + 1, 'x');
|
|
ASSERT_NE(0, __system_property_add(name.c_str(), name.size(), value.c_str(), value.size()));
|
|
|
|
#else // __BIONIC__
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif // __BIONIC__
|
|
}
|