blob: e0d38a8225d5d382e4a3fe5adc86a6e3f7a807e6 [file] [log] [blame]
Tom Cherryfd44b9f2017-11-08 14:01:00 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
Tom Cherrye275d6d2017-12-11 23:31:33 -080029#include "system_properties/system_properties.h"
30
Tom Cherryfd44b9f2017-11-08 14:01:00 -080031#include <errno.h>
Nate Myrenb8c87b12023-08-28 16:46:39 -070032#include <private/android_filesystem_config.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080033#include <stdatomic.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080034#include <stdlib.h>
35#include <string.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080036#include <sys/stat.h>
37#include <sys/types.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080038#include <unistd.h>
39
Tom Cherry8d366a82017-11-30 15:41:32 -080040#include <new>
41
Nate Myrenb8c87b12023-08-28 16:46:39 -070042#include <async_safe/CHECK.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080043#include <async_safe/log.h>
44
45#include "private/ErrnoRestorer.h"
Tom Cherryfd44b9f2017-11-08 14:01:00 -080046#include "private/bionic_futex.h"
Tom Cherryfd44b9f2017-11-08 14:01:00 -080047
Tom Cherrye275d6d2017-12-11 23:31:33 -080048#include "system_properties/context_node.h"
49#include "system_properties/prop_area.h"
50#include "system_properties/prop_info.h"
Tom Cherryfd44b9f2017-11-08 14:01:00 -080051
52#define SERIAL_DIRTY(serial) ((serial)&1)
53#define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
Nate Myrenb8c87b12023-08-28 16:46:39 -070054#define APPCOMPAT_PREFIX "ro.appcompat_override."
Tom Cherryfd44b9f2017-11-08 14:01:00 -080055
Tom Cherryfd44b9f2017-11-08 14:01:00 -080056static bool is_dir(const char* pathname) {
57 struct stat info;
58 if (stat(pathname, &info) == -1) {
59 return false;
60 }
61 return S_ISDIR(info.st_mode);
62}
63
Tom Cherrye275d6d2017-12-11 23:31:33 -080064bool SystemProperties::Init(const char* filename) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -080065 // This is called from __libc_init_common, and should leave errno at 0 (http://b/37248982).
66 ErrnoRestorer errno_restorer;
67
Tom Cherrye275d6d2017-12-11 23:31:33 -080068 if (initialized_) {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080069 contexts_->ResetAccess();
Tom Cherrye275d6d2017-12-11 23:31:33 -080070 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -080071 }
Tom Cherrye275d6d2017-12-11 23:31:33 -080072
Elliott Hughesd19f7b12023-08-30 21:19:55 +000073 properties_filename_ = filename;
Tom Cherrye275d6d2017-12-11 23:31:33 -080074
Nate Myrenb8c87b12023-08-28 16:46:39 -070075 if (!InitContexts(false)) {
76 return false;
77 }
78
79 initialized_ = true;
80 return true;
81}
82
83bool SystemProperties::InitContexts(bool load_default_path) {
Elliott Hughesd19f7b12023-08-30 21:19:55 +000084 if (is_dir(properties_filename_.c_str())) {
Nate Myrenb8c87b12023-08-28 16:46:39 -070085 if (access(PROP_TREE_FILE, R_OK) == 0) {
86 auto serial_contexts = new (contexts_data_) ContextsSerialized();
87 contexts_ = serial_contexts;
88 if (!serial_contexts->Initialize(false, properties_filename_.c_str(), nullptr,
89 load_default_path)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080090 return false;
Tom Cherry8be995b2017-12-14 01:57:37 +000091 }
Tom Cherry8be995b2017-12-14 01:57:37 +000092 } else {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080093 contexts_ = new (contexts_data_) ContextsSplit();
Elliott Hughesd19f7b12023-08-30 21:19:55 +000094 if (!contexts_->Initialize(false, properties_filename_.c_str(), nullptr)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080095 return false;
Tom Cherry8be995b2017-12-14 01:57:37 +000096 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -080097 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -080098 } else {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080099 contexts_ = new (contexts_data_) ContextsPreSplit();
Elliott Hughesd19f7b12023-08-30 21:19:55 +0000100 if (!contexts_->Initialize(false, properties_filename_.c_str(), nullptr)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800101 return false;
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800102 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800103 }
Tom Cherrye275d6d2017-12-11 23:31:33 -0800104 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800105}
106
Tom Cherrye275d6d2017-12-11 23:31:33 -0800107bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed) {
Nate Myrenb8c87b12023-08-28 16:46:39 -0700108 return AreaInit(filename, fsetxattr_failed, false);
109}
110
111// Note: load_default_path is only used for testing, as it will cause properties to be loaded from
112// one file (specified by PropertyInfoAreaFile.LoadDefaultPath), but be written to "filename".
113bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed,
114 bool load_default_path) {
Elliott Hughesd19f7b12023-08-30 21:19:55 +0000115 properties_filename_ = filename;
Nate Myrenb8c87b12023-08-28 16:46:39 -0700116 auto serial_contexts = new (contexts_data_) ContextsSerialized();
117 contexts_ = serial_contexts;
118 if (!serial_contexts->Initialize(true, properties_filename_.c_str(), fsetxattr_failed,
119 load_default_path)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800120 return false;
121 }
Nate Myrenb8c87b12023-08-28 16:46:39 -0700122
Nate Myrenb8c87b12023-08-28 16:46:39 -0700123 appcompat_filename_ = PropertiesFilename(properties_filename_.c_str(), "appcompat_override");
Nate Myren94374442024-04-19 19:07:34 +0000124 appcompat_override_contexts_ = nullptr;
125 if (access(appcompat_filename_.c_str(), F_OK) != -1) {
126 auto* appcompat_contexts = new (appcompat_override_contexts_data_) ContextsSerialized();
127 if (!appcompat_contexts->Initialize(true, appcompat_filename_.c_str(), fsetxattr_failed,
128 load_default_path)) {
129 // The appcompat folder exists, but initializing it failed
130 return false;
131 } else {
132 appcompat_override_contexts_ = appcompat_contexts;
133 }
Nate Myrenb8c87b12023-08-28 16:46:39 -0700134 }
Nate Myrenb8c87b12023-08-28 16:46:39 -0700135
Tom Cherrye275d6d2017-12-11 23:31:33 -0800136 initialized_ = true;
137 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800138}
139
Nate Myrenb8c87b12023-08-28 16:46:39 -0700140bool SystemProperties::Reload(bool load_default_path) {
141 if (!initialized_) {
142 return true;
143 }
144
145 return InitContexts(load_default_path);
146}
147
Tom Cherrye275d6d2017-12-11 23:31:33 -0800148uint32_t SystemProperties::AreaSerial() {
149 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800150 return -1;
151 }
152
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800153 prop_area* pa = contexts_->GetSerialPropArea();
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800154 if (!pa) {
155 return -1;
156 }
Tom Cherryf76bbf52017-11-08 14:01:00 -0800157
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800158 // Make sure this read fulfilled before __system_property_serial
159 return atomic_load_explicit(pa->serial(), memory_order_acquire);
160}
161
Tom Cherrye275d6d2017-12-11 23:31:33 -0800162const prop_info* SystemProperties::Find(const char* name) {
163 if (!initialized_) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800164 return nullptr;
165 }
166
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800167 prop_area* pa = contexts_->GetPropAreaForName(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800168 if (!pa) {
Tom Cherry8f11c5f2021-04-01 15:07:40 -0700169 async_safe_format_log(ANDROID_LOG_WARN, "libc", "Access denied finding property \"%s\"", name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800170 return nullptr;
171 }
172
173 return pa->find(name);
174}
175
Nate Myrenb8c87b12023-08-28 16:46:39 -0700176static bool is_appcompat_override(const char* name) {
177 return strncmp(name, APPCOMPAT_PREFIX, strlen(APPCOMPAT_PREFIX)) == 0;
178}
179
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800180static bool is_read_only(const char* name) {
181 return strncmp(name, "ro.", 3) == 0;
182}
183
Raman Tennetib481a2e2019-11-12 20:41:55 +0000184uint32_t SystemProperties::ReadMutablePropertyValue(const prop_info* pi, char* value) {
185 // We assume the memcpy below gets serialized by the acquire fence.
186 uint32_t new_serial = load_const_atomic(&pi->serial, memory_order_acquire);
187 uint32_t serial;
188 unsigned int len;
189 for (;;) {
190 serial = new_serial;
191 len = SERIAL_VALUE_LEN(serial);
192 if (__predict_false(SERIAL_DIRTY(serial))) {
193 // See the comment in the prop_area constructor.
194 prop_area* pa = contexts_->GetPropAreaForName(pi->name);
195 memcpy(value, pa->dirty_backup_area(), len + 1);
196 } else {
197 memcpy(value, pi->value, len + 1);
198 }
Raman Tennetide39d922019-11-12 18:24:06 +0000199 atomic_thread_fence(memory_order_acquire);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000200 new_serial = load_const_atomic(&pi->serial, memory_order_relaxed);
201 if (__predict_true(serial == new_serial)) {
202 break;
203 }
204 // We need another fence here because we want to ensure that the memcpy in the
205 // next iteration of the loop occurs after the load of new_serial above. We could
206 // get this guarantee by making the load_const_atomic of new_serial
207 // memory_order_acquire instead of memory_order_relaxed, but then we'd pay the
208 // penalty of the memory_order_acquire even in the overwhelmingly common case
209 // that the serial number didn't change.
210 atomic_thread_fence(memory_order_acquire);
211 }
212 return serial;
213}
214
215int SystemProperties::Read(const prop_info* pi, char* name, char* value) {
216 uint32_t serial = ReadMutablePropertyValue(pi, value);
217 if (name != nullptr) {
218 size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX);
219 if (namelen >= PROP_NAME_MAX) {
220 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
221 "The property name length for \"%s\" is >= %d;"
222 " please use __system_property_read_callback"
223 " to read this property. (the name is truncated to \"%s\")",
224 pi->name, PROP_NAME_MAX - 1, name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800225 }
226 }
Raman Tennetib481a2e2019-11-12 20:41:55 +0000227 if (is_read_only(pi->name) && pi->is_long()) {
228 async_safe_format_log(
229 ANDROID_LOG_ERROR, "libc",
230 "The property \"%s\" has a value with length %zu that is too large for"
231 " __system_property_get()/__system_property_read(); use"
232 " __system_property_read_callback() instead.",
233 pi->name, strlen(pi->long_value()));
234 }
235 return SERIAL_VALUE_LEN(serial);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800236}
237
Tom Cherrye275d6d2017-12-11 23:31:33 -0800238void SystemProperties::ReadCallback(const prop_info* pi,
239 void (*callback)(void* cookie, const char* name,
240 const char* value, uint32_t serial),
241 void* cookie) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800242 // Read only properties don't need to copy the value to a temporary buffer, since it can never
Raman Tennetib481a2e2019-11-12 20:41:55 +0000243 // change. We use relaxed memory order on the serial load for the same reason.
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800244 if (is_read_only(pi->name)) {
Raman Tennetib481a2e2019-11-12 20:41:55 +0000245 uint32_t serial = load_const_atomic(&pi->serial, memory_order_relaxed);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800246 if (pi->is_long()) {
247 callback(cookie, pi->name, pi->long_value(), serial);
248 } else {
249 callback(cookie, pi->name, pi->value, serial);
250 }
251 return;
252 }
253
Raman Tennetib481a2e2019-11-12 20:41:55 +0000254 char value_buf[PROP_VALUE_MAX];
255 uint32_t serial = ReadMutablePropertyValue(pi, value_buf);
256 callback(cookie, pi->name, value_buf, serial);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800257}
258
Tom Cherrye275d6d2017-12-11 23:31:33 -0800259int SystemProperties::Get(const char* name, char* value) {
260 const prop_info* pi = Find(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800261
Yi Kong32bc0fc2018-08-02 17:31:13 -0700262 if (pi != nullptr) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800263 return Read(pi, nullptr, value);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800264 } else {
265 value[0] = 0;
266 return 0;
267 }
268}
269
Tom Cherrye275d6d2017-12-11 23:31:33 -0800270int SystemProperties::Update(prop_info* pi, const char* value, unsigned int len) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800271 if (len >= PROP_VALUE_MAX) {
272 return -1;
273 }
274
Tom Cherrye275d6d2017-12-11 23:31:33 -0800275 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800276 return -1;
277 }
Nate Myrenb8c87b12023-08-28 16:46:39 -0700278 bool have_override = appcompat_override_contexts_ != nullptr;
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800279
Raman Tennetib481a2e2019-11-12 20:41:55 +0000280 prop_area* serial_pa = contexts_->GetSerialPropArea();
Nate Myrenb8c87b12023-08-28 16:46:39 -0700281 prop_area* override_serial_pa =
282 have_override ? appcompat_override_contexts_->GetSerialPropArea() : nullptr;
Raman Tennetib481a2e2019-11-12 20:41:55 +0000283 if (!serial_pa) {
284 return -1;
285 }
286 prop_area* pa = contexts_->GetPropAreaForName(pi->name);
Nate Myrenb8c87b12023-08-28 16:46:39 -0700287 prop_area* override_pa =
288 have_override ? appcompat_override_contexts_->GetPropAreaForName(pi->name) : nullptr;
Raman Tennetib481a2e2019-11-12 20:41:55 +0000289 if (__predict_false(!pa)) {
290 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Could not find area for \"%s\"", pi->name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800291 return -1;
292 }
Nate Myrenb8c87b12023-08-28 16:46:39 -0700293 CHECK(!have_override || (override_pa && override_serial_pa));
294
295 auto* override_pi = const_cast<prop_info*>(have_override ? override_pa->find(pi->name) : nullptr);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800296
297 uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000298 unsigned int old_len = SERIAL_VALUE_LEN(serial);
299
300 // The contract with readers is that whenever the dirty bit is set, an undamaged copy
301 // of the pre-dirty value is available in the dirty backup area. The fence ensures
302 // that we publish our dirty area update before allowing readers to see a
303 // dirty serial.
304 memcpy(pa->dirty_backup_area(), pi->value, old_len + 1);
Nate Myrenb8c87b12023-08-28 16:46:39 -0700305 if (have_override) {
306 memcpy(override_pa->dirty_backup_area(), override_pi->value, old_len + 1);
307 }
Raman Tennetib481a2e2019-11-12 20:41:55 +0000308 atomic_thread_fence(memory_order_release);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800309 serial |= 1;
310 atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
Raman Tennetide39d922019-11-12 18:24:06 +0000311 strlcpy(pi->value, value, len + 1);
Nate Myrenb8c87b12023-08-28 16:46:39 -0700312 if (have_override) {
313 atomic_store_explicit(&override_pi->serial, serial, memory_order_relaxed);
314 strlcpy(override_pi->value, value, len + 1);
315 }
Raman Tennetib481a2e2019-11-12 20:41:55 +0000316 // Now the primary value property area is up-to-date. Let readers know that they should
317 // look at the property value instead of the backup area.
318 atomic_thread_fence(memory_order_release);
Nate Myrenb8c87b12023-08-28 16:46:39 -0700319 int new_serial = (len << 24) | ((serial + 1) & 0xffffff);
320 atomic_store_explicit(&pi->serial, new_serial, memory_order_relaxed);
321 if (have_override) {
322 atomic_store_explicit(&override_pi->serial, new_serial, memory_order_relaxed);
323 }
Raman Tennetib481a2e2019-11-12 20:41:55 +0000324 __futex_wake(&pi->serial, INT32_MAX); // Fence by side effect
325 atomic_store_explicit(serial_pa->serial(),
326 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800327 memory_order_release);
Nate Myrenb8c87b12023-08-28 16:46:39 -0700328 if (have_override) {
329 atomic_store_explicit(override_serial_pa->serial(),
330 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
331 memory_order_release);
332 }
Raman Tennetib481a2e2019-11-12 20:41:55 +0000333 __futex_wake(serial_pa->serial(), INT32_MAX);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800334
335 return 0;
336}
337
Tom Cherrye275d6d2017-12-11 23:31:33 -0800338int SystemProperties::Add(const char* name, unsigned int namelen, const char* value,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800339 unsigned int valuelen) {
Elliott Hughes622b6ae2024-05-01 23:46:45 +0000340 if (namelen < 1) {
341 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
342 "__system_property_add failed: name length 0");
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800343 return -1;
344 }
345
Elliott Hughes622b6ae2024-05-01 23:46:45 +0000346 if (valuelen >= PROP_VALUE_MAX && !is_read_only(name)) {
347 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
348 "__system_property_add failed: \"%s\" value too long: %d >= PROP_VALUE_MAX",
349 name, valuelen);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800350 return -1;
351 }
352
Tom Cherrye275d6d2017-12-11 23:31:33 -0800353 if (!initialized_) {
Elliott Hughes622b6ae2024-05-01 23:46:45 +0000354 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
355 "__system_property_add failed: properties not initialized");
Tom Cherryf76bbf52017-11-08 14:01:00 -0800356 return -1;
357 }
358
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800359 prop_area* serial_pa = contexts_->GetSerialPropArea();
Tom Cherryf76bbf52017-11-08 14:01:00 -0800360 if (serial_pa == nullptr) {
Elliott Hughes622b6ae2024-05-01 23:46:45 +0000361 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
362 "__system_property_add failed: property area not found");
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800363 return -1;
364 }
365
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800366 prop_area* pa = contexts_->GetPropAreaForName(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800367 if (!pa) {
Elliott Hughes622b6ae2024-05-01 23:46:45 +0000368 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
369 "__system_property_add failed: access denied for \"%s\"", name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800370 return -1;
371 }
372
Elliott Hughes622b6ae2024-05-01 23:46:45 +0000373 if (!pa->add(name, namelen, value, valuelen)) {
374 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
375 "__system_property_add failed: add failed for \"%s\"", name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800376 return -1;
377 }
378
Nate Myrenb8c87b12023-08-28 16:46:39 -0700379 if (appcompat_override_contexts_ != nullptr) {
380 bool is_override = is_appcompat_override(name);
381 const char* override_name = name;
382 if (is_override) override_name += strlen(APPCOMPAT_PREFIX);
383 prop_area* other_pa = appcompat_override_contexts_->GetPropAreaForName(override_name);
384 prop_area* other_serial_pa = appcompat_override_contexts_->GetSerialPropArea();
385 CHECK(other_pa && other_serial_pa);
386 // We may write a property twice to overrides, once for the ro.*, and again for the
387 // ro.appcompat_override.ro.* property. If we've already written, then we should essentially
388 // perform an Update, not an Add.
389 auto other_pi = const_cast<prop_info*>(other_pa->find(override_name));
390 if (!other_pi) {
391 if (other_pa->add(override_name, strlen(override_name), value, valuelen)) {
392 atomic_store_explicit(
393 other_serial_pa->serial(),
394 atomic_load_explicit(other_serial_pa->serial(), memory_order_relaxed) + 1,
395 memory_order_release);
396 }
397 } else if (is_override) {
398 // We already wrote the ro.*, but appcompat_override.ro.* should override that. We don't
399 // need to do the usual dirty bit setting, as this only happens during the init process,
Nate Myren0ab06152023-10-19 16:50:59 -0700400 // before any readers are started. Check that only init or root can write appcompat props.
401 CHECK(getpid() == 1 || getuid() == 0);
Nate Myrenb8c87b12023-08-28 16:46:39 -0700402 atomic_thread_fence(memory_order_release);
403 strlcpy(other_pi->value, value, valuelen + 1);
404 }
405 }
406
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800407 // There is only a single mutator, but we want to make sure that
408 // updates are visible to a reader waiting for the update.
Tom Cherryf76bbf52017-11-08 14:01:00 -0800409 atomic_store_explicit(serial_pa->serial(),
410 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
411 memory_order_release);
412 __futex_wake(serial_pa->serial(), INT32_MAX);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800413 return 0;
414}
415
Tom Cherrye275d6d2017-12-11 23:31:33 -0800416uint32_t SystemProperties::WaitAny(uint32_t old_serial) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800417 uint32_t new_serial;
Tom Cherrye275d6d2017-12-11 23:31:33 -0800418 Wait(nullptr, old_serial, &new_serial, nullptr);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800419 return new_serial;
420}
421
Tom Cherrye275d6d2017-12-11 23:31:33 -0800422bool SystemProperties::Wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800423 const timespec* relative_timeout) {
424 // Are we waiting on the global serial or a specific serial?
425 atomic_uint_least32_t* serial_ptr;
426 if (pi == nullptr) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800427 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800428 return -1;
429 }
430
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800431 prop_area* serial_pa = contexts_->GetSerialPropArea();
Tom Cherryf76bbf52017-11-08 14:01:00 -0800432 if (serial_pa == nullptr) {
433 return -1;
434 }
435
436 serial_ptr = serial_pa->serial();
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800437 } else {
438 serial_ptr = const_cast<atomic_uint_least32_t*>(&pi->serial);
439 }
440
441 uint32_t new_serial;
442 do {
443 int rc;
444 if ((rc = __futex_wait(serial_ptr, old_serial, relative_timeout)) != 0 && rc == -ETIMEDOUT) {
445 return false;
446 }
447 new_serial = load_const_atomic(serial_ptr, memory_order_acquire);
448 } while (new_serial == old_serial);
449
450 *new_serial_ptr = new_serial;
451 return true;
452}
453
Tom Cherrye275d6d2017-12-11 23:31:33 -0800454const prop_info* SystemProperties::FindNth(unsigned n) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800455 struct find_nth {
456 const uint32_t sought;
457 uint32_t current;
458 const prop_info* result;
459
460 explicit find_nth(uint32_t n) : sought(n), current(0), result(nullptr) {
461 }
462 static void fn(const prop_info* pi, void* ptr) {
463 find_nth* self = reinterpret_cast<find_nth*>(ptr);
464 if (self->current++ == self->sought) self->result = pi;
465 }
466 } state(n);
Tom Cherrye275d6d2017-12-11 23:31:33 -0800467 Foreach(find_nth::fn, &state);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800468 return state.result;
469}
470
Tom Cherrye275d6d2017-12-11 23:31:33 -0800471int SystemProperties::Foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
472 if (!initialized_) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800473 return -1;
474 }
475
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800476 contexts_->ForEach(propfn, cookie);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800477
478 return 0;
479}