Merge "Split properties into their own class to make testing better"
diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp
index c7c8a29..be61eda 100644
--- a/benchmarks/Android.bp
+++ b/benchmarks/Android.bp
@@ -61,6 +61,11 @@
name: "bionic-benchmarks",
defaults: ["bionic-benchmarks-defaults"],
data: ["suites/*"],
+ static_libs: [
+ "libsystemproperties",
+ "libasync_safe",
+ ],
+ include_dirs: ["bionic/libc",],
}
// We don't build a static benchmark executable because it's not usually
diff --git a/benchmarks/property_benchmark.cpp b/benchmarks/property_benchmark.cpp
index 5760bf1..9868765 100644
--- a/benchmarks/property_benchmark.cpp
+++ b/benchmarks/property_benchmark.cpp
@@ -21,37 +21,28 @@
#include <string>
+#include <android-base/test_utils.h>
+
+using namespace std::literals;
+
#if defined(__BIONIC__)
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
#include <benchmark/benchmark.h>
+#include <system_properties/system_properties.h>
#include "util.h"
struct LocalPropertyTestState {
- explicit LocalPropertyTestState(int nprops) : nprops(nprops), valid(false) {
+ explicit LocalPropertyTestState(int nprops)
+ : nprops(nprops), valid(false), system_properties_(false) {
static const char prop_name_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.";
- const char* android_data = getenv("ANDROID_DATA");
- if (android_data == NULL) {
- printf("ANDROID_DATA environment variable not set\n");
+ valid = system_properties_.AreaInit(dir_.path, nullptr);
+ if (!valid) {
return;
}
- 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) {
- printf("making temp file for test state failed (is %s/local/tmp writable?): %s\n",
- android_data, strerror(errno));
- return;
- }
-
- pa_dirname = dirname;
- pa_filename = pa_dirname + "/__properties__";
-
- __system_property_set_filename(pa_filename.c_str());
- __system_property_area_init();
names = new char* [nprops];
name_lens = new int[nprops];
@@ -88,7 +79,7 @@
values[i][j] = prop_name_chars[random() % (sizeof(prop_name_chars) - 1)];
}
- if (__system_property_add(names[i], name_lens[i], values[i], value_lens[i]) < 0) {
+ if (system_properties_.Add(names[i], name_lens[i], values[i], value_lens[i]) < 0) {
printf("Failed to add a property, terminating...\n");
printf("%s = %.*s\n", names[i], value_lens[i], values[i]);
exit(1);
@@ -98,14 +89,16 @@
valid = true;
}
- ~LocalPropertyTestState() {
- if (!valid)
- return;
+ SystemProperties& system_properties() {
+ return system_properties_;
+ }
- __system_property_set_filename(PROP_FILENAME);
- __system_property_area_init();
- unlink(pa_filename.c_str());
- rmdir(pa_dirname.c_str());
+ ~LocalPropertyTestState() {
+ if (!valid) {
+ return;
+ }
+
+ system_properties_.contexts()->FreeAndUnmap();
for (int i = 0; i < nprops; i++) {
delete names[i];
@@ -126,8 +119,8 @@
bool valid;
private:
- std::string pa_dirname;
- std::string pa_filename;
+ SystemProperties system_properties_;
+ TemporaryDir dir_;
};
static void BM_property_get(benchmark::State& state) {
@@ -138,7 +131,7 @@
while (state.KeepRunning()) {
char value[PROP_VALUE_MAX];
- __system_property_get(pa.names[random() % nprops], value);
+ pa.system_properties().Get(pa.names[random() % nprops], value);
}
}
BIONIC_BENCHMARK_WITH_ARG(BM_property_get, "NUM_PROPS");
@@ -150,7 +143,7 @@
if (!pa.valid) return;
while (state.KeepRunning()) {
- __system_property_find(pa.names[random() % nprops]);
+ pa.system_properties().Find(pa.names[random() % nprops]);
}
}
BIONIC_BENCHMARK_WITH_ARG(BM_property_find, "NUM_PROPS");
@@ -165,12 +158,12 @@
char propvalue[PROP_VALUE_MAX];
for (size_t i = 0; i < nprops; ++i) {
- pinfo[i] = __system_property_find(pa.names[random() % nprops]);
+ pinfo[i] = pa.system_properties().Find(pa.names[random() % nprops]);
}
size_t i = 0;
while (state.KeepRunning()) {
- __system_property_read(pinfo[i], 0, propvalue);
+ pa.system_properties().Read(pinfo[i], 0, propvalue);
i = (i + 1) % nprops;
}
@@ -186,12 +179,12 @@
const prop_info** pinfo = new const prop_info*[nprops];
for (size_t i = 0; i < nprops; ++i) {
- pinfo[i] = __system_property_find(pa.names[random() % nprops]);
+ pinfo[i] = pa.system_properties().Find(pa.names[random() % nprops]);
}
size_t i = 0;
while (state.KeepRunning()) {
- __system_property_serial(pinfo[i]);
+ pa.system_properties().Serial(pinfo[i]);
i = (i + 1) % nprops;
}
diff --git a/libc/Android.bp b/libc/Android.bp
index 1017fa5..4db4f56 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1387,6 +1387,8 @@
"bionic/sys_time.cpp",
"bionic/sysinfo.cpp",
"bionic/syslog.cpp",
+ "bionic/system_property_api.cpp",
+ "bionic/system_property_set.cpp",
"bionic/tdestroy.cpp",
"bionic/termios.cpp",
"bionic/thread_private.cpp",
@@ -1400,13 +1402,6 @@
"bionic/wctype.cpp",
"bionic/wcwidth.cpp",
"bionic/wmempcpy.cpp",
- "system_properties/context_node.cpp",
- "system_properties/contexts_split.cpp",
- "system_properties/contexts_serialized.cpp",
- "system_properties/prop_area.cpp",
- "system_properties/prop_info.cpp",
- "system_properties/system_properties.cpp",
-
// This contains a weak stub implementation of __find_icu_symbol for wctype.cpp,
// which will be overridden by the actual one in libc.so.
@@ -1424,7 +1419,7 @@
cflags: ["-DTREBLE_LINKER_NAMESPACES"],
},
},
- whole_static_libs: ["libpropertyinfoparser"],
+ whole_static_libs: ["libsystemproperties"],
cppflags: ["-Wold-style-cast"],
local_include_dirs: ["stdio"],
include_dirs: ["bionic/libstdc++/include"],
diff --git a/libc/bionic/system_property_api.cpp b/libc/bionic/system_property_api.cpp
new file mode 100644
index 0000000..f2e1032
--- /dev/null
+++ b/libc/bionic/system_property_api.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
+#include <system_properties/prop_area.h>
+#include <system_properties/system_properties.h>
+
+#include "private/bionic_defs.h"
+
+static SystemProperties system_properties;
+
+// This is public because it was exposed in the NDK. As of 2017-01, ~60 apps reference this symbol.
+// It is set to nullptr and never modified.
+__BIONIC_WEAK_VARIABLE_FOR_NATIVE_BRIDGE
+prop_area* __system_property_area__ = nullptr;
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+int __system_properties_init() {
+ return system_properties.Init(PROP_FILENAME) ? 0 : -1;
+}
+
+// This was previously for testing, but now that SystemProperties is its own testable class,
+// there is never a reason to call this function.
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+int __system_property_set_filename(const char*) {
+ return -1;
+}
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+int __system_property_area_init() {
+ bool fsetxattr_failed = false;
+ return system_properties.AreaInit(PROP_FILENAME, &fsetxattr_failed) && !fsetxattr_failed ? 0 : -1;
+}
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+uint32_t __system_property_area_serial() {
+ return system_properties.AreaSerial();
+}
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+const prop_info* __system_property_find(const char* name) {
+ return system_properties.Find(name);
+}
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+int __system_property_read(const prop_info* pi, char* name, char* value) {
+ return system_properties.Read(pi, name, value);
+}
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+void __system_property_read_callback(const prop_info* pi,
+ void (*callback)(void* cookie, const char* name,
+ const char* value, uint32_t serial),
+ void* cookie) {
+ return system_properties.ReadCallback(pi, callback, cookie);
+}
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+int __system_property_get(const char* name, char* value) {
+ return system_properties.Get(name, value);
+}
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+int __system_property_update(prop_info* pi, const char* value, unsigned int len) {
+ return system_properties.Update(pi, value, len);
+}
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+int __system_property_add(const char* name, unsigned int namelen, const char* value,
+ unsigned int valuelen) {
+ return system_properties.Add(name, namelen, value, valuelen);
+}
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+uint32_t __system_property_serial(const prop_info* pi) {
+ return system_properties.Serial(pi);
+}
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+uint32_t __system_property_wait_any(uint32_t old_serial) {
+ return system_properties.WaitAny(old_serial);
+}
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+bool __system_property_wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr,
+ const timespec* relative_timeout) {
+ return system_properties.Wait(pi, old_serial, new_serial_ptr, relative_timeout);
+}
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+const prop_info* __system_property_find_nth(unsigned n) {
+ return system_properties.FindNth(n);
+}
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+int __system_property_foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
+ return system_properties.Foreach(propfn, cookie);
+}
diff --git a/libc/bionic/system_property_set.cpp b/libc/bionic/system_property_set.cpp
new file mode 100644
index 0000000..a70a376
--- /dev/null
+++ b/libc/bionic/system_property_set.cpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <poll.h>
+#include <stdatomic.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+#include <unistd.h>
+
+#include <async_safe/log.h>
+
+#include "private/bionic_defs.h"
+#include "private/bionic_macros.h"
+
+static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
+static const char* kServiceVersionPropertyName = "ro.property_service.version";
+
+class PropertyServiceConnection {
+ public:
+ PropertyServiceConnection() : last_error_(0) {
+ socket_ = ::socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (socket_ == -1) {
+ last_error_ = errno;
+ return;
+ }
+
+ const size_t namelen = strlen(property_service_socket);
+ sockaddr_un addr;
+ memset(&addr, 0, sizeof(addr));
+ strlcpy(addr.sun_path, property_service_socket, sizeof(addr.sun_path));
+ addr.sun_family = AF_LOCAL;
+ socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
+
+ if (TEMP_FAILURE_RETRY(connect(socket_, reinterpret_cast<sockaddr*>(&addr), alen)) == -1) {
+ last_error_ = errno;
+ close(socket_);
+ socket_ = -1;
+ }
+ }
+
+ bool IsValid() {
+ return socket_ != -1;
+ }
+
+ int GetLastError() {
+ return last_error_;
+ }
+
+ bool RecvInt32(int32_t* value) {
+ int result = TEMP_FAILURE_RETRY(recv(socket_, value, sizeof(*value), MSG_WAITALL));
+ return CheckSendRecvResult(result, sizeof(*value));
+ }
+
+ int socket() {
+ return socket_;
+ }
+
+ ~PropertyServiceConnection() {
+ if (socket_ != -1) {
+ close(socket_);
+ }
+ }
+
+ private:
+ bool CheckSendRecvResult(int result, int expected_len) {
+ if (result == -1) {
+ last_error_ = errno;
+ } else if (result != expected_len) {
+ last_error_ = -1;
+ } else {
+ last_error_ = 0;
+ }
+
+ return last_error_ == 0;
+ }
+
+ int socket_;
+ int last_error_;
+
+ friend class SocketWriter;
+};
+
+class SocketWriter {
+ public:
+ explicit SocketWriter(PropertyServiceConnection* connection)
+ : connection_(connection), iov_index_(0), uint_buf_index_(0) {
+ }
+
+ SocketWriter& WriteUint32(uint32_t value) {
+ CHECK(uint_buf_index_ < kUintBufSize);
+ CHECK(iov_index_ < kIovSize);
+ uint32_t* ptr = uint_buf_ + uint_buf_index_;
+ uint_buf_[uint_buf_index_++] = value;
+ iov_[iov_index_].iov_base = ptr;
+ iov_[iov_index_].iov_len = sizeof(*ptr);
+ ++iov_index_;
+ return *this;
+ }
+
+ SocketWriter& WriteString(const char* value) {
+ uint32_t valuelen = strlen(value);
+ WriteUint32(valuelen);
+ if (valuelen == 0) {
+ return *this;
+ }
+
+ CHECK(iov_index_ < kIovSize);
+ iov_[iov_index_].iov_base = const_cast<char*>(value);
+ iov_[iov_index_].iov_len = valuelen;
+ ++iov_index_;
+
+ return *this;
+ }
+
+ bool Send() {
+ if (!connection_->IsValid()) {
+ return false;
+ }
+
+ if (writev(connection_->socket(), iov_, iov_index_) == -1) {
+ connection_->last_error_ = errno;
+ return false;
+ }
+
+ iov_index_ = uint_buf_index_ = 0;
+ return true;
+ }
+
+ private:
+ static constexpr size_t kUintBufSize = 8;
+ static constexpr size_t kIovSize = 8;
+
+ PropertyServiceConnection* connection_;
+ iovec iov_[kIovSize];
+ size_t iov_index_;
+ uint32_t uint_buf_[kUintBufSize];
+ size_t uint_buf_index_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(SocketWriter);
+};
+
+struct prop_msg {
+ unsigned cmd;
+ char name[PROP_NAME_MAX];
+ char value[PROP_VALUE_MAX];
+};
+
+static int send_prop_msg(const prop_msg* msg) {
+ PropertyServiceConnection connection;
+ if (!connection.IsValid()) {
+ return connection.GetLastError();
+ }
+
+ int result = -1;
+ int s = connection.socket();
+
+ const int num_bytes = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));
+ if (num_bytes == sizeof(prop_msg)) {
+ // We successfully wrote to the property server but now we
+ // wait for the property server to finish its work. It
+ // acknowledges its completion by closing the socket so we
+ // poll here (on nothing), waiting for the socket to close.
+ // If you 'adb shell setprop foo bar' you'll see the POLLHUP
+ // once the socket closes. Out of paranoia we cap our poll
+ // at 250 ms.
+ pollfd pollfds[1];
+ pollfds[0].fd = s;
+ pollfds[0].events = 0;
+ const int poll_result = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
+ if (poll_result == 1 && (pollfds[0].revents & POLLHUP) != 0) {
+ result = 0;
+ } else {
+ // Ignore the timeout and treat it like a success anyway.
+ // The init process is single-threaded and its property
+ // service is sometimes slow to respond (perhaps it's off
+ // starting a child process or something) and thus this
+ // times out and the caller thinks it failed, even though
+ // it's still getting around to it. So we fake it here,
+ // mostly for ctl.* properties, but we do try and wait 250
+ // ms so callers who do read-after-write can reliably see
+ // what they've written. Most of the time.
+ // TODO: fix the system properties design.
+ async_safe_format_log(ANDROID_LOG_WARN, "libc",
+ "Property service has timed out while trying to set \"%s\" to \"%s\"",
+ msg->name, msg->value);
+ result = 0;
+ }
+ }
+
+ return result;
+}
+
+static constexpr uint32_t kProtocolVersion1 = 1;
+static constexpr uint32_t kProtocolVersion2 = 2; // current
+
+static atomic_uint_least32_t g_propservice_protocol_version = 0;
+
+static void detect_protocol_version() {
+ char value[PROP_VALUE_MAX];
+ if (__system_property_get(kServiceVersionPropertyName, value) == 0) {
+ g_propservice_protocol_version = kProtocolVersion1;
+ async_safe_format_log(ANDROID_LOG_WARN, "libc",
+ "Using old property service protocol (\"%s\" is not set)",
+ kServiceVersionPropertyName);
+ } else {
+ uint32_t version = static_cast<uint32_t>(atoll(value));
+ if (version >= kProtocolVersion2) {
+ g_propservice_protocol_version = kProtocolVersion2;
+ } else {
+ async_safe_format_log(ANDROID_LOG_WARN, "libc",
+ "Using old property service protocol (\"%s\"=\"%s\")",
+ kServiceVersionPropertyName, value);
+ g_propservice_protocol_version = kProtocolVersion1;
+ }
+ }
+}
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+int __system_property_set(const char* key, const char* value) {
+ if (key == nullptr) return -1;
+ if (value == nullptr) value = "";
+
+ if (g_propservice_protocol_version == 0) {
+ detect_protocol_version();
+ }
+
+ if (g_propservice_protocol_version == kProtocolVersion1) {
+ // Old protocol does not support long names or values
+ if (strlen(key) >= PROP_NAME_MAX) return -1;
+ if (strlen(value) >= PROP_VALUE_MAX) return -1;
+
+ prop_msg msg;
+ memset(&msg, 0, sizeof msg);
+ msg.cmd = PROP_MSG_SETPROP;
+ strlcpy(msg.name, key, sizeof msg.name);
+ strlcpy(msg.value, value, sizeof msg.value);
+
+ return send_prop_msg(&msg);
+ } else {
+ // New protocol only allows long values for ro. properties only.
+ if (strlen(value) >= PROP_VALUE_MAX && strncmp(key, "ro.", 3) != 0) return -1;
+ // Use proper protocol
+ PropertyServiceConnection connection;
+ if (!connection.IsValid()) {
+ errno = connection.GetLastError();
+ async_safe_format_log(
+ ANDROID_LOG_WARN, "libc",
+ "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)", key, value,
+ errno, strerror(errno));
+ return -1;
+ }
+
+ SocketWriter writer(&connection);
+ if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) {
+ errno = connection.GetLastError();
+ async_safe_format_log(ANDROID_LOG_WARN, "libc",
+ "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
+ key, value, errno, strerror(errno));
+ return -1;
+ }
+
+ int result = -1;
+ if (!connection.RecvInt32(&result)) {
+ errno = connection.GetLastError();
+ async_safe_format_log(ANDROID_LOG_WARN, "libc",
+ "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
+ key, value, errno, strerror(errno));
+ return -1;
+ }
+
+ if (result != PROP_SUCCESS) {
+ async_safe_format_log(ANDROID_LOG_WARN, "libc",
+ "Unable to set property \"%s\" to \"%s\": error code: 0x%x", key, value,
+ result);
+ return -1;
+ }
+
+ return 0;
+ }
+}
diff --git a/libc/system_properties/Android.bp b/libc/system_properties/Android.bp
new file mode 100644
index 0000000..f94cda9
--- /dev/null
+++ b/libc/system_properties/Android.bp
@@ -0,0 +1,24 @@
+cc_library_static {
+ name: "libsystemproperties",
+ defaults: ["libc_defaults"],
+ srcs: [
+ "context_node.cpp",
+ "contexts_split.cpp",
+ "contexts_serialized.cpp",
+ "prop_area.cpp",
+ "prop_info.cpp",
+ "system_properties.cpp",
+ ],
+ whole_static_libs: [
+ "libpropertyinfoparser",
+ ],
+ static_libs: [
+ "libasync_safe",
+ ],
+
+ include_dirs: [
+ "bionic/libc",
+ "bionic/libstdc++/include",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/libc/system_properties/context_node.cpp b/libc/system_properties/context_node.cpp
index 13cef75..5496b5a 100644
--- a/libc/system_properties/context_node.cpp
+++ b/libc/system_properties/context_node.cpp
@@ -26,13 +26,14 @@
* SUCH DAMAGE.
*/
-#include "context_node.h"
+#include "system_properties/context_node.h"
+#include <limits.h>
#include <unistd.h>
#include <async_safe/log.h>
-#include "property_filename.h"
+#include "system_properties/system_properties.h"
// pthread_mutex_lock() calls into system_properties in the case of contention.
// This creates a risk of dead lock if any system_properties functions
@@ -49,8 +50,7 @@
}
char filename[PROP_FILENAME_MAX];
- int len =
- async_safe_format_buffer(filename, sizeof(filename), "%s/%s", property_filename, context_);
+ int len = async_safe_format_buffer(filename, sizeof(filename), "%s/%s", filename_, context_);
if (len < 0 || len > PROP_FILENAME_MAX) {
lock_.unlock();
return false;
@@ -85,8 +85,7 @@
bool ContextNode::CheckAccess() {
char filename[PROP_FILENAME_MAX];
- int len =
- async_safe_format_buffer(filename, sizeof(filename), "%s/%s", property_filename, context_);
+ int len = async_safe_format_buffer(filename, sizeof(filename), "%s/%s", filename_, context_);
if (len < 0 || len > PROP_FILENAME_MAX) {
return false;
}
diff --git a/libc/system_properties/contexts_serialized.cpp b/libc/system_properties/contexts_serialized.cpp
index 117b5cf..062e8a5 100644
--- a/libc/system_properties/contexts_serialized.cpp
+++ b/libc/system_properties/contexts_serialized.cpp
@@ -26,9 +26,10 @@
* SUCH DAMAGE.
*/
-#include "contexts_serialized.h"
+#include "system_properties/contexts_serialized.h"
#include <fcntl.h>
+#include <limits.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -38,7 +39,7 @@
#include <async_safe/log.h>
#include "private/bionic_prctl.h"
-#include "property_filename.h"
+#include "system_properties/system_properties.h"
bool ContextsSerialized::InitializeContextNodes() {
auto num_context_nodes = property_info_area_file_->num_contexts();
@@ -58,7 +59,7 @@
context_nodes_mmap_size_ = context_nodes_mmap_size;
for (size_t i = 0; i < num_context_nodes; ++i) {
- new (&context_nodes_[i]) ContextNode(property_info_area_file_->context(i));
+ new (&context_nodes_[i]) ContextNode(property_info_area_file_->context(i), filename_);
}
return true;
@@ -66,8 +67,7 @@
bool ContextsSerialized::MapSerialPropertyArea(bool access_rw, bool* fsetxattr_failed) {
char filename[PROP_FILENAME_MAX];
- int len = async_safe_format_buffer(filename, sizeof(filename), "%s/properties_serial",
- property_filename);
+ int len = async_safe_format_buffer(filename, sizeof(filename), "%s/properties_serial", filename_);
if (len < 0 || len > PROP_FILENAME_MAX) {
serial_prop_area_ = nullptr;
return false;
@@ -95,27 +95,28 @@
return true;
}
-bool ContextsSerialized::Initialize(bool writable) {
+bool ContextsSerialized::Initialize(bool writable, const char* filename, bool* fsetxattr_failed) {
+ filename_ = filename;
if (!InitializeProperties()) {
return false;
}
if (writable) {
- mkdir(property_filename, S_IRWXU | S_IXGRP | S_IXOTH);
+ mkdir(filename_, S_IRWXU | S_IXGRP | S_IXOTH);
bool open_failed = false;
- bool fsetxattr_failed = false;
+ if (fsetxattr_failed) {
+ *fsetxattr_failed = false;
+ }
for (size_t i = 0; i < num_context_nodes_; ++i) {
- if (!context_nodes_[i].Open(true, &fsetxattr_failed)) {
+ if (!context_nodes_[i].Open(true, fsetxattr_failed)) {
open_failed = true;
}
}
- if (open_failed || !MapSerialPropertyArea(true, &fsetxattr_failed)) {
+ if (open_failed || !MapSerialPropertyArea(true, fsetxattr_failed)) {
FreeAndUnmap();
return false;
}
-
- return !fsetxattr_failed;
} else {
if (!MapSerialPropertyArea(false, nullptr)) {
FreeAndUnmap();
diff --git a/libc/system_properties/contexts_split.cpp b/libc/system_properties/contexts_split.cpp
index 77f2069..b8afa29 100644
--- a/libc/system_properties/contexts_split.cpp
+++ b/libc/system_properties/contexts_split.cpp
@@ -26,22 +26,23 @@
* SUCH DAMAGE.
*/
-#include "contexts_split.h"
+#include "system_properties/contexts_split.h"
#include <ctype.h>
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <async_safe/log.h>
-#include "context_node.h"
-#include "property_filename.h"
+#include "system_properties/context_node.h"
+#include "system_properties/system_properties.h"
class ContextListNode : public ContextNode {
public:
- ContextListNode(ContextListNode* next, const char* context)
- : ContextNode(strdup(context)), next(next) {
+ ContextListNode(ContextListNode* next, const char* context, const char* filename)
+ : ContextNode(strdup(context), filename), next(next) {
}
~ContextListNode() {
@@ -194,8 +195,7 @@
bool ContextsSplit::MapSerialPropertyArea(bool access_rw, bool* fsetxattr_failed) {
char filename[PROP_FILENAME_MAX];
- int len = async_safe_format_buffer(filename, sizeof(filename), "%s/properties_serial",
- property_filename);
+ int len = async_safe_format_buffer(filename, sizeof(filename), "%s/properties_serial", filename_);
if (len < 0 || len > PROP_FILENAME_MAX) {
serial_prop_area_ = nullptr;
return false;
@@ -245,7 +245,7 @@
if (old_context) {
ListAddAfterLen(&prefixes_, prop_prefix, old_context);
} else {
- ListAdd(&contexts_, context);
+ ListAdd(&contexts_, context, filename_);
ListAddAfterLen(&prefixes_, prop_prefix, contexts_);
}
free(prop_prefix);
@@ -285,26 +285,28 @@
return true;
}
-bool ContextsSplit::Initialize(bool writable) {
+bool ContextsSplit::Initialize(bool writable, const char* filename, bool* fsetxattr_failed) {
+ filename_ = filename;
if (!InitializeProperties()) {
return false;
}
if (writable) {
- mkdir(property_filename, S_IRWXU | S_IXGRP | S_IXOTH);
+ mkdir(filename_, S_IRWXU | S_IXGRP | S_IXOTH);
bool open_failed = false;
- bool fsetxattr_failed = false;
+ if (fsetxattr_failed) {
+ *fsetxattr_failed = false;
+ }
+
ListForEach(contexts_, [&fsetxattr_failed, &open_failed](ContextListNode* l) {
- if (!l->Open(true, &fsetxattr_failed)) {
+ if (!l->Open(true, fsetxattr_failed)) {
open_failed = true;
}
});
- if (open_failed || !MapSerialPropertyArea(true, &fsetxattr_failed)) {
+ if (open_failed || !MapSerialPropertyArea(true, fsetxattr_failed)) {
FreeAndUnmap();
return false;
}
-
- return !fsetxattr_failed;
} else {
if (!MapSerialPropertyArea(false, nullptr)) {
FreeAndUnmap();
diff --git a/libc/system_properties/context_node.h b/libc/system_properties/include/system_properties/context_node.h
similarity index 87%
rename from libc/system_properties/context_node.h
rename to libc/system_properties/include/system_properties/context_node.h
index 769b853..6a3bbcd 100644
--- a/libc/system_properties/context_node.h
+++ b/libc/system_properties/include/system_properties/context_node.h
@@ -35,17 +35,15 @@
class ContextNode {
public:
- ContextNode(const char* context) : context_(context), pa_(nullptr), no_access_(false) {
+ ContextNode(const char* context, const char* filename)
+ : context_(context), pa_(nullptr), no_access_(false), filename_(filename) {
lock_.init(false);
}
~ContextNode() {
Unmap();
}
- ContextNode(const ContextNode&) = delete;
- ContextNode(ContextNode&&) = delete;
- void operator=(const ContextNode&) = delete;
- void operator=(const ContextNode&&) = delete;
+ DISALLOW_COPY_AND_ASSIGN(ContextNode);
bool Open(bool access_rw, bool* fsetxattr_failed);
bool CheckAccessAndOpen();
@@ -66,6 +64,7 @@
const char* context_;
prop_area* pa_;
bool no_access_;
+ const char* filename_;
};
#endif
diff --git a/libc/system_properties/contexts.h b/libc/system_properties/include/system_properties/contexts.h
similarity index 95%
rename from libc/system_properties/contexts.h
rename to libc/system_properties/include/system_properties/contexts.h
index 5df9d96..8f154ed 100644
--- a/libc/system_properties/contexts.h
+++ b/libc/system_properties/include/system_properties/contexts.h
@@ -37,7 +37,7 @@
virtual ~Contexts() {
}
- virtual bool Initialize(bool writable) = 0;
+ virtual bool Initialize(bool writable, const char* filename, bool* fsetxattr_failed) = 0;
virtual prop_area* GetPropAreaForName(const char* name) = 0;
virtual prop_area* GetSerialPropArea() = 0;
virtual void ForEach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) = 0;
diff --git a/libc/system_properties/contexts_pre_split.h b/libc/system_properties/include/system_properties/contexts_pre_split.h
similarity index 94%
rename from libc/system_properties/contexts_pre_split.h
rename to libc/system_properties/include/system_properties/contexts_pre_split.h
index bbc8529..14b00f1 100644
--- a/libc/system_properties/contexts_pre_split.h
+++ b/libc/system_properties/include/system_properties/contexts_pre_split.h
@@ -32,7 +32,6 @@
#include "contexts.h"
#include "prop_area.h"
#include "prop_info.h"
-#include "property_filename.h"
class ContextsPreSplit : public Contexts {
public:
@@ -40,8 +39,8 @@
}
// We'll never initialize this legacy option as writable, so don't even check the arg.
- virtual bool Initialize(bool) override {
- pre_split_prop_area_ = prop_area::map_prop_area(property_filename);
+ virtual bool Initialize(bool, const char* filename, bool*) override {
+ pre_split_prop_area_ = prop_area::map_prop_area(filename);
return pre_split_prop_area_ != nullptr;
}
diff --git a/libc/system_properties/contexts_serialized.h b/libc/system_properties/include/system_properties/contexts_serialized.h
similarity index 94%
rename from libc/system_properties/contexts_serialized.h
rename to libc/system_properties/include/system_properties/contexts_serialized.h
index 52474c3..010730a 100644
--- a/libc/system_properties/contexts_serialized.h
+++ b/libc/system_properties/include/system_properties/contexts_serialized.h
@@ -39,7 +39,7 @@
virtual ~ContextsSerialized() override {
}
- virtual bool Initialize(bool writable) override;
+ virtual bool Initialize(bool writable, const char* filename, bool* fsetxattr_failed) override;
virtual prop_area* GetPropAreaForName(const char* name) override;
virtual prop_area* GetSerialPropArea() override {
return serial_prop_area_;
@@ -53,6 +53,7 @@
bool InitializeProperties();
bool MapSerialPropertyArea(bool access_rw, bool* fsetxattr_failed);
+ const char* filename_;
android::properties::PropertyInfoAreaFile property_info_area_file_;
ContextNode* context_nodes_ = nullptr;
size_t num_context_nodes_ = 0;
diff --git a/libc/system_properties/contexts_split.h b/libc/system_properties/include/system_properties/contexts_split.h
similarity index 94%
rename from libc/system_properties/contexts_split.h
rename to libc/system_properties/include/system_properties/contexts_split.h
index f98eb44..06c405a 100644
--- a/libc/system_properties/contexts_split.h
+++ b/libc/system_properties/include/system_properties/contexts_split.h
@@ -39,7 +39,7 @@
virtual ~ContextsSplit() override {
}
- virtual bool Initialize(bool writable) override;
+ virtual bool Initialize(bool writable, const char* filename, bool* fsetxattr_failed) override;
virtual prop_area* GetPropAreaForName(const char* name) override;
virtual prop_area* GetSerialPropArea() override {
return serial_prop_area_;
@@ -56,6 +56,7 @@
PrefixNode* prefixes_ = nullptr;
ContextListNode* contexts_ = nullptr;
prop_area* serial_prop_area_ = nullptr;
+ const char* filename_ = nullptr;
};
#endif
diff --git a/libc/system_properties/prop_area.h b/libc/system_properties/include/system_properties/prop_area.h
similarity index 99%
rename from libc/system_properties/prop_area.h
rename to libc/system_properties/include/system_properties/prop_area.h
index 10c1adb..a7d5d22 100644
--- a/libc/system_properties/prop_area.h
+++ b/libc/system_properties/include/system_properties/prop_area.h
@@ -103,7 +103,7 @@
}
prop_area(const uint32_t magic, const uint32_t version) : magic_(magic), version_(version) {
- atomic_init(&serial_, 0);
+ atomic_init(&serial_, 0u);
memset(reserved_, 0, sizeof(reserved_));
// Allocate enough space for the root node.
bytes_used_ = sizeof(prop_bt);
diff --git a/libc/system_properties/prop_info.h b/libc/system_properties/include/system_properties/prop_info.h
similarity index 100%
rename from libc/system_properties/prop_info.h
rename to libc/system_properties/include/system_properties/prop_info.h
diff --git a/libc/system_properties/include/system_properties/system_properties.h b/libc/system_properties/include/system_properties/system_properties.h
new file mode 100644
index 0000000..c74f875
--- /dev/null
+++ b/libc/system_properties/include/system_properties/system_properties.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef SYSTEM_PROPERTIES_SYSTEM_PROPERTIES_H
+#define SYSTEM_PROPERTIES_SYSTEM_PROPERTIES_H
+
+#include <stdint.h>
+#include <sys/system_properties.h>
+
+#include "contexts.h"
+#include "contexts_pre_split.h"
+#include "contexts_serialized.h"
+#include "contexts_split.h"
+
+constexpr int PROP_FILENAME_MAX = 1024;
+
+class SystemProperties {
+ public:
+ // Note that system properties are initialized before libc calls static initializers, so
+ // doing any initialization in this constructor is an error. Even a Constructor that zero
+ // initializes this class will clobber the previous property initialization.
+ // We rely on the static SystemProperties in libc to be placed in .bss and zero initialized.
+ SystemProperties() {
+ }
+ // Special constructor for testing that also zero initializes the important members.
+ SystemProperties(bool initialized) : initialized_(initialized) {
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(SystemProperties);
+
+ bool Init(const char* filename);
+ bool AreaInit(const char* filename, bool* fsetxattr_failed);
+ uint32_t AreaSerial();
+ const prop_info* Find(const char* name);
+ int Read(const prop_info* pi, char* name, char* value);
+ void ReadCallback(const prop_info* pi,
+ void (*callback)(void* cookie, const char* name, const char* value,
+ uint32_t serial),
+ void* cookie);
+ int Get(const char* name, char* value);
+ int Update(prop_info* pi, const char* value, unsigned int len);
+ int Add(const char* name, unsigned int namelen, const char* value, unsigned int valuelen);
+ uint32_t Serial(const prop_info* pi);
+ uint32_t WaitAny(uint32_t old_serial);
+ bool Wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr,
+ const timespec* relative_timeout);
+ const prop_info* FindNth(unsigned n);
+ int Foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie);
+
+ Contexts* contexts() {
+ return reinterpret_cast<Contexts*>(&contexts_union_);
+ }
+
+ private:
+ // We don't want to use new or malloc in properties (b/31659220), and since these classes
+ // are small enough and we place them in a union. See the above note about Constructors
+ // for why there is a no-op constructor here.
+ union ContextsUnion {
+ ContextsUnion() {
+ }
+ ~ContextsUnion() {
+ }
+ ContextsSerialized contexts_serialized;
+ ContextsSplit contexts_split;
+ ContextsPreSplit contexts_pre_split;
+ } contexts_union_;
+ bool initialized_;
+ char property_filename_[PROP_FILENAME_MAX];
+};
+
+#endif
diff --git a/libc/system_properties/prop_area.cpp b/libc/system_properties/prop_area.cpp
index 032fa4e..42bee9f 100644
--- a/libc/system_properties/prop_area.cpp
+++ b/libc/system_properties/prop_area.cpp
@@ -26,6 +26,8 @@
* SUCH DAMAGE.
*/
+#include "system_properties/prop_area.h"
+
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
@@ -39,8 +41,6 @@
#include <async_safe/log.h>
-#include "prop_area.h"
-
constexpr size_t PA_SIZE = 128 * 1024;
constexpr uint32_t PROP_AREA_MAGIC = 0x504f5250;
constexpr uint32_t PROP_AREA_VERSION = 0xfc6ed0ab;
diff --git a/libc/system_properties/prop_info.cpp b/libc/system_properties/prop_info.cpp
index 5123f92..890d1cf 100644
--- a/libc/system_properties/prop_info.cpp
+++ b/libc/system_properties/prop_info.cpp
@@ -26,7 +26,7 @@
* SUCH DAMAGE.
*/
-#include "prop_info.h"
+#include "system_properties/prop_info.h"
#include <string.h>
diff --git a/libc/system_properties/property_filename.h b/libc/system_properties/property_filename.h
deleted file mode 100644
index 0f7bcf7..0000000
--- a/libc/system_properties/property_filename.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef SYSTEM_PROPERTIES_PROPERTY_FILENAME_H
-#define SYSTEM_PROPERTIES_PROPERTY_FILENAME_H
-
-// These are globals set by __system_property_set_filename().
-// There isn't huge benefit in refactoring them, so they're alone in this header.
-constexpr int PROP_FILENAME_MAX = 1024;
-extern char property_filename[PROP_FILENAME_MAX];
-
-#endif
diff --git a/libc/system_properties/system_properties.cpp b/libc/system_properties/system_properties.cpp
index f67fc4d..c610df2 100644
--- a/libc/system_properties/system_properties.cpp
+++ b/libc/system_properties/system_properties.cpp
@@ -26,246 +26,30 @@
* SUCH DAMAGE.
*/
+#include "system_properties/system_properties.h"
+
#include <errno.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <poll.h>
#include <stdatomic.h>
-#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/select.h>
-#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/uio.h>
-#include <sys/un.h>
#include <unistd.h>
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-#include <sys/system_properties.h>
-
#include <new>
#include <async_safe/log.h>
#include "private/ErrnoRestorer.h"
-#include "private/bionic_defs.h"
#include "private/bionic_futex.h"
-#include "private/bionic_macros.h"
-#include "private/bionic_sdk_version.h"
-#include "context_node.h"
-#include "contexts.h"
-#include "contexts_pre_split.h"
-#include "contexts_serialized.h"
-#include "contexts_split.h"
-#include "prop_area.h"
-#include "prop_info.h"
-#include "property_filename.h"
-
-// We don't want to use new or malloc in properties (b/31659220), and since these classes are
-// small enough and we place them in a static union. Note that system properties are initialized
-// before static initializers are called, so using a Constructor here is an error. Even a
-// Constructor that zero initializes a class will clobber the previous property initialization.
-static union ContextsUnion {
- ContextsUnion() {}
- ~ContextsUnion() {}
- ContextsSerialized contexts_serialized;
- ContextsSplit contexts_split;
- ContextsPreSplit contexts_pre_split;
-} contexts_union;
-static Contexts* contexts = nullptr;
+#include "system_properties/context_node.h"
+#include "system_properties/prop_area.h"
+#include "system_properties/prop_info.h"
#define SERIAL_DIRTY(serial) ((serial)&1)
#define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
-static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
-static const char* kServiceVersionPropertyName = "ro.property_service.version";
-
-// This is public because it was exposed in the NDK. As of 2017-01, ~60 apps reference this symbol.
-// It is set to nullptr and never modified.
-__BIONIC_WEAK_VARIABLE_FOR_NATIVE_BRIDGE
-prop_area* __system_property_area__ = nullptr;
-
-char property_filename[PROP_FILENAME_MAX] = PROP_FILENAME;
-
-class PropertyServiceConnection {
- public:
- PropertyServiceConnection() : last_error_(0) {
- socket_ = ::socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
- if (socket_ == -1) {
- last_error_ = errno;
- return;
- }
-
- const size_t namelen = strlen(property_service_socket);
- sockaddr_un addr;
- memset(&addr, 0, sizeof(addr));
- strlcpy(addr.sun_path, property_service_socket, sizeof(addr.sun_path));
- addr.sun_family = AF_LOCAL;
- socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
-
- if (TEMP_FAILURE_RETRY(connect(socket_, reinterpret_cast<sockaddr*>(&addr), alen)) == -1) {
- last_error_ = errno;
- close(socket_);
- socket_ = -1;
- }
- }
-
- bool IsValid() {
- return socket_ != -1;
- }
-
- int GetLastError() {
- return last_error_;
- }
-
- bool RecvInt32(int32_t* value) {
- int result = TEMP_FAILURE_RETRY(recv(socket_, value, sizeof(*value), MSG_WAITALL));
- return CheckSendRecvResult(result, sizeof(*value));
- }
-
- int socket() {
- return socket_;
- }
-
- ~PropertyServiceConnection() {
- if (socket_ != -1) {
- close(socket_);
- }
- }
-
- private:
- bool CheckSendRecvResult(int result, int expected_len) {
- if (result == -1) {
- last_error_ = errno;
- } else if (result != expected_len) {
- last_error_ = -1;
- } else {
- last_error_ = 0;
- }
-
- return last_error_ == 0;
- }
-
- int socket_;
- int last_error_;
-
- friend class SocketWriter;
-};
-
-class SocketWriter {
- public:
- explicit SocketWriter(PropertyServiceConnection* connection)
- : connection_(connection), iov_index_(0), uint_buf_index_(0) {
- }
-
- SocketWriter& WriteUint32(uint32_t value) {
- CHECK(uint_buf_index_ < kUintBufSize);
- CHECK(iov_index_ < kIovSize);
- uint32_t* ptr = uint_buf_ + uint_buf_index_;
- uint_buf_[uint_buf_index_++] = value;
- iov_[iov_index_].iov_base = ptr;
- iov_[iov_index_].iov_len = sizeof(*ptr);
- ++iov_index_;
- return *this;
- }
-
- SocketWriter& WriteString(const char* value) {
- uint32_t valuelen = strlen(value);
- WriteUint32(valuelen);
- if (valuelen == 0) {
- return *this;
- }
-
- CHECK(iov_index_ < kIovSize);
- iov_[iov_index_].iov_base = const_cast<char*>(value);
- iov_[iov_index_].iov_len = valuelen;
- ++iov_index_;
-
- return *this;
- }
-
- bool Send() {
- if (!connection_->IsValid()) {
- return false;
- }
-
- if (writev(connection_->socket(), iov_, iov_index_) == -1) {
- connection_->last_error_ = errno;
- return false;
- }
-
- iov_index_ = uint_buf_index_ = 0;
- return true;
- }
-
- private:
- static constexpr size_t kUintBufSize = 8;
- static constexpr size_t kIovSize = 8;
-
- PropertyServiceConnection* connection_;
- iovec iov_[kIovSize];
- size_t iov_index_;
- uint32_t uint_buf_[kUintBufSize];
- size_t uint_buf_index_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(SocketWriter);
-};
-
-struct prop_msg {
- unsigned cmd;
- char name[PROP_NAME_MAX];
- char value[PROP_VALUE_MAX];
-};
-
-static int send_prop_msg(const prop_msg* msg) {
- PropertyServiceConnection connection;
- if (!connection.IsValid()) {
- return connection.GetLastError();
- }
-
- int result = -1;
- int s = connection.socket();
-
- const int num_bytes = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));
- if (num_bytes == sizeof(prop_msg)) {
- // We successfully wrote to the property server but now we
- // wait for the property server to finish its work. It
- // acknowledges its completion by closing the socket so we
- // poll here (on nothing), waiting for the socket to close.
- // If you 'adb shell setprop foo bar' you'll see the POLLHUP
- // once the socket closes. Out of paranoia we cap our poll
- // at 250 ms.
- pollfd pollfds[1];
- pollfds[0].fd = s;
- pollfds[0].events = 0;
- const int poll_result = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
- if (poll_result == 1 && (pollfds[0].revents & POLLHUP) != 0) {
- result = 0;
- } else {
- // Ignore the timeout and treat it like a success anyway.
- // The init process is single-threaded and its property
- // service is sometimes slow to respond (perhaps it's off
- // starting a child process or something) and thus this
- // times out and the caller thinks it failed, even though
- // it's still getting around to it. So we fake it here,
- // mostly for ctl.* properties, but we do try and wait 250
- // ms so callers who do read-after-write can reliably see
- // what they've written. Most of the time.
- // TODO: fix the system properties design.
- async_safe_format_log(ANDROID_LOG_WARN, "libc",
- "Property service has timed out while trying to set \"%s\" to \"%s\"",
- msg->name, msg->value);
- result = 0;
- }
- }
-
- return result;
-}
-
static bool is_dir(const char* pathname) {
struct stat info;
if (stat(pathname, &info) == -1) {
@@ -274,71 +58,62 @@
return S_ISDIR(info.st_mode);
}
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-int __system_properties_init() {
+bool SystemProperties::Init(const char* filename) {
// This is called from __libc_init_common, and should leave errno at 0 (http://b/37248982).
ErrnoRestorer errno_restorer;
- if (contexts != nullptr) {
- contexts->ResetAccess();
- return 0;
+ if (initialized_) {
+ contexts()->ResetAccess();
+ return true;
}
- contexts = nullptr;
- if (is_dir(property_filename)) {
+
+ if (strlen(filename) > PROP_FILENAME_MAX) {
+ return false;
+ }
+ strcpy(property_filename_, filename);
+
+ if (is_dir(property_filename_)) {
if (access("/dev/__properties__/property_info", R_OK) == 0) {
- new (&contexts_union.contexts_serialized) ContextsSerialized();
- if (!contexts_union.contexts_serialized.Initialize(false)) {
- return -1;
+ new (&contexts_union_.contexts_serialized) ContextsSerialized();
+ if (!contexts_union_.contexts_serialized.Initialize(false, property_filename_, nullptr)) {
+ return false;
}
- contexts = &contexts_union.contexts_serialized;
} else {
- new (&contexts_union.contexts_split) ContextsSplit();
- if (!contexts_union.contexts_split.Initialize(false)) {
- return -1;
+ new (&contexts_union_.contexts_split) ContextsSplit();
+ if (!contexts_union_.contexts_split.Initialize(false, property_filename_, nullptr)) {
+ return false;
}
- contexts = &contexts_union.contexts_split;
}
} else {
- new (&contexts_union.contexts_pre_split) ContextsPreSplit();
- if (!contexts_union.contexts_pre_split.Initialize(false)) {
- return -1;
+ new (&contexts_union_.contexts_pre_split) ContextsPreSplit();
+ if (!contexts_union_.contexts_pre_split.Initialize(false, property_filename_, nullptr)) {
+ return false;
}
- contexts = &contexts_union.contexts_pre_split;
}
- return 0;
+ initialized_ = true;
+ return true;
}
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-int __system_property_set_filename(const char* filename) {
- size_t len = strlen(filename);
- if (len >= sizeof(property_filename)) return -1;
+bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed) {
+ if (strlen(filename) > PROP_FILENAME_MAX) {
+ return false;
+ }
+ strcpy(property_filename_, filename);
- strcpy(property_filename, filename);
- return 0;
+ new (&contexts_union_.contexts_serialized) ContextsSerialized();
+ if (!contexts_union_.contexts_serialized.Initialize(true, property_filename_, fsetxattr_failed)) {
+ return false;
+ }
+ initialized_ = true;
+ return true;
}
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-int __system_property_area_init() {
- if (contexts != nullptr) {
- contexts->FreeAndUnmap();
- }
- // We set this unconditionally as we want tests to continue on regardless of if this failed
- // and property_service will abort on an error condition, so no harm done.
- new (&contexts_union.contexts_serialized) ContextsSerialized;
- contexts = &contexts_union.contexts_serialized;
- if (!contexts_union.contexts_serialized.Initialize(true)) {
- return -1;
- }
- return 0;
-}
-
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-uint32_t __system_property_area_serial() {
- if (contexts == nullptr) {
+uint32_t SystemProperties::AreaSerial() {
+ if (!initialized_) {
return -1;
}
- prop_area* pa = contexts->GetSerialPropArea();
+ prop_area* pa = contexts()->GetSerialPropArea();
if (!pa) {
return -1;
}
@@ -347,13 +122,12 @@
return atomic_load_explicit(pa->serial(), memory_order_acquire);
}
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-const prop_info* __system_property_find(const char* name) {
- if (contexts == nullptr) {
+const prop_info* SystemProperties::Find(const char* name) {
+ if (!initialized_) {
return nullptr;
}
- prop_area* pa = contexts->GetPropAreaForName(name);
+ prop_area* pa = contexts()->GetPropAreaForName(name);
if (!pa) {
async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
return nullptr;
@@ -366,10 +140,9 @@
return strncmp(name, "ro.", 3) == 0;
}
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-int __system_property_read(const prop_info* pi, char* name, char* value) {
+int SystemProperties::Read(const prop_info* pi, char* name, char* value) {
while (true) {
- uint32_t serial = __system_property_serial(pi); // acquire semantics
+ uint32_t serial = Serial(pi); // acquire semantics
size_t len = SERIAL_VALUE_LEN(serial);
memcpy(value, pi->value, len + 1);
// TODO: Fix the synchronization scheme here.
@@ -405,15 +178,14 @@
}
}
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-void __system_property_read_callback(const prop_info* pi,
- void (*callback)(void* cookie, const char* name,
- const char* value, uint32_t serial),
- void* cookie) {
+void SystemProperties::ReadCallback(const prop_info* pi,
+ void (*callback)(void* cookie, const char* name,
+ const char* value, uint32_t serial),
+ void* cookie) {
// Read only properties don't need to copy the value to a temporary buffer, since it can never
// change.
if (is_read_only(pi->name)) {
- uint32_t serial = __system_property_serial(pi);
+ uint32_t serial = Serial(pi);
if (pi->is_long()) {
callback(cookie, pi->name, pi->long_value(), serial);
} else {
@@ -423,14 +195,14 @@
}
while (true) {
- uint32_t serial = __system_property_serial(pi); // acquire semantics
+ uint32_t serial = Serial(pi); // acquire semantics
size_t len = SERIAL_VALUE_LEN(serial);
char value_buf[len + 1];
memcpy(value_buf, pi->value, len);
value_buf[len] = '\0';
- // TODO: see todo in __system_property_read function
+ // TODO: see todo in Read function
atomic_thread_fence(memory_order_acquire);
if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) {
callback(cookie, pi->name, value_buf, serial);
@@ -439,118 +211,27 @@
}
}
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-int __system_property_get(const char* name, char* value) {
- const prop_info* pi = __system_property_find(name);
+int SystemProperties::Get(const char* name, char* value) {
+ const prop_info* pi = Find(name);
if (pi != 0) {
- return __system_property_read(pi, nullptr, value);
+ return Read(pi, nullptr, value);
} else {
value[0] = 0;
return 0;
}
}
-static constexpr uint32_t kProtocolVersion1 = 1;
-static constexpr uint32_t kProtocolVersion2 = 2; // current
-
-static atomic_uint_least32_t g_propservice_protocol_version = 0;
-
-static void detect_protocol_version() {
- char value[PROP_VALUE_MAX];
- if (__system_property_get(kServiceVersionPropertyName, value) == 0) {
- g_propservice_protocol_version = kProtocolVersion1;
- async_safe_format_log(ANDROID_LOG_WARN, "libc",
- "Using old property service protocol (\"%s\" is not set)",
- kServiceVersionPropertyName);
- } else {
- uint32_t version = static_cast<uint32_t>(atoll(value));
- if (version >= kProtocolVersion2) {
- g_propservice_protocol_version = kProtocolVersion2;
- } else {
- async_safe_format_log(ANDROID_LOG_WARN, "libc",
- "Using old property service protocol (\"%s\"=\"%s\")",
- kServiceVersionPropertyName, value);
- g_propservice_protocol_version = kProtocolVersion1;
- }
- }
-}
-
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-int __system_property_set(const char* key, const char* value) {
- if (key == nullptr) return -1;
- if (value == nullptr) value = "";
-
- if (g_propservice_protocol_version == 0) {
- detect_protocol_version();
- }
-
- if (g_propservice_protocol_version == kProtocolVersion1) {
- // Old protocol does not support long names or values
- if (strlen(key) >= PROP_NAME_MAX) return -1;
- if (strlen(value) >= PROP_VALUE_MAX) return -1;
-
- prop_msg msg;
- memset(&msg, 0, sizeof msg);
- msg.cmd = PROP_MSG_SETPROP;
- strlcpy(msg.name, key, sizeof msg.name);
- strlcpy(msg.value, value, sizeof msg.value);
-
- return send_prop_msg(&msg);
- } else {
- // New protocol only allows long values for ro. properties only.
- if (strlen(value) >= PROP_VALUE_MAX && !is_read_only(key)) return -1;
- // Use proper protocol
- PropertyServiceConnection connection;
- if (!connection.IsValid()) {
- errno = connection.GetLastError();
- async_safe_format_log(
- ANDROID_LOG_WARN, "libc",
- "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)", key, value,
- errno, strerror(errno));
- return -1;
- }
-
- SocketWriter writer(&connection);
- if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) {
- errno = connection.GetLastError();
- async_safe_format_log(ANDROID_LOG_WARN, "libc",
- "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
- key, value, errno, strerror(errno));
- return -1;
- }
-
- int result = -1;
- if (!connection.RecvInt32(&result)) {
- errno = connection.GetLastError();
- async_safe_format_log(ANDROID_LOG_WARN, "libc",
- "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
- key, value, errno, strerror(errno));
- return -1;
- }
-
- if (result != PROP_SUCCESS) {
- async_safe_format_log(ANDROID_LOG_WARN, "libc",
- "Unable to set property \"%s\" to \"%s\": error code: 0x%x", key, value,
- result);
- return -1;
- }
-
- return 0;
- }
-}
-
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-int __system_property_update(prop_info* pi, const char* value, unsigned int len) {
+int SystemProperties::Update(prop_info* pi, const char* value, unsigned int len) {
if (len >= PROP_VALUE_MAX) {
return -1;
}
- if (contexts == nullptr) {
+ if (!initialized_) {
return -1;
}
- prop_area* pa = contexts->GetSerialPropArea();
+ prop_area* pa = contexts()->GetSerialPropArea();
if (!pa) {
return -1;
}
@@ -574,8 +255,7 @@
return 0;
}
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-int __system_property_add(const char* name, unsigned int namelen, const char* value,
+int SystemProperties::Add(const char* name, unsigned int namelen, const char* value,
unsigned int valuelen) {
if (valuelen >= PROP_VALUE_MAX && !is_read_only(name)) {
return -1;
@@ -585,16 +265,16 @@
return -1;
}
- if (contexts == nullptr) {
+ if (!initialized_) {
return -1;
}
- prop_area* serial_pa = contexts->GetSerialPropArea();
+ prop_area* serial_pa = contexts()->GetSerialPropArea();
if (serial_pa == nullptr) {
return -1;
}
- prop_area* pa = contexts->GetPropAreaForName(name);
+ prop_area* pa = contexts()->GetPropAreaForName(name);
if (!pa) {
async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
return -1;
@@ -615,8 +295,7 @@
}
// Wait for non-locked serial, and retrieve it with acquire semantics.
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-uint32_t __system_property_serial(const prop_info* pi) {
+uint32_t SystemProperties::Serial(const prop_info* pi) {
uint32_t serial = load_const_atomic(&pi->serial, memory_order_acquire);
while (SERIAL_DIRTY(serial)) {
__futex_wait(const_cast<_Atomic(uint_least32_t)*>(&pi->serial), serial, nullptr);
@@ -625,24 +304,22 @@
return serial;
}
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-uint32_t __system_property_wait_any(uint32_t old_serial) {
+uint32_t SystemProperties::WaitAny(uint32_t old_serial) {
uint32_t new_serial;
- __system_property_wait(nullptr, old_serial, &new_serial, nullptr);
+ Wait(nullptr, old_serial, &new_serial, nullptr);
return new_serial;
}
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-bool __system_property_wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr,
+bool SystemProperties::Wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr,
const timespec* relative_timeout) {
// Are we waiting on the global serial or a specific serial?
atomic_uint_least32_t* serial_ptr;
if (pi == nullptr) {
- if (contexts == nullptr) {
+ if (!initialized_) {
return -1;
}
- prop_area* serial_pa = contexts->GetSerialPropArea();
+ prop_area* serial_pa = contexts()->GetSerialPropArea();
if (serial_pa == nullptr) {
return -1;
}
@@ -665,8 +342,7 @@
return true;
}
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-const prop_info* __system_property_find_nth(unsigned n) {
+const prop_info* SystemProperties::FindNth(unsigned n) {
struct find_nth {
const uint32_t sought;
uint32_t current;
@@ -679,17 +355,16 @@
if (self->current++ == self->sought) self->result = pi;
}
} state(n);
- __system_property_foreach(find_nth::fn, &state);
+ Foreach(find_nth::fn, &state);
return state.result;
}
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-int __system_property_foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
- if (contexts == nullptr) {
+int SystemProperties::Foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
+ if (!initialized_) {
return -1;
}
- contexts->ForEach(propfn, cookie);
+ contexts()->ForEach(propfn, cookie);
return 0;
}
diff --git a/tests/Android.bp b/tests/Android.bp
index 51a721a..c1e455d 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -173,7 +173,10 @@
target: {
bionic: {
- whole_static_libs: ["libasync_safe"],
+ whole_static_libs: [
+ "libasync_safe",
+ "libsystemproperties",
+ ],
},
},
diff --git a/tests/system_properties_test.cpp b/tests/system_properties_test.cpp
index 69647bf..f2151e1 100644
--- a/tests/system_properties_test.cpp
+++ b/tests/system_properties_test.cpp
@@ -24,6 +24,8 @@
#include <string>
#include <thread>
+#include <android-base/test_utils.h>
+
using namespace std::literals;
#if defined(__BIONIC__)
@@ -31,41 +33,26 @@
#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;
- }
+#include <system_properties/system_properties.h>
- pa_dirname = dirname;
- pa_filename = pa_dirname + "/__properties__";
-
- __system_property_set_filename(pa_filename.c_str());
- __system_property_area_init();
- valid = true;
+class SystemPropertiesTest : public SystemProperties {
+ public:
+ SystemPropertiesTest() : SystemProperties(false) {
+ valid_ = AreaInit(dir_.path, nullptr);
+ }
+ ~SystemPropertiesTest() {
+ if (valid_) {
+ contexts()->FreeAndUnmap();
}
+ }
- ~LocalPropertyTestState() {
- if (!valid) {
- return;
- }
+ bool valid() const {
+ return valid_;
+ }
- __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;
+ private:
+ TemporaryDir dir_;
+ bool valid_;
};
static void foreach_test_callback(const prop_info *pi, void* cookie) {
@@ -100,27 +87,16 @@
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);
+ SystemPropertiesTest system_properties;
+ ASSERT_TRUE(system_properties.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));
+ ASSERT_EQ(0, system_properties.Add("property", 8, "value1", 6));
+ ASSERT_EQ(0, system_properties.Add("other_property", 14, "value2", 6));
+ ASSERT_EQ(0, system_properties.Add("property_other", 14, "value3", 6));
// check that there is no limit on property name length
char name[PROP_NAME_MAX + 11];
@@ -130,19 +106,19 @@
}
name[sizeof(name)-1] = '\0';
- ASSERT_EQ(0, __system_property_add(name, strlen(name), "value", 5));
+ ASSERT_EQ(0, system_properties.Add(name, strlen(name), "value", 5));
char propvalue[PROP_VALUE_MAX];
- ASSERT_EQ(6, __system_property_get("property", propvalue));
+ ASSERT_EQ(6, system_properties.Get("property", propvalue));
ASSERT_STREQ(propvalue, "value1");
- ASSERT_EQ(6, __system_property_get("other_property", propvalue));
+ ASSERT_EQ(6, system_properties.Get("other_property", propvalue));
ASSERT_STREQ(propvalue, "value2");
- ASSERT_EQ(6, __system_property_get("property_other", propvalue));
+ ASSERT_EQ(6, system_properties.Get("property_other", propvalue));
ASSERT_STREQ(propvalue, "value3");
- ASSERT_EQ(5, __system_property_get(name, propvalue));
+ ASSERT_EQ(5, system_properties.Get(name, propvalue));
ASSERT_STREQ(propvalue, "value");
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -151,33 +127,33 @@
TEST(properties, __system_property_update) {
#if defined(__BIONIC__)
- LocalPropertyTestState pa;
- ASSERT_TRUE(pa.valid);
+ SystemPropertiesTest system_properties;
+ ASSERT_TRUE(system_properties.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));
+ ASSERT_EQ(0, system_properties.Add("property", 8, "oldvalue1", 9));
+ ASSERT_EQ(0, system_properties.Add("other_property", 14, "value2", 6));
+ ASSERT_EQ(0, system_properties.Add("property_other", 14, "value3", 6));
- const prop_info* pi = __system_property_find("property");
+ const prop_info* pi = system_properties.Find("property");
ASSERT_TRUE(pi != nullptr);
- __system_property_update(const_cast<prop_info*>(pi), "value4", 6);
+ system_properties.Update(const_cast<prop_info*>(pi), "value4", 6);
- pi = __system_property_find("other_property");
+ pi = system_properties.Find("other_property");
ASSERT_TRUE(pi != nullptr);
- __system_property_update(const_cast<prop_info*>(pi), "newvalue5", 9);
+ system_properties.Update(const_cast<prop_info*>(pi), "newvalue5", 9);
- pi = __system_property_find("property_other");
+ pi = system_properties.Find("property_other");
ASSERT_TRUE(pi != nullptr);
- __system_property_update(const_cast<prop_info*>(pi), "value6", 6);
+ system_properties.Update(const_cast<prop_info*>(pi), "value6", 6);
char propvalue[PROP_VALUE_MAX];
- ASSERT_EQ(6, __system_property_get("property", propvalue));
+ ASSERT_EQ(6, system_properties.Get("property", propvalue));
ASSERT_STREQ(propvalue, "value4");
- ASSERT_EQ(9, __system_property_get("other_property", propvalue));
+ ASSERT_EQ(9, system_properties.Get("other_property", propvalue));
ASSERT_STREQ(propvalue, "newvalue5");
- ASSERT_EQ(6, __system_property_get("property_other", propvalue));
+ ASSERT_EQ(6, system_properties.Get("property_other", propvalue));
ASSERT_STREQ(propvalue, "value6");
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -186,8 +162,9 @@
TEST(properties, fill) {
#if defined(__BIONIC__)
- LocalPropertyTestState pa;
- ASSERT_TRUE(pa.valid);
+ SystemPropertiesTest system_properties;
+ ASSERT_TRUE(system_properties.valid());
+
char prop_name[PROP_NAME_MAX];
char prop_value[PROP_VALUE_MAX];
char prop_value_ret[PROP_VALUE_MAX];
@@ -202,7 +179,7 @@
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);
+ ret = system_properties.Add(prop_name, PROP_NAME_MAX - 1, prop_value, PROP_VALUE_MAX - 1);
if (ret < 0)
break;
@@ -221,7 +198,7 @@
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(PROP_VALUE_MAX - 1, system_properties.Get(prop_name, prop_value_ret));
ASSERT_EQ(0, memcmp(prop_value, prop_value_ret, PROP_VALUE_MAX));
}
#else // __BIONIC__
@@ -231,15 +208,15 @@
TEST(properties, __system_property_foreach) {
#if defined(__BIONIC__)
- LocalPropertyTestState pa;
- ASSERT_TRUE(pa.valid);
+ SystemPropertiesTest system_properties;
+ ASSERT_TRUE(system_properties.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));
+ ASSERT_EQ(0, system_properties.Add("property", 8, "value1", 6));
+ ASSERT_EQ(0, system_properties.Add("other_property", 14, "value2", 6));
+ ASSERT_EQ(0, system_properties.Add("property_other", 14, "value3", 6));
size_t count = 0;
- ASSERT_EQ(0, __system_property_foreach(foreach_test_callback, &count));
+ ASSERT_EQ(0, system_properties.Foreach(foreach_test_callback, &count));
ASSERT_EQ(3U, count);
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -248,27 +225,27 @@
TEST(properties, __system_property_find_nth) {
#if defined(__BIONIC__)
- LocalPropertyTestState pa;
- ASSERT_TRUE(pa.valid);
+ SystemPropertiesTest system_properties;
+ ASSERT_TRUE(system_properties.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));
+ ASSERT_EQ(0, system_properties.Add("property", 8, "value1", 6));
+ ASSERT_EQ(0, system_properties.Add("other_property", 14, "value2", 6));
+ ASSERT_EQ(0, system_properties.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_EQ(6, system_properties.Read(system_properties.FindNth(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_EQ(6, system_properties.Read(system_properties.FindNth(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_EQ(6, system_properties.Read(system_properties.FindNth(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);
+ ASSERT_TRUE(system_properties.FindNth(i) == nullptr);
}
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -277,8 +254,9 @@
TEST(properties, fill_hierarchical) {
#if defined(__BIONIC__)
- LocalPropertyTestState pa;
- ASSERT_TRUE(pa.valid);
+ SystemPropertiesTest system_properties;
+ ASSERT_TRUE(system_properties.valid());
+
char prop_name[PROP_NAME_MAX];
char prop_value[PROP_VALUE_MAX];
char prop_value_ret[PROP_VALUE_MAX];
@@ -294,7 +272,8 @@
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));
+ ASSERT_EQ(0, system_properties.Add(
+ prop_name, PROP_NAME_MAX - 1, prop_value, PROP_VALUE_MAX - 1));
}
}
}
@@ -310,7 +289,7 @@
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(PROP_VALUE_MAX - 1, system_properties.Get(prop_name, prop_value_ret));
ASSERT_EQ(0, memcmp(prop_value, prop_value_ret, PROP_VALUE_MAX));
}
}
@@ -318,7 +297,7 @@
bool ok[8][8][8];
memset(ok, 0, sizeof(ok));
- __system_property_foreach(hierarchical_test_callback, ok);
+ system_properties.Foreach(hierarchical_test_callback, ok);
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
@@ -334,19 +313,20 @@
TEST(properties, errors) {
#if defined(__BIONIC__)
- LocalPropertyTestState pa;
- ASSERT_TRUE(pa.valid);
+ SystemPropertiesTest system_properties;
+ ASSERT_TRUE(system_properties.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_properties.Add("property", 8, "value1", 6));
+ ASSERT_EQ(0, system_properties.Add("other_property", 14, "value2", 6));
+ ASSERT_EQ(0, system_properties.Add("property_other", 14, "value3", 6));
- ASSERT_EQ(0, __system_property_find("property1"));
- ASSERT_EQ(0, __system_property_get("property1", prop_value));
+ ASSERT_EQ(0, system_properties.Find("property1"));
+ ASSERT_EQ(0, system_properties.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));
+ ASSERT_EQ(-1, system_properties.Add("name", 4, "value", PROP_VALUE_MAX));
+ ASSERT_EQ(-1, system_properties.Update(NULL, "value", PROP_VALUE_MAX));
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif // __BIONIC__
@@ -354,15 +334,15 @@
TEST(properties, __system_property_serial) {
#if defined(__BIONIC__)
- LocalPropertyTestState pa;
- ASSERT_TRUE(pa.valid);
+ SystemPropertiesTest system_properties;
+ ASSERT_TRUE(system_properties.valid());
- ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6));
- const prop_info* pi = __system_property_find("property");
+ ASSERT_EQ(0, system_properties.Add("property", 8, "value1", 6));
+ const prop_info* pi = system_properties.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));
+ unsigned serial = system_properties.Serial(pi);
+ ASSERT_EQ(0, system_properties.Update(const_cast<prop_info*>(pi), "value2", 6));
+ ASSERT_NE(serial, system_properties.Serial(pi));
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif // __BIONIC__
@@ -370,25 +350,30 @@
TEST(properties, __system_property_wait_any) {
#if defined(__BIONIC__)
- LocalPropertyTestState pa;
- ASSERT_TRUE(pa.valid);
+ SystemPropertiesTest system_properties;
+ ASSERT_TRUE(system_properties.valid());
- ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6));
- unsigned serial = __system_property_wait_any(0);
+ ASSERT_EQ(0, system_properties.Add("property", 8, "value1", 6));
+ unsigned serial = system_properties.WaitAny(0);
- prop_info* pi = const_cast<prop_info*>(__system_property_find("property"));
+ prop_info* pi = const_cast<prop_info*>(system_properties.Find("property"));
ASSERT_TRUE(pi != nullptr);
- __system_property_update(pi, "value2", 6);
- serial = __system_property_wait_any(serial);
+ system_properties.Update(pi, "value2", 6);
+ serial = system_properties.WaitAny(serial);
int flag = 0;
- pthread_t t;
- ASSERT_EQ(0, pthread_create(&t, nullptr, PropertyWaitHelperFn, &flag));
+ std::thread thread([&system_properties, &flag]() {
+ prop_info* pi = const_cast<prop_info*>(system_properties.Find("property"));
+ usleep(100000);
+
+ flag = 1;
+ system_properties.Update(pi, "value3", 6);
+ });
ASSERT_EQ(flag, 0);
- serial = __system_property_wait_any(serial);
+ serial = system_properties.WaitAny(serial);
ASSERT_EQ(flag, 1);
- ASSERT_EQ(0, pthread_join(t, nullptr));
+ thread.join();
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif // __BIONIC__
@@ -396,29 +381,29 @@
TEST(properties, __system_property_wait) {
#if defined(__BIONIC__)
- LocalPropertyTestState pa;
- ASSERT_TRUE(pa.valid);
+ SystemPropertiesTest system_properties;
+ ASSERT_TRUE(system_properties.valid());
- ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6));
+ ASSERT_EQ(0, system_properties.Add("property", 8, "value1", 6));
- prop_info* pi = const_cast<prop_info*>(__system_property_find("property"));
+ prop_info* pi = const_cast<prop_info*>(system_properties.Find("property"));
ASSERT_TRUE(pi != nullptr);
- unsigned serial = __system_property_serial(pi);
+ unsigned serial = system_properties.Serial(pi);
- std::thread thread([]() {
- prop_info* pi = const_cast<prop_info*>(__system_property_find("property"));
+ std::thread thread([&system_properties]() {
+ prop_info* pi = const_cast<prop_info*>(system_properties.Find("property"));
ASSERT_TRUE(pi != nullptr);
- __system_property_update(pi, "value2", 6);
+ system_properties.Update(pi, "value2", 6);
});
uint32_t new_serial;
- __system_property_wait(pi, serial, &new_serial, nullptr);
+ system_properties.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_EQ(6, system_properties.Get("property", value));
ASSERT_STREQ("value2", value);
thread.join();
@@ -457,8 +442,8 @@
TEST(properties, __system_property_extra_long_read_only) {
#if defined(__BIONIC__)
- LocalPropertyTestState pa;
- ASSERT_TRUE(pa.valid);
+ SystemPropertiesTest system_properties;
+ ASSERT_TRUE(system_properties.valid());
std::vector<std::pair<std::string, std::string>> short_properties = {
{ "ro.0char", std::string() },
@@ -475,33 +460,34 @@
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()));
+ ASSERT_EQ(0, system_properties.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()));
+ ASSERT_EQ(0, system_properties.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) {
+ auto check_with_legacy_read = [&system_properties](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))
+ EXPECT_EQ(static_cast<int>(expected_value.size()), system_properties.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());
+ auto check_with_read_callback = [&system_properties](const std::string& name,
+ const std::string& expected_value) {
+ const prop_info* pi = system_properties.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);
+ system_properties.ReadCallback(pi,
+ [](void* cookie, const char*, const char* value, uint32_t) {
+ auto* out_value = reinterpret_cast<std::string*>(cookie);
+ *out_value = value;
+ },
+ &value);
EXPECT_EQ(expected_value, value) << name;
};
@@ -529,12 +515,12 @@
// 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);
+ SystemPropertiesTest system_properties;
+ ASSERT_TRUE(system_properties.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()));
+ ASSERT_NE(0, system_properties.Add(name.c_str(), name.size(), value.c_str(), value.size()));
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";