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 <atomic>
20 #include <functional>
21 #include <optional>
22 #include <string>
23 #include <thread>
24 #include <utility>
25 #include <vector>
26
27 #include <android-base/logging.h>
28
WaitForSerialChange(uint32_t current_serial)29 static uint32_t WaitForSerialChange(uint32_t current_serial) {
30 uint32_t result;
31 __system_property_wait(nullptr, current_serial, &result, nullptr);
32 return result;
33 }
34
FindProperty(const std::string & property_name,PropertyMonitorData * data)35 static bool FindProperty(const std::string& property_name, PropertyMonitorData* data) {
36 const prop_info* p = __system_property_find(property_name.c_str());
37 if (!p) {
38 return false;
39 }
40
41 data->prop_info = p;
42 return true;
43 }
44
45 // Read a property and return its value if it's been changed, while updating our cached serial.
ReadProperty(PropertyMonitorData * data)46 static std::optional<std::string> ReadProperty(PropertyMonitorData* data) {
47 struct ReadData {
48 std::string value;
49 uint32_t serial;
50 };
51
52 ReadData result;
53 __system_property_read_callback(
54 data->prop_info,
55 [](void* cookie, const char* name, const char* value, uint32_t serial) {
56 ReadData* result = static_cast<ReadData*>(cookie);
57 result->value = value;
58 result->serial = serial;
59 },
60 &result);
61
62 if (result.serial <= data->serial) {
63 return {};
64 }
65
66 data->serial = result.serial;
67 return result.value;
68 }
69
Add(std::string property,std::function<PropertyMonitorCallback> callback)70 void PropertyMonitor::Add(std::string property, std::function<PropertyMonitorCallback> callback) {
71 PropertyMonitorData data = {
72 .callback = std::move(callback),
73 .prop_info = nullptr,
74 .serial = 0,
75 };
76
77 if (FindProperty(property, &data)) {
78 data.callback(ReadProperty(&data).value());
79 } else {
80 data.callback(std::string());
81 }
82
83 properties_.emplace(std::move(property), std::move(data));
84 }
85
Run()86 void PropertyMonitor::Run() {
87 bool result = true;
88 while (result) {
89 uint32_t current_serial = WaitForSerialChange(last_serial_);
90 for (auto& [property_name, data] : properties_) {
91 if (!data.prop_info) {
92 if (FindProperty(property_name, &data)) {
93 result &= data.callback(ReadProperty(&data).value());
94 }
95 } else {
96 if (auto value = ReadProperty(&data); value) {
97 result &= data.callback(value.value());
98 }
99 }
100 }
101
102 last_serial_ = current_serial;
103 }
104 }
105