blob: 5a851b8d1ced0b8f783e01330797c97b195de8ce [file] [log] [blame]
// 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"
#include "base/macros.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_