blob: b9a373eb98c831b53ab46cd305aec1d4621a2132 [file] [log] [blame]
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001/*
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 */
Tom Cherry49a309f2015-09-23 16:09:47 -070028#include <ctype.h>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000029#include <errno.h>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000030#include <fcntl.h>
Tom Cherry49a309f2015-09-23 16:09:47 -070031#include <poll.h>
32#include <stdatomic.h>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000033#include <stdbool.h>
Tom Cherry49a309f2015-09-23 16:09:47 -070034#include <stddef.h>
35#include <stdint.h>
36#include <stdio.h>
37#include <stdlib.h>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000038#include <string.h>
Tom Cherry49a309f2015-09-23 16:09:47 -070039#include <unistd.h>
40#include <new>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000041
Tom Cherry49a309f2015-09-23 16:09:47 -070042#include <linux/xattr.h>
43#include <netinet/in.h>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000044#include <sys/mman.h>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000045#include <sys/select.h>
Tom Cherry49a309f2015-09-23 16:09:47 -070046#include <sys/socket.h>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000047#include <sys/stat.h>
48#include <sys/types.h>
Tom Cherry49a309f2015-09-23 16:09:47 -070049#include <sys/un.h>
50#include <sys/xattr.h>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000051
52#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
53#include <sys/_system_properties.h>
54#include <sys/system_properties.h>
55
Elliott Hughesd5ed63a2014-05-21 18:27:40 -070056#include "private/bionic_futex.h"
Tom Cherry49a309f2015-09-23 16:09:47 -070057#include "private/bionic_lock.h"
Elliott Hughes8eac9af2014-05-09 19:12:08 -070058#include "private/bionic_macros.h"
Tom Cherry49a309f2015-09-23 16:09:47 -070059#include "private/libc_logging.h"
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000060
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000061static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
62
63
64/*
65 * Properties are stored in a hybrid trie/binary tree structure.
66 * Each property's name is delimited at '.' characters, and the tokens are put
67 * into a trie structure. Siblings at each level of the trie are stored in a
68 * binary tree. For instance, "ro.secure"="1" could be stored as follows:
69 *
70 * +-----+ children +----+ children +--------+
71 * | |-------------->| ro |-------------->| secure |
72 * +-----+ +----+ +--------+
73 * / \ / |
74 * left / \ right left / | prop +===========+
75 * v v v +-------->| ro.secure |
76 * +-----+ +-----+ +-----+ +-----------+
77 * | net | | sys | | com | | 1 |
78 * +-----+ +-----+ +-----+ +===========+
79 */
80
81// Represents a node in the trie.
82struct prop_bt {
83 uint8_t namelen;
84 uint8_t reserved[3];
85
Yabin Cuib8ce4742015-02-10 21:35:56 -080086 // The property trie is updated only by the init process (single threaded) which provides
87 // property service. And it can be read by multiple threads at the same time.
88 // As the property trie is not protected by locks, we use atomic_uint_least32_t types for the
89 // left, right, children "pointers" in the trie node. To make sure readers who see the
90 // change of "pointers" can also notice the change of prop_bt structure contents pointed by
91 // the "pointers", we always use release-consume ordering pair when accessing these "pointers".
92
93 // prop "points" to prop_info structure if there is a propery associated with the trie node.
94 // Its situation is similar to the left, right, children "pointers". So we use
95 // atomic_uint_least32_t and release-consume ordering to protect it as well.
96
Hans Boehm30214b92014-07-31 15:53:22 -070097 // We should also avoid rereading these fields redundantly, since not
98 // all processor implementations ensure that multiple loads from the
99 // same field are carried out in the right order.
Yabin Cuib8ce4742015-02-10 21:35:56 -0800100 atomic_uint_least32_t prop;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000101
Yabin Cuib8ce4742015-02-10 21:35:56 -0800102 atomic_uint_least32_t left;
103 atomic_uint_least32_t right;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000104
Yabin Cuib8ce4742015-02-10 21:35:56 -0800105 atomic_uint_least32_t children;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000106
107 char name[0];
108
109 prop_bt(const char *name, const uint8_t name_length) {
110 this->namelen = name_length;
111 memcpy(this->name, name, name_length);
112 this->name[name_length] = '\0';
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000113 }
114
115private:
Elliott Hughes8eac9af2014-05-09 19:12:08 -0700116 DISALLOW_COPY_AND_ASSIGN(prop_bt);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000117};
118
Tom Cherry926ebe12015-09-23 15:34:40 -0700119class prop_area {
120public:
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000121
122 prop_area(const uint32_t magic, const uint32_t version) :
Tom Cherry926ebe12015-09-23 15:34:40 -0700123 magic_(magic), version_(version) {
124 atomic_init(&serial_, 0);
125 memset(reserved_, 0, sizeof(reserved_));
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000126 // Allocate enough space for the root node.
Tom Cherry926ebe12015-09-23 15:34:40 -0700127 bytes_used_ = sizeof(prop_bt);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000128 }
129
Tom Cherry926ebe12015-09-23 15:34:40 -0700130 const prop_info *find(const char *name);
131 bool add(const char *name, unsigned int namelen,
132 const char *value, unsigned int valuelen);
133
134 bool foreach(void (*propfn)(const prop_info *pi, void *cookie), void *cookie);
135
136 atomic_uint_least32_t *serial() { return &serial_; }
137 uint32_t magic() const { return magic_; }
138 uint32_t version() const { return version_; }
139
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000140private:
Tom Cherry926ebe12015-09-23 15:34:40 -0700141 void *allocate_obj(const size_t size, uint_least32_t *const off);
142 prop_bt *new_prop_bt(const char *name, uint8_t namelen, uint_least32_t *const off);
143 prop_info *new_prop_info(const char *name, uint8_t namelen,
144 const char *value, uint8_t valuelen,
145 uint_least32_t *const off);
146 void *to_prop_obj(uint_least32_t off);
147 prop_bt *to_prop_bt(atomic_uint_least32_t *off_p);
148 prop_info *to_prop_info(atomic_uint_least32_t *off_p);
149
150 prop_bt *root_node();
151
152 prop_bt *find_prop_bt(prop_bt *const bt, const char *name,
153 uint8_t namelen, bool alloc_if_needed);
154
155 const prop_info *find_property(prop_bt *const trie, const char *name,
156 uint8_t namelen, const char *value,
157 uint8_t valuelen, bool alloc_if_needed);
158
159 bool foreach_property(prop_bt *const trie,
160 void (*propfn)(const prop_info *pi, void *cookie),
161 void *cookie);
162
163 uint32_t bytes_used_;
164 atomic_uint_least32_t serial_;
165 uint32_t magic_;
166 uint32_t version_;
167 uint32_t reserved_[28];
168 char data_[0];
169
Elliott Hughes8eac9af2014-05-09 19:12:08 -0700170 DISALLOW_COPY_AND_ASSIGN(prop_area);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000171};
172
173struct prop_info {
Hans Boehm30214b92014-07-31 15:53:22 -0700174 atomic_uint_least32_t serial;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000175 char value[PROP_VALUE_MAX];
176 char name[0];
177
178 prop_info(const char *name, const uint8_t namelen, const char *value,
179 const uint8_t valuelen) {
180 memcpy(this->name, name, namelen);
181 this->name[namelen] = '\0';
Hans Boehm30214b92014-07-31 15:53:22 -0700182 atomic_init(&this->serial, valuelen << 24);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000183 memcpy(this->value, value, valuelen);
184 this->value[valuelen] = '\0';
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000185 }
186private:
Elliott Hughes8eac9af2014-05-09 19:12:08 -0700187 DISALLOW_COPY_AND_ASSIGN(prop_info);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000188};
189
190struct find_nth_cookie {
191 uint32_t count;
192 const uint32_t n;
193 const prop_info *pi;
194
195 find_nth_cookie(uint32_t n) : count(0), n(n), pi(NULL) {
196 }
197};
198
Tom Cherry49a309f2015-09-23 16:09:47 -0700199static char property_filename[PROP_FILENAME_MAX] = PROP_FILENAME;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000200static bool compat_mode = false;
201static size_t pa_data_size;
202static size_t pa_size;
203
204// NOTE: This isn't static because system_properties_compat.c
205// requires it.
206prop_area *__system_property_area__ = NULL;
207
208static int get_fd_from_env(void)
209{
210 // This environment variable consistes of two decimal integer
211 // values separated by a ",". The first value is a file descriptor
212 // and the second is the size of the system properties area. The
213 // size is currently unused.
214 char *env = getenv("ANDROID_PROPERTY_WORKSPACE");
215
216 if (!env) {
217 return -1;
218 }
219
220 return atoi(env);
221}
222
Tom Cherry49a309f2015-09-23 16:09:47 -0700223static prop_area* map_prop_area_rw(const char* filename, const char* context,
224 bool* fsetxattr_failed) {
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000225 /* dev is a tmpfs that we can use to carve a shared workspace
226 * out of, so let's do that...
227 */
Tom Cherry49a309f2015-09-23 16:09:47 -0700228 const int fd = open(filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000229
230 if (fd < 0) {
231 if (errno == EACCES) {
232 /* for consistency with the case where the process has already
233 * mapped the page in and segfaults when trying to write to it
234 */
235 abort();
236 }
Tom Cherry49a309f2015-09-23 16:09:47 -0700237 return nullptr;
238 }
239
240 if (context) {
241 if (fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0) != 0) {
242 __libc_format_log(ANDROID_LOG_ERROR, "libc",
243 "fsetxattr failed to set context (%s) for \"%s\"", context, filename);
244 /*
245 * fsetxattr() will fail during system properties tests due to selinux policy.
246 * We do not want to create a custom policy for the tester, so we will continue in
247 * this function but set a flag that an error has occurred.
248 * Init, which is the only daemon that should ever call this function will abort
249 * when this error occurs.
250 * Otherwise, the tester will ignore it and continue, albeit without any selinux
251 * property separation.
252 */
253 if (fsetxattr_failed) {
254 *fsetxattr_failed = true;
255 }
256 }
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000257 }
258
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000259 if (ftruncate(fd, PA_SIZE) < 0) {
260 close(fd);
Tom Cherry49a309f2015-09-23 16:09:47 -0700261 return nullptr;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000262 }
263
264 pa_size = PA_SIZE;
265 pa_data_size = pa_size - sizeof(prop_area);
266 compat_mode = false;
267
268 void *const memory_area = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
269 if (memory_area == MAP_FAILED) {
270 close(fd);
Tom Cherry49a309f2015-09-23 16:09:47 -0700271 return nullptr;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000272 }
273
274 prop_area *pa = new(memory_area) prop_area(PROP_AREA_MAGIC, PROP_AREA_VERSION);
275
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000276 close(fd);
Tom Cherry49a309f2015-09-23 16:09:47 -0700277 return pa;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000278}
279
Tom Cherry49a309f2015-09-23 16:09:47 -0700280static prop_area* map_fd_ro(const int fd) {
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000281 struct stat fd_stat;
282 if (fstat(fd, &fd_stat) < 0) {
Tom Cherry49a309f2015-09-23 16:09:47 -0700283 return nullptr;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000284 }
285
286 if ((fd_stat.st_uid != 0)
287 || (fd_stat.st_gid != 0)
288 || ((fd_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0)
Narayan Kamath37e95702014-02-24 11:05:02 +0000289 || (fd_stat.st_size < static_cast<off_t>(sizeof(prop_area))) ) {
Tom Cherry49a309f2015-09-23 16:09:47 -0700290 return nullptr;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000291 }
292
293 pa_size = fd_stat.st_size;
294 pa_data_size = pa_size - sizeof(prop_area);
295
296 void* const map_result = mmap(NULL, pa_size, PROT_READ, MAP_SHARED, fd, 0);
297 if (map_result == MAP_FAILED) {
Tom Cherry49a309f2015-09-23 16:09:47 -0700298 return nullptr;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000299 }
300
301 prop_area* pa = reinterpret_cast<prop_area*>(map_result);
Tom Cherry926ebe12015-09-23 15:34:40 -0700302 if ((pa->magic() != PROP_AREA_MAGIC) ||
303 (pa->version() != PROP_AREA_VERSION &&
304 pa->version() != PROP_AREA_VERSION_COMPAT)) {
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000305 munmap(pa, pa_size);
Tom Cherry49a309f2015-09-23 16:09:47 -0700306 return nullptr;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000307 }
308
Tom Cherry926ebe12015-09-23 15:34:40 -0700309 if (pa->version() == PROP_AREA_VERSION_COMPAT) {
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000310 compat_mode = true;
311 }
312
Tom Cherry49a309f2015-09-23 16:09:47 -0700313 return pa;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000314}
315
Tom Cherry49a309f2015-09-23 16:09:47 -0700316static prop_area* map_prop_area(const char* filename, bool is_legacy) {
317 int fd = open(filename, O_CLOEXEC | O_NOFOLLOW | O_RDONLY);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000318 bool close_fd = true;
Tom Cherry49a309f2015-09-23 16:09:47 -0700319 if (fd == -1 && errno == ENOENT && is_legacy) {
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000320 /*
321 * For backwards compatibility, if the file doesn't
322 * exist, we use the environment to get the file descriptor.
323 * For security reasons, we only use this backup if the kernel
324 * returns ENOENT. We don't want to use the backup if the kernel
325 * returns other errors such as ENOMEM or ENFILE, since it
326 * might be possible for an external program to trigger this
327 * condition.
Tom Cherry49a309f2015-09-23 16:09:47 -0700328 * Only do this for the legacy prop file, secured prop files
329 * do not have a backup
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000330 */
331 fd = get_fd_from_env();
332 close_fd = false;
333 }
334
335 if (fd < 0) {
Tom Cherry49a309f2015-09-23 16:09:47 -0700336 return nullptr;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000337 }
338
Tom Cherry49a309f2015-09-23 16:09:47 -0700339 prop_area* map_result = map_fd_ro(fd);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000340 if (close_fd) {
341 close(fd);
342 }
343
344 return map_result;
345}
346
Tom Cherry926ebe12015-09-23 15:34:40 -0700347void *prop_area::allocate_obj(const size_t size, uint_least32_t *const off)
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000348{
Yabin Cuib8ce4742015-02-10 21:35:56 -0800349 const size_t aligned = BIONIC_ALIGN(size, sizeof(uint_least32_t));
Tom Cherry926ebe12015-09-23 15:34:40 -0700350 if (bytes_used_ + aligned > pa_data_size) {
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000351 return NULL;
352 }
353
Tom Cherry926ebe12015-09-23 15:34:40 -0700354 *off = bytes_used_;
355 bytes_used_ += aligned;
356 return data_ + *off;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000357}
358
Tom Cherry926ebe12015-09-23 15:34:40 -0700359prop_bt *prop_area::new_prop_bt(const char *name, uint8_t namelen, uint_least32_t *const off)
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000360{
Yabin Cuib8ce4742015-02-10 21:35:56 -0800361 uint_least32_t new_offset;
362 void *const p = allocate_obj(sizeof(prop_bt) + namelen + 1, &new_offset);
363 if (p != NULL) {
364 prop_bt* bt = new(p) prop_bt(name, namelen);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000365 *off = new_offset;
366 return bt;
367 }
368
369 return NULL;
370}
371
Tom Cherry926ebe12015-09-23 15:34:40 -0700372prop_info *prop_area::new_prop_info(const char *name, uint8_t namelen,
Yabin Cuib8ce4742015-02-10 21:35:56 -0800373 const char *value, uint8_t valuelen, uint_least32_t *const off)
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000374{
Yabin Cuib8ce4742015-02-10 21:35:56 -0800375 uint_least32_t new_offset;
376 void* const p = allocate_obj(sizeof(prop_info) + namelen + 1, &new_offset);
377 if (p != NULL) {
378 prop_info* info = new(p) prop_info(name, namelen, value, valuelen);
379 *off = new_offset;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000380 return info;
381 }
382
383 return NULL;
384}
385
Tom Cherry926ebe12015-09-23 15:34:40 -0700386void *prop_area::to_prop_obj(uint_least32_t off)
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000387{
388 if (off > pa_data_size)
389 return NULL;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000390
Tom Cherry926ebe12015-09-23 15:34:40 -0700391 return (data_ + off);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000392}
393
Tom Cherry926ebe12015-09-23 15:34:40 -0700394inline prop_bt *prop_area::to_prop_bt(atomic_uint_least32_t* off_p) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800395 uint_least32_t off = atomic_load_explicit(off_p, memory_order_consume);
396 return reinterpret_cast<prop_bt*>(to_prop_obj(off));
397}
398
Tom Cherry926ebe12015-09-23 15:34:40 -0700399inline prop_info *prop_area::to_prop_info(atomic_uint_least32_t* off_p) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800400 uint_least32_t off = atomic_load_explicit(off_p, memory_order_consume);
401 return reinterpret_cast<prop_info*>(to_prop_obj(off));
402}
403
Tom Cherry926ebe12015-09-23 15:34:40 -0700404inline prop_bt *prop_area::root_node()
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000405{
406 return reinterpret_cast<prop_bt*>(to_prop_obj(0));
407}
408
409static int cmp_prop_name(const char *one, uint8_t one_len, const char *two,
410 uint8_t two_len)
411{
412 if (one_len < two_len)
413 return -1;
414 else if (one_len > two_len)
415 return 1;
416 else
417 return strncmp(one, two, one_len);
418}
419
Tom Cherry926ebe12015-09-23 15:34:40 -0700420prop_bt *prop_area::find_prop_bt(prop_bt *const bt, const char *name,
421 uint8_t namelen, bool alloc_if_needed)
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000422{
423
424 prop_bt* current = bt;
425 while (true) {
426 if (!current) {
427 return NULL;
428 }
429
430 const int ret = cmp_prop_name(name, namelen, current->name, current->namelen);
431 if (ret == 0) {
432 return current;
433 }
434
435 if (ret < 0) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800436 uint_least32_t left_offset = atomic_load_explicit(&current->left, memory_order_relaxed);
437 if (left_offset != 0) {
438 current = to_prop_bt(&current->left);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000439 } else {
440 if (!alloc_if_needed) {
441 return NULL;
442 }
443
Yabin Cuib8ce4742015-02-10 21:35:56 -0800444 uint_least32_t new_offset;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000445 prop_bt* new_bt = new_prop_bt(name, namelen, &new_offset);
446 if (new_bt) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800447 atomic_store_explicit(&current->left, new_offset, memory_order_release);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000448 }
449 return new_bt;
450 }
451 } else {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800452 uint_least32_t right_offset = atomic_load_explicit(&current->right, memory_order_relaxed);
453 if (right_offset != 0) {
454 current = to_prop_bt(&current->right);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000455 } else {
456 if (!alloc_if_needed) {
457 return NULL;
458 }
459
Yabin Cuib8ce4742015-02-10 21:35:56 -0800460 uint_least32_t new_offset;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000461 prop_bt* new_bt = new_prop_bt(name, namelen, &new_offset);
462 if (new_bt) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800463 atomic_store_explicit(&current->right, new_offset, memory_order_release);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000464 }
465 return new_bt;
466 }
467 }
468 }
469}
470
Tom Cherry926ebe12015-09-23 15:34:40 -0700471const prop_info *prop_area::find_property(prop_bt *const trie, const char *name,
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000472 uint8_t namelen, const char *value, uint8_t valuelen,
473 bool alloc_if_needed)
474{
475 if (!trie) return NULL;
476
477 const char *remaining_name = name;
478 prop_bt* current = trie;
479 while (true) {
480 const char *sep = strchr(remaining_name, '.');
481 const bool want_subtree = (sep != NULL);
482 const uint8_t substr_size = (want_subtree) ?
483 sep - remaining_name : strlen(remaining_name);
484
485 if (!substr_size) {
486 return NULL;
487 }
488
489 prop_bt* root = NULL;
Yabin Cuib8ce4742015-02-10 21:35:56 -0800490 uint_least32_t children_offset = atomic_load_explicit(&current->children, memory_order_relaxed);
491 if (children_offset != 0) {
492 root = to_prop_bt(&current->children);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000493 } else if (alloc_if_needed) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800494 uint_least32_t new_offset;
495 root = new_prop_bt(remaining_name, substr_size, &new_offset);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000496 if (root) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800497 atomic_store_explicit(&current->children, new_offset, memory_order_release);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000498 }
499 }
500
501 if (!root) {
502 return NULL;
503 }
504
505 current = find_prop_bt(root, remaining_name, substr_size, alloc_if_needed);
506 if (!current) {
507 return NULL;
508 }
509
510 if (!want_subtree)
511 break;
512
513 remaining_name = sep + 1;
514 }
515
Yabin Cuib8ce4742015-02-10 21:35:56 -0800516 uint_least32_t prop_offset = atomic_load_explicit(&current->prop, memory_order_relaxed);
517 if (prop_offset != 0) {
518 return to_prop_info(&current->prop);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000519 } else if (alloc_if_needed) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800520 uint_least32_t new_offset;
521 prop_info* new_info = new_prop_info(name, namelen, value, valuelen, &new_offset);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000522 if (new_info) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800523 atomic_store_explicit(&current->prop, new_offset, memory_order_release);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000524 }
525
526 return new_info;
527 } else {
528 return NULL;
529 }
530}
531
532static int send_prop_msg(const prop_msg *msg)
533{
Elliott Hughes0dc39f92014-09-22 17:43:09 -0700534 const int fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
535 if (fd == -1) {
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000536 return -1;
537 }
538
539 const size_t namelen = strlen(property_service_socket);
540
541 sockaddr_un addr;
542 memset(&addr, 0, sizeof(addr));
543 strlcpy(addr.sun_path, property_service_socket, sizeof(addr.sun_path));
544 addr.sun_family = AF_LOCAL;
545 socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
546 if (TEMP_FAILURE_RETRY(connect(fd, reinterpret_cast<sockaddr*>(&addr), alen)) < 0) {
547 close(fd);
548 return -1;
549 }
550
551 const int num_bytes = TEMP_FAILURE_RETRY(send(fd, msg, sizeof(prop_msg), 0));
552
553 int result = -1;
554 if (num_bytes == sizeof(prop_msg)) {
555 // We successfully wrote to the property server but now we
556 // wait for the property server to finish its work. It
557 // acknowledges its completion by closing the socket so we
558 // poll here (on nothing), waiting for the socket to close.
559 // If you 'adb shell setprop foo bar' you'll see the POLLHUP
560 // once the socket closes. Out of paranoia we cap our poll
561 // at 250 ms.
562 pollfd pollfds[1];
563 pollfds[0].fd = fd;
564 pollfds[0].events = 0;
565 const int poll_result = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
566 if (poll_result == 1 && (pollfds[0].revents & POLLHUP) != 0) {
567 result = 0;
568 } else {
569 // Ignore the timeout and treat it like a success anyway.
570 // The init process is single-threaded and its property
571 // service is sometimes slow to respond (perhaps it's off
572 // starting a child process or something) and thus this
573 // times out and the caller thinks it failed, even though
574 // it's still getting around to it. So we fake it here,
575 // mostly for ctl.* properties, but we do try and wait 250
576 // ms so callers who do read-after-write can reliably see
577 // what they've written. Most of the time.
578 // TODO: fix the system properties design.
579 result = 0;
580 }
581 }
582
583 close(fd);
584 return result;
585}
586
587static void find_nth_fn(const prop_info *pi, void *ptr)
588{
589 find_nth_cookie *cookie = reinterpret_cast<find_nth_cookie*>(ptr);
590
591 if (cookie->n == cookie->count)
592 cookie->pi = pi;
593
594 cookie->count++;
595}
596
Tom Cherry926ebe12015-09-23 15:34:40 -0700597bool prop_area::foreach_property(prop_bt *const trie,
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000598 void (*propfn)(const prop_info *pi, void *cookie), void *cookie)
599{
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000600 if (!trie)
Tom Cherry926ebe12015-09-23 15:34:40 -0700601 return false;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000602
Yabin Cuib8ce4742015-02-10 21:35:56 -0800603 uint_least32_t left_offset = atomic_load_explicit(&trie->left, memory_order_relaxed);
604 if (left_offset != 0) {
605 const int err = foreach_property(to_prop_bt(&trie->left), propfn, cookie);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000606 if (err < 0)
Tom Cherry926ebe12015-09-23 15:34:40 -0700607 return false;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000608 }
Yabin Cuib8ce4742015-02-10 21:35:56 -0800609 uint_least32_t prop_offset = atomic_load_explicit(&trie->prop, memory_order_relaxed);
610 if (prop_offset != 0) {
611 prop_info *info = to_prop_info(&trie->prop);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000612 if (!info)
Tom Cherry926ebe12015-09-23 15:34:40 -0700613 return false;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000614 propfn(info, cookie);
615 }
Yabin Cuib8ce4742015-02-10 21:35:56 -0800616 uint_least32_t children_offset = atomic_load_explicit(&trie->children, memory_order_relaxed);
617 if (children_offset != 0) {
618 const int err = foreach_property(to_prop_bt(&trie->children), propfn, cookie);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000619 if (err < 0)
Tom Cherry926ebe12015-09-23 15:34:40 -0700620 return false;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000621 }
Yabin Cuib8ce4742015-02-10 21:35:56 -0800622 uint_least32_t right_offset = atomic_load_explicit(&trie->right, memory_order_relaxed);
623 if (right_offset != 0) {
624 const int err = foreach_property(to_prop_bt(&trie->right), propfn, cookie);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000625 if (err < 0)
Tom Cherry926ebe12015-09-23 15:34:40 -0700626 return false;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000627 }
628
Tom Cherry926ebe12015-09-23 15:34:40 -0700629 return true;
630}
631
632const prop_info *prop_area::find(const char *name) {
633 return find_property(root_node(), name, strlen(name), nullptr, 0, false);
634}
635
636bool prop_area::add(const char *name, unsigned int namelen,
637 const char *value, unsigned int valuelen) {
638 return find_property(root_node(), name, namelen, value, valuelen, true);
639}
640
641bool prop_area::foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
642 return foreach_property(root_node(), propfn, cookie);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000643}
644
Tom Cherry49a309f2015-09-23 16:09:47 -0700645struct context_node {
646 context_node(struct context_node* next, const char* context, prop_area* pa)
647 : context(strdup(context)), pa(pa), checked_access(false), next(next) {
648 lock.init(false);
649 }
650 ~context_node() {
651 if (pa) {
652 munmap(pa, pa_size);
653 }
654 free(context);
655 }
656 Lock lock;
657 char* context;
658 prop_area* pa;
659 bool checked_access;
660 struct context_node* next;
661};
662
663struct prefix_node {
664 prefix_node(struct prefix_node* next, const char* prefix, context_node* context)
665 : prefix(strdup(prefix)), prefix_len(strlen(prefix)), context(context), next(next) {
666 }
667 ~prefix_node() {
668 free(prefix);
669 }
670 char* prefix;
671 const size_t prefix_len;
672 context_node* context;
673 struct prefix_node* next;
674};
675
676template <typename List, typename... Args>
677static inline void list_add(List** list, Args... args) {
678 *list = new List(*list, args...);
679}
680
681static void list_add_after_len(prefix_node** list, const char* prefix, context_node* context) {
682 size_t prefix_len = strlen(prefix);
683
684 auto next_list = list;
685
686 while (*next_list) {
687 if ((*next_list)->prefix_len < prefix_len || (*next_list)->prefix[0] == '*') {
688 list_add(next_list, prefix, context);
689 return;
690 }
691 next_list = &(*next_list)->next;
692 }
693 list_add(next_list, prefix, context);
694}
695
696template <typename List, typename Func>
697static void list_foreach(List* list, Func func) {
698 while (list) {
699 func(list);
700 list = list->next;
701 }
702}
703
704template <typename List, typename Func>
705static List* list_find(List* list, Func func) {
706 while (list) {
707 if (func(list)) {
708 return list;
709 }
710 list = list->next;
711 }
712 return nullptr;
713}
714
715template <typename List>
716static void list_free(List** list) {
717 while (*list) {
718 auto old_list = *list;
719 *list = old_list->next;
720 delete old_list;
721 }
722}
723
724static prefix_node* prefixes = nullptr;
725static context_node* contexts = nullptr;
726
727/*
728 * pthread_mutex_lock() calls into system_properties in the case of contention.
729 * This creates a risk of dead lock if any system_properties functions
730 * use pthread locks after system_property initialization.
731 *
732 * For this reason, the below three functions use a bionic Lock and static
733 * allocation of memory for each filename.
734 */
735
736static bool open_prop_file(context_node* cnode, bool access_rw, bool* fsetxattr_failed) {
737 cnode->lock.lock();
738 if (cnode->pa) {
739 cnode->lock.unlock();
740 return true;
741 }
742
743 char filename[PROP_FILENAME_MAX];
744 int len = snprintf(filename, sizeof(filename), "%s/%s", property_filename, cnode->context);
745 if (len < 0 || len > PROP_FILENAME_MAX) {
746 cnode->lock.unlock();
747 return false;
748 }
749
750 if (access_rw) {
751 cnode->pa = map_prop_area_rw(filename, cnode->context, fsetxattr_failed);
752 } else {
753 cnode->pa = map_prop_area(filename, false);
754 }
755 cnode->lock.unlock();
756 return cnode->pa;
757}
758
759static bool check_access(context_node* cnode) {
760 char filename[PROP_FILENAME_MAX];
761 int len = snprintf(filename, sizeof(filename), "%s/%s", property_filename, cnode->context);
762 if (len < 0 || len > PROP_FILENAME_MAX) {
763 return false;
764 }
765
766 return access(filename, R_OK) == 0;
767}
768
769static bool map_system_property_area(bool access_rw, bool* fsetxattr_failed) {
770 char filename[PROP_FILENAME_MAX];
771 int len = snprintf(filename, sizeof(filename), "%s/properties_serial", property_filename);
772 if (len < 0 || len > PROP_FILENAME_MAX) {
773 __system_property_area__ = nullptr;
774 return false;
775 }
776
777 if (access_rw) {
778 __system_property_area__ =
779 map_prop_area_rw(filename, "u:object_r:properties_serial:s0", fsetxattr_failed);
780 } else {
781 __system_property_area__ = map_prop_area(filename, false);
782 }
783 return __system_property_area__;
784}
785
786static prop_area* get_prop_area_for_name(const char* name) {
Tom Cherry845e24a2015-12-03 15:38:52 -0800787 auto entry = list_find(prefixes, [name](prefix_node* l) {
Tom Cherry49a309f2015-09-23 16:09:47 -0700788 return l->prefix[0] == '*' || !strncmp(l->prefix, name, l->prefix_len);
789 });
790 if (!entry) {
791 return nullptr;
792 }
793
794 auto cnode = entry->context;
795 if (!cnode->pa) {
796 open_prop_file(cnode, false, nullptr);
797 }
798 return cnode->pa;
799}
800
801/*
802 * The below two functions are duplicated from label_support.c in libselinux.
803 * TODO: Find a location suitable for these functions such that both libc and
804 * libselinux can share a common source file.
805 */
806
807/*
808 * The read_spec_entries and read_spec_entry functions may be used to
809 * replace sscanf to read entries from spec files. The file and
810 * property services now use these.
811 */
812
813/* Read an entry from a spec file (e.g. file_contexts) */
814static inline int read_spec_entry(char **entry, char **ptr, int *len)
815{
816 *entry = NULL;
817 char *tmp_buf = NULL;
818
819 while (isspace(**ptr) && **ptr != '\0')
820 (*ptr)++;
821
822 tmp_buf = *ptr;
823 *len = 0;
824
825 while (!isspace(**ptr) && **ptr != '\0') {
826 (*ptr)++;
827 (*len)++;
828 }
829
830 if (*len) {
831 *entry = strndup(tmp_buf, *len);
832 if (!*entry)
833 return -1;
834 }
835
836 return 0;
837}
838
839/*
840 * line_buf - Buffer containing the spec entries .
841 * num_args - The number of spec parameter entries to process.
842 * ... - A 'char **spec_entry' for each parameter.
843 * returns - The number of items processed.
844 *
845 * This function calls read_spec_entry() to do the actual string processing.
846 */
847static int read_spec_entries(char *line_buf, int num_args, ...)
848{
849 char **spec_entry, *buf_p;
850 int len, rc, items, entry_len = 0;
851 va_list ap;
852
853 len = strlen(line_buf);
854 if (line_buf[len - 1] == '\n')
855 line_buf[len - 1] = '\0';
856 else
857 /* Handle case if line not \n terminated by bumping
858 * the len for the check below (as the line is NUL
859 * terminated by getline(3)) */
860 len++;
861
862 buf_p = line_buf;
863 while (isspace(*buf_p))
864 buf_p++;
865
866 /* Skip comment lines and empty lines. */
867 if (*buf_p == '#' || *buf_p == '\0')
868 return 0;
869
870 /* Process the spec file entries */
871 va_start(ap, num_args);
872
873 items = 0;
874 while (items < num_args) {
875 spec_entry = va_arg(ap, char **);
876
877 if (len - 1 == buf_p - line_buf) {
878 va_end(ap);
879 return items;
880 }
881
882 rc = read_spec_entry(spec_entry, &buf_p, &entry_len);
883 if (rc < 0) {
884 va_end(ap);
885 return rc;
886 }
887 if (entry_len)
888 items++;
889 }
890 va_end(ap);
891 return items;
892}
893
894static bool initialize_properties() {
895 list_free(&prefixes);
896 list_free(&contexts);
897
898 FILE* file = fopen("/property_contexts", "re");
899
900 if (!file) {
901 return false;
902 }
903
904 char* buffer = nullptr;
905 size_t line_len;
906 char* prop_prefix = nullptr;
907 char* context = nullptr;
908
909 while (getline(&buffer, &line_len, file) > 0) {
910 int items = read_spec_entries(buffer, 2, &prop_prefix, &context);
911 if (items <= 0) {
912 continue;
913 }
914 if (items == 1) {
915 free(prop_prefix);
916 continue;
917 }
Tom Cherry21eadee2015-12-04 15:53:25 -0800918 /*
919 * init uses ctl.* properties as an IPC mechanism and does not write them
920 * to a property file, therefore we do not need to create property files
921 * to store them.
922 */
923 if (!strncmp(prop_prefix, "ctl.", 4)) {
924 free(prop_prefix);
925 free(context);
926 continue;
927 }
Tom Cherry49a309f2015-09-23 16:09:47 -0700928
Tom Cherry845e24a2015-12-03 15:38:52 -0800929 auto old_context = list_find(
930 contexts, [context](context_node* l) { return !strcmp(l->context, context); });
Tom Cherry49a309f2015-09-23 16:09:47 -0700931 if (old_context) {
932 list_add_after_len(&prefixes, prop_prefix, old_context);
933 } else {
934 list_add(&contexts, context, nullptr);
935 list_add_after_len(&prefixes, prop_prefix, contexts);
936 }
937 free(prop_prefix);
938 free(context);
939 }
940
941 free(buffer);
942 fclose(file);
943 return true;
944}
945
946static bool is_dir(const char* pathname) {
947 struct stat info;
948 if (stat(pathname, &info) == -1) {
949 return false;
950 }
951 return S_ISDIR(info.st_mode);
952}
953
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000954int __system_properties_init()
955{
Tom Cherry49a309f2015-09-23 16:09:47 -0700956 if (is_dir(property_filename)) {
957 if (!initialize_properties()) {
958 return -1;
959 }
960 if (!map_system_property_area(false, nullptr)) {
961 list_free(&prefixes);
962 list_free(&contexts);
963 return -1;
964 }
965 } else {
966 __system_property_area__ = map_prop_area(property_filename, true);
967 if (!__system_property_area__) {
968 return -1;
969 }
970 list_add(&contexts, "legacy_system_prop_area", __system_property_area__);
971 list_add_after_len(&prefixes, "*", contexts);
972 }
973 return 0;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000974}
975
976int __system_property_set_filename(const char *filename)
977{
978 size_t len = strlen(filename);
979 if (len >= sizeof(property_filename))
980 return -1;
981
982 strcpy(property_filename, filename);
983 return 0;
984}
985
986int __system_property_area_init()
987{
Tom Cherry49a309f2015-09-23 16:09:47 -0700988 mkdir(property_filename, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
989 if (!initialize_properties()) {
990 return -1;
991 }
992 bool open_prop_file_failed = false;
993 bool fsetxattr_failed = false;
Tom Cherry845e24a2015-12-03 15:38:52 -0800994 list_foreach(contexts, [&fsetxattr_failed, &open_prop_file_failed](context_node* l) {
Tom Cherry49a309f2015-09-23 16:09:47 -0700995 if (!open_prop_file(l, true, &fsetxattr_failed)) {
996 open_prop_file_failed = true;
997 }
998 });
999 if (open_prop_file_failed || !map_system_property_area(true, &fsetxattr_failed)) {
1000 list_free(&prefixes);
1001 list_free(&contexts);
1002 return -1;
1003 }
1004 return fsetxattr_failed ? -2 : 0;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001005}
1006
Mark Salyzynbfd65272015-04-24 09:31:32 -07001007unsigned int __system_property_area_serial()
1008{
1009 prop_area *pa = __system_property_area__;
1010 if (!pa) {
1011 return -1;
1012 }
1013 // Make sure this read fulfilled before __system_property_serial
Tom Cherry926ebe12015-09-23 15:34:40 -07001014 return atomic_load_explicit(pa->serial(), memory_order_acquire);
Mark Salyzynbfd65272015-04-24 09:31:32 -07001015}
1016
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001017const prop_info *__system_property_find(const char *name)
1018{
Tom Cherry6ed51c02015-12-04 11:34:42 -08001019 if (!__system_property_area__) {
1020 return nullptr;
1021 }
1022
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001023 if (__predict_false(compat_mode)) {
1024 return __system_property_find_compat(name);
1025 }
Tom Cherry926ebe12015-09-23 15:34:40 -07001026
Tom Cherry49a309f2015-09-23 16:09:47 -07001027 prop_area* pa = get_prop_area_for_name(name);
1028 if (!pa) {
1029 __libc_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
Tom Cherry926ebe12015-09-23 15:34:40 -07001030 return nullptr;
1031 }
1032
Tom Cherry49a309f2015-09-23 16:09:47 -07001033 return pa->find(name);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001034}
1035
Hans Boehm1e8587a2014-08-19 14:07:55 -07001036// The C11 standard doesn't allow atomic loads from const fields,
1037// though C++11 does. Fudge it until standards get straightened out.
1038static inline uint_least32_t load_const_atomic(const atomic_uint_least32_t* s,
1039 memory_order mo) {
1040 atomic_uint_least32_t* non_const_s = const_cast<atomic_uint_least32_t*>(s);
1041 return atomic_load_explicit(non_const_s, mo);
1042}
1043
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001044int __system_property_read(const prop_info *pi, char *name, char *value)
1045{
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001046 if (__predict_false(compat_mode)) {
1047 return __system_property_read_compat(pi, name, value);
1048 }
1049
jiaguo879d3302014-03-13 17:39:58 +08001050 while (true) {
Hans Boehm30214b92014-07-31 15:53:22 -07001051 uint32_t serial = __system_property_serial(pi); // acquire semantics
jiaguo879d3302014-03-13 17:39:58 +08001052 size_t len = SERIAL_VALUE_LEN(serial);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001053 memcpy(value, pi->value, len + 1);
Hans Boehm30214b92014-07-31 15:53:22 -07001054 // TODO: Fix the synchronization scheme here.
1055 // There is no fully supported way to implement this kind
1056 // of synchronization in C++11, since the memcpy races with
1057 // updates to pi, and the data being accessed is not atomic.
1058 // The following fence is unintuitive, but would be the
1059 // correct one if memcpy used memory_order_relaxed atomic accesses.
1060 // In practice it seems unlikely that the generated code would
1061 // would be any different, so this should be OK.
1062 atomic_thread_fence(memory_order_acquire);
1063 if (serial ==
Hans Boehm1e8587a2014-08-19 14:07:55 -07001064 load_const_atomic(&(pi->serial), memory_order_relaxed)) {
jiaguo879d3302014-03-13 17:39:58 +08001065 if (name != 0) {
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001066 strcpy(name, pi->name);
1067 }
1068 return len;
1069 }
1070 }
1071}
1072
1073int __system_property_get(const char *name, char *value)
1074{
1075 const prop_info *pi = __system_property_find(name);
1076
1077 if (pi != 0) {
1078 return __system_property_read(pi, 0, value);
1079 } else {
1080 value[0] = 0;
1081 return 0;
1082 }
1083}
1084
1085int __system_property_set(const char *key, const char *value)
1086{
1087 if (key == 0) return -1;
1088 if (value == 0) value = "";
1089 if (strlen(key) >= PROP_NAME_MAX) return -1;
1090 if (strlen(value) >= PROP_VALUE_MAX) return -1;
1091
1092 prop_msg msg;
1093 memset(&msg, 0, sizeof msg);
1094 msg.cmd = PROP_MSG_SETPROP;
1095 strlcpy(msg.name, key, sizeof msg.name);
1096 strlcpy(msg.value, value, sizeof msg.value);
1097
1098 const int err = send_prop_msg(&msg);
1099 if (err < 0) {
1100 return err;
1101 }
1102
1103 return 0;
1104}
1105
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001106int __system_property_update(prop_info *pi, const char *value, unsigned int len)
1107{
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001108 if (len >= PROP_VALUE_MAX)
1109 return -1;
1110
Tom Cherry6ed51c02015-12-04 11:34:42 -08001111 prop_area* pa = __system_property_area__;
1112
1113 if (!pa) {
1114 return -1;
1115 }
1116
Hans Boehm30214b92014-07-31 15:53:22 -07001117 uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
1118 serial |= 1;
1119 atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
1120 // The memcpy call here also races. Again pretend it
1121 // used memory_order_relaxed atomics, and use the analogous
1122 // counterintuitive fence.
1123 atomic_thread_fence(memory_order_release);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001124 memcpy(pi->value, value, len + 1);
Hans Boehm30214b92014-07-31 15:53:22 -07001125 atomic_store_explicit(
1126 &pi->serial,
1127 (len << 24) | ((serial + 1) & 0xffffff),
1128 memory_order_release);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001129 __futex_wake(&pi->serial, INT32_MAX);
1130
Hans Boehm30214b92014-07-31 15:53:22 -07001131 atomic_store_explicit(
Tom Cherry926ebe12015-09-23 15:34:40 -07001132 pa->serial(),
1133 atomic_load_explicit(pa->serial(), memory_order_relaxed) + 1,
Hans Boehm30214b92014-07-31 15:53:22 -07001134 memory_order_release);
Tom Cherry926ebe12015-09-23 15:34:40 -07001135 __futex_wake(pa->serial(), INT32_MAX);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001136
1137 return 0;
1138}
jiaguo879d3302014-03-13 17:39:58 +08001139
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001140int __system_property_add(const char *name, unsigned int namelen,
1141 const char *value, unsigned int valuelen)
1142{
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001143 if (namelen >= PROP_NAME_MAX)
1144 return -1;
1145 if (valuelen >= PROP_VALUE_MAX)
1146 return -1;
1147 if (namelen < 1)
1148 return -1;
1149
Tom Cherry6ed51c02015-12-04 11:34:42 -08001150 if (!__system_property_area__) {
1151 return -1;
1152 }
1153
Tom Cherry49a309f2015-09-23 16:09:47 -07001154 prop_area* pa = get_prop_area_for_name(name);
1155
1156 if (!pa) {
1157 __libc_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
Tom Cherry926ebe12015-09-23 15:34:40 -07001158 return -1;
1159 }
1160
Tom Cherry49a309f2015-09-23 16:09:47 -07001161 bool ret = pa->add(name, namelen, value, valuelen);
Tom Cherry926ebe12015-09-23 15:34:40 -07001162 if (!ret)
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001163 return -1;
1164
Hans Boehm30214b92014-07-31 15:53:22 -07001165 // There is only a single mutator, but we want to make sure that
1166 // updates are visible to a reader waiting for the update.
1167 atomic_store_explicit(
Tom Cherry49a309f2015-09-23 16:09:47 -07001168 __system_property_area__->serial(),
1169 atomic_load_explicit(__system_property_area__->serial(), memory_order_relaxed) + 1,
Hans Boehm30214b92014-07-31 15:53:22 -07001170 memory_order_release);
Tom Cherry49a309f2015-09-23 16:09:47 -07001171 __futex_wake(__system_property_area__->serial(), INT32_MAX);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001172 return 0;
1173}
1174
Hans Boehm30214b92014-07-31 15:53:22 -07001175// Wait for non-locked serial, and retrieve it with acquire semantics.
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001176unsigned int __system_property_serial(const prop_info *pi)
1177{
Hans Boehm1e8587a2014-08-19 14:07:55 -07001178 uint32_t serial = load_const_atomic(&pi->serial, memory_order_acquire);
jiaguo879d3302014-03-13 17:39:58 +08001179 while (SERIAL_DIRTY(serial)) {
Hans Boehm30214b92014-07-31 15:53:22 -07001180 __futex_wait(const_cast<volatile void *>(
1181 reinterpret_cast<const void *>(&pi->serial)),
1182 serial, NULL);
Hans Boehm1e8587a2014-08-19 14:07:55 -07001183 serial = load_const_atomic(&pi->serial, memory_order_acquire);
jiaguo879d3302014-03-13 17:39:58 +08001184 }
1185 return serial;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001186}
1187
1188unsigned int __system_property_wait_any(unsigned int serial)
1189{
1190 prop_area *pa = __system_property_area__;
Hans Boehm30214b92014-07-31 15:53:22 -07001191 uint32_t my_serial;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001192
Tom Cherry6ed51c02015-12-04 11:34:42 -08001193 if (!pa) {
1194 return 0;
1195 }
1196
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001197 do {
Tom Cherry926ebe12015-09-23 15:34:40 -07001198 __futex_wait(pa->serial(), serial, NULL);
1199 my_serial = atomic_load_explicit(pa->serial(), memory_order_acquire);
Hans Boehm30214b92014-07-31 15:53:22 -07001200 } while (my_serial == serial);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001201
Hans Boehm30214b92014-07-31 15:53:22 -07001202 return my_serial;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001203}
1204
1205const prop_info *__system_property_find_nth(unsigned n)
1206{
1207 find_nth_cookie cookie(n);
1208
1209 const int err = __system_property_foreach(find_nth_fn, &cookie);
1210 if (err < 0) {
1211 return NULL;
1212 }
1213
1214 return cookie.pi;
1215}
1216
1217int __system_property_foreach(void (*propfn)(const prop_info *pi, void *cookie),
1218 void *cookie)
1219{
Tom Cherry6ed51c02015-12-04 11:34:42 -08001220 if (!__system_property_area__) {
1221 return -1;
1222 }
1223
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001224 if (__predict_false(compat_mode)) {
1225 return __system_property_foreach_compat(propfn, cookie);
1226 }
1227
Tom Cherry845e24a2015-12-03 15:38:52 -08001228 list_foreach(contexts, [propfn, cookie](context_node* l) {
Tom Cherry49a309f2015-09-23 16:09:47 -07001229 if (!l->pa && !l->checked_access) {
1230 if (check_access(l)) {
1231 open_prop_file(l, false, nullptr);
1232 }
1233 l->checked_access = true;
1234 }
1235 if (l->pa) {
1236 l->pa->foreach(propfn, cookie);
1237 }
1238 });
1239 return 0;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001240}