blob: 3fd20b7498ff35478e295ee3d1783e2502d13906 [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"
Chienyuan Huangf2b4a972020-08-20 08:42:31 +000049#include "system_properties/prop_trace.h"
Tom Cherryfd44b9f2017-11-08 14:01:00 -080050
51#define SERIAL_DIRTY(serial) ((serial)&1)
52#define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
53
Tom Cherryfd44b9f2017-11-08 14:01:00 -080054static bool is_dir(const char* pathname) {
55 struct stat info;
56 if (stat(pathname, &info) == -1) {
57 return false;
58 }
59 return S_ISDIR(info.st_mode);
60}
61
Tom Cherrye275d6d2017-12-11 23:31:33 -080062bool SystemProperties::Init(const char* filename) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -080063 // This is called from __libc_init_common, and should leave errno at 0 (http://b/37248982).
64 ErrnoRestorer errno_restorer;
65
Tom Cherrye275d6d2017-12-11 23:31:33 -080066 if (initialized_) {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080067 contexts_->ResetAccess();
Tom Cherrye275d6d2017-12-11 23:31:33 -080068 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -080069 }
Tom Cherrye275d6d2017-12-11 23:31:33 -080070
Ryan Prichardd91285f2018-05-01 18:03:05 -070071 if (strlen(filename) >= PROP_FILENAME_MAX) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080072 return false;
73 }
74 strcpy(property_filename_, filename);
75
76 if (is_dir(property_filename_)) {
Tom Cherry8be995b2017-12-14 01:57:37 +000077 if (access("/dev/__properties__/property_info", R_OK) == 0) {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080078 contexts_ = new (contexts_data_) ContextsSerialized();
79 if (!contexts_->Initialize(false, property_filename_, nullptr)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080080 return false;
Tom Cherry8be995b2017-12-14 01:57:37 +000081 }
Tom Cherry8be995b2017-12-14 01:57:37 +000082 } else {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080083 contexts_ = new (contexts_data_) ContextsSplit();
84 if (!contexts_->Initialize(false, property_filename_, nullptr)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080085 return false;
Tom Cherry8be995b2017-12-14 01:57:37 +000086 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -080087 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -080088 } else {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080089 contexts_ = new (contexts_data_) ContextsPreSplit();
90 if (!contexts_->Initialize(false, property_filename_, nullptr)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080091 return false;
Tom Cherryfd44b9f2017-11-08 14:01:00 -080092 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -080093 }
Tom Cherrye275d6d2017-12-11 23:31:33 -080094 initialized_ = true;
95 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -080096}
97
Tom Cherrye275d6d2017-12-11 23:31:33 -080098bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed) {
Ryan Prichardd91285f2018-05-01 18:03:05 -070099 if (strlen(filename) >= PROP_FILENAME_MAX) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800100 return false;
101 }
102 strcpy(property_filename_, filename);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800103
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800104 contexts_ = new (contexts_data_) ContextsSerialized();
105 if (!contexts_->Initialize(true, property_filename_, fsetxattr_failed)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800106 return false;
107 }
108 initialized_ = true;
109 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800110}
111
Tom Cherrye275d6d2017-12-11 23:31:33 -0800112uint32_t SystemProperties::AreaSerial() {
113 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800114 return -1;
115 }
116
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800117 prop_area* pa = contexts_->GetSerialPropArea();
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800118 if (!pa) {
119 return -1;
120 }
Tom Cherryf76bbf52017-11-08 14:01:00 -0800121
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800122 // Make sure this read fulfilled before __system_property_serial
123 return atomic_load_explicit(pa->serial(), memory_order_acquire);
124}
125
Tom Cherrye275d6d2017-12-11 23:31:33 -0800126const prop_info* SystemProperties::Find(const char* name) {
127 if (!initialized_) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800128 return nullptr;
129 }
130
Chienyuan Huangf2b4a972020-08-20 08:42:31 +0000131 SyspropTrace trace(name, nullptr /* prop_value */, nullptr /* prop_info */,
132 PropertyAction::kPropertyFind);
133
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800134 prop_area* pa = contexts_->GetPropAreaForName(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800135 if (!pa) {
136 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
137 return nullptr;
138 }
139
140 return pa->find(name);
141}
142
143static bool is_read_only(const char* name) {
144 return strncmp(name, "ro.", 3) == 0;
145}
146
Raman Tennetib481a2e2019-11-12 20:41:55 +0000147uint32_t SystemProperties::ReadMutablePropertyValue(const prop_info* pi, char* value) {
148 // We assume the memcpy below gets serialized by the acquire fence.
149 uint32_t new_serial = load_const_atomic(&pi->serial, memory_order_acquire);
150 uint32_t serial;
151 unsigned int len;
152 for (;;) {
153 serial = new_serial;
154 len = SERIAL_VALUE_LEN(serial);
155 if (__predict_false(SERIAL_DIRTY(serial))) {
156 // See the comment in the prop_area constructor.
157 prop_area* pa = contexts_->GetPropAreaForName(pi->name);
158 memcpy(value, pa->dirty_backup_area(), len + 1);
159 } else {
160 memcpy(value, pi->value, len + 1);
161 }
Raman Tennetide39d922019-11-12 18:24:06 +0000162 atomic_thread_fence(memory_order_acquire);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000163 new_serial = load_const_atomic(&pi->serial, memory_order_relaxed);
164 if (__predict_true(serial == new_serial)) {
165 break;
166 }
167 // We need another fence here because we want to ensure that the memcpy in the
168 // next iteration of the loop occurs after the load of new_serial above. We could
169 // get this guarantee by making the load_const_atomic of new_serial
170 // memory_order_acquire instead of memory_order_relaxed, but then we'd pay the
171 // penalty of the memory_order_acquire even in the overwhelmingly common case
172 // that the serial number didn't change.
173 atomic_thread_fence(memory_order_acquire);
174 }
175 return serial;
176}
177
178int SystemProperties::Read(const prop_info* pi, char* name, char* value) {
179 uint32_t serial = ReadMutablePropertyValue(pi, value);
180 if (name != nullptr) {
181 size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX);
182 if (namelen >= PROP_NAME_MAX) {
183 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
184 "The property name length for \"%s\" is >= %d;"
185 " please use __system_property_read_callback"
186 " to read this property. (the name is truncated to \"%s\")",
187 pi->name, PROP_NAME_MAX - 1, name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800188 }
189 }
Raman Tennetib481a2e2019-11-12 20:41:55 +0000190 if (is_read_only(pi->name) && pi->is_long()) {
191 async_safe_format_log(
192 ANDROID_LOG_ERROR, "libc",
193 "The property \"%s\" has a value with length %zu that is too large for"
194 " __system_property_get()/__system_property_read(); use"
195 " __system_property_read_callback() instead.",
196 pi->name, strlen(pi->long_value()));
197 }
198 return SERIAL_VALUE_LEN(serial);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800199}
200
Tom Cherrye275d6d2017-12-11 23:31:33 -0800201void SystemProperties::ReadCallback(const prop_info* pi,
202 void (*callback)(void* cookie, const char* name,
203 const char* value, uint32_t serial),
204 void* cookie) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800205 // 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 +0000206 // change. We use relaxed memory order on the serial load for the same reason.
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800207 if (is_read_only(pi->name)) {
Chienyuan Huangf2b4a972020-08-20 08:42:31 +0000208 // The 2nd argument is not required for read-only property tracing, as the
209 // value can be obtained via pi->value or pi->long_value().
210 SyspropTrace trace(pi->name, nullptr /* prop_value */, pi /* prop_info */,
211 PropertyAction::kPropertyGetReadOnly);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000212 uint32_t serial = load_const_atomic(&pi->serial, memory_order_relaxed);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800213 if (pi->is_long()) {
214 callback(cookie, pi->name, pi->long_value(), serial);
215 } else {
216 callback(cookie, pi->name, pi->value, serial);
217 }
218 return;
219 }
220
Raman Tennetib481a2e2019-11-12 20:41:55 +0000221 char value_buf[PROP_VALUE_MAX];
Chienyuan Huangf2b4a972020-08-20 08:42:31 +0000222 SyspropTrace trace(pi->name, value_buf, pi /* prop_info */,
223 PropertyAction::kPropertyGetReadWrite);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000224 uint32_t serial = ReadMutablePropertyValue(pi, value_buf);
225 callback(cookie, pi->name, value_buf, serial);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800226}
227
Tom Cherrye275d6d2017-12-11 23:31:33 -0800228int SystemProperties::Get(const char* name, char* value) {
229 const prop_info* pi = Find(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800230
Yi Kong32bc0fc2018-08-02 17:31:13 -0700231 if (pi != nullptr) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800232 return Read(pi, nullptr, value);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800233 } else {
234 value[0] = 0;
235 return 0;
236 }
237}
238
Tom Cherrye275d6d2017-12-11 23:31:33 -0800239int SystemProperties::Update(prop_info* pi, const char* value, unsigned int len) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800240 if (len >= PROP_VALUE_MAX) {
241 return -1;
242 }
243
Tom Cherrye275d6d2017-12-11 23:31:33 -0800244 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800245 return -1;
246 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800247
Raman Tennetib481a2e2019-11-12 20:41:55 +0000248 prop_area* serial_pa = contexts_->GetSerialPropArea();
249 if (!serial_pa) {
250 return -1;
251 }
252 prop_area* pa = contexts_->GetPropAreaForName(pi->name);
253 if (__predict_false(!pa)) {
254 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Could not find area for \"%s\"", pi->name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800255 return -1;
256 }
257
258 uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000259 unsigned int old_len = SERIAL_VALUE_LEN(serial);
260
261 // The contract with readers is that whenever the dirty bit is set, an undamaged copy
262 // of the pre-dirty value is available in the dirty backup area. The fence ensures
263 // that we publish our dirty area update before allowing readers to see a
264 // dirty serial.
265 memcpy(pa->dirty_backup_area(), pi->value, old_len + 1);
266 atomic_thread_fence(memory_order_release);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800267 serial |= 1;
268 atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
Raman Tennetide39d922019-11-12 18:24:06 +0000269 strlcpy(pi->value, value, len + 1);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000270 // Now the primary value property area is up-to-date. Let readers know that they should
271 // look at the property value instead of the backup area.
272 atomic_thread_fence(memory_order_release);
273 atomic_store_explicit(&pi->serial, (len << 24) | ((serial + 1) & 0xffffff), memory_order_relaxed);
274 __futex_wake(&pi->serial, INT32_MAX); // Fence by side effect
275 atomic_store_explicit(serial_pa->serial(),
276 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800277 memory_order_release);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000278 __futex_wake(serial_pa->serial(), INT32_MAX);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800279
280 return 0;
281}
282
Tom Cherrye275d6d2017-12-11 23:31:33 -0800283int SystemProperties::Add(const char* name, unsigned int namelen, const char* value,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800284 unsigned int valuelen) {
285 if (valuelen >= PROP_VALUE_MAX && !is_read_only(name)) {
286 return -1;
287 }
288
289 if (namelen < 1) {
290 return -1;
291 }
292
Tom Cherrye275d6d2017-12-11 23:31:33 -0800293 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800294 return -1;
295 }
296
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800297 prop_area* serial_pa = contexts_->GetSerialPropArea();
Tom Cherryf76bbf52017-11-08 14:01:00 -0800298 if (serial_pa == nullptr) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800299 return -1;
300 }
301
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800302 prop_area* pa = contexts_->GetPropAreaForName(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800303 if (!pa) {
304 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
305 return -1;
306 }
307
308 bool ret = pa->add(name, namelen, value, valuelen);
309 if (!ret) {
310 return -1;
311 }
312
313 // There is only a single mutator, but we want to make sure that
314 // updates are visible to a reader waiting for the update.
Tom Cherryf76bbf52017-11-08 14:01:00 -0800315 atomic_store_explicit(serial_pa->serial(),
316 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
317 memory_order_release);
318 __futex_wake(serial_pa->serial(), INT32_MAX);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800319 return 0;
320}
321
Tom Cherrye275d6d2017-12-11 23:31:33 -0800322uint32_t SystemProperties::WaitAny(uint32_t old_serial) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800323 uint32_t new_serial;
Tom Cherrye275d6d2017-12-11 23:31:33 -0800324 Wait(nullptr, old_serial, &new_serial, nullptr);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800325 return new_serial;
326}
327
Tom Cherrye275d6d2017-12-11 23:31:33 -0800328bool SystemProperties::Wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800329 const timespec* relative_timeout) {
330 // Are we waiting on the global serial or a specific serial?
331 atomic_uint_least32_t* serial_ptr;
332 if (pi == nullptr) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800333 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800334 return -1;
335 }
336
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800337 prop_area* serial_pa = contexts_->GetSerialPropArea();
Tom Cherryf76bbf52017-11-08 14:01:00 -0800338 if (serial_pa == nullptr) {
339 return -1;
340 }
341
342 serial_ptr = serial_pa->serial();
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800343 } else {
344 serial_ptr = const_cast<atomic_uint_least32_t*>(&pi->serial);
345 }
346
347 uint32_t new_serial;
348 do {
349 int rc;
350 if ((rc = __futex_wait(serial_ptr, old_serial, relative_timeout)) != 0 && rc == -ETIMEDOUT) {
351 return false;
352 }
353 new_serial = load_const_atomic(serial_ptr, memory_order_acquire);
354 } while (new_serial == old_serial);
355
356 *new_serial_ptr = new_serial;
357 return true;
358}
359
Tom Cherrye275d6d2017-12-11 23:31:33 -0800360const prop_info* SystemProperties::FindNth(unsigned n) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800361 struct find_nth {
362 const uint32_t sought;
363 uint32_t current;
364 const prop_info* result;
365
366 explicit find_nth(uint32_t n) : sought(n), current(0), result(nullptr) {
367 }
368 static void fn(const prop_info* pi, void* ptr) {
369 find_nth* self = reinterpret_cast<find_nth*>(ptr);
370 if (self->current++ == self->sought) self->result = pi;
371 }
372 } state(n);
Tom Cherrye275d6d2017-12-11 23:31:33 -0800373 Foreach(find_nth::fn, &state);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800374 return state.result;
375}
376
Tom Cherrye275d6d2017-12-11 23:31:33 -0800377int SystemProperties::Foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
378 if (!initialized_) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800379 return -1;
380 }
381
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800382 contexts_->ForEach(propfn, cookie);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800383
384 return 0;
385}