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