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