system_properties_test.cpp revision e4375196d650f68ad486e2202699c98f9342d616
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <gtest/gtest.h> 18#include <sys/wait.h> 19#include <errno.h> 20#include <unistd.h> 21#include <string> 22 23#if __BIONIC__ 24 25#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ 26#include <sys/_system_properties.h> 27 28extern void *__system_property_area__; 29 30struct LocalPropertyTestState { 31 LocalPropertyTestState() : valid(false) { 32 const char* ANDROID_DATA = getenv("ANDROID_DATA"); 33 char dir_template[PATH_MAX]; 34 snprintf(dir_template, sizeof(dir_template), "%s/local/tmp/prop-XXXXXX", ANDROID_DATA); 35 char* dirname = mkdtemp(dir_template); 36 if (!dirname) { 37 fprintf(stderr, "making temp file for test state failed (is %s writable?): %s", 38 dir_template, strerror(errno)); 39 return; 40 } 41 42 old_pa = __system_property_area__; 43 __system_property_area__ = NULL; 44 45 pa_dirname = dirname; 46 pa_filename = pa_dirname + "/__properties__"; 47 48 __system_property_set_filename(pa_filename.c_str()); 49 __system_property_area_init(); 50 valid = true; 51 } 52 53 ~LocalPropertyTestState() { 54 if (!valid) { 55 return; 56 } 57 58 __system_property_area__ = old_pa; 59 60 __system_property_set_filename(PROP_FILENAME); 61 unlink(pa_filename.c_str()); 62 rmdir(pa_dirname.c_str()); 63 } 64public: 65 bool valid; 66private: 67 std::string pa_dirname; 68 std::string pa_filename; 69 void *old_pa; 70}; 71 72TEST(properties, add) { 73 LocalPropertyTestState pa; 74 ASSERT_TRUE(pa.valid); 75 76 char propvalue[PROP_VALUE_MAX]; 77 78 ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6)); 79 ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6)); 80 ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6)); 81 82 ASSERT_EQ(6, __system_property_get("property", propvalue)); 83 ASSERT_STREQ(propvalue, "value1"); 84 85 ASSERT_EQ(6, __system_property_get("other_property", propvalue)); 86 ASSERT_STREQ(propvalue, "value2"); 87 88 ASSERT_EQ(6, __system_property_get("property_other", propvalue)); 89 ASSERT_STREQ(propvalue, "value3"); 90} 91 92TEST(properties, update) { 93 LocalPropertyTestState pa; 94 ASSERT_TRUE(pa.valid); 95 96 char propvalue[PROP_VALUE_MAX]; 97 prop_info *pi; 98 99 ASSERT_EQ(0, __system_property_add("property", 8, "oldvalue1", 9)); 100 ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6)); 101 ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6)); 102 103 pi = (prop_info *)__system_property_find("property"); 104 ASSERT_NE((prop_info *)NULL, pi); 105 __system_property_update(pi, "value4", 6); 106 107 pi = (prop_info *)__system_property_find("other_property"); 108 ASSERT_NE((prop_info *)NULL, pi); 109 __system_property_update(pi, "newvalue5", 9); 110 111 pi = (prop_info *)__system_property_find("property_other"); 112 ASSERT_NE((prop_info *)NULL, pi); 113 __system_property_update(pi, "value6", 6); 114 115 ASSERT_EQ(6, __system_property_get("property", propvalue)); 116 ASSERT_STREQ(propvalue, "value4"); 117 118 ASSERT_EQ(9, __system_property_get("other_property", propvalue)); 119 ASSERT_STREQ(propvalue, "newvalue5"); 120 121 ASSERT_EQ(6, __system_property_get("property_other", propvalue)); 122 ASSERT_STREQ(propvalue, "value6"); 123} 124 125TEST(properties, fill) { 126 LocalPropertyTestState pa; 127 ASSERT_TRUE(pa.valid); 128 char prop_name[PROP_NAME_MAX]; 129 char prop_value[PROP_VALUE_MAX]; 130 char prop_value_ret[PROP_VALUE_MAX]; 131 int count = 0; 132 int ret; 133 134 while (true) { 135 ret = snprintf(prop_name, PROP_NAME_MAX - 1, "property_%d", count); 136 memset(prop_name + ret, 'a', PROP_NAME_MAX - 1 - ret); 137 ret = snprintf(prop_value, PROP_VALUE_MAX - 1, "value_%d", count); 138 memset(prop_value + ret, 'b', PROP_VALUE_MAX - 1 - ret); 139 prop_name[PROP_NAME_MAX - 1] = 0; 140 prop_value[PROP_VALUE_MAX - 1] = 0; 141 142 ret = __system_property_add(prop_name, PROP_NAME_MAX - 1, prop_value, PROP_VALUE_MAX - 1); 143 if (ret < 0) 144 break; 145 146 count++; 147 } 148 149 // For historical reasons at least 247 properties must be supported 150 ASSERT_GE(count, 247); 151 152 for (int i = 0; i < count; i++) { 153 ret = snprintf(prop_name, PROP_NAME_MAX - 1, "property_%d", i); 154 memset(prop_name + ret, 'a', PROP_NAME_MAX - 1 - ret); 155 ret = snprintf(prop_value, PROP_VALUE_MAX - 1, "value_%d", i); 156 memset(prop_value + ret, 'b', PROP_VALUE_MAX - 1 - ret); 157 prop_name[PROP_NAME_MAX - 1] = 0; 158 prop_value[PROP_VALUE_MAX - 1] = 0; 159 memset(prop_value_ret, '\0', PROP_VALUE_MAX); 160 161 ASSERT_EQ(PROP_VALUE_MAX - 1, __system_property_get(prop_name, prop_value_ret)); 162 ASSERT_EQ(0, memcmp(prop_value, prop_value_ret, PROP_VALUE_MAX)); 163 } 164} 165 166static void foreach_test_callback(const prop_info *pi, void* cookie) { 167 size_t *count = static_cast<size_t *>(cookie); 168 169 ASSERT_NE((prop_info *)NULL, pi); 170 (*count)++; 171} 172 173TEST(properties, foreach) { 174 LocalPropertyTestState pa; 175 ASSERT_TRUE(pa.valid); 176 size_t count = 0; 177 178 ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6)); 179 ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6)); 180 ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6)); 181 182 ASSERT_EQ(0, __system_property_foreach(foreach_test_callback, &count)); 183 ASSERT_EQ(3U, count); 184} 185 186TEST(properties, find_nth) { 187 LocalPropertyTestState pa; 188 ASSERT_TRUE(pa.valid); 189 190 ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6)); 191 ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6)); 192 ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6)); 193 194 ASSERT_NE((const prop_info *)NULL, __system_property_find_nth(0)); 195 ASSERT_NE((const prop_info *)NULL, __system_property_find_nth(1)); 196 ASSERT_NE((const prop_info *)NULL, __system_property_find_nth(2)); 197 198 ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(3)); 199 ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(4)); 200 ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(5)); 201 ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(100)); 202 ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(200)); 203 ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(247)); 204} 205 206TEST(properties, errors) { 207 LocalPropertyTestState pa; 208 ASSERT_TRUE(pa.valid); 209 char prop_value[PROP_NAME_MAX]; 210 211 ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6)); 212 ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6)); 213 ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6)); 214 215 ASSERT_EQ(0, __system_property_find("property1")); 216 ASSERT_EQ(0, __system_property_get("property1", prop_value)); 217 218 ASSERT_EQ(-1, __system_property_add("name", PROP_NAME_MAX, "value", 5)); 219 ASSERT_EQ(-1, __system_property_add("name", 4, "value", PROP_VALUE_MAX)); 220 ASSERT_EQ(-1, __system_property_update(NULL, "value", PROP_VALUE_MAX)); 221} 222 223TEST(properties, serial) { 224 LocalPropertyTestState pa; 225 ASSERT_TRUE(pa.valid); 226 const prop_info *pi; 227 unsigned int serial; 228 229 ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6)); 230 ASSERT_NE((const prop_info *)NULL, pi = __system_property_find("property")); 231 serial = __system_property_serial(pi); 232 ASSERT_EQ(0, __system_property_update((prop_info *)pi, "value2", 6)); 233 ASSERT_NE(serial, __system_property_serial(pi)); 234} 235 236static void *PropertyWaitHelperFn(void *arg) 237{ 238 int *flag = (int *)arg; 239 prop_info *pi; 240 pi = (prop_info *)__system_property_find("property"); 241 usleep(100000); 242 243 *flag = 1; 244 __system_property_update(pi, "value3", 6); 245 246 return NULL; 247} 248 249TEST(properties, wait) { 250 LocalPropertyTestState pa; 251 ASSERT_TRUE(pa.valid); 252 unsigned int serial; 253 prop_info *pi; 254 pthread_t t; 255 int flag = 0; 256 257 ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6)); 258 serial = __system_property_wait_any(0); 259 pi = (prop_info *)__system_property_find("property"); 260 ASSERT_NE((prop_info *)NULL, pi); 261 __system_property_update(pi, "value2", 6); 262 serial = __system_property_wait_any(serial); 263 264 ASSERT_EQ(0, pthread_create(&t, NULL, PropertyWaitHelperFn, &flag)); 265 ASSERT_EQ(flag, 0); 266 serial = __system_property_wait_any(serial); 267 ASSERT_EQ(flag, 1); 268 269 void* result; 270 ASSERT_EQ(0, pthread_join(t, &result)); 271} 272 273class KilledByFault { 274 public: 275 explicit KilledByFault() {}; 276 bool operator()(int exit_status) const; 277}; 278 279bool KilledByFault::operator()(int exit_status) const { 280 return WIFSIGNALED(exit_status) && 281 (WTERMSIG(exit_status) == SIGSEGV || 282 WTERMSIG(exit_status) == SIGBUS || 283 WTERMSIG(exit_status) == SIGABRT); 284} 285 286TEST(properties_DeathTest, read_only) { 287 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; 288 289 // This test only makes sense if we're talking to the real system property service. 290 struct stat sb; 291 if (stat(PROP_FILENAME, &sb) == -1 && errno == ENOENT) { 292 return; 293 } 294 295 ASSERT_EXIT(__system_property_add("property", 8, "value", 5), KilledByFault(), ""); 296} 297 298#endif 299