blob: 89a6fe74dd43868cd7849b54772af0e1329089ff [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
29#include <errno.h>
30#include <fcntl.h>
31#include <netinet/in.h>
32#include <poll.h>
33#include <stdatomic.h>
34#include <stdint.h>
35#include <stdlib.h>
36#include <string.h>
37#include <sys/select.h>
38#include <sys/socket.h>
39#include <sys/stat.h>
40#include <sys/types.h>
41#include <sys/uio.h>
42#include <sys/un.h>
43#include <unistd.h>
44
45#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
46#include <sys/_system_properties.h>
47#include <sys/system_properties.h>
48
Tom Cherry8d366a82017-11-30 15:41:32 -080049#include <new>
50
Tom Cherryfd44b9f2017-11-08 14:01:00 -080051#include <async_safe/log.h>
52
53#include "private/ErrnoRestorer.h"
54#include "private/bionic_defs.h"
55#include "private/bionic_futex.h"
56#include "private/bionic_macros.h"
57#include "private/bionic_sdk_version.h"
58
59#include "context_node.h"
60#include "contexts.h"
61#include "contexts_pre_split.h"
62#include "contexts_split.h"
63#include "prop_area.h"
64#include "prop_info.h"
Tom Cherryf76bbf52017-11-08 14:01:00 -080065#include "property_filename.h"
Tom Cherryfd44b9f2017-11-08 14:01:00 -080066
67// We don't want to use new or malloc in properties (b/31659220), and since these classes are
Tom Cherry8d366a82017-11-30 15:41:32 -080068// small enough and we place them in a static union. Note that system properties are initialized
69// before static initializers are called, so using a Constructor here is an error. Even a
70// Constructor that zero initializes a class will clobber the previous property initialization.
71static union ContextsUnion {
72 ContextsUnion() {}
73 ~ContextsUnion() {}
74 ContextsSplit contexts_split;
75 ContextsPreSplit contexts_pre_split;
76} contexts_union;
Tom Cherryfd44b9f2017-11-08 14:01:00 -080077static Contexts* contexts = nullptr;
78
79#define SERIAL_DIRTY(serial) ((serial)&1)
80#define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
81
82static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
83static const char* kServiceVersionPropertyName = "ro.property_service.version";
84
85// This is public because it was exposed in the NDK. As of 2017-01, ~60 apps reference this symbol.
Tom Cherryf76bbf52017-11-08 14:01:00 -080086// It is set to nullptr and never modified.
Tom Cherryfd44b9f2017-11-08 14:01:00 -080087__BIONIC_WEAK_VARIABLE_FOR_NATIVE_BRIDGE
88prop_area* __system_property_area__ = nullptr;
89
90char property_filename[PROP_FILENAME_MAX] = PROP_FILENAME;
Tom Cherryfd44b9f2017-11-08 14:01:00 -080091
92class PropertyServiceConnection {
93 public:
94 PropertyServiceConnection() : last_error_(0) {
95 socket_ = ::socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
96 if (socket_ == -1) {
97 last_error_ = errno;
98 return;
99 }
100
101 const size_t namelen = strlen(property_service_socket);
102 sockaddr_un addr;
103 memset(&addr, 0, sizeof(addr));
104 strlcpy(addr.sun_path, property_service_socket, sizeof(addr.sun_path));
105 addr.sun_family = AF_LOCAL;
106 socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
107
108 if (TEMP_FAILURE_RETRY(connect(socket_, reinterpret_cast<sockaddr*>(&addr), alen)) == -1) {
109 last_error_ = errno;
110 close(socket_);
111 socket_ = -1;
112 }
113 }
114
115 bool IsValid() {
116 return socket_ != -1;
117 }
118
119 int GetLastError() {
120 return last_error_;
121 }
122
123 bool RecvInt32(int32_t* value) {
124 int result = TEMP_FAILURE_RETRY(recv(socket_, value, sizeof(*value), MSG_WAITALL));
125 return CheckSendRecvResult(result, sizeof(*value));
126 }
127
128 int socket() {
129 return socket_;
130 }
131
132 ~PropertyServiceConnection() {
133 if (socket_ != -1) {
134 close(socket_);
135 }
136 }
137
138 private:
139 bool CheckSendRecvResult(int result, int expected_len) {
140 if (result == -1) {
141 last_error_ = errno;
142 } else if (result != expected_len) {
143 last_error_ = -1;
144 } else {
145 last_error_ = 0;
146 }
147
148 return last_error_ == 0;
149 }
150
151 int socket_;
152 int last_error_;
153
154 friend class SocketWriter;
155};
156
157class SocketWriter {
158 public:
159 explicit SocketWriter(PropertyServiceConnection* connection)
160 : connection_(connection), iov_index_(0), uint_buf_index_(0) {
161 }
162
163 SocketWriter& WriteUint32(uint32_t value) {
164 CHECK(uint_buf_index_ < kUintBufSize);
165 CHECK(iov_index_ < kIovSize);
166 uint32_t* ptr = uint_buf_ + uint_buf_index_;
167 uint_buf_[uint_buf_index_++] = value;
168 iov_[iov_index_].iov_base = ptr;
169 iov_[iov_index_].iov_len = sizeof(*ptr);
170 ++iov_index_;
171 return *this;
172 }
173
174 SocketWriter& WriteString(const char* value) {
175 uint32_t valuelen = strlen(value);
176 WriteUint32(valuelen);
177 if (valuelen == 0) {
178 return *this;
179 }
180
181 CHECK(iov_index_ < kIovSize);
182 iov_[iov_index_].iov_base = const_cast<char*>(value);
183 iov_[iov_index_].iov_len = valuelen;
184 ++iov_index_;
185
186 return *this;
187 }
188
189 bool Send() {
190 if (!connection_->IsValid()) {
191 return false;
192 }
193
194 if (writev(connection_->socket(), iov_, iov_index_) == -1) {
195 connection_->last_error_ = errno;
196 return false;
197 }
198
199 iov_index_ = uint_buf_index_ = 0;
200 return true;
201 }
202
203 private:
204 static constexpr size_t kUintBufSize = 8;
205 static constexpr size_t kIovSize = 8;
206
207 PropertyServiceConnection* connection_;
208 iovec iov_[kIovSize];
209 size_t iov_index_;
210 uint32_t uint_buf_[kUintBufSize];
211 size_t uint_buf_index_;
212
213 DISALLOW_IMPLICIT_CONSTRUCTORS(SocketWriter);
214};
215
216struct prop_msg {
217 unsigned cmd;
218 char name[PROP_NAME_MAX];
219 char value[PROP_VALUE_MAX];
220};
221
222static int send_prop_msg(const prop_msg* msg) {
223 PropertyServiceConnection connection;
224 if (!connection.IsValid()) {
225 return connection.GetLastError();
226 }
227
228 int result = -1;
229 int s = connection.socket();
230
231 const int num_bytes = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));
232 if (num_bytes == sizeof(prop_msg)) {
233 // We successfully wrote to the property server but now we
234 // wait for the property server to finish its work. It
235 // acknowledges its completion by closing the socket so we
236 // poll here (on nothing), waiting for the socket to close.
237 // If you 'adb shell setprop foo bar' you'll see the POLLHUP
238 // once the socket closes. Out of paranoia we cap our poll
239 // at 250 ms.
240 pollfd pollfds[1];
241 pollfds[0].fd = s;
242 pollfds[0].events = 0;
243 const int poll_result = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
244 if (poll_result == 1 && (pollfds[0].revents & POLLHUP) != 0) {
245 result = 0;
246 } else {
247 // Ignore the timeout and treat it like a success anyway.
248 // The init process is single-threaded and its property
249 // service is sometimes slow to respond (perhaps it's off
250 // starting a child process or something) and thus this
251 // times out and the caller thinks it failed, even though
252 // it's still getting around to it. So we fake it here,
253 // mostly for ctl.* properties, but we do try and wait 250
254 // ms so callers who do read-after-write can reliably see
255 // what they've written. Most of the time.
256 // TODO: fix the system properties design.
257 async_safe_format_log(ANDROID_LOG_WARN, "libc",
258 "Property service has timed out while trying to set \"%s\" to \"%s\"",
259 msg->name, msg->value);
260 result = 0;
261 }
262 }
263
264 return result;
265}
266
267static bool is_dir(const char* pathname) {
268 struct stat info;
269 if (stat(pathname, &info) == -1) {
270 return false;
271 }
272 return S_ISDIR(info.st_mode);
273}
274
275__BIONIC_WEAK_FOR_NATIVE_BRIDGE
276int __system_properties_init() {
277 // This is called from __libc_init_common, and should leave errno at 0 (http://b/37248982).
278 ErrnoRestorer errno_restorer;
279
280 if (contexts != nullptr) {
281 contexts->ResetAccess();
282 return 0;
283 }
284 contexts = nullptr;
285 if (is_dir(property_filename)) {
Tom Cherry8d366a82017-11-30 15:41:32 -0800286 new (&contexts_union.contexts_split) ContextsSplit();
287 if (!contexts_union.contexts_split.Initialize(false)) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800288 return -1;
289 }
Tom Cherry8d366a82017-11-30 15:41:32 -0800290 contexts = &contexts_union.contexts_split;
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800291 } else {
Tom Cherry8d366a82017-11-30 15:41:32 -0800292 new (&contexts_union.contexts_pre_split) ContextsPreSplit();
293 if (!contexts_union.contexts_pre_split.Initialize(false)) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800294 return -1;
295 }
Tom Cherry8d366a82017-11-30 15:41:32 -0800296 contexts = &contexts_union.contexts_pre_split;
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800297 }
298 return 0;
299}
300
301__BIONIC_WEAK_FOR_NATIVE_BRIDGE
302int __system_property_set_filename(const char* filename) {
303 size_t len = strlen(filename);
304 if (len >= sizeof(property_filename)) return -1;
305
306 strcpy(property_filename, filename);
307 return 0;
308}
309
310__BIONIC_WEAK_FOR_NATIVE_BRIDGE
311int __system_property_area_init() {
312 if (contexts != nullptr) {
313 contexts->FreeAndUnmap();
314 }
315 // We set this unconditionally as we want tests to continue on regardless of if this failed
316 // and property_service will abort on an error condition, so no harm done.
Tom Cherry8d366a82017-11-30 15:41:32 -0800317 new (&contexts_union.contexts_split) ContextsSplit;
318 contexts = &contexts_union.contexts_split;
319 if (!contexts_union.contexts_split.Initialize(true)) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800320 return -1;
321 }
322 return 0;
323}
324
325__BIONIC_WEAK_FOR_NATIVE_BRIDGE
326uint32_t __system_property_area_serial() {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800327 if (contexts == nullptr) {
328 return -1;
329 }
330
331 prop_area* pa = contexts->GetSerialPropArea();
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800332 if (!pa) {
333 return -1;
334 }
Tom Cherryf76bbf52017-11-08 14:01:00 -0800335
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800336 // Make sure this read fulfilled before __system_property_serial
337 return atomic_load_explicit(pa->serial(), memory_order_acquire);
338}
339
340__BIONIC_WEAK_FOR_NATIVE_BRIDGE
341const prop_info* __system_property_find(const char* name) {
342 if (contexts == nullptr) {
343 return nullptr;
344 }
345
346 prop_area* pa = contexts->GetPropAreaForName(name);
347 if (!pa) {
348 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
349 return nullptr;
350 }
351
352 return pa->find(name);
353}
354
355static bool is_read_only(const char* name) {
356 return strncmp(name, "ro.", 3) == 0;
357}
358
359__BIONIC_WEAK_FOR_NATIVE_BRIDGE
360int __system_property_read(const prop_info* pi, char* name, char* value) {
361 while (true) {
362 uint32_t serial = __system_property_serial(pi); // acquire semantics
363 size_t len = SERIAL_VALUE_LEN(serial);
364 memcpy(value, pi->value, len + 1);
365 // TODO: Fix the synchronization scheme here.
366 // There is no fully supported way to implement this kind
367 // of synchronization in C++11, since the memcpy races with
368 // updates to pi, and the data being accessed is not atomic.
369 // The following fence is unintuitive, but would be the
370 // correct one if memcpy used memory_order_relaxed atomic accesses.
371 // In practice it seems unlikely that the generated code would
372 // would be any different, so this should be OK.
373 atomic_thread_fence(memory_order_acquire);
374 if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) {
375 if (name != nullptr) {
376 size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX);
377 if (namelen >= PROP_NAME_MAX) {
378 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
379 "The property name length for \"%s\" is >= %d;"
380 " please use __system_property_read_callback"
381 " to read this property. (the name is truncated to \"%s\")",
382 pi->name, PROP_NAME_MAX - 1, name);
383 }
384 }
385 if (is_read_only(pi->name) && pi->is_long()) {
386 async_safe_format_log(
387 ANDROID_LOG_ERROR, "libc",
388 "The property \"%s\" has a value with length %zu that is too large for"
389 " __system_property_get()/__system_property_read(); use"
390 " __system_property_read_callback() instead.",
391 pi->name, strlen(pi->long_value()));
392 }
393 return len;
394 }
395 }
396}
397
398__BIONIC_WEAK_FOR_NATIVE_BRIDGE
399void __system_property_read_callback(const prop_info* pi,
400 void (*callback)(void* cookie, const char* name,
401 const char* value, uint32_t serial),
402 void* cookie) {
403 // Read only properties don't need to copy the value to a temporary buffer, since it can never
404 // change.
405 if (is_read_only(pi->name)) {
406 uint32_t serial = __system_property_serial(pi);
407 if (pi->is_long()) {
408 callback(cookie, pi->name, pi->long_value(), serial);
409 } else {
410 callback(cookie, pi->name, pi->value, serial);
411 }
412 return;
413 }
414
415 while (true) {
416 uint32_t serial = __system_property_serial(pi); // acquire semantics
417 size_t len = SERIAL_VALUE_LEN(serial);
418 char value_buf[len + 1];
419
420 memcpy(value_buf, pi->value, len);
421 value_buf[len] = '\0';
422
423 // TODO: see todo in __system_property_read function
424 atomic_thread_fence(memory_order_acquire);
425 if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) {
426 callback(cookie, pi->name, value_buf, serial);
427 return;
428 }
429 }
430}
431
432__BIONIC_WEAK_FOR_NATIVE_BRIDGE
433int __system_property_get(const char* name, char* value) {
434 const prop_info* pi = __system_property_find(name);
435
436 if (pi != 0) {
437 return __system_property_read(pi, nullptr, value);
438 } else {
439 value[0] = 0;
440 return 0;
441 }
442}
443
444static constexpr uint32_t kProtocolVersion1 = 1;
445static constexpr uint32_t kProtocolVersion2 = 2; // current
446
447static atomic_uint_least32_t g_propservice_protocol_version = 0;
448
449static void detect_protocol_version() {
450 char value[PROP_VALUE_MAX];
451 if (__system_property_get(kServiceVersionPropertyName, value) == 0) {
452 g_propservice_protocol_version = kProtocolVersion1;
453 async_safe_format_log(ANDROID_LOG_WARN, "libc",
454 "Using old property service protocol (\"%s\" is not set)",
455 kServiceVersionPropertyName);
456 } else {
457 uint32_t version = static_cast<uint32_t>(atoll(value));
458 if (version >= kProtocolVersion2) {
459 g_propservice_protocol_version = kProtocolVersion2;
460 } else {
461 async_safe_format_log(ANDROID_LOG_WARN, "libc",
462 "Using old property service protocol (\"%s\"=\"%s\")",
463 kServiceVersionPropertyName, value);
464 g_propservice_protocol_version = kProtocolVersion1;
465 }
466 }
467}
468
469__BIONIC_WEAK_FOR_NATIVE_BRIDGE
470int __system_property_set(const char* key, const char* value) {
471 if (key == nullptr) return -1;
472 if (value == nullptr) value = "";
473
474 if (g_propservice_protocol_version == 0) {
475 detect_protocol_version();
476 }
477
478 if (g_propservice_protocol_version == kProtocolVersion1) {
479 // Old protocol does not support long names or values
480 if (strlen(key) >= PROP_NAME_MAX) return -1;
481 if (strlen(value) >= PROP_VALUE_MAX) return -1;
482
483 prop_msg msg;
484 memset(&msg, 0, sizeof msg);
485 msg.cmd = PROP_MSG_SETPROP;
486 strlcpy(msg.name, key, sizeof msg.name);
487 strlcpy(msg.value, value, sizeof msg.value);
488
489 return send_prop_msg(&msg);
490 } else {
491 // New protocol only allows long values for ro. properties only.
492 if (strlen(value) >= PROP_VALUE_MAX && !is_read_only(key)) return -1;
493 // Use proper protocol
494 PropertyServiceConnection connection;
495 if (!connection.IsValid()) {
496 errno = connection.GetLastError();
497 async_safe_format_log(
498 ANDROID_LOG_WARN, "libc",
499 "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)", key, value,
500 errno, strerror(errno));
501 return -1;
502 }
503
504 SocketWriter writer(&connection);
505 if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) {
506 errno = connection.GetLastError();
507 async_safe_format_log(ANDROID_LOG_WARN, "libc",
508 "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
509 key, value, errno, strerror(errno));
510 return -1;
511 }
512
513 int result = -1;
514 if (!connection.RecvInt32(&result)) {
515 errno = connection.GetLastError();
516 async_safe_format_log(ANDROID_LOG_WARN, "libc",
517 "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
518 key, value, errno, strerror(errno));
519 return -1;
520 }
521
522 if (result != PROP_SUCCESS) {
523 async_safe_format_log(ANDROID_LOG_WARN, "libc",
524 "Unable to set property \"%s\" to \"%s\": error code: 0x%x", key, value,
525 result);
526 return -1;
527 }
528
529 return 0;
530 }
531}
532
533__BIONIC_WEAK_FOR_NATIVE_BRIDGE
534int __system_property_update(prop_info* pi, const char* value, unsigned int len) {
535 if (len >= PROP_VALUE_MAX) {
536 return -1;
537 }
538
Tom Cherryf76bbf52017-11-08 14:01:00 -0800539 if (contexts == nullptr) {
540 return -1;
541 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800542
Tom Cherryf76bbf52017-11-08 14:01:00 -0800543 prop_area* pa = contexts->GetSerialPropArea();
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800544 if (!pa) {
545 return -1;
546 }
547
548 uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
549 serial |= 1;
550 atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
551 // The memcpy call here also races. Again pretend it
552 // used memory_order_relaxed atomics, and use the analogous
553 // counterintuitive fence.
554 atomic_thread_fence(memory_order_release);
555 strlcpy(pi->value, value, len + 1);
556
557 atomic_store_explicit(&pi->serial, (len << 24) | ((serial + 1) & 0xffffff), memory_order_release);
558 __futex_wake(&pi->serial, INT32_MAX);
559
560 atomic_store_explicit(pa->serial(), atomic_load_explicit(pa->serial(), memory_order_relaxed) + 1,
561 memory_order_release);
562 __futex_wake(pa->serial(), INT32_MAX);
563
564 return 0;
565}
566
567__BIONIC_WEAK_FOR_NATIVE_BRIDGE
568int __system_property_add(const char* name, unsigned int namelen, const char* value,
569 unsigned int valuelen) {
570 if (valuelen >= PROP_VALUE_MAX && !is_read_only(name)) {
571 return -1;
572 }
573
574 if (namelen < 1) {
575 return -1;
576 }
577
Tom Cherryf76bbf52017-11-08 14:01:00 -0800578 if (contexts == nullptr) {
579 return -1;
580 }
581
582 prop_area* serial_pa = contexts->GetSerialPropArea();
583 if (serial_pa == nullptr) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800584 return -1;
585 }
586
587 prop_area* pa = contexts->GetPropAreaForName(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800588 if (!pa) {
589 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
590 return -1;
591 }
592
593 bool ret = pa->add(name, namelen, value, valuelen);
594 if (!ret) {
595 return -1;
596 }
597
598 // There is only a single mutator, but we want to make sure that
599 // updates are visible to a reader waiting for the update.
Tom Cherryf76bbf52017-11-08 14:01:00 -0800600 atomic_store_explicit(serial_pa->serial(),
601 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
602 memory_order_release);
603 __futex_wake(serial_pa->serial(), INT32_MAX);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800604 return 0;
605}
606
607// Wait for non-locked serial, and retrieve it with acquire semantics.
608__BIONIC_WEAK_FOR_NATIVE_BRIDGE
609uint32_t __system_property_serial(const prop_info* pi) {
610 uint32_t serial = load_const_atomic(&pi->serial, memory_order_acquire);
611 while (SERIAL_DIRTY(serial)) {
612 __futex_wait(const_cast<_Atomic(uint_least32_t)*>(&pi->serial), serial, nullptr);
613 serial = load_const_atomic(&pi->serial, memory_order_acquire);
614 }
615 return serial;
616}
617
618__BIONIC_WEAK_FOR_NATIVE_BRIDGE
619uint32_t __system_property_wait_any(uint32_t old_serial) {
620 uint32_t new_serial;
621 __system_property_wait(nullptr, old_serial, &new_serial, nullptr);
622 return new_serial;
623}
624
625__BIONIC_WEAK_FOR_NATIVE_BRIDGE
626bool __system_property_wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr,
627 const timespec* relative_timeout) {
628 // Are we waiting on the global serial or a specific serial?
629 atomic_uint_least32_t* serial_ptr;
630 if (pi == nullptr) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800631 if (contexts == nullptr) {
632 return -1;
633 }
634
635 prop_area* serial_pa = contexts->GetSerialPropArea();
636 if (serial_pa == nullptr) {
637 return -1;
638 }
639
640 serial_ptr = serial_pa->serial();
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800641 } else {
642 serial_ptr = const_cast<atomic_uint_least32_t*>(&pi->serial);
643 }
644
645 uint32_t new_serial;
646 do {
647 int rc;
648 if ((rc = __futex_wait(serial_ptr, old_serial, relative_timeout)) != 0 && rc == -ETIMEDOUT) {
649 return false;
650 }
651 new_serial = load_const_atomic(serial_ptr, memory_order_acquire);
652 } while (new_serial == old_serial);
653
654 *new_serial_ptr = new_serial;
655 return true;
656}
657
658__BIONIC_WEAK_FOR_NATIVE_BRIDGE
659const prop_info* __system_property_find_nth(unsigned n) {
660 struct find_nth {
661 const uint32_t sought;
662 uint32_t current;
663 const prop_info* result;
664
665 explicit find_nth(uint32_t n) : sought(n), current(0), result(nullptr) {
666 }
667 static void fn(const prop_info* pi, void* ptr) {
668 find_nth* self = reinterpret_cast<find_nth*>(ptr);
669 if (self->current++ == self->sought) self->result = pi;
670 }
671 } state(n);
672 __system_property_foreach(find_nth::fn, &state);
673 return state.result;
674}
675
676__BIONIC_WEAK_FOR_NATIVE_BRIDGE
677int __system_property_foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
678 if (contexts == nullptr) {
679 return -1;
680 }
681
682 contexts->ForEach(propfn, cookie);
683
684 return 0;
685}