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