blob: 049236f22deb2bca4a21a4eae74b55acd2327463 [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>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080032#include <stdatomic.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080033#include <stdlib.h>
34#include <string.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080035#include <sys/stat.h>
36#include <sys/types.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080037#include <unistd.h>
38
Tom Cherry8d366a82017-11-30 15:41:32 -080039#include <new>
40
Tom Cherryfd44b9f2017-11-08 14:01:00 -080041#include <async_safe/log.h>
42
43#include "private/ErrnoRestorer.h"
Tom Cherryfd44b9f2017-11-08 14:01:00 -080044#include "private/bionic_futex.h"
Tom Cherryfd44b9f2017-11-08 14:01:00 -080045
Tom Cherrye275d6d2017-12-11 23:31:33 -080046#include "system_properties/context_node.h"
47#include "system_properties/prop_area.h"
48#include "system_properties/prop_info.h"
Tom Cherryfd44b9f2017-11-08 14:01:00 -080049
50#define SERIAL_DIRTY(serial) ((serial)&1)
51#define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
52
Tom Cherryfd44b9f2017-11-08 14:01:00 -080053static bool is_dir(const char* pathname) {
54 struct stat info;
55 if (stat(pathname, &info) == -1) {
56 return false;
57 }
58 return S_ISDIR(info.st_mode);
59}
60
Tom Cherrye275d6d2017-12-11 23:31:33 -080061bool SystemProperties::Init(const char* filename) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -080062 // This is called from __libc_init_common, and should leave errno at 0 (http://b/37248982).
63 ErrnoRestorer errno_restorer;
64
Tom Cherrye275d6d2017-12-11 23:31:33 -080065 if (initialized_) {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080066 contexts_->ResetAccess();
Tom Cherrye275d6d2017-12-11 23:31:33 -080067 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -080068 }
Tom Cherrye275d6d2017-12-11 23:31:33 -080069
Elliott Hughesd19f7b12023-08-30 21:19:55 +000070 properties_filename_ = filename;
Tom Cherrye275d6d2017-12-11 23:31:33 -080071
Elliott Hughesd19f7b12023-08-30 21:19:55 +000072 if (is_dir(properties_filename_.c_str())) {
Tom Cherry8be995b2017-12-14 01:57:37 +000073 if (access("/dev/__properties__/property_info", R_OK) == 0) {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080074 contexts_ = new (contexts_data_) ContextsSerialized();
Elliott Hughesd19f7b12023-08-30 21:19:55 +000075 if (!contexts_->Initialize(false, properties_filename_.c_str(), nullptr)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080076 return false;
Tom Cherry8be995b2017-12-14 01:57:37 +000077 }
Tom Cherry8be995b2017-12-14 01:57:37 +000078 } else {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080079 contexts_ = new (contexts_data_) ContextsSplit();
Elliott Hughesd19f7b12023-08-30 21:19:55 +000080 if (!contexts_->Initialize(false, properties_filename_.c_str(), nullptr)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080081 return false;
Tom Cherry8be995b2017-12-14 01:57:37 +000082 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -080083 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -080084 } else {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080085 contexts_ = new (contexts_data_) ContextsPreSplit();
Elliott Hughesd19f7b12023-08-30 21:19:55 +000086 if (!contexts_->Initialize(false, properties_filename_.c_str(), nullptr)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080087 return false;
Tom Cherryfd44b9f2017-11-08 14:01:00 -080088 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -080089 }
Tom Cherrye275d6d2017-12-11 23:31:33 -080090 initialized_ = true;
91 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -080092}
93
Tom Cherrye275d6d2017-12-11 23:31:33 -080094bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed) {
Elliott Hughesd19f7b12023-08-30 21:19:55 +000095 properties_filename_ = filename;
Tom Cherryee8e3dd2018-02-21 15:01:22 -080096 contexts_ = new (contexts_data_) ContextsSerialized();
Elliott Hughesd19f7b12023-08-30 21:19:55 +000097 if (!contexts_->Initialize(true, properties_filename_.c_str(), fsetxattr_failed)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080098 return false;
99 }
100 initialized_ = true;
101 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800102}
103
Tom Cherrye275d6d2017-12-11 23:31:33 -0800104uint32_t SystemProperties::AreaSerial() {
105 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800106 return -1;
107 }
108
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800109 prop_area* pa = contexts_->GetSerialPropArea();
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800110 if (!pa) {
111 return -1;
112 }
Tom Cherryf76bbf52017-11-08 14:01:00 -0800113
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800114 // Make sure this read fulfilled before __system_property_serial
115 return atomic_load_explicit(pa->serial(), memory_order_acquire);
116}
117
Tom Cherrye275d6d2017-12-11 23:31:33 -0800118const prop_info* SystemProperties::Find(const char* name) {
119 if (!initialized_) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800120 return nullptr;
121 }
122
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800123 prop_area* pa = contexts_->GetPropAreaForName(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800124 if (!pa) {
Tom Cherry8f11c5f2021-04-01 15:07:40 -0700125 async_safe_format_log(ANDROID_LOG_WARN, "libc", "Access denied finding property \"%s\"", name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800126 return nullptr;
127 }
128
129 return pa->find(name);
130}
131
132static bool is_read_only(const char* name) {
133 return strncmp(name, "ro.", 3) == 0;
134}
135
Raman Tennetib481a2e2019-11-12 20:41:55 +0000136uint32_t SystemProperties::ReadMutablePropertyValue(const prop_info* pi, char* value) {
137 // We assume the memcpy below gets serialized by the acquire fence.
138 uint32_t new_serial = load_const_atomic(&pi->serial, memory_order_acquire);
139 uint32_t serial;
140 unsigned int len;
141 for (;;) {
142 serial = new_serial;
143 len = SERIAL_VALUE_LEN(serial);
144 if (__predict_false(SERIAL_DIRTY(serial))) {
145 // See the comment in the prop_area constructor.
146 prop_area* pa = contexts_->GetPropAreaForName(pi->name);
147 memcpy(value, pa->dirty_backup_area(), len + 1);
148 } else {
149 memcpy(value, pi->value, len + 1);
150 }
Raman Tennetide39d922019-11-12 18:24:06 +0000151 atomic_thread_fence(memory_order_acquire);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000152 new_serial = load_const_atomic(&pi->serial, memory_order_relaxed);
153 if (__predict_true(serial == new_serial)) {
154 break;
155 }
156 // We need another fence here because we want to ensure that the memcpy in the
157 // next iteration of the loop occurs after the load of new_serial above. We could
158 // get this guarantee by making the load_const_atomic of new_serial
159 // memory_order_acquire instead of memory_order_relaxed, but then we'd pay the
160 // penalty of the memory_order_acquire even in the overwhelmingly common case
161 // that the serial number didn't change.
162 atomic_thread_fence(memory_order_acquire);
163 }
164 return serial;
165}
166
167int SystemProperties::Read(const prop_info* pi, char* name, char* value) {
168 uint32_t serial = ReadMutablePropertyValue(pi, value);
169 if (name != nullptr) {
170 size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX);
171 if (namelen >= PROP_NAME_MAX) {
172 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
173 "The property name length for \"%s\" is >= %d;"
174 " please use __system_property_read_callback"
175 " to read this property. (the name is truncated to \"%s\")",
176 pi->name, PROP_NAME_MAX - 1, name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800177 }
178 }
Raman Tennetib481a2e2019-11-12 20:41:55 +0000179 if (is_read_only(pi->name) && pi->is_long()) {
180 async_safe_format_log(
181 ANDROID_LOG_ERROR, "libc",
182 "The property \"%s\" has a value with length %zu that is too large for"
183 " __system_property_get()/__system_property_read(); use"
184 " __system_property_read_callback() instead.",
185 pi->name, strlen(pi->long_value()));
186 }
187 return SERIAL_VALUE_LEN(serial);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800188}
189
Tom Cherrye275d6d2017-12-11 23:31:33 -0800190void SystemProperties::ReadCallback(const prop_info* pi,
191 void (*callback)(void* cookie, const char* name,
192 const char* value, uint32_t serial),
193 void* cookie) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800194 // 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 +0000195 // change. We use relaxed memory order on the serial load for the same reason.
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800196 if (is_read_only(pi->name)) {
Raman Tennetib481a2e2019-11-12 20:41:55 +0000197 uint32_t serial = load_const_atomic(&pi->serial, memory_order_relaxed);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800198 if (pi->is_long()) {
199 callback(cookie, pi->name, pi->long_value(), serial);
200 } else {
201 callback(cookie, pi->name, pi->value, serial);
202 }
203 return;
204 }
205
Raman Tennetib481a2e2019-11-12 20:41:55 +0000206 char value_buf[PROP_VALUE_MAX];
207 uint32_t serial = ReadMutablePropertyValue(pi, value_buf);
208 callback(cookie, pi->name, value_buf, serial);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800209}
210
Tom Cherrye275d6d2017-12-11 23:31:33 -0800211int SystemProperties::Get(const char* name, char* value) {
212 const prop_info* pi = Find(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800213
Yi Kong32bc0fc2018-08-02 17:31:13 -0700214 if (pi != nullptr) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800215 return Read(pi, nullptr, value);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800216 } else {
217 value[0] = 0;
218 return 0;
219 }
220}
221
Tom Cherrye275d6d2017-12-11 23:31:33 -0800222int SystemProperties::Update(prop_info* pi, const char* value, unsigned int len) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800223 if (len >= PROP_VALUE_MAX) {
224 return -1;
225 }
226
Tom Cherrye275d6d2017-12-11 23:31:33 -0800227 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800228 return -1;
229 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800230
Raman Tennetib481a2e2019-11-12 20:41:55 +0000231 prop_area* serial_pa = contexts_->GetSerialPropArea();
232 if (!serial_pa) {
233 return -1;
234 }
235 prop_area* pa = contexts_->GetPropAreaForName(pi->name);
236 if (__predict_false(!pa)) {
237 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Could not find area for \"%s\"", pi->name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800238 return -1;
239 }
240
241 uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000242 unsigned int old_len = SERIAL_VALUE_LEN(serial);
243
244 // The contract with readers is that whenever the dirty bit is set, an undamaged copy
245 // of the pre-dirty value is available in the dirty backup area. The fence ensures
246 // that we publish our dirty area update before allowing readers to see a
247 // dirty serial.
248 memcpy(pa->dirty_backup_area(), pi->value, old_len + 1);
249 atomic_thread_fence(memory_order_release);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800250 serial |= 1;
251 atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
Raman Tennetide39d922019-11-12 18:24:06 +0000252 strlcpy(pi->value, value, len + 1);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000253 // Now the primary value property area is up-to-date. Let readers know that they should
254 // look at the property value instead of the backup area.
255 atomic_thread_fence(memory_order_release);
256 atomic_store_explicit(&pi->serial, (len << 24) | ((serial + 1) & 0xffffff), memory_order_relaxed);
257 __futex_wake(&pi->serial, INT32_MAX); // Fence by side effect
258 atomic_store_explicit(serial_pa->serial(),
259 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800260 memory_order_release);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000261 __futex_wake(serial_pa->serial(), INT32_MAX);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800262
263 return 0;
264}
265
Tom Cherrye275d6d2017-12-11 23:31:33 -0800266int SystemProperties::Add(const char* name, unsigned int namelen, const char* value,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800267 unsigned int valuelen) {
268 if (valuelen >= PROP_VALUE_MAX && !is_read_only(name)) {
269 return -1;
270 }
271
272 if (namelen < 1) {
273 return -1;
274 }
275
Tom Cherrye275d6d2017-12-11 23:31:33 -0800276 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800277 return -1;
278 }
279
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800280 prop_area* serial_pa = contexts_->GetSerialPropArea();
Tom Cherryf76bbf52017-11-08 14:01:00 -0800281 if (serial_pa == nullptr) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800282 return -1;
283 }
284
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800285 prop_area* pa = contexts_->GetPropAreaForName(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800286 if (!pa) {
287 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
288 return -1;
289 }
290
291 bool ret = pa->add(name, namelen, value, valuelen);
292 if (!ret) {
293 return -1;
294 }
295
296 // There is only a single mutator, but we want to make sure that
297 // updates are visible to a reader waiting for the update.
Tom Cherryf76bbf52017-11-08 14:01:00 -0800298 atomic_store_explicit(serial_pa->serial(),
299 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
300 memory_order_release);
301 __futex_wake(serial_pa->serial(), INT32_MAX);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800302 return 0;
303}
304
Tom Cherrye275d6d2017-12-11 23:31:33 -0800305uint32_t SystemProperties::WaitAny(uint32_t old_serial) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800306 uint32_t new_serial;
Tom Cherrye275d6d2017-12-11 23:31:33 -0800307 Wait(nullptr, old_serial, &new_serial, nullptr);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800308 return new_serial;
309}
310
Tom Cherrye275d6d2017-12-11 23:31:33 -0800311bool SystemProperties::Wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800312 const timespec* relative_timeout) {
313 // Are we waiting on the global serial or a specific serial?
314 atomic_uint_least32_t* serial_ptr;
315 if (pi == nullptr) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800316 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800317 return -1;
318 }
319
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800320 prop_area* serial_pa = contexts_->GetSerialPropArea();
Tom Cherryf76bbf52017-11-08 14:01:00 -0800321 if (serial_pa == nullptr) {
322 return -1;
323 }
324
325 serial_ptr = serial_pa->serial();
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800326 } else {
327 serial_ptr = const_cast<atomic_uint_least32_t*>(&pi->serial);
328 }
329
330 uint32_t new_serial;
331 do {
332 int rc;
333 if ((rc = __futex_wait(serial_ptr, old_serial, relative_timeout)) != 0 && rc == -ETIMEDOUT) {
334 return false;
335 }
336 new_serial = load_const_atomic(serial_ptr, memory_order_acquire);
337 } while (new_serial == old_serial);
338
339 *new_serial_ptr = new_serial;
340 return true;
341}
342
Tom Cherrye275d6d2017-12-11 23:31:33 -0800343const prop_info* SystemProperties::FindNth(unsigned n) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800344 struct find_nth {
345 const uint32_t sought;
346 uint32_t current;
347 const prop_info* result;
348
349 explicit find_nth(uint32_t n) : sought(n), current(0), result(nullptr) {
350 }
351 static void fn(const prop_info* pi, void* ptr) {
352 find_nth* self = reinterpret_cast<find_nth*>(ptr);
353 if (self->current++ == self->sought) self->result = pi;
354 }
355 } state(n);
Tom Cherrye275d6d2017-12-11 23:31:33 -0800356 Foreach(find_nth::fn, &state);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800357 return state.result;
358}
359
Tom Cherrye275d6d2017-12-11 23:31:33 -0800360int SystemProperties::Foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
361 if (!initialized_) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800362 return -1;
363 }
364
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800365 contexts_->ForEach(propfn, cookie);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800366
367 return 0;
368}