• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 "property_monitor.h"
18 
19 #include <stdlib.h>
20 #include <unistd.h>
21 
22 #include <chrono>
23 #include <functional>
24 #include <mutex>
25 #include <string>
26 #include <thread>
27 #include <unordered_map>
28 #include <vector>
29 
30 #include <android-base/logging.h>
31 #include <android-base/properties.h>
32 #include <android-base/thread_annotations.h>
33 #include <gtest/gtest.h>
34 
35 using namespace std::chrono_literals;
36 
37 struct PropertyChanges {
38     std::unordered_map<std::string, std::vector<std::string>> changes GUARDED_BY(mutex);
39     std::mutex mutex;
40 };
41 
ManglePropertyName(std::string name)42 static std::string ManglePropertyName(std::string name) {
43     name.push_back('.');
44     name.append(std::to_string(gettid()));
45     name.append(std::to_string(rand()));
46     return name;
47 }
48 
SpawnThread(PropertyMonitor * pm)49 static std::thread SpawnThread(PropertyMonitor* pm) {
50     return std::thread([pm]() {
51         pm->Run();
52     });
53 }
54 
RegisterExitCallback(PropertyMonitor * pm)55 static std::function<void()> RegisterExitCallback(PropertyMonitor* pm) {
56     std::string prop_name = ManglePropertyName("debug.property_monitor_test.exit");
57     android::base::SetProperty(prop_name, "0");
58     pm->Add(prop_name, [](std::string value) { return value != "1"; });
59     return [prop_name]() {
60         android::base::SetProperty(prop_name, "1");
61     };
62 }
63 
RegisterCallback(PropertyMonitor * pm,PropertyChanges * output,std::string property_name)64 static void RegisterCallback(PropertyMonitor* pm, PropertyChanges* output,
65                              std::string property_name) {
66     pm->Add(property_name, [output, property_name](std::string value) {
67         std::lock_guard<std::mutex> lock(output->mutex);
68         LOG(INFO) << property_name << " = " << value;
69         output->changes[property_name].emplace_back(std::move(value));
70         return true;
71     });
72 }
73 
TEST(PropertyMonitorTest,initial)74 TEST(PropertyMonitorTest, initial) {
75     PropertyMonitor pm;
76     PropertyChanges output;
77 
78     auto exit_fn = RegisterExitCallback(&pm);
79 
80     std::string foo = ManglePropertyName("debug.property_monitor_test.initial");
81     std::string never_set = ManglePropertyName("debug.property_monitor_test.never_set");
82     RegisterCallback(&pm, &output, foo);
83     android::base::SetProperty(foo, "foo");
84 
85     RegisterCallback(&pm, &output, never_set);
86 
87     auto thread = SpawnThread(&pm);
88 
89     exit_fn();
90     thread.join();
91 
92     std::lock_guard<std::mutex> lock(output.mutex);
93     ASSERT_EQ(2UL, output.changes.size());
94     ASSERT_EQ(2UL, output.changes[foo].size());
95     ASSERT_EQ("", output.changes[foo][0]);
96     ASSERT_EQ("foo", output.changes[foo][1]);
97     ASSERT_EQ("", output.changes[never_set][0]);
98 }
99 
TEST(PropertyMonitorTest,change)100 TEST(PropertyMonitorTest, change) {
101     PropertyMonitor pm;
102     PropertyChanges output;
103 
104     auto exit_fn = RegisterExitCallback(&pm);
105 
106     std::string foo = ManglePropertyName("debug.property_monitor_test.foo");
107 
108     RegisterCallback(&pm, &output, foo);
109     android::base::SetProperty(foo, "foo");
110 
111     auto thread = SpawnThread(&pm);
112     std::this_thread::sleep_for(100ms);
113 
114     {
115         std::lock_guard<std::mutex> lock(output.mutex);
116         ASSERT_EQ(1UL, output.changes.size());
117         ASSERT_EQ(2UL, output.changes[foo].size());
118         ASSERT_EQ("", output.changes[foo][0]);
119         ASSERT_EQ("foo", output.changes[foo][1]);
120     }
121 
122     android::base::SetProperty(foo, "bar");
123     std::this_thread::sleep_for(100ms);
124 
125     {
126         std::lock_guard<std::mutex> lock(output.mutex);
127         ASSERT_EQ(1UL, output.changes.size());
128         ASSERT_EQ(3UL, output.changes[foo].size());
129         ASSERT_EQ("", output.changes[foo][0]);
130         ASSERT_EQ("foo", output.changes[foo][1]);
131         ASSERT_EQ("bar", output.changes[foo][2]);
132     }
133 
134     exit_fn();
135     thread.join();
136 }
137 
TEST(PropertyMonitorTest,multiple)138 TEST(PropertyMonitorTest, multiple) {
139     PropertyMonitor pm;
140     PropertyChanges output;
141 
142     auto exit_fn = RegisterExitCallback(&pm);
143 
144     std::string foo = ManglePropertyName("debug.property_monitor_test.foo");
145     std::string bar = ManglePropertyName("debug.property_monitor_test.bar");
146 
147     RegisterCallback(&pm, &output, foo);
148     RegisterCallback(&pm, &output, bar);
149 
150     android::base::SetProperty(foo, "foo");
151     android::base::SetProperty(bar, "bar");
152 
153     auto thread = SpawnThread(&pm);
154     std::this_thread::sleep_for(100ms);
155 
156     {
157         std::lock_guard<std::mutex> lock(output.mutex);
158         ASSERT_EQ(2UL, output.changes.size());
159 
160         ASSERT_EQ(2UL, output.changes[foo].size());
161         ASSERT_EQ("", output.changes[foo][0]);
162         ASSERT_EQ("foo", output.changes[foo][1]);
163 
164         ASSERT_EQ(2UL, output.changes[bar].size());
165         ASSERT_EQ("", output.changes[bar][0]);
166         ASSERT_EQ("bar", output.changes[bar][1]);
167     }
168 
169     android::base::SetProperty(foo, "bar");
170     android::base::SetProperty(bar, "foo");
171     std::this_thread::sleep_for(100ms);
172 
173     {
174         std::lock_guard<std::mutex> lock(output.mutex);
175         ASSERT_EQ(2UL, output.changes.size());
176 
177         ASSERT_EQ(3UL, output.changes[foo].size());
178         ASSERT_EQ("", output.changes[foo][0]);
179         ASSERT_EQ("foo", output.changes[foo][1]);
180         ASSERT_EQ("bar", output.changes[foo][2]);
181 
182         ASSERT_EQ(3UL, output.changes[bar].size());
183         ASSERT_EQ("", output.changes[foo][0]);
184         ASSERT_EQ("bar", output.changes[bar][1]);
185         ASSERT_EQ("foo", output.changes[bar][2]);
186     }
187 
188     exit_fn();
189     thread.join();
190 }
191