1 /* 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 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <stddef.h> 32 #include <errno.h> 33 #include <poll.h> 34 35 #include <sys/mman.h> 36 37 #include <sys/socket.h> 38 #include <sys/un.h> 39 #include <sys/select.h> 40 #include <sys/types.h> 41 #include <netinet/in.h> 42 #include <unistd.h> 43 44 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ 45 #include <sys/_system_properties.h> 46 47 #include <sys/atomics.h> 48 49 static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME; 50 51 static unsigned dummy_props = 0; 52 53 prop_area *__system_property_area__ = (void*) &dummy_props; 54 55 int __system_properties_init(void) 56 { 57 prop_area *pa; 58 int s, fd; 59 unsigned sz; 60 char *env; 61 62 if(__system_property_area__ != ((void*) &dummy_props)) { 63 return 0; 64 } 65 66 env = getenv("ANDROID_PROPERTY_WORKSPACE"); 67 if (!env) { 68 return -1; 69 } 70 fd = atoi(env); 71 env = strchr(env, ','); 72 if (!env) { 73 return -1; 74 } 75 sz = atoi(env + 1); 76 77 pa = mmap(0, sz, PROT_READ, MAP_SHARED, fd, 0); 78 79 if(pa == MAP_FAILED) { 80 return -1; 81 } 82 83 if((pa->magic != PROP_AREA_MAGIC) || (pa->version != PROP_AREA_VERSION)) { 84 munmap(pa, sz); 85 return -1; 86 } 87 88 __system_property_area__ = pa; 89 return 0; 90 } 91 92 const prop_info *__system_property_find_nth(unsigned n) 93 { 94 prop_area *pa = __system_property_area__; 95 96 if(n >= pa->count) { 97 return 0; 98 } else { 99 return TOC_TO_INFO(pa, pa->toc[n]); 100 } 101 } 102 103 const prop_info *__system_property_find(const char *name) 104 { 105 prop_area *pa = __system_property_area__; 106 unsigned count = pa->count; 107 unsigned *toc = pa->toc; 108 unsigned len = strlen(name); 109 prop_info *pi; 110 111 while(count--) { 112 unsigned entry = *toc++; 113 if(TOC_NAME_LEN(entry) != len) continue; 114 115 pi = TOC_TO_INFO(pa, entry); 116 if(memcmp(name, pi->name, len)) continue; 117 118 return pi; 119 } 120 121 return 0; 122 } 123 124 int __system_property_read(const prop_info *pi, char *name, char *value) 125 { 126 unsigned serial, len; 127 128 for(;;) { 129 serial = pi->serial; 130 while(SERIAL_DIRTY(serial)) { 131 __futex_wait((volatile void *)&pi->serial, serial, 0); 132 serial = pi->serial; 133 } 134 len = SERIAL_VALUE_LEN(serial); 135 memcpy(value, pi->value, len + 1); 136 if(serial == pi->serial) { 137 if(name != 0) { 138 strcpy(name, pi->name); 139 } 140 return len; 141 } 142 } 143 } 144 145 int __system_property_get(const char *name, char *value) 146 { 147 const prop_info *pi = __system_property_find(name); 148 149 if(pi != 0) { 150 return __system_property_read(pi, 0, value); 151 } else { 152 value[0] = 0; 153 return 0; 154 } 155 } 156 157 158 static int send_prop_msg(prop_msg *msg) 159 { 160 struct pollfd pollfds[1]; 161 struct sockaddr_un addr; 162 socklen_t alen; 163 size_t namelen; 164 int s; 165 int r; 166 int result = -1; 167 168 s = socket(AF_LOCAL, SOCK_STREAM, 0); 169 if(s < 0) { 170 return result; 171 } 172 173 memset(&addr, 0, sizeof(addr)); 174 namelen = strlen(property_service_socket); 175 strlcpy(addr.sun_path, property_service_socket, sizeof addr.sun_path); 176 addr.sun_family = AF_LOCAL; 177 alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1; 178 179 if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen) < 0)) { 180 close(s); 181 return result; 182 } 183 184 r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0)); 185 186 if(r == sizeof(prop_msg)) { 187 // We successfully wrote to the property server but now we 188 // wait for the property server to finish its work. It 189 // acknowledges its completion by closing the socket so we 190 // poll here (on nothing), waiting for the socket to close. 191 // If you 'adb shell setprop foo bar' you'll see the POLLHUP 192 // once the socket closes. Out of paranoia we cap our poll 193 // at 250 ms. 194 pollfds[0].fd = s; 195 pollfds[0].events = 0; 196 r = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */)); 197 if (r == 1 && (pollfds[0].revents & POLLHUP) != 0) { 198 result = 0; 199 } else { 200 // Ignore the timeout and treat it like a success anyway. 201 // The init process is single-threaded and its property 202 // service is sometimes slow to respond (perhaps it's off 203 // starting a child process or something) and thus this 204 // times out and the caller thinks it failed, even though 205 // it's still getting around to it. So we fake it here, 206 // mostly for ctl.* properties, but we do try and wait 250 207 // ms so callers who do read-after-write can reliably see 208 // what they've written. Most of the time. 209 // TODO: fix the system properties design. 210 result = 0; 211 } 212 } 213 214 close(s); 215 return result; 216 } 217 218 int __system_property_set(const char *key, const char *value) 219 { 220 int err; 221 int tries = 0; 222 int update_seen = 0; 223 prop_msg msg; 224 225 if(key == 0) return -1; 226 if(value == 0) value = ""; 227 if(strlen(key) >= PROP_NAME_MAX) return -1; 228 if(strlen(value) >= PROP_VALUE_MAX) return -1; 229 230 memset(&msg, 0, sizeof msg); 231 msg.cmd = PROP_MSG_SETPROP; 232 strlcpy(msg.name, key, sizeof msg.name); 233 strlcpy(msg.value, value, sizeof msg.value); 234 235 err = send_prop_msg(&msg); 236 if(err < 0) { 237 return err; 238 } 239 240 return 0; 241 } 242 243 int __system_property_wait(const prop_info *pi) 244 { 245 unsigned n; 246 if(pi == 0) { 247 prop_area *pa = __system_property_area__; 248 n = pa->serial; 249 do { 250 __futex_wait(&pa->serial, n, 0); 251 } while(n == pa->serial); 252 } else { 253 n = pi->serial; 254 do { 255 __futex_wait((volatile void *)&pi->serial, n, 0); 256 } while(n == pi->serial); 257 } 258 return 0; 259 } 260