summaryrefslogtreecommitdiff
path: root/chromium/components/metrics/persistent_system_profile.h
blob: 6c854a927539a48698f69493f73998af9bc54088 (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
152
153
154
155
156
157
158
159
160
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_METRICS_PERSISTENT_SYSTEM_PROFILE_H_
#define BASE_METRICS_PERSISTENT_SYSTEM_PROFILE_H_

#include <vector>

#include "base/strings/string_piece.h"
#include "base/threading/thread_checker.h"
#include "third_party/metrics_proto/system_profile.pb.h"

namespace base {
template <typename T>
struct DefaultSingletonTraits;
class PersistentMemoryAllocator;
}  // namespace base

namespace metrics {

// Manages a copy of the system profile inside persistent memory segments.
class PersistentSystemProfile {
 public:
  PersistentSystemProfile();
  ~PersistentSystemProfile();

  // This object can store records in multiple memory allocators.
  void RegisterPersistentAllocator(
      base::PersistentMemoryAllocator* memory_allocator);
  void DeregisterPersistentAllocator(
      base::PersistentMemoryAllocator* memory_allocator);

  // Stores a complete system profile. Use the version taking the serialized
  // version if available to avoid multiple serialization actions. The
  // |complete| flag indicates that this profile contains all known information
  // and can replace whatever exists. If the flag is false, the profile will be
  // stored only if there is nothing else already present.
  void SetSystemProfile(const std::string& serialized_profile, bool complete);
  void SetSystemProfile(const SystemProfileProto& profile, bool complete);

  // Records the existence of a field trial.
  void AddFieldTrial(base::StringPiece trial, base::StringPiece group);

  // Tests if a persistent memory allocator contains an system profile.
  static bool HasSystemProfile(
      const base::PersistentMemoryAllocator& memory_allocator);

  // Retrieves the system profile from a persistent memory allocator. Returns
  // true if a profile was successfully retrieved. If null is passed for the
  // |system_profile|, only a basic check for the existence of one will be
  // done.
  static bool GetSystemProfile(
      const base::PersistentMemoryAllocator& memory_allocator,
      SystemProfileProto* system_profile);

 private:
  friend class PersistentSystemProfileTest;

  // Defines record types that can be stored inside our local Allocators.
  enum RecordType : uint8_t {
    kUnusedSpace = 0,  // The default value for empty memory.
    kSystemProfileProto,
    kFieldTrialInfo,
  };

  // A class for managing record allocations inside a persistent memory segment.
  class RecordAllocator {
   public:
    // Construct an allocator for writing.
    RecordAllocator(base::PersistentMemoryAllocator* memory_allocator,
                    size_t min_size);

    // Construct an allocator for reading.
    RecordAllocator(const base::PersistentMemoryAllocator* memory_allocator);

    // These methods manage writing records to the allocator. Do not mix these
    // with "read" calls; it's one or the other.
    void Reset();
    bool Write(RecordType type, base::StringPiece record);

    // Read a record from the allocator. Do not mix this with "write" calls;
    // it's one or the other.
    bool HasMoreData() const;
    bool Read(RecordType* type, std::string* record) const;

    base::PersistentMemoryAllocator* allocator() { return allocator_; }

    bool has_complete_profile() { return has_complete_profile_; }
    void set_complete_profile() { has_complete_profile_ = true; }

   private:
    // Advance to the next record segment in the memory allocator.
    bool NextSegment() const;

    // Advance to the next record segment, creating a new one if necessary with
    // sufficent |min_size| space.
    bool AddSegment(size_t min_size);

    // Writes data to the current position, updating the passed values past
    // the amount written. Returns false in case of an error.
    bool WriteData(RecordType type, const char** data, size_t* data_size);

    // Reads data from the current position, updating the passed string
    // in-place. |type| must be initialized to kUnusedSpace and |record| must
    // be an empty string before the first call but unchanged thereafter.
    // Returns true when record is complete.
    bool ReadData(RecordType* type, std::string* record) const;

    // This never changes but can't be "const" because vector calls operator=().
    base::PersistentMemoryAllocator* allocator_;  // Storage location.

    // Indicates if a complete profile has been stored.
    bool has_complete_profile_;

    // These change even though the underlying data may be "const".
    mutable uint32_t alloc_reference_;  // Last storage block.
    mutable size_t alloc_size_;         // Size of the block.
    mutable size_t end_offset_;         // End of data in block.

    // Copy and assign are allowed for easy use with STL containers.
  };

  // Write a record to all registered allocators.
  void WriteToAll(RecordType type, base::StringPiece record);

  // Merges all "update" records into a system profile.
  static void MergeUpdateRecords(
      const base::PersistentMemoryAllocator& memory_allocator,
      SystemProfileProto* system_profile);

  // The list of registered persistent allocators, described by RecordAllocator
  // instances.
  std::vector<RecordAllocator> allocators_;

  // Indicates if a complete profile has been stored to all allocators.
  bool all_have_complete_profile_ = false;

  THREAD_CHECKER(thread_checker_);

  DISALLOW_COPY_AND_ASSIGN(PersistentSystemProfile);
};

// A singleton instance of the above.
class GlobalPersistentSystemProfile : public PersistentSystemProfile {
 public:
  static GlobalPersistentSystemProfile* GetInstance();

 private:
  friend struct base::DefaultSingletonTraits<GlobalPersistentSystemProfile>;

  GlobalPersistentSystemProfile() {}
  ~GlobalPersistentSystemProfile() {}

  DISALLOW_COPY_AND_ASSIGN(GlobalPersistentSystemProfile);
};

}  // namespace metrics

#endif  // BASE_METRICS_PERSISTENT_SYSTEM_PROFILE_H_