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