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 <unistd.h> 20#include <string> 21 22#if __BIONIC__ 23 24#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ 25#include <sys/_system_properties.h> 26 27extern void *__system_property_area__; 28 29struct LocalPropertyTestState { 30 LocalPropertyTestState() : valid(false) { 31 char dir_template[] = "/data/local/tmp/prop-XXXXXX"; 32 char *dirname = mkdtemp(dir_template); 33 if (!dirname) { 34 perror("making temp file for test state failed (is /data/local/tmp writable?)"); 35 return; 36 } 37 38 old_pa = __system_property_area__; 39 __system_property_area__ = NULL; 40 41 pa_dirname = dirname; 42 pa_filename = pa_dirname + "/__properties__"; 43 44 __system_property_set_filename(pa_filename.c_str()); 45 __system_property_area_init(); 46 valid = true; 47 } 48 49 ~LocalPropertyTestState() { 50 if (!valid) 51 return; 52 53 __system_property_area__ = old_pa; 54 55 __system_property_set_filename(PROP_FILENAME); 56 unlink(pa_filename.c_str()); 57 rmdir(pa_dirname.c_str()); 58 } 59public: 60 bool valid; 61private: 62 std::string pa_dirname; 63 std::string pa_filename; 64 void *old_pa; 65}; 66 67TEST(properties, add) { 68 LocalPropertyTestState pa; 69 ASSERT_TRUE(pa.valid); 70 71 char propvalue[PROP_VALUE_MAX]; 72 73 ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6)); 74 ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6)); 75 ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6)); 76 77 ASSERT_EQ(6, __system_property_get("property", propvalue)); 78 ASSERT_STREQ(propvalue, "value1"); 79 80 ASSERT_EQ(6, __system_property_get("other_property", propvalue)); 81 ASSERT_STREQ(propvalue, "value2"); 82 83 ASSERT_EQ(6, __system_property_get("property_other", propvalue)); 84 ASSERT_STREQ(propvalue, "value3"); 85} 86 87TEST(properties, update) { 88 LocalPropertyTestState pa; 89 ASSERT_TRUE(pa.valid); 90 91 char propvalue[PROP_VALUE_MAX]; 92 prop_info *pi; 93 94 ASSERT_EQ(0, __system_property_add("property", 8, "oldvalue1", 9)); 95 ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6)); 96 ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6)); 97 98 pi = (prop_info *)__system_property_find("property"); 99 ASSERT_NE((prop_info *)NULL, pi); 100 __system_property_update(pi, "value4", 6); 101 102 pi = (prop_info *)__system_property_find("other_property"); 103 ASSERT_NE((prop_info *)NULL, pi); 104 __system_property_update(pi, "newvalue5", 9); 105 106 pi = (prop_info *)__system_property_find("property_other"); 107 ASSERT_NE((prop_info *)NULL, pi); 108 __system_property_update(pi, "value6", 6); 109 110 ASSERT_EQ(6, __system_property_get("property", propvalue)); 111 ASSERT_STREQ(propvalue, "value4"); 112 113 ASSERT_EQ(9, __system_property_get("other_property", propvalue)); 114 ASSERT_STREQ(propvalue, "newvalue5"); 115 116 ASSERT_EQ(6, __system_property_get("property_other", propvalue)); 117 ASSERT_STREQ(propvalue, "value6"); 118} 119 120TEST(properties, fill) { 121 LocalPropertyTestState pa; 122 ASSERT_TRUE(pa.valid); 123 char prop_name[PROP_NAME_MAX]; 124 char prop_value[PROP_VALUE_MAX]; 125 char prop_value_ret[PROP_VALUE_MAX]; 126 int count = 0; 127 int ret; 128 129 while (true) { 130 ret = snprintf(prop_name, PROP_NAME_MAX - 1, "property_%d", count); 131 memset(prop_name + ret, 'a', PROP_NAME_MAX - 1 - ret); 132 ret = snprintf(prop_value, PROP_VALUE_MAX - 1, "value_%d", count); 133 memset(prop_value + ret, 'b', PROP_VALUE_MAX - 1 - ret); 134 prop_name[PROP_NAME_MAX - 1] = 0; 135 prop_value[PROP_VALUE_MAX - 1] = 0; 136 137 ret = __system_property_add(prop_name, PROP_NAME_MAX - 1, prop_value, PROP_VALUE_MAX - 1); 138 if (ret < 0) 139 break; 140 141 count++; 142 } 143 144 // For historical reasons at least 247 properties must be supported 145 ASSERT_GE(count, 247); 146 147 for (int i = 0; i < count; i++) { 148 ret = snprintf(prop_name, PROP_NAME_MAX - 1, "property_%d", i); 149 memset(prop_name + ret, 'a', PROP_NAME_MAX - 1 - ret); 150 ret = snprintf(prop_value, PROP_VALUE_MAX - 1, "value_%d", i); 151 memset(prop_value + ret, 'b', PROP_VALUE_MAX - 1 - ret); 152 prop_name[PROP_NAME_MAX - 1] = 0; 153 prop_value[PROP_VALUE_MAX - 1] = 0; 154 memset(prop_value_ret, '\0', PROP_VALUE_MAX); 155 156 ASSERT_EQ(PROP_VALUE_MAX - 1, __system_property_get(prop_name, prop_value_ret)); 157 ASSERT_EQ(0, memcmp(prop_value, prop_value_ret, PROP_VALUE_MAX)); 158 } 159} 160 161static void foreach_test_callback(const prop_info *pi, void* cookie) { 162 size_t *count = static_cast<size_t *>(cookie); 163 164 ASSERT_NE((prop_info *)NULL, pi); 165 (*count)++; 166} 167 168TEST(properties, foreach) { 169 LocalPropertyTestState pa; 170 ASSERT_TRUE(pa.valid); 171 size_t count = 0; 172 173 ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6)); 174 ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6)); 175 ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6)); 176 177 ASSERT_EQ(0, __system_property_foreach(foreach_test_callback, &count)); 178 ASSERT_EQ(3U, count); 179} 180 181TEST(properties, find_nth) { 182 LocalPropertyTestState pa; 183 ASSERT_TRUE(pa.valid); 184 185 ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6)); 186 ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6)); 187 ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6)); 188 189 ASSERT_NE((const prop_info *)NULL, __system_property_find_nth(0)); 190 ASSERT_NE((const prop_info *)NULL, __system_property_find_nth(1)); 191 ASSERT_NE((const prop_info *)NULL, __system_property_find_nth(2)); 192 193 ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(3)); 194 ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(4)); 195 ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(5)); 196 ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(100)); 197 ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(200)); 198 ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(247)); 199} 200 201static void hierarchical_test_callback(const prop_info *pi, void *cookie) { 202 bool (*ok)[8][8] = static_cast<bool (*)[8][8]>(cookie); 203 204 char name[PROP_NAME_MAX]; 205 char value[PROP_VALUE_MAX]; 206 207 __system_property_read(pi, name, value); 208 209 int name_i, name_j, name_k; 210 int value_i, value_j, value_k; 211 ASSERT_EQ(3, sscanf(name, "property_%d.%d.%d", &name_i, &name_j, &name_k)); 212 ASSERT_EQ(3, sscanf(value, "value_%d.%d.%d", &value_i, &value_j, &value_k)); 213 ASSERT_EQ(name_i, value_i); 214 ASSERT_GE(name_i, 0); 215 ASSERT_LT(name_i, 8); 216 ASSERT_EQ(name_j, value_j); 217 ASSERT_GE(name_j, 0); 218 ASSERT_LT(name_j, 8); 219 ASSERT_EQ(name_k, value_k); 220 ASSERT_GE(name_k, 0); 221 ASSERT_LT(name_k, 8); 222 223 ok[name_i][name_j][name_k] = true; 224} 225 226TEST(properties, fill_hierarchical) { 227 LocalPropertyTestState pa; 228 ASSERT_TRUE(pa.valid); 229 char prop_name[PROP_NAME_MAX]; 230 char prop_value[PROP_VALUE_MAX]; 231 char prop_value_ret[PROP_VALUE_MAX]; 232 int ret; 233 234 for (int i = 0; i < 8; i++) { 235 for (int j = 0; j < 8; j++) { 236 for (int k = 0; k < 8; k++) { 237 ret = snprintf(prop_name, PROP_NAME_MAX - 1, "property_%d.%d.%d", i, j, k); 238 memset(prop_name + ret, 'a', PROP_NAME_MAX - 1 - ret); 239 ret = snprintf(prop_value, PROP_VALUE_MAX - 1, "value_%d.%d.%d", i, j, k); 240 memset(prop_value + ret, 'b', PROP_VALUE_MAX - 1 - ret); 241 prop_name[PROP_NAME_MAX - 1] = 0; 242 prop_value[PROP_VALUE_MAX - 1] = 0; 243 244 ASSERT_EQ(0, __system_property_add(prop_name, PROP_NAME_MAX - 1, prop_value, PROP_VALUE_MAX - 1)); 245 } 246 } 247 } 248 249 for (int i = 0; i < 8; i++) { 250 for (int j = 0; j < 8; j++) { 251 for (int k = 0; k < 8; k++) { 252 ret = snprintf(prop_name, PROP_NAME_MAX - 1, "property_%d.%d.%d", i, j, k); 253 memset(prop_name + ret, 'a', PROP_NAME_MAX - 1 - ret); 254 ret = snprintf(prop_value, PROP_VALUE_MAX - 1, "value_%d.%d.%d", i, j, k); 255 memset(prop_value + ret, 'b', PROP_VALUE_MAX - 1 - ret); 256 prop_name[PROP_NAME_MAX - 1] = 0; 257 prop_value[PROP_VALUE_MAX - 1] = 0; 258 memset(prop_value_ret, '\0', PROP_VALUE_MAX); 259 260 ASSERT_EQ(PROP_VALUE_MAX - 1, __system_property_get(prop_name, prop_value_ret)); 261 ASSERT_EQ(0, memcmp(prop_value, prop_value_ret, PROP_VALUE_MAX)); 262 } 263 } 264 } 265 266 bool ok[8][8][8]; 267 memset(ok, 0, sizeof(ok)); 268 __system_property_foreach(hierarchical_test_callback, ok); 269 270 for (int i = 0; i < 8; i++) { 271 for (int j = 0; j < 8; j++) { 272 for (int k = 0; k < 8; k++) { 273 ASSERT_TRUE(ok[i][j][k]); 274 } 275 } 276 } 277} 278 279TEST(properties, errors) { 280 LocalPropertyTestState pa; 281 ASSERT_TRUE(pa.valid); 282 char prop_value[PROP_NAME_MAX]; 283 284 ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6)); 285 ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6)); 286 ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6)); 287 288 ASSERT_EQ(0, __system_property_find("property1")); 289 ASSERT_EQ(0, __system_property_get("property1", prop_value)); 290 291 ASSERT_EQ(-1, __system_property_add("name", PROP_NAME_MAX, "value", 5)); 292 ASSERT_EQ(-1, __system_property_add("name", 4, "value", PROP_VALUE_MAX)); 293 ASSERT_EQ(-1, __system_property_update(NULL, "value", PROP_VALUE_MAX)); 294} 295 296TEST(properties, serial) { 297 LocalPropertyTestState pa; 298 ASSERT_TRUE(pa.valid); 299 const prop_info *pi; 300 unsigned int serial; 301 302 ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6)); 303 ASSERT_NE((const prop_info *)NULL, pi = __system_property_find("property")); 304 serial = __system_property_serial(pi); 305 ASSERT_EQ(0, __system_property_update((prop_info *)pi, "value2", 6)); 306 ASSERT_NE(serial, __system_property_serial(pi)); 307} 308 309static void *PropertyWaitHelperFn(void *arg) 310{ 311 int *flag = (int *)arg; 312 prop_info *pi; 313 pi = (prop_info *)__system_property_find("property"); 314 usleep(100000); 315 316 *flag = 1; 317 __system_property_update(pi, "value3", 6); 318 319 return NULL; 320} 321 322TEST(properties, wait) { 323 LocalPropertyTestState pa; 324 ASSERT_TRUE(pa.valid); 325 unsigned int serial; 326 prop_info *pi; 327 pthread_t t; 328 int flag = 0; 329 330 ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6)); 331 serial = __system_property_wait_any(0); 332 pi = (prop_info *)__system_property_find("property"); 333 ASSERT_NE((prop_info *)NULL, pi); 334 __system_property_update(pi, "value2", 6); 335 serial = __system_property_wait_any(serial); 336 337 ASSERT_EQ(0, pthread_create(&t, NULL, PropertyWaitHelperFn, &flag)); 338 ASSERT_EQ(flag, 0); 339 serial = __system_property_wait_any(serial); 340 ASSERT_EQ(flag, 1); 341 342 void* result; 343 ASSERT_EQ(0, pthread_join(t, &result)); 344} 345 346class KilledByFault { 347 public: 348 explicit KilledByFault() {}; 349 bool operator()(int exit_status) const; 350}; 351 352bool KilledByFault::operator()(int exit_status) const { 353 return WIFSIGNALED(exit_status) && 354 (WTERMSIG(exit_status) == SIGSEGV || 355 WTERMSIG(exit_status) == SIGBUS || 356 WTERMSIG(exit_status) == SIGABRT); 357} 358 359TEST(properties_DeathTest, read_only) { 360 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; 361 ASSERT_EXIT(__system_property_add("property", 8, "value", 5), 362 KilledByFault(), ""); 363} 364#endif 365