| /* |
| * Copyright (C) 2020 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "property_monitor.h" |
| |
| #include <atomic> |
| #include <functional> |
| #include <optional> |
| #include <string> |
| #include <thread> |
| #include <utility> |
| #include <vector> |
| |
| #include <android-base/logging.h> |
| |
| static uint32_t WaitForSerialChange(uint32_t current_serial) { |
| uint32_t result; |
| __system_property_wait(nullptr, current_serial, &result, nullptr); |
| return result; |
| } |
| |
| static bool FindProperty(const std::string& property_name, PropertyMonitorData* data) { |
| const prop_info* p = __system_property_find(property_name.c_str()); |
| if (!p) { |
| return false; |
| } |
| |
| data->prop_info = p; |
| return true; |
| } |
| |
| // Read a property and return its value if it's been changed, while updating our cached serial. |
| static std::optional<std::string> ReadProperty(PropertyMonitorData* data) { |
| struct ReadData { |
| std::string value; |
| uint32_t serial; |
| }; |
| |
| ReadData result; |
| __system_property_read_callback( |
| data->prop_info, |
| [](void* cookie, const char* name, const char* value, uint32_t serial) { |
| ReadData* result = static_cast<ReadData*>(cookie); |
| result->value = value; |
| result->serial = serial; |
| }, |
| &result); |
| |
| if (result.serial <= data->serial) { |
| return {}; |
| } |
| |
| data->serial = result.serial; |
| return result.value; |
| } |
| |
| void PropertyMonitor::Add(std::string property, std::function<PropertyMonitorCallback> callback) { |
| PropertyMonitorData data = { |
| .callback = std::move(callback), |
| .prop_info = nullptr, |
| .serial = 0, |
| }; |
| |
| if (FindProperty(property, &data)) { |
| data.callback(ReadProperty(&data).value()); |
| } else { |
| data.callback(std::string()); |
| } |
| |
| properties_.emplace(std::move(property), std::move(data)); |
| } |
| |
| void PropertyMonitor::Run() { |
| bool result = true; |
| while (result) { |
| uint32_t current_serial = WaitForSerialChange(last_serial_); |
| for (auto& [property_name, data] : properties_) { |
| if (!data.prop_info) { |
| if (FindProperty(property_name, &data)) { |
| result &= data.callback(ReadProperty(&data).value()); |
| } |
| } else { |
| if (auto value = ReadProperty(&data); value) { |
| result &= data.callback(value.value()); |
| } |
| } |
| } |
| |
| last_serial_ = current_serial; |
| } |
| } |