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 // Returns all property names in the specific section. 100 virtual std::vector<std::string> GetPropertyNames(const std::string& section) const; 101 102 // modifiers 103 // Commit all mutation entries in sequence while holding the config mutex 104 virtual void Commit(std::queue<MutationEntry>& mutation); 105 virtual void SetProperty(std::string section, std::string property, std::string value); 106 virtual bool RemoveSection(const std::string& section); 107 virtual bool RemoveProperty(const std::string& section, const std::string& property); 108 virtual void ConvertEncryptOrDecryptKeyIfNeeded(); 109 // TODO: have a systematic way of doing this instead of specialized methods 110 // Remove sections with |property| set 111 virtual void RemoveSectionWithProperty(const std::string& property); 112 // remove all content in this config cache, restore it to the state after the explicit constructor 113 virtual void Clear(); 114 // Set a callback to notify interested party that a persistent config change has just happened 115 virtual void SetPersistentConfigChangedCallback(std::function<void()> persistent_config_changed_callback); 116 117 // Device config specific methods 118 // TODO: methods here should be moved to a device specific config cache if this config cache is supposed to be generic 119 // Legacy stack has device type inconsistencies, this method is trying to fix it 120 virtual bool FixDeviceTypeInconsistencies(); 121 122 // static methods 123 // Check if section is formatted as a MAC address 124 static bool IsDeviceSection(const std::string& section); 125 126 // constants 127 static const std::string kDefaultSectionName; 128 129 private: 130 mutable std::recursive_mutex mutex_; 131 // A callback to notify interested party that a persistent config change has just happened, empty by default 132 std::function<void()> persistent_config_changed_callback_; 133 // A set of property names that if set would make a section persistent and if non of these properties are set, a 134 // section would become temporary again 135 std::unordered_set<std::string_view> persistent_property_names_; 136 // Common section that does not relate to remote device, will be written to disk 137 common::ListMap<std::string, common::ListMap<std::string, std::string>> information_sections_; 138 // Information about persistent devices, normally paired, will be written to disk 139 common::ListMap<std::string, common::ListMap<std::string, std::string>> persistent_devices_; 140 // Information about temporary devices, normally unpaired, will not be written to disk, will be evicted automatically 141 // if capacity exceeds given value during initialization 142 common::LruCache<std::string, common::ListMap<std::string, std::string>> temporary_devices_; 143 144 // Convenience method to check if the callback is valid before calling it PersistentConfigChangedCallback()145 inline void PersistentConfigChangedCallback() const { 146 if (persistent_config_changed_callback_) { 147 persistent_config_changed_callback_(); 148 } 149 } 150 }; 151 152 } // namespace storage 153 } // namespace bluetooth 154