// 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 COMPONENTS_METRICS_PERSISTENT_SYSTEM_PROFILE_H_ #define COMPONENTS_METRICS_PERSISTENT_SYSTEM_PROFILE_H_ #include #include "base/strings/string_piece.h" #include "base/threading/thread_checker.h" #include "third_party/metrics_proto/system_profile.pb.h" namespace base { template struct DefaultSingletonTraits; class PersistentMemoryAllocator; } // namespace base namespace metrics { // Manages a copy of the system profile inside persistent memory segments. class PersistentSystemProfile { public: PersistentSystemProfile(); PersistentSystemProfile(const PersistentSystemProfile&) = delete; PersistentSystemProfile& operator=(const PersistentSystemProfile&) = delete; ~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 existing profile // will only be replaced if it is also incomplete. This method should not be // called too many times with incomplete profiles before setting a complete // profile to prevent impact on startup. 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 allocators_; // Indicates if a complete profile has been stored to all allocators. bool all_have_complete_profile_ = false; THREAD_CHECKER(thread_checker_); }; // A singleton instance of the above. class GlobalPersistentSystemProfile : public PersistentSystemProfile { public: static GlobalPersistentSystemProfile* GetInstance(); GlobalPersistentSystemProfile(const GlobalPersistentSystemProfile&) = delete; GlobalPersistentSystemProfile& operator=( const GlobalPersistentSystemProfile&) = delete; private: friend struct base::DefaultSingletonTraits; GlobalPersistentSystemProfile() {} ~GlobalPersistentSystemProfile() {} }; } // namespace metrics #endif // COMPONENTS_METRICS_PERSISTENT_SYSTEM_PROFILE_H_