| Index: base/debug/activity_tracker.h
|
| diff --git a/base/debug/activity_tracker.h b/base/debug/activity_tracker.h
|
| index 719a31865ca76ad1def768204a022400e16c3f2f..922528fb38702fdd023eeec906bba6fb8d7cb22c 100644
|
| --- a/base/debug/activity_tracker.h
|
| +++ b/base/debug/activity_tracker.h
|
| @@ -23,12 +23,15 @@
|
|
|
| #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 +44,6 @@ class FilePath;
|
| class Lock;
|
| class PlatformThreadHandle;
|
| class Process;
|
| -class StaticAtomicSequenceNumber;
|
| class WaitableEvent;
|
|
|
| namespace debug {
|
| @@ -56,6 +58,39 @@ enum : int {
|
| kActivityCallStackSize = 10,
|
| };
|
|
|
| +// A class for keeping all information needed to verify that a structure is
|
| +// associated with a given process.
|
| +struct OwningProcess {
|
| + OwningProcess();
|
| + ~OwningProcess();
|
| +
|
| + // 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::OwningProcess): Increment this if structure changes!
|
| + static constexpr uint32_t kPersistentTypeId = 0xB1179672 + 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
|
| @@ -293,7 +328,9 @@ struct Activity {
|
| // This class manages arbitrary user data that can be associated with activities
|
| // done by a thread by supporting key/value pairs of any type. This can provide
|
| // additional information during debugging. It is also used to store arbitrary
|
| -// global data. All updates must be done from the same thread.
|
| +// global data. All updates must be done from the same thread though other
|
| +// threads can read it concurrently if they create new objects using the same
|
| +// memory.
|
| class BASE_EXPORT ActivityUserData {
|
| public:
|
| // List of known value type. REFERENCE types must immediately follow the non-
|
| @@ -355,7 +392,7 @@ 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_->owner.data_id.load(std::memory_order_relaxed) : 0;
|
| }
|
|
|
| // Writes a |value| (as part of a key/value pair) that will be included with
|
| @@ -409,7 +446,17 @@ class BASE_EXPORT ActivityUserData {
|
| bool CreateSnapshot(Snapshot* output_snapshot) const;
|
|
|
| // Gets the base memory address used for storing data.
|
| - const void* GetBaseAddress();
|
| + const void* GetBaseAddress() const;
|
| +
|
| + // 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,
|
| @@ -422,20 +469,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();
|
| +
|
| + OwningProcess owner; // 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 {
|
| @@ -470,12 +528,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);
|
| };
|
| @@ -618,6 +672,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);
|
| @@ -649,15 +716,45 @@ 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 are generic and may have meaning to the tracker.
|
| + PROCESS_PHASE_UNKNOWN = 0,
|
| + PROCESS_LAUNCHED = 1,
|
| + PROCESS_LAUNCH_FAILED = 2,
|
| + PROCESS_EXITED_CLEANLY = 10,
|
| + PROCESS_EXITED_WITH_CODE = 11,
|
| +
|
| + // Add here whatever is useful for analysis.
|
| + PROCESS_SHUTDOWN_STARTED = 100,
|
| + PROCESS_MAIN_LOOP_STARTED = 101,
|
| + };
|
| +
|
| + // 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 it's 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,
|
| + std::string&& command_line,
|
| + ActivityUserData::Snapshot&& process_data)>;
|
| +
|
| // This structure contains information about a loaded module, as shown to
|
| // users of the tracker.
|
| struct BASE_EXPORT ModuleInfo {
|
| @@ -789,6 +886,49 @@ 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. If it is expensive
|
| + // to generate the parameters, Get() the global tracker and call these
|
| + // conditionally rather than using the static versions.
|
| + void RecordProcessLaunch(ProcessId process_id,
|
| + const FilePath::StringType& cmd);
|
| + void RecordProcessLaunch(ProcessId process_id,
|
| + const FilePath::StringType& exe,
|
| + const FilePath::StringType& args);
|
| + void RecordProcessExit(ProcessId process_id, int exit_code);
|
| + static void RecordProcessLaunchIfEnabled(ProcessId process_id,
|
| + const FilePath::StringType& cmd) {
|
| + GlobalActivityTracker* tracker = Get();
|
| + if (tracker)
|
| + tracker->RecordProcessLaunch(process_id, cmd);
|
| + }
|
| + static void RecordProcessLaunchIfEnabled(ProcessId process_id,
|
| + const FilePath::StringType& exe,
|
| + const FilePath::StringType& args) {
|
| + GlobalActivityTracker* tracker = Get();
|
| + if (tracker)
|
| + tracker->RecordProcessLaunch(process_id, exe, args);
|
| + }
|
| + 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);
|
| @@ -818,7 +958,12 @@ class BASE_EXPORT GlobalActivityTracker {
|
| tracker->RecordFieldTrial(trial_name, 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:
|
| @@ -837,10 +982,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,
|
| @@ -850,7 +995,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
|
| @@ -862,7 +1007,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 =
|
| + OwningProcess::kExpectedInstanceSize + 56;
|
|
|
| // The atomic unfortunately makes this a "complex" class on some compilers
|
| // and thus requires an out-of-line constructor & destructor even though
|
| @@ -870,6 +1016,7 @@ class BASE_EXPORT GlobalActivityTracker {
|
| ModuleInfoRecord();
|
| ~ModuleInfoRecord();
|
|
|
| + OwningProcess owner; // 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.
|
| @@ -933,6 +1080,12 @@ 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,
|
| + std::string&& command_line);
|
| +
|
| // The persistent-memory allocator from which the memory for all trackers
|
| // is taken.
|
| std::unique_ptr<PersistentMemoryAllocator> allocator_;
|
| @@ -955,9 +1108,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_;
|
| @@ -966,6 +1119,21 @@ class BASE_EXPORT GlobalActivityTracker {
|
| // The active global activity tracker.
|
| static subtle::AtomicWord g_tracker_;
|
|
|
| + // A lock that is used to protect access to the following fields.
|
| + base::Lock global_tracker_lock_;
|
| +
|
| + // The collection of processes being tracked and their command-lines.
|
| + std::map<int64_t, std::string> 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);
|
| };
|
|
|
|
|