1 /* 2 * Copyright 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 #pragma once 17 18 #include <functional> 19 #include <list> 20 #include <mutex> 21 #include <optional> 22 #include <queue> 23 #include <string> 24 #include <string_view> 25 #include <unordered_set> 26 #include <utility> 27 #include <vector> 28 29 #include "common/list_map.h" 30 #include "common/lru_cache.h" 31 #include "hci/address.h" 32 #include "os/utils.h" 33 #include "storage/mutation_entry.h" 34 35 namespace bluetooth { 36 namespace storage { 37 38 class Mutation; 39 40 // A memory operated section-key-value structured config 41 // 42 // A section can be either persistent or temporary. When a section becomes persistent, all its properties are 43 // written to disk. 44 // 45 // A section becomes persistent when a property that is part of persistent_property_names_ is written to config cache; 46 // A section becomes temporary when all properties that are part of persistent_property_names_ is removed 47 // 48 // The definition of persistent sections is up to the user and is defined through the |persistent_property_names| 49 // argument. When these properties are link key properties, then persistent sections is equal to bonded devices 50 // 51 // This class is thread safe 52 class ConfigCache { 53 public: 54 ConfigCache(size_t temp_device_capacity, std::unordered_set<std::string_view> persistent_property_names); 55 virtual ~ConfigCache() = default; 56 57 // no copy 58 DISALLOW_COPY_AND_ASSIGN(ConfigCache); 59 60 // can move 61 ConfigCache(ConfigCache&& other) noexcept; 62 ConfigCache& operator=(ConfigCache&& other) noexcept; 63 64 // comparison operators, callback doesn't count 65 bool operator==(const ConfigCache& rhs) const; 66 bool operator!=(const ConfigCache& rhs) const; 67 68 // observers 69 virtual bool HasSection(const std::string& section) const; 70 virtual bool HasProperty(const std::string& section, const std::string& property) const; 71 // Get property, return std::nullopt if section or property does not exist 72 virtual std::optional<std::string> GetProperty(const std::string& section, const std::string& property) const; 73 // Returns a copy of persistent device MAC addresses 74 virtual std::vector<std::string> GetPersistentSections() const; 75 // Return true if a section is persistent 76 virtual bool IsPersistentSection(const std::string& section) const; 77 // Return true if a section has one of the properties in |property_names| 78 virtual bool HasAtLeastOneMatchingPropertiesInSection( 79 const std::string& section, const std::unordered_set<std::string_view>& property_names) const; 80 // Return true if a property is part of persistent_property_names_ 81 virtual bool IsPersistentProperty(const std::string& property) const; 82 // Serialize to legacy config format 83 virtual std::string SerializeToLegacyFormat() const; 84 // Return a copy of pair<section_name, property_value> with property 85 struct SectionAndPropertyValue { 86 std::string section; 87 std::string property; 88 bool operator==(const SectionAndPropertyValue& rhs) const { 89 return section == rhs.section && property == rhs.property; 90 } 91 bool operator!=(const SectionAndPropertyValue& rhs) const { 92 return !(*this == rhs); 93 } 94 }; 95 virtual std::vector<SectionAndPropertyValue> GetSectionNamesWithProperty(const std::string& property) const; 96 97 // modifiers 98 // Commit all mutation entries in sequence while holding the config mutex 99 virtual void Commit(std::queue<MutationEntry>& mutation); 100 virtual void SetProperty(std::string section, std::string property, std::string value); 101 virtual bool RemoveSection(const std::string& section); 102 virtual bool RemoveProperty(const std::string& section, const std::string& property); 103 // TODO: have a systematic way of doing this instead of specialized methods 104 // Remove sections with |property| set 105 virtual void RemoveSectionWithProperty(const std::string& property); 106 // remove all content in this config cache, restore it to the state after the explicit constructor 107 virtual void Clear(); 108 // Set a callback to notify interested party that a persistent config change has just happened 109 virtual void SetPersistentConfigChangedCallback(std::function<void()> persistent_config_changed_callback); 110 111 // Device config specific methods 112 // TODO: methods here should be moved to a device specific config cache if this config cache is supposed to be generic 113 // Legacy stack has device type inconsistencies, this method is trying to fix it 114 virtual bool FixDeviceTypeInconsistencies(); 115 116 // static methods 117 // Check if section is formatted as a MAC address 118 static bool IsDeviceSection(const std::string& section); 119 120 // constants 121 static const std::string kDefaultSectionName; 122 123 private: 124 mutable std::recursive_mutex mutex_; 125 // A callback to notify interested party that a persistent config change has just happened, empty by default 126 std::function<void()> persistent_config_changed_callback_; 127 // A set of property names that if set would make a section persistent and if non of these properties are set, a 128 // section would become temporary again 129 std::unordered_set<std::string_view> persistent_property_names_; 130 // Common section that does not relate to remote device, will be written to disk 131 common::ListMap<std::string, common::ListMap<std::string, std::string>> information_sections_; 132 // Information about persistent devices, normally paired, will be written to disk 133 common::ListMap<std::string, common::ListMap<std::string, std::string>> persistent_devices_; 134 // Information about temporary devices, normally unpaired, will not be written to disk, will be evicted automatically 135 // if capacity exceeds given value during initialization 136 common::LruCache<std::string, common::ListMap<std::string, std::string>> temporary_devices_; 137 138 // Convenience method to check if the callback is valid before calling it PersistentConfigChangedCallback()139 inline void PersistentConfigChangedCallback() const { 140 if (persistent_config_changed_callback_) { 141 persistent_config_changed_callback_(); 142 } 143 } 144 }; 145 146 } // namespace storage 147 } // namespace bluetooth 148