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 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 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. 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 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 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