static void refresh_cache(struct cache *cache, const char *key) { uint32_t serial; char buf[PROP_VALUE_MAX]; if (!cache->pinfo) { cache->pinfo = __system_property_find(key); if (!cache->pinfo) { return; } cache->serial = -1; } serial = __system_property_serial(cache->pinfo); if (serial == cache->serial) { return; } cache->serial = serial; __system_property_read(cache->pinfo, 0, buf); switch(buf[0]) { case 't': case 'T': cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE; break; case 'f': case 'F': cache->c = strcasecmp(buf + 1, "alse") ? buf[0] : BOOLEAN_FALSE; break; default: cache->c = buf[0]; } }
int __system_property_read(const prop_info *pi, char *name, char *value) { if (__predict_false(compat_mode)) { return __system_property_read_compat(pi, name, value); } while (true) { uint32_t serial = __system_property_serial(pi); // acquire semantics size_t len = SERIAL_VALUE_LEN(serial); memcpy(value, pi->value, len + 1); // TODO: Fix the synchronization scheme here. // There is no fully supported way to implement this kind // of synchronization in C++11, since the memcpy races with // updates to pi, and the data being accessed is not atomic. // The following fence is unintuitive, but would be the // correct one if memcpy used memory_order_relaxed atomic accesses. // In practice it seems unlikely that the generated code would // would be any different, so this should be OK. atomic_thread_fence(memory_order_acquire); if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) { if (name != 0) { strcpy(name, pi->name); } return len; } } }
TEST(properties, serial) { #if defined(__BIONIC__) LocalPropertyTestState pa; ASSERT_TRUE(pa.valid); const prop_info *pi; unsigned int serial; ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6)); ASSERT_NE((const prop_info *)NULL, pi = __system_property_find("property")); serial = __system_property_serial(pi); ASSERT_EQ(0, __system_property_update((prop_info *)pi, "value2", 6)); ASSERT_NE(serial, __system_property_serial(pi)); #else // __BIONIC__ GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif // __BIONIC__ }
static void BM_property_serial(int iters, int nprops) { StopBenchmarkTiming(); LocalPropertyTestState pa(nprops); if (!pa.valid) return; srandom(iters * nprops); const prop_info** pinfo = new const prop_info*[iters]; for (int i = 0; i < iters; i++) { pinfo[i] = __system_property_find(pa.names[random() % nprops]); } // StartBenchmarkTiming(); for (int i = 0; i < iters; i++) { StartBenchmarkTiming(); __system_property_serial(pinfo[i]); StopBenchmarkTimingWithStd(); } // StopBenchmarkTiming(); delete[] pinfo; }
static void refresh_cache_property(struct cache_property* cache, const char* key) { if (!cache->cache.pinfo) { cache->cache.pinfo = __system_property_find(key); if (!cache->cache.pinfo) { return; } } cache->cache.serial = __system_property_serial(cache->cache.pinfo); __system_property_read(cache->cache.pinfo, 0, cache->property); }
static void print_sys_prop(const struct prop_info *pi, void *cookies) { char key[PROP_NAME_MAX]; char name[PROP_VALUE_MAX]; unsigned int serial; int valuelen; serial = __system_property_serial(pi); valuelen = __system_property_read(pi, key, name); if (valuelen < 1 || valuelen > PROP_VALUE_MAX) return; klog_write(6, "<6> [+%3u]%-32s = %s\n", (serial & 0xffffff) >> 1, key, name); }
static _res_thread* _res_thread_alloc(void) { _res_thread* rt = calloc(1, sizeof(*rt)); if (rt) { rt->_h_errno = 0; /* Special system property which tracks any changes to 'net.*'. */ rt->_serial = 0; rt->_pi = (struct prop_info*) __system_property_find("net.change"); if (rt->_pi) { rt->_serial = __system_property_serial(rt->_pi); } memset(rt->_rstatic, 0, sizeof rt->_rstatic); } return rt; }
static void refresh_cache(struct cache *cache, const char *key) { uint32_t serial; char buf[PROP_VALUE_MAX]; if (!cache->pinfo) { cache->pinfo = __system_property_find(key); if (!cache->pinfo) { return; } } serial = __system_property_serial(cache->pinfo); if (serial == cache->serial) { return; } cache->serial = serial; __system_property_read(cache->pinfo, 0, buf); cache->c = buf[0]; }
static int check_cache(struct cache *cache) { return cache->pinfo && __system_property_serial(cache->pinfo) != cache->serial; }
int wifi_start_supplicant(int p2p_supported) { char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; int count = 200; /* wait at most 20 seconds for completion */ #ifdef HAVE_LIBC_SYSTEM_PROPERTIES const prop_info *pi; unsigned serial = 0, i; #endif if (p2p_supported) { strcpy(supplicant_name, P2P_SUPPLICANT_NAME); strcpy(supplicant_prop_name, P2P_PROP_NAME); /* Ensure p2p config file is created */ if (ensure_config_file_exists(P2P_CONFIG_FILE) < 0) { ALOGE("Failed to create a p2p config file"); return -1; } } else { strcpy(supplicant_name, SUPPLICANT_NAME); strcpy(supplicant_prop_name, SUPP_PROP_NAME); } /* Check whether already running */ if (property_get(supplicant_prop_name, supp_status, NULL) && strcmp(supp_status, "running") == 0) { return 0; } /* Before starting the daemon, make sure its config file exists */ if (ensure_config_file_exists(SUPP_CONFIG_FILE) < 0) { ALOGE("Wi-Fi will not be enabled"); return -1; } if (ensure_entropy_file_exists() < 0) { ALOGE("Wi-Fi entropy file was not created"); } /* Clear out any stale socket files that might be left over. */ wpa_ctrl_cleanup(); /* Reset sockets used for exiting from hung state */ exit_sockets[0] = exit_sockets[1] = -1; #ifdef HAVE_LIBC_SYSTEM_PROPERTIES /* * Get a reference to the status property, so we can distinguish * the case where it goes stopped => running => stopped (i.e., * it start up, but fails right away) from the case in which * it starts in the stopped state and never manages to start * running at all. */ pi = __system_property_find(supplicant_prop_name); if (pi != NULL) { serial = __system_property_serial(pi); } #endif property_get("wifi.interface", primary_iface, WIFI_TEST_INTERFACE); property_set("ctl.start", supplicant_name); sched_yield(); while (count-- > 0) { #ifdef HAVE_LIBC_SYSTEM_PROPERTIES if (pi == NULL) { pi = __system_property_find(supplicant_prop_name); } if (pi != NULL) { /* * property serial updated means that init process is scheduled * after we sched_yield, further property status checking is based on this */ if (__system_property_serial(pi) != serial) { __system_property_read(pi, NULL, supp_status); if (strcmp(supp_status, "running") == 0) { return 0; } else if (strcmp(supp_status, "stopped") == 0) { return -1; } } } #else if (property_get(supplicant_prop_name, supp_status, NULL)) { if (strcmp(supp_status, "running") == 0) return 0; } #endif usleep(100000); } return -1; }
static _res_thread* _res_thread_get(void) { _res_thread* rt; pthread_once( &_res_once, _res_init_key ); rt = pthread_getspecific( _res_key ); if (rt != NULL) { /* We already have one thread-specific DNS state object. * Check the serial value for any changes to net.* properties */ D("%s: Called for tid=%d rt=%p rt->pi=%p rt->serial=%d", __FUNCTION__, gettid(), rt, rt->_pi, rt->_serial); if (rt->_pi == NULL) { /* The property wasn't created when _res_thread_get() was * called the last time. This should only happen very * early during the boot sequence. First, let's try to see if it * is here now. */ rt->_pi = (struct prop_info*) __system_property_find("net.change"); if (rt->_pi == NULL) { /* Still nothing, return current state */ D("%s: exiting for tid=%d rt=%d since system property not found", __FUNCTION__, gettid(), rt); return rt; } } if (rt->_serial == __system_property_serial(rt->_pi)) { /* Nothing changed, so return the current state */ D("%s: tid=%d rt=%p nothing changed, returning", __FUNCTION__, gettid(), rt); return rt; } /* Update the recorded serial number, and go reset the state */ rt->_serial = __system_property_serial(rt->_pi); goto RESET_STATE; } /* It is the first time this function is called in this thread, * we need to create a new thread-specific DNS resolver state. */ rt = _res_thread_alloc(); if (rt == NULL) { return NULL; } pthread_setspecific( _res_key, rt ); D("%s: tid=%d Created new DNS state rt=%p", __FUNCTION__, gettid(), rt); RESET_STATE: /* Reset the state, note that res_ninit() can now properly reset * an existing state without leaking memory. */ D("%s: tid=%d, rt=%p, resetting DNS state (options RES_INIT=%d)", __FUNCTION__, gettid(), rt, (rt->_nres->options & RES_INIT) != 0); if ( res_ninit( rt->_nres ) < 0 ) { /* This should not happen */ D("%s: tid=%d rt=%p, woot, res_ninit() returned < 0", __FUNCTION__, gettid(), rt); _res_thread_free(rt); pthread_setspecific( _res_key, NULL ); return NULL; } return rt; }