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 "BionicDeathTest.h" 19 20 #include <errno.h> 21 #include <sys/wait.h> 22 #include <unistd.h> 23 24 #include <string> 25 #include <thread> 26 27 #include <android-base/test_utils.h> 28 29 using namespace std::literals; 30 31 #if defined(__BIONIC__) 32 33 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ 34 #include <sys/_system_properties.h> 35 36 #include <system_properties/system_properties.h> 37 38 class SystemPropertiesTest : public SystemProperties { 39 public: 40 SystemPropertiesTest() : SystemProperties(false) { 41 valid_ = AreaInit(dir_.path, nullptr); 42 } 43 ~SystemPropertiesTest() { 44 if (valid_) { 45 contexts_->FreeAndUnmap(); 46 } 47 } 48 49 bool valid() const { 50 return valid_; 51 } 52 53 private: 54 TemporaryDir dir_; 55 bool valid_; 56 }; 57 58 static void foreach_test_callback(const prop_info *pi, void* cookie) { 59 size_t *count = static_cast<size_t *>(cookie); 60 61 ASSERT_TRUE(pi != nullptr); 62 (*count)++; 63 } 64 65 static void hierarchical_test_callback(const prop_info *pi, void *cookie) { 66 bool (*ok)[8][8] = static_cast<bool (*)[8][8]>(cookie); 67 68 char name[PROP_NAME_MAX]; 69 char value[PROP_VALUE_MAX]; 70 71 __system_property_read(pi, name, value); 72 73 int name_i, name_j, name_k; 74 int value_i, value_j, value_k; 75 ASSERT_EQ(3, sscanf(name, "property_%d.%d.%d", &name_i, &name_j, &name_k)); 76 ASSERT_EQ(3, sscanf(value, "value_%d.%d.%d", &value_i, &value_j, &value_k)); 77 ASSERT_EQ(name_i, value_i); 78 ASSERT_GE(name_i, 0); 79 ASSERT_LT(name_i, 8); 80 ASSERT_EQ(name_j, value_j); 81 ASSERT_GE(name_j, 0); 82 ASSERT_LT(name_j, 8); 83 ASSERT_EQ(name_k, value_k); 84 ASSERT_GE(name_k, 0); 85 ASSERT_LT(name_k, 8); 86 87 ok[name_i][name_j][name_k] = true; 88 } 89 90 #endif // __BIONIC__ 91 92 TEST(properties, __system_property_add) { 93 #if defined(__BIONIC__) 94 SystemPropertiesTest system_properties; 95 ASSERT_TRUE(system_properties.valid()); 96 97 ASSERT_EQ(0, system_properties.Add("property", 8, "value1", 6)); 98 ASSERT_EQ(0, system_properties.Add("other_property", 14, "value2", 6)); 99 ASSERT_EQ(0, system_properties.Add("property_other", 14, "value3", 6)); 100 101 // check that there is no limit on property name length 102 char name[PROP_NAME_MAX + 11]; 103 name[0] = 'p'; 104 for (size_t i = 1; i < sizeof(name); i++) { 105 name[i] = 'x'; 106 } 107 108 name[sizeof(name)-1] = '\0'; 109 ASSERT_EQ(0, system_properties.Add(name, strlen(name), "value", 5)); 110 111 char propvalue[PROP_VALUE_MAX]; 112 ASSERT_EQ(6, system_properties.Get("property", propvalue)); 113 ASSERT_STREQ(propvalue, "value1"); 114 115 ASSERT_EQ(6, system_properties.Get("other_property", propvalue)); 116 ASSERT_STREQ(propvalue, "value2"); 117 118 ASSERT_EQ(6, system_properties.Get("property_other", propvalue)); 119 ASSERT_STREQ(propvalue, "value3"); 120 121 ASSERT_EQ(5, system_properties.Get(name, propvalue)); 122 ASSERT_STREQ(propvalue, "value"); 123 #else // __BIONIC__ 124 GTEST_LOG_(INFO) << "This test does nothing.\n"; 125 #endif // __BIONIC__ 126 } 127 128 TEST(properties, __system_property_update) { 129 #if defined(__BIONIC__) 130 SystemPropertiesTest system_properties; 131 ASSERT_TRUE(system_properties.valid()); 132 133 ASSERT_EQ(0, system_properties.Add("property", 8, "oldvalue1", 9)); 134 ASSERT_EQ(0, system_properties.Add("other_property", 14, "value2", 6)); 135 ASSERT_EQ(0, system_properties.Add("property_other", 14, "value3", 6)); 136 137 const prop_info* pi = system_properties.Find("property"); 138 ASSERT_TRUE(pi != nullptr); 139 system_properties.Update(const_cast<prop_info*>(pi), "value4", 6); 140 141 pi = system_properties.Find("other_property"); 142 ASSERT_TRUE(pi != nullptr); 143 system_properties.Update(const_cast<prop_info*>(pi), "newvalue5", 9); 144 145 pi = system_properties.Find("property_other"); 146 ASSERT_TRUE(pi != nullptr); 147 system_properties.Update(const_cast<prop_info*>(pi), "value6", 6); 148 149 char propvalue[PROP_VALUE_MAX]; 150 ASSERT_EQ(6, system_properties.Get("property", propvalue)); 151 ASSERT_STREQ(propvalue, "value4"); 152 153 ASSERT_EQ(9, system_properties.Get("other_property", propvalue)); 154 ASSERT_STREQ(propvalue, "newvalue5"); 155 156 ASSERT_EQ(6, system_properties.Get("property_other", propvalue)); 157 ASSERT_STREQ(propvalue, "value6"); 158 #else // __BIONIC__ 159 GTEST_LOG_(INFO) << "This test does nothing.\n"; 160 #endif // __BIONIC__ 161 } 162 163 TEST(properties, fill) { 164 #if defined(__BIONIC__) 165 SystemPropertiesTest system_properties; 166 ASSERT_TRUE(system_properties.valid()); 167 168 char prop_name[PROP_NAME_MAX]; 169 char prop_value[PROP_VALUE_MAX]; 170 char prop_value_ret[PROP_VALUE_MAX]; 171 int count = 0; 172 int ret; 173 174 while (true) { 175 ret = snprintf(prop_name, PROP_NAME_MAX - 1, "property_%d", count); 176 memset(prop_name + ret, 'a', PROP_NAME_MAX - 1 - ret); 177 ret = snprintf(prop_value, PROP_VALUE_MAX - 1, "value_%d", count); 178 memset(prop_value + ret, 'b', PROP_VALUE_MAX - 1 - ret); 179 prop_name[PROP_NAME_MAX - 1] = 0; 180 prop_value[PROP_VALUE_MAX - 1] = 0; 181 182 ret = system_properties.Add(prop_name, PROP_NAME_MAX - 1, prop_value, PROP_VALUE_MAX - 1); 183 if (ret < 0) 184 break; 185 186 count++; 187 } 188 189 // For historical reasons at least 247 properties must be supported 190 ASSERT_GE(count, 247); 191 192 for (int i = 0; i < count; i++) { 193 ret = snprintf(prop_name, PROP_NAME_MAX - 1, "property_%d", i); 194 memset(prop_name + ret, 'a', PROP_NAME_MAX - 1 - ret); 195 ret = snprintf(prop_value, PROP_VALUE_MAX - 1, "value_%d", i); 196 memset(prop_value + ret, 'b', PROP_VALUE_MAX - 1 - ret); 197 prop_name[PROP_NAME_MAX - 1] = 0; 198 prop_value[PROP_VALUE_MAX - 1] = 0; 199 memset(prop_value_ret, '\0', PROP_VALUE_MAX); 200 201 ASSERT_EQ(PROP_VALUE_MAX - 1, system_properties.Get(prop_name, prop_value_ret)); 202 ASSERT_EQ(0, memcmp(prop_value, prop_value_ret, PROP_VALUE_MAX)); 203 } 204 #else // __BIONIC__ 205 GTEST_LOG_(INFO) << "This test does nothing.\n"; 206 #endif // __BIONIC__ 207 } 208 209 TEST(properties, __system_property_foreach) { 210 #if defined(__BIONIC__) 211 SystemPropertiesTest system_properties; 212 ASSERT_TRUE(system_properties.valid()); 213 214 ASSERT_EQ(0, system_properties.Add("property", 8, "value1", 6)); 215 ASSERT_EQ(0, system_properties.Add("other_property", 14, "value2", 6)); 216 ASSERT_EQ(0, system_properties.Add("property_other", 14, "value3", 6)); 217 218 size_t count = 0; 219 ASSERT_EQ(0, system_properties.Foreach(foreach_test_callback, &count)); 220 ASSERT_EQ(3U, count); 221 #else // __BIONIC__ 222 GTEST_LOG_(INFO) << "This test does nothing.\n"; 223 #endif // __BIONIC__ 224 } 225 226 TEST(properties, __system_property_find_nth) { 227 #if defined(__BIONIC__) 228 SystemPropertiesTest system_properties; 229 ASSERT_TRUE(system_properties.valid()); 230 231 ASSERT_EQ(0, system_properties.Add("property", 8, "value1", 6)); 232 ASSERT_EQ(0, system_properties.Add("other_property", 14, "value2", 6)); 233 ASSERT_EQ(0, system_properties.Add("property_other", 14, "value3", 6)); 234 235 char name[PROP_NAME_MAX]; 236 char value[PROP_VALUE_MAX]; 237 EXPECT_EQ(6, system_properties.Read(system_properties.FindNth(0), name, value)); 238 EXPECT_STREQ("property", name); 239 EXPECT_STREQ("value1", value); 240 EXPECT_EQ(6, system_properties.Read(system_properties.FindNth(1), name, value)); 241 EXPECT_STREQ("other_property", name); 242 EXPECT_STREQ("value2", value); 243 EXPECT_EQ(6, system_properties.Read(system_properties.FindNth(2), name, value)); 244 EXPECT_STREQ("property_other", name); 245 EXPECT_STREQ("value3", value); 246 247 for (unsigned i = 3; i < 1024; ++i) { 248 ASSERT_TRUE(system_properties.FindNth(i) == nullptr); 249 } 250 #else // __BIONIC__ 251 GTEST_LOG_(INFO) << "This test does nothing.\n"; 252 #endif // __BIONIC__ 253 } 254 255 TEST(properties, fill_hierarchical) { 256 #if defined(__BIONIC__) 257 SystemPropertiesTest system_properties; 258 ASSERT_TRUE(system_properties.valid()); 259 260 char prop_name[PROP_NAME_MAX]; 261 char prop_value[PROP_VALUE_MAX]; 262 char prop_value_ret[PROP_VALUE_MAX]; 263 int ret; 264 265 for (int i = 0; i < 8; i++) { 266 for (int j = 0; j < 8; j++) { 267 for (int k = 0; k < 8; k++) { 268 ret = snprintf(prop_name, PROP_NAME_MAX - 1, "property_%d.%d.%d", i, j, k); 269 memset(prop_name + ret, 'a', PROP_NAME_MAX - 1 - ret); 270 ret = snprintf(prop_value, PROP_VALUE_MAX - 1, "value_%d.%d.%d", i, j, k); 271 memset(prop_value + ret, 'b', PROP_VALUE_MAX - 1 - ret); 272 prop_name[PROP_NAME_MAX - 1] = 0; 273 prop_value[PROP_VALUE_MAX - 1] = 0; 274 275 ASSERT_EQ(0, system_properties.Add( 276 prop_name, PROP_NAME_MAX - 1, prop_value, PROP_VALUE_MAX - 1)); 277 } 278 } 279 } 280 281 for (int i = 0; i < 8; i++) { 282 for (int j = 0; j < 8; j++) { 283 for (int k = 0; k < 8; k++) { 284 ret = snprintf(prop_name, PROP_NAME_MAX - 1, "property_%d.%d.%d", i, j, k); 285 memset(prop_name + ret, 'a', PROP_NAME_MAX - 1 - ret); 286 ret = snprintf(prop_value, PROP_VALUE_MAX - 1, "value_%d.%d.%d", i, j, k); 287 memset(prop_value + ret, 'b', PROP_VALUE_MAX - 1 - ret); 288 prop_name[PROP_NAME_MAX - 1] = 0; 289 prop_value[PROP_VALUE_MAX - 1] = 0; 290 memset(prop_value_ret, '\0', PROP_VALUE_MAX); 291 292 ASSERT_EQ(PROP_VALUE_MAX - 1, system_properties.Get(prop_name, prop_value_ret)); 293 ASSERT_EQ(0, memcmp(prop_value, prop_value_ret, PROP_VALUE_MAX)); 294 } 295 } 296 } 297 298 bool ok[8][8][8]; 299 memset(ok, 0, sizeof(ok)); 300 system_properties.Foreach(hierarchical_test_callback, ok); 301 302 for (int i = 0; i < 8; i++) { 303 for (int j = 0; j < 8; j++) { 304 for (int k = 0; k < 8; k++) { 305 ASSERT_TRUE(ok[i][j][k]); 306 } 307 } 308 } 309 #else // __BIONIC__ 310 GTEST_LOG_(INFO) << "This test does nothing.\n"; 311 #endif // __BIONIC__ 312 } 313 314 TEST(properties, errors) { 315 #if defined(__BIONIC__) 316 SystemPropertiesTest system_properties; 317 ASSERT_TRUE(system_properties.valid()); 318 319 char prop_value[PROP_NAME_MAX]; 320 321 ASSERT_EQ(0, system_properties.Add("property", 8, "value1", 6)); 322 ASSERT_EQ(0, system_properties.Add("other_property", 14, "value2", 6)); 323 ASSERT_EQ(0, system_properties.Add("property_other", 14, "value3", 6)); 324 325 ASSERT_EQ(0, system_properties.Find("property1")); 326 ASSERT_EQ(0, system_properties.Get("property1", prop_value)); 327 328 ASSERT_EQ(-1, system_properties.Add("name", 4, "value", PROP_VALUE_MAX)); 329 ASSERT_EQ(-1, system_properties.Update(NULL, "value", PROP_VALUE_MAX)); 330 #else // __BIONIC__ 331 GTEST_LOG_(INFO) << "This test does nothing.\n"; 332 #endif // __BIONIC__ 333 } 334 335 TEST(properties, __system_property_serial) { 336 #if defined(__BIONIC__) 337 SystemPropertiesTest system_properties; 338 ASSERT_TRUE(system_properties.valid()); 339 340 ASSERT_EQ(0, system_properties.Add("property", 8, "value1", 6)); 341 const prop_info* pi = system_properties.Find("property"); 342 ASSERT_TRUE(pi != nullptr); 343 unsigned serial = system_properties.Serial(pi); 344 ASSERT_EQ(0, system_properties.Update(const_cast<prop_info*>(pi), "value2", 6)); 345 ASSERT_NE(serial, system_properties.Serial(pi)); 346 #else // __BIONIC__ 347 GTEST_LOG_(INFO) << "This test does nothing.\n"; 348 #endif // __BIONIC__ 349 } 350 351 TEST(properties, __system_property_wait_any) { 352 #if defined(__BIONIC__) 353 SystemPropertiesTest system_properties; 354 ASSERT_TRUE(system_properties.valid()); 355 356 ASSERT_EQ(0, system_properties.Add("property", 8, "value1", 6)); 357 unsigned serial = system_properties.WaitAny(0); 358 359 prop_info* pi = const_cast<prop_info*>(system_properties.Find("property")); 360 ASSERT_TRUE(pi != nullptr); 361 system_properties.Update(pi, "value2", 6); 362 serial = system_properties.WaitAny(serial); 363 364 int flag = 0; 365 std::thread thread([&system_properties, &flag]() { 366 prop_info* pi = const_cast<prop_info*>(system_properties.Find("property")); 367 usleep(100000); 368 369 flag = 1; 370 system_properties.Update(pi, "value3", 6); 371 }); 372 ASSERT_EQ(flag, 0); 373 serial = system_properties.WaitAny(serial); 374 ASSERT_EQ(flag, 1); 375 376 thread.join(); 377 #else // __BIONIC__ 378 GTEST_LOG_(INFO) << "This test does nothing.\n"; 379 #endif // __BIONIC__ 380 } 381 382 TEST(properties, __system_property_wait) { 383 #if defined(__BIONIC__) 384 SystemPropertiesTest system_properties; 385 ASSERT_TRUE(system_properties.valid()); 386 387 ASSERT_EQ(0, system_properties.Add("property", 8, "value1", 6)); 388 389 prop_info* pi = const_cast<prop_info*>(system_properties.Find("property")); 390 ASSERT_TRUE(pi != nullptr); 391 392 unsigned serial = system_properties.Serial(pi); 393 394 std::thread thread([&system_properties]() { 395 prop_info* pi = const_cast<prop_info*>(system_properties.Find("property")); 396 ASSERT_TRUE(pi != nullptr); 397 398 system_properties.Update(pi, "value2", 6); 399 }); 400 401 uint32_t new_serial; 402 system_properties.Wait(pi, serial, &new_serial, nullptr); 403 ASSERT_GT(new_serial, serial); 404 405 char value[PROP_VALUE_MAX]; 406 ASSERT_EQ(6, system_properties.Get("property", value)); 407 ASSERT_STREQ("value2", value); 408 409 thread.join(); 410 #else // __BIONIC__ 411 GTEST_LOG_(INFO) << "This test does nothing.\n"; 412 #endif // __BIONIC__ 413 } 414 415 class KilledByFault { 416 public: 417 explicit KilledByFault() {}; 418 bool operator()(int exit_status) const; 419 }; 420 421 bool KilledByFault::operator()(int exit_status) const { 422 return WIFSIGNALED(exit_status) && 423 (WTERMSIG(exit_status) == SIGSEGV || 424 WTERMSIG(exit_status) == SIGBUS || 425 WTERMSIG(exit_status) == SIGABRT); 426 } 427 428 class properties_DeathTest : public BionicDeathTest {}; 429 430 TEST_F(properties_DeathTest, read_only) { 431 #if defined(__BIONIC__) 432 433 // This test only makes sense if we're talking to the real system property service. 434 struct stat sb; 435 ASSERT_FALSE(stat(PROP_FILENAME, &sb) == -1 && errno == ENOENT); 436 437 ASSERT_EXIT(__system_property_add("property", 8, "value", 5), KilledByFault(), ""); 438 #else // __BIONIC__ 439 GTEST_LOG_(INFO) << "This test does nothing.\n"; 440 #endif // __BIONIC__ 441 } 442 443 TEST(properties, __system_property_extra_long_read_only) { 444 #if defined(__BIONIC__) 445 SystemPropertiesTest system_properties; 446 ASSERT_TRUE(system_properties.valid()); 447 448 std::vector<std::pair<std::string, std::string>> short_properties = { 449 { "ro.0char", std::string() }, 450 { "ro.50char", std::string(50, 'x') }, 451 { "ro.91char", std::string(91, 'x') }, 452 }; 453 454 std::vector<std::pair<std::string, std::string>> long_properties = { 455 { "ro.92char", std::string(92, 'x') }, 456 { "ro.93char", std::string(93, 'x') }, 457 { "ro.1000char", std::string(1000, 'x') }, 458 }; 459 460 for (const auto& property : short_properties) { 461 const std::string& name = property.first; 462 const std::string& value = property.second; 463 ASSERT_EQ(0, system_properties.Add(name.c_str(), name.size(), value.c_str(), value.size())); 464 } 465 466 for (const auto& property : long_properties) { 467 const std::string& name = property.first; 468 const std::string& value = property.second; 469 ASSERT_EQ(0, system_properties.Add(name.c_str(), name.size(), value.c_str(), value.size())); 470 } 471 472 auto check_with_legacy_read = [&system_properties](const std::string& name, 473 const std::string& expected_value) { 474 char value[PROP_VALUE_MAX]; 475 EXPECT_EQ(static_cast<int>(expected_value.size()), system_properties.Get(name.c_str(), value)) 476 << name; 477 EXPECT_EQ(expected_value, value) << name; 478 }; 479 480 auto check_with_read_callback = [&system_properties](const std::string& name, 481 const std::string& expected_value) { 482 const prop_info* pi = system_properties.Find(name.c_str()); 483 ASSERT_NE(nullptr, pi); 484 std::string value; 485 system_properties.ReadCallback(pi, 486 [](void* cookie, const char*, const char* value, uint32_t) { 487 auto* out_value = reinterpret_cast<std::string*>(cookie); 488 *out_value = value; 489 }, 490 &value); 491 EXPECT_EQ(expected_value, value) << name; 492 }; 493 494 for (const auto& property : short_properties) { 495 const std::string& name = property.first; 496 const std::string& value = property.second; 497 check_with_legacy_read(name, value); 498 check_with_read_callback(name, value); 499 } 500 501 constexpr static const char* kExtraLongLegacyError = 502 "Must use __system_property_read_callback() to read"; 503 for (const auto& property : long_properties) { 504 const std::string& name = property.first; 505 const std::string& value = property.second; 506 check_with_legacy_read(name, kExtraLongLegacyError); 507 check_with_read_callback(name, value); 508 } 509 510 #else // __BIONIC__ 511 GTEST_LOG_(INFO) << "This test does nothing.\n"; 512 #endif // __BIONIC__ 513 } 514 515 // pa_size is 128 * 1024 currently, if a property is longer then we expect it to fail gracefully. 516 TEST(properties, __system_property_extra_long_read_only_too_long) { 517 #if defined(__BIONIC__) 518 SystemPropertiesTest system_properties; 519 ASSERT_TRUE(system_properties.valid()); 520 521 auto name = "ro.super_long_property"s; 522 auto value = std::string(128 * 1024 + 1, 'x'); 523 ASSERT_NE(0, system_properties.Add(name.c_str(), name.size(), value.c_str(), value.size())); 524 525 #else // __BIONIC__ 526 GTEST_LOG_(INFO) << "This test does nothing.\n"; 527 #endif // __BIONIC__ 528 } 529