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/file.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:
SystemPropertiesTest()40 SystemPropertiesTest() : SystemProperties(false) {
41 valid_ = AreaInit(dir_.path, nullptr);
42 }
~SystemPropertiesTest()43 ~SystemPropertiesTest() {
44 if (valid_) {
45 contexts_->FreeAndUnmap();
46 }
47 }
48
valid() const49 bool valid() const {
50 return valid_;
51 }
52
53 private:
54 TemporaryDir dir_;
55 bool valid_;
56 };
57
foreach_test_callback(const prop_info * pi,void * cookie)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
hierarchical_test_callback(const prop_info * pi,void * cookie)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
TEST(properties,__system_property_add)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_SKIP() << "bionic-only test";
125 #endif // __BIONIC__
126 }
127
TEST(properties,__system_property_update)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_SKIP() << "bionic-only test";
160 #endif // __BIONIC__
161 }
162
TEST(properties,fill)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_SKIP() << "bionic-only test";
206 #endif // __BIONIC__
207 }
208
TEST(properties,__system_property_foreach)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_SKIP() << "bionic-only test";
223 #endif // __BIONIC__
224 }
225
TEST(properties,__system_property_find_nth)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_SKIP() << "bionic-only test";
252 #endif // __BIONIC__
253 }
254
TEST(properties,fill_hierarchical)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_SKIP() << "bionic-only test";
311 #endif // __BIONIC__
312 }
313
TEST(properties,errors)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_SKIP() << "bionic-only test";
332 #endif // __BIONIC__
333 }
334
TEST(properties,__system_property_serial)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_SKIP() << "bionic-only test";
348 #endif // __BIONIC__
349 }
350
TEST(properties,__system_property_wait_any)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_SKIP() << "bionic-only test";
379 #endif // __BIONIC__
380 }
381
TEST(properties,__system_property_wait)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_SKIP() << "bionic-only test";
412 #endif // __BIONIC__
413 }
414
415 class KilledByFault {
416 public:
KilledByFault()417 explicit KilledByFault() {};
418 bool operator()(int exit_status) const;
419 };
420
operator ()(int exit_status) const421 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
TEST_F(properties_DeathTest,read_only)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_SKIP() << "bionic-only test";
440 #endif // __BIONIC__
441 }
442
TEST(properties,__system_property_extra_long_read_only)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_SKIP() << "bionic-only test";
512 #endif // __BIONIC__
513 }
514
515 // pa_size is 128 * 1024 currently, if a property is longer then we expect it to fail gracefully.
TEST(properties,__system_property_extra_long_read_only_too_long)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_SKIP() << "bionic-only test";
527 #endif // __BIONIC__
528 }
529