/* * Copyright 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. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include "common/list_map.h" #include "common/lru_cache.h" #include "hci/address.h" #include "os/utils.h" #include "storage/mutation_entry.h" namespace bluetooth { namespace storage { class Mutation; // A memory operated section-key-value structured config // // A section can be either persistent or temporary. When a section becomes persistent, all its properties are // written to disk. // // A section becomes persistent when a property that is part of persistent_property_names_ is written to config cache; // A section becomes temporary when all properties that are part of persistent_property_names_ is removed // // The definition of persistent sections is up to the user and is defined through the |persistent_property_names| // argument. When these properties are link key properties, then persistent sections is equal to bonded devices // // This class is thread safe class ConfigCache { public: ConfigCache(size_t temp_device_capacity, std::unordered_set persistent_property_names); virtual ~ConfigCache() = default; // no copy DISALLOW_COPY_AND_ASSIGN(ConfigCache); // can move ConfigCache(ConfigCache&& other) noexcept; ConfigCache& operator=(ConfigCache&& other) noexcept; // comparison operators, callback doesn't count bool operator==(const ConfigCache& rhs) const; bool operator!=(const ConfigCache& rhs) const; // observers virtual bool HasSection(const std::string& section) const; virtual bool HasProperty(const std::string& section, const std::string& property) const; // Get property, return std::nullopt if section or property does not exist virtual std::optional GetProperty(const std::string& section, const std::string& property) const; // Returns a copy of persistent device MAC addresses virtual std::vector GetPersistentSections() const; // Return true if a section is persistent virtual bool IsPersistentSection(const std::string& section) const; // Return true if a section has one of the properties in |property_names| virtual bool HasAtLeastOneMatchingPropertiesInSection( const std::string& section, const std::unordered_set& property_names) const; // Return true if a property is part of persistent_property_names_ virtual bool IsPersistentProperty(const std::string& property) const; // Serialize to legacy config format virtual std::string SerializeToLegacyFormat() const; // Return a copy of pair with property struct SectionAndPropertyValue { std::string section; std::string property; bool operator==(const SectionAndPropertyValue& rhs) const { return section == rhs.section && property == rhs.property; } bool operator!=(const SectionAndPropertyValue& rhs) const { return !(*this == rhs); } }; virtual std::vector GetSectionNamesWithProperty(const std::string& property) const; // modifiers // Commit all mutation entries in sequence while holding the config mutex virtual void Commit(std::queue& mutation); virtual void SetProperty(std::string section, std::string property, std::string value); virtual bool RemoveSection(const std::string& section); virtual bool RemoveProperty(const std::string& section, const std::string& property); // TODO: have a systematic way of doing this instead of specialized methods // Remove sections with |property| set virtual void RemoveSectionWithProperty(const std::string& property); // remove all content in this config cache, restore it to the state after the explicit constructor virtual void Clear(); // Set a callback to notify interested party that a persistent config change has just happened virtual void SetPersistentConfigChangedCallback(std::function persistent_config_changed_callback); // Device config specific methods // TODO: methods here should be moved to a device specific config cache if this config cache is supposed to be generic // Legacy stack has device type inconsistencies, this method is trying to fix it virtual bool FixDeviceTypeInconsistencies(); // static methods // Check if section is formatted as a MAC address static bool IsDeviceSection(const std::string& section); // constants static const std::string kDefaultSectionName; private: mutable std::recursive_mutex mutex_; // A callback to notify interested party that a persistent config change has just happened, empty by default std::function persistent_config_changed_callback_; // A set of property names that if set would make a section persistent and if non of these properties are set, a // section would become temporary again std::unordered_set persistent_property_names_; // Common section that does not relate to remote device, will be written to disk common::ListMap> information_sections_; // Information about persistent devices, normally paired, will be written to disk common::ListMap> persistent_devices_; // Information about temporary devices, normally unpaired, will not be written to disk, will be evicted automatically // if capacity exceeds given value during initialization common::LruCache> temporary_devices_; // Convenience method to check if the callback is valid before calling it inline void PersistentConfigChangedCallback() const { if (persistent_config_changed_callback_) { persistent_config_changed_callback_(); } } }; } // namespace storage } // namespace bluetooth