summaryrefslogtreecommitdiff
path: root/system/gd/storage/config_cache.h
blob: 44229e473d0c21f1e59e30d3ef4919e30549f4ad (plain)
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