| Index: base/debug/activity_tracker.h
|
| diff --git a/base/debug/activity_tracker.h b/base/debug/activity_tracker.h
|
| index 9ffcfaa844ba22ee9edee16dcade2481f5a4f011..82e395d035ab83c22f42be22ea60f1718029fe8c 100644
|
| --- a/base/debug/activity_tracker.h
|
| +++ b/base/debug/activity_tracker.h
|
| @@ -18,17 +18,21 @@
|
| #include <atomic>
|
| #include <map>
|
| #include <memory>
|
| +#include <set>
|
| #include <string>
|
| #include <vector>
|
|
|
| #include "base/atomicops.h"
|
| #include "base/base_export.h"
|
| +#include "base/callback.h"
|
| #include "base/compiler_specific.h"
|
| #include "base/gtest_prod_util.h"
|
| #include "base/location.h"
|
| #include "base/metrics/persistent_memory_allocator.h"
|
| +#include "base/process/process_handle.h"
|
| #include "base/strings/string_piece.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| +#include "base/task_runner.h"
|
| #include "base/threading/platform_thread.h"
|
| #include "base/threading/thread_checker.h"
|
| #include "base/threading/thread_local_storage.h"
|
| @@ -41,7 +45,6 @@ class FilePath;
|
| class Lock;
|
| class PlatformThreadHandle;
|
| class Process;
|
| -class StaticAtomicSequenceNumber;
|
| class WaitableEvent;
|
|
|
| namespace debug {
|
| @@ -56,6 +59,39 @@ enum : int {
|
| kActivityCallStackSize = 10,
|
| };
|
|
|
| +// A class for keeping all information needed to verify that a structure is
|
| +// associated with a given process.
|
| +struct ProcessInfo {
|
| + ProcessInfo();
|
| + ~ProcessInfo();
|
| +
|
| + // Initializes structure with the current process id and the current time.
|
| + // These can uniquely identify a process. A unique non-zero data_id will be
|
| + // set making it possible to tell using atomic reads if the data has changed.
|
| + void Release_Initialize();
|
| +
|
| + // Explicitly sets the process ID.
|
| + void SetOwningProcessIdForTesting(ProcessId pid, int64_t stamp);
|
| +
|
| + // Gets the associated process ID, in native form, and the creation timestamp
|
| + // from memory without loading the entire structure for analysis. This will
|
| + // return false if no valid process ID is available.
|
| + static bool GetOwningProcessId(const void* memory,
|
| + ProcessId* out_id,
|
| + int64_t* out_stamp);
|
| +
|
| + // SHA1(base::debug::ProcessInfo): Increment this if structure changes!
|
| + static constexpr uint32_t kPersistentTypeId = 0xD485C718 + 1;
|
| +
|
| + // Expected size for 32/64-bit check by PersistentMemoryAllocator.
|
| + static constexpr size_t kExpectedInstanceSize = 24;
|
| +
|
| + std::atomic<uint32_t> data_id;
|
| + uint32_t padding;
|
| + int64_t process_id;
|
| + int64_t create_stamp;
|
| +};
|
| +
|
| // The data associated with an activity is dependent upon the activity type.
|
| // This union defines all of the various fields. All fields must be explicitly
|
| // sized types to ensure no interoperability problems between 32-bit and
|
| @@ -349,7 +385,9 @@ class BASE_EXPORT ActivityUserData {
|
| // contents have been overwritten by another thread. The return value is
|
| // always non-zero unless it's actually just a data "sink".
|
| uint32_t id() const {
|
| - return memory_ ? id_->load(std::memory_order_relaxed) : 0;
|
| + return header_
|
| + ? header_->process_info.data_id.load(std::memory_order_relaxed)
|
| + : 0;
|
| }
|
|
|
| // Writes a |value| (as part of a key/value pair) that will be included with
|
| @@ -405,6 +443,16 @@ class BASE_EXPORT ActivityUserData {
|
| // Gets the base memory address used for storing data.
|
| const void* GetBaseAddress();
|
|
|
| + // Explicitly sets the process ID.
|
| + void SetOwningProcessIdForTesting(ProcessId pid, int64_t stamp);
|
| +
|
| + // Gets the associated process ID, in native form, and the creation timestamp
|
| + // from tracker memory without loading the entire structure for analysis. This
|
| + // will return false if no valid process ID is available.
|
| + static bool GetOwningProcessId(const void* memory,
|
| + ProcessId* out_id,
|
| + int64_t* out_stamp);
|
| +
|
| protected:
|
| virtual void Set(StringPiece name,
|
| ValueType type,
|
| @@ -416,20 +464,31 @@ class BASE_EXPORT ActivityUserData {
|
|
|
| enum : size_t { kMemoryAlignment = sizeof(uint64_t) };
|
|
|
| - // A structure used to reference data held outside of persistent memory.
|
| - struct ReferenceRecord {
|
| - uint64_t address;
|
| - uint64_t size;
|
| + // A structure that defines the structure header in memory.
|
| + struct MemoryHeader {
|
| + MemoryHeader();
|
| + ~MemoryHeader();
|
| +
|
| + ProcessInfo process_info; // Information about the creating process.
|
| };
|
|
|
| // Header to a key/value record held in persistent memory.
|
| - struct Header {
|
| + struct FieldHeader {
|
| + FieldHeader();
|
| + ~FieldHeader();
|
| +
|
| std::atomic<uint8_t> type; // Encoded ValueType
|
| uint8_t name_size; // Length of "name" key.
|
| std::atomic<uint16_t> value_size; // Actual size of of the stored value.
|
| uint16_t record_size; // Total storage of name, value, header.
|
| };
|
|
|
| + // A structure used to reference data held outside of persistent memory.
|
| + struct ReferenceRecord {
|
| + uint64_t address;
|
| + uint64_t size;
|
| + };
|
| +
|
| // This record is used to hold known value is a map so that they can be
|
| // found and overwritten later.
|
| struct ValueInfo {
|
| @@ -464,12 +523,8 @@ class BASE_EXPORT ActivityUserData {
|
| mutable char* memory_;
|
| mutable size_t available_;
|
|
|
| - // A pointer to the unique ID for this instance.
|
| - std::atomic<uint32_t>* const id_;
|
| -
|
| - // This ID is used to create unique indentifiers for user data so that it's
|
| - // possible to tell if the information has been overwritten.
|
| - static StaticAtomicSequenceNumber next_id_;
|
| + // A pointer to the memory header for this instance.
|
| + MemoryHeader* const header_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(ActivityUserData);
|
| };
|
| @@ -612,6 +667,19 @@ class BASE_EXPORT ThreadActivityTracker {
|
| // implementation does not support concurrent snapshot operations.
|
| bool CreateSnapshot(Snapshot* output_snapshot) const;
|
|
|
| + // Gets the base memory address used for storing data.
|
| + const void* GetBaseAddress();
|
| +
|
| + // Explicitly sets the process ID.
|
| + void SetOwningProcessIdForTesting(ProcessId pid, int64_t stamp);
|
| +
|
| + // Gets the associated process ID, in native form, and the creation timestamp
|
| + // from tracker memory without loading the entire structure for analysis. This
|
| + // will return false if no valid process ID is available.
|
| + static bool GetOwningProcessId(const void* memory,
|
| + ProcessId* out_id,
|
| + int64_t* out_stamp);
|
| +
|
| // Calculates the memory size required for a given stack depth, including
|
| // the internal header structure for the stack.
|
| static size_t SizeForStackDepth(int stack_depth);
|
| @@ -643,15 +711,42 @@ class BASE_EXPORT GlobalActivityTracker {
|
| // will be safely ignored. These are public so that an external process
|
| // can recognize records of this type within an allocator.
|
| enum : uint32_t {
|
| - kTypeIdActivityTracker = 0x5D7381AF + 3, // SHA1(ActivityTracker) v3
|
| - kTypeIdUserDataRecord = 0x615EDDD7 + 2, // SHA1(UserDataRecord) v2
|
| + kTypeIdActivityTracker = 0x5D7381AF + 4, // SHA1(ActivityTracker) v4
|
| + kTypeIdUserDataRecord = 0x615EDDD7 + 3, // SHA1(UserDataRecord) v3
|
| kTypeIdGlobalLogMessage = 0x4CF434F9 + 1, // SHA1(GlobalLogMessage) v1
|
| - kTypeIdGlobalDataRecord = kTypeIdUserDataRecord + 1000,
|
| + kTypeIdProcessDataRecord = kTypeIdUserDataRecord + 0x100,
|
| + kTypeIdGlobalDataRecord = kTypeIdUserDataRecord + 0x200,
|
|
|
| kTypeIdActivityTrackerFree = ~kTypeIdActivityTracker,
|
| kTypeIdUserDataRecordFree = ~kTypeIdUserDataRecord,
|
| + kTypeIdProcessDataRecordFree = ~kTypeIdProcessDataRecord,
|
| + };
|
| +
|
| + // An enumeration of common process life stages. All entries are given an
|
| + // explicit number so they are known and remain constant; this allows for
|
| + // cross-version analysis either locally or on a server.
|
| + enum ProcessPhase : int {
|
| + // The phases have meaning to the tracker.
|
| + PROCESS_PHASE_UNKNOWN = 0,
|
| + PROCESS_LAUNCHED = 1,
|
| + PROCESS_EXITED_CLEANLY = 2,
|
| +
|
| + // Add here whatever is useful for analysis.
|
| + PROCESS_SHUTDOWN_STARTED = 10,
|
| + PROCESS_MAIN_LOOP_STARTED = 11,
|
| };
|
|
|
| + // A callback made when a process exits to allow immediate analysis of its
|
| + // data. Note that the system may reuse the |process_id| so when fetching
|
| + // records its important to ensure that what is returned was created before
|
| + // the |exit_stamp|. Movement of |process_data| information is allowed.
|
| + using ProcessExitCallback =
|
| + Callback<void(int64_t process_id,
|
| + int64_t exit_stamp,
|
| + int exit_code,
|
| + ProcessPhase exit_phase,
|
| + ActivityUserData::Snapshot&& process_data)>;
|
| +
|
| // This structure contains information about a loaded module, as shown to
|
| // users of the tracker.
|
| struct BASE_EXPORT ModuleInfo {
|
| @@ -780,6 +875,36 @@ class BASE_EXPORT GlobalActivityTracker {
|
| // Releases the activity-tracker for the current thread (for testing only).
|
| void ReleaseTrackerForCurrentThreadForTesting();
|
|
|
| + // Sets a task-runner that can be used for background work.
|
| + void SetBackgroundTaskRunner(const scoped_refptr<TaskRunner>& runner);
|
| +
|
| + // Sets an optional callback to be called when a process exits.
|
| + void SetProcessExitCallback(ProcessExitCallback callback);
|
| +
|
| + // Manages process lifetimes. These are called by the process that launched
|
| + // and reaped the subprocess, not the subprocess itself.
|
| + void RecordProcessLaunch(ProcessId process_id);
|
| + void RecordProcessExit(ProcessId process_id, int exit_code);
|
| + static void RecordProcessLaunchIfEnabled(ProcessId process_id) {
|
| + GlobalActivityTracker* tracker = Get();
|
| + if (tracker)
|
| + tracker->RecordProcessLaunch(process_id);
|
| + }
|
| + static void RecordProcessExitIfEnabled(ProcessId process_id, int exit_code) {
|
| + GlobalActivityTracker* tracker = Get();
|
| + if (tracker)
|
| + tracker->RecordProcessExit(process_id, exit_code);
|
| + }
|
| +
|
| + // Sets the "phase" of the current process, useful for knowing what it was
|
| + // doing when it last reported.
|
| + void SetProcessPhase(ProcessPhase phase);
|
| + static void SetProcessPhaseIfEnabled(ProcessPhase phase) {
|
| + GlobalActivityTracker* tracker = Get();
|
| + if (tracker)
|
| + tracker->SetProcessPhase(phase);
|
| + }
|
| +
|
| // Records a log message. The current implementation does NOT recycle these
|
| // only store critical messages such as FATAL ones.
|
| void RecordLogMessage(StringPiece message);
|
| @@ -793,7 +918,12 @@ class BASE_EXPORT GlobalActivityTracker {
|
| // active field trials to be fetched and recorded.
|
| void RecordFieldTrial(const std::string& trial_name, StringPiece group_name);
|
|
|
| + // Accesses the process data record for storing arbitrary key/value pairs.
|
| + // Updates to this are thread-safe.
|
| + ActivityUserData& process_data() { return process_data_; }
|
| +
|
| // Accesses the global data record for storing arbitrary key/value pairs.
|
| + // Updates to this are thread-safe.
|
| ActivityUserData& global_data() { return global_data_; }
|
|
|
| private:
|
| @@ -812,10 +942,10 @@ class BASE_EXPORT GlobalActivityTracker {
|
| // A wrapper around ActivityUserData that is thread-safe and thus can be used
|
| // in the global scope without the requirement of being called from only one
|
| // thread.
|
| - class GlobalUserData : public ActivityUserData {
|
| + class ThreadSafeUserData : public ActivityUserData {
|
| public:
|
| - GlobalUserData(void* memory, size_t size);
|
| - ~GlobalUserData() override;
|
| + ThreadSafeUserData(void* memory, size_t size);
|
| + ~ThreadSafeUserData() override;
|
|
|
| private:
|
| void Set(StringPiece name,
|
| @@ -825,7 +955,7 @@ class BASE_EXPORT GlobalActivityTracker {
|
|
|
| Lock data_lock_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(GlobalUserData);
|
| + DISALLOW_COPY_AND_ASSIGN(ThreadSafeUserData);
|
| };
|
|
|
| // State of a module as stored in persistent memory. This supports a single
|
| @@ -837,7 +967,8 @@ class BASE_EXPORT GlobalActivityTracker {
|
| static constexpr uint32_t kPersistentTypeId = 0x05DB5F41 + 1;
|
|
|
| // Expected size for 32/64-bit check by PersistentMemoryAllocator.
|
| - static constexpr size_t kExpectedInstanceSize = 56;
|
| + static constexpr size_t kExpectedInstanceSize =
|
| + ProcessInfo::kExpectedInstanceSize + 56;
|
|
|
| // The atomic unfortunately makes this a "complex" class on some compilers
|
| // and thus requires an out-of-line constructor & destructor even though
|
| @@ -845,6 +976,7 @@ class BASE_EXPORT GlobalActivityTracker {
|
| ModuleInfoRecord();
|
| ~ModuleInfoRecord();
|
|
|
| + ProcessInfo process_info; // The process that created this record.
|
| uint64_t address; // The base address of the module.
|
| uint64_t load_time; // Time of last load/unload.
|
| uint64_t size; // The size of the module in bytes.
|
| @@ -908,6 +1040,11 @@ class BASE_EXPORT GlobalActivityTracker {
|
| // be tracked. |value| is a pointer to a ManagedActivityTracker.
|
| static void OnTLSDestroy(void* value);
|
|
|
| + // Does process-exit work. This can be run on any thread.
|
| + void CleanupAfterProcess(ProcessId process_id,
|
| + int64_t exit_stamp,
|
| + int exit_code);
|
| +
|
| // The persistent-memory allocator from which the memory for all trackers
|
| // is taken.
|
| std::unique_ptr<PersistentMemoryAllocator> allocator_;
|
| @@ -930,9 +1067,9 @@ class BASE_EXPORT GlobalActivityTracker {
|
| ActivityTrackerMemoryAllocator user_data_allocator_;
|
| base::Lock user_data_allocator_lock_;
|
|
|
| - // An object for holding global arbitrary key value pairs. Values must always
|
| - // be written from the main UI thread.
|
| - GlobalUserData global_data_;
|
| + // An object for holding arbitrary key value pairs with thread-safe access.
|
| + ThreadSafeUserData process_data_;
|
| + ThreadSafeUserData global_data_;
|
|
|
| // A map of global module information, keyed by module path.
|
| std::map<const std::string, ModuleInfoRecord*> modules_;
|
| @@ -941,6 +1078,21 @@ class BASE_EXPORT GlobalActivityTracker {
|
| // The active global activity tracker.
|
| static subtle::AtomicWord g_tracker_;
|
|
|
| + // A lock that is used to procect access to the following fields.
|
| + base::Lock global_tracker_lock_;
|
| +
|
| + // The collection of processes being tracked.
|
| + std::set<int64_t> known_processes_;
|
| +
|
| + // A task-runner that can be used for doing background processing.
|
| + scoped_refptr<TaskRunner> background_task_runner_;
|
| +
|
| + // A callback performed when a subprocess exits, including its exit-code
|
| + // and the phase it was in when that occurred. This will be called via
|
| + // the |background_task_runner_| if one is set or whatever thread reaped
|
| + // the process otherwise.
|
| + ProcessExitCallback process_exit_callback_;
|
| +
|
| DISALLOW_COPY_AND_ASSIGN(GlobalActivityTracker);
|
| };
|
|
|
|
|