1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
/*
* 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 <functional>
#include <list>
#include <mutex>
#include <optional>
#include <queue>
#include <string>
#include <string_view>
#include <unordered_set>
#include <utility>
#include <vector>
#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<std::string_view> persistent_property_names);
ConfigCache(const ConfigCache&) = delete;
ConfigCache& operator=(const ConfigCache&) = delete;
virtual ~ConfigCache() = default;
// no copy
// 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<std::string> GetProperty(const std::string& section, const std::string& property) const;
// Returns a copy of persistent device MAC addresses
virtual std::vector<std::string> 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<std::string_view>& 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<section_name, property_value> 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<SectionAndPropertyValue> GetSectionNamesWithProperty(const std::string& property) const;
// modifiers
// Commit all mutation entries in sequence while holding the config mutex
virtual void Commit(std::queue<MutationEntry>& 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);
virtual void ConvertEncryptOrDecryptKeyIfNeeded();
// 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<void()> 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<void()> 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<std::string_view> persistent_property_names_;
// Common section that does not relate to remote device, will be written to disk
common::ListMap<std::string, common::ListMap<std::string, std::string>> information_sections_;
// Information about persistent devices, normally paired, will be written to disk
common::ListMap<std::string, common::ListMap<std::string, std::string>> 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<std::string, common::ListMap<std::string, std::string>> 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
|