• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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