• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/debug/activity_tracker.h"
6 
7 #include <memory>
8 
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/files/file.h"
12 #include "base/files/file_util.h"
13 #include "base/files/memory_mapped_file.h"
14 #include "base/files/scoped_temp_dir.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/pending_task.h"
17 #include "base/rand_util.h"
18 #include "base/synchronization/condition_variable.h"
19 #include "base/synchronization/lock.h"
20 #include "base/synchronization/spin_wait.h"
21 #include "base/threading/platform_thread.h"
22 #include "base/threading/simple_thread.h"
23 #include "base/time/time.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 
26 namespace base {
27 namespace debug {
28 
29 namespace {
30 
31 class TestActivityTracker : public ThreadActivityTracker {
32  public:
TestActivityTracker(std::unique_ptr<char[]> memory,size_t mem_size)33   TestActivityTracker(std::unique_ptr<char[]> memory, size_t mem_size)
34       : ThreadActivityTracker(memset(memory.get(), 0, mem_size), mem_size),
35         mem_segment_(std::move(memory)) {}
36 
37   ~TestActivityTracker() override = default;
38 
39  private:
40   std::unique_ptr<char[]> mem_segment_;
41 };
42 
43 }  // namespace
44 
45 
46 class ActivityTrackerTest : public testing::Test {
47  public:
48   const int kMemorySize = 1 << 20;  // 1MiB
49   const int kStackSize  = 1 << 10;  // 1KiB
50 
51   using ActivityId = ThreadActivityTracker::ActivityId;
52 
53   ActivityTrackerTest() = default;
54 
~ActivityTrackerTest()55   ~ActivityTrackerTest() override {
56     GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
57     if (global_tracker) {
58       global_tracker->ReleaseTrackerForCurrentThreadForTesting();
59       delete global_tracker;
60     }
61   }
62 
CreateActivityTracker()63   std::unique_ptr<ThreadActivityTracker> CreateActivityTracker() {
64     std::unique_ptr<char[]> memory(new char[kStackSize]);
65     return std::make_unique<TestActivityTracker>(std::move(memory), kStackSize);
66   }
67 
GetGlobalActiveTrackerCount()68   size_t GetGlobalActiveTrackerCount() {
69     GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
70     if (!global_tracker)
71       return 0;
72     return global_tracker->thread_tracker_count_.load(
73         std::memory_order_relaxed);
74   }
75 
GetGlobalInactiveTrackerCount()76   size_t GetGlobalInactiveTrackerCount() {
77     GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
78     if (!global_tracker)
79       return 0;
80     AutoLock autolock(global_tracker->thread_tracker_allocator_lock_);
81     return global_tracker->thread_tracker_allocator_.cache_used();
82   }
83 
GetGlobalUserDataMemoryCacheUsed()84   size_t GetGlobalUserDataMemoryCacheUsed() {
85     return GlobalActivityTracker::Get()->user_data_allocator_.cache_used();
86   }
87 
HandleProcessExit(int64_t id,int64_t stamp,int code,GlobalActivityTracker::ProcessPhase phase,std::string && command,ActivityUserData::Snapshot && data)88   void HandleProcessExit(int64_t id,
89                          int64_t stamp,
90                          int code,
91                          GlobalActivityTracker::ProcessPhase phase,
92                          std::string&& command,
93                          ActivityUserData::Snapshot&& data) {
94     exit_id_ = id;
95     exit_stamp_ = stamp;
96     exit_code_ = code;
97     exit_phase_ = phase;
98     exit_command_ = std::move(command);
99     exit_data_ = std::move(data);
100   }
101 
102   int64_t exit_id_ = 0;
103   int64_t exit_stamp_;
104   int exit_code_;
105   GlobalActivityTracker::ProcessPhase exit_phase_;
106   std::string exit_command_;
107   ActivityUserData::Snapshot exit_data_;
108 };
109 
TEST_F(ActivityTrackerTest,UserDataTest)110 TEST_F(ActivityTrackerTest, UserDataTest) {
111   char buffer[256];
112   memset(buffer, 0, sizeof(buffer));
113   ActivityUserData data(buffer, sizeof(buffer));
114   size_t space = sizeof(buffer) - sizeof(ActivityUserData::MemoryHeader);
115   ASSERT_EQ(space, data.available_);
116 
117   data.SetInt("foo", 1);
118   space -= 24;
119   ASSERT_EQ(space, data.available_);
120 
121   data.SetUint("b", 1U);  // Small names fit beside header in a word.
122   space -= 16;
123   ASSERT_EQ(space, data.available_);
124 
125   data.Set("c", buffer, 10);
126   space -= 24;
127   ASSERT_EQ(space, data.available_);
128 
129   data.SetString("dear john", "it's been fun");
130   space -= 32;
131   ASSERT_EQ(space, data.available_);
132 
133   data.Set("c", buffer, 20);
134   ASSERT_EQ(space, data.available_);
135 
136   data.SetString("dear john", "but we're done together");
137   ASSERT_EQ(space, data.available_);
138 
139   data.SetString("dear john", "bye");
140   ASSERT_EQ(space, data.available_);
141 
142   data.SetChar("d", 'x');
143   space -= 8;
144   ASSERT_EQ(space, data.available_);
145 
146   data.SetBool("ee", true);
147   space -= 16;
148   ASSERT_EQ(space, data.available_);
149 
150   data.SetString("f", "");
151   space -= 8;
152   ASSERT_EQ(space, data.available_);
153 }
154 
TEST_F(ActivityTrackerTest,PushPopTest)155 TEST_F(ActivityTrackerTest, PushPopTest) {
156   std::unique_ptr<ThreadActivityTracker> tracker = CreateActivityTracker();
157   ThreadActivityTracker::Snapshot snapshot;
158 
159   ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
160   ASSERT_EQ(0U, snapshot.activity_stack_depth);
161   ASSERT_EQ(0U, snapshot.activity_stack.size());
162 
163   char origin1;
164   ActivityId id1 = tracker->PushActivity(&origin1, Activity::ACT_TASK,
165                                          ActivityData::ForTask(11));
166   ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
167   ASSERT_EQ(1U, snapshot.activity_stack_depth);
168   ASSERT_EQ(1U, snapshot.activity_stack.size());
169   EXPECT_NE(0, snapshot.activity_stack[0].time_internal);
170   EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[0].activity_type);
171   EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin1),
172             snapshot.activity_stack[0].origin_address);
173   EXPECT_EQ(11U, snapshot.activity_stack[0].data.task.sequence_id);
174 
175   char origin2;
176   char lock2;
177   ActivityId id2 = tracker->PushActivity(&origin2, Activity::ACT_LOCK,
178                                          ActivityData::ForLock(&lock2));
179   ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
180   ASSERT_EQ(2U, snapshot.activity_stack_depth);
181   ASSERT_EQ(2U, snapshot.activity_stack.size());
182   EXPECT_LE(snapshot.activity_stack[0].time_internal,
183             snapshot.activity_stack[1].time_internal);
184   EXPECT_EQ(Activity::ACT_LOCK, snapshot.activity_stack[1].activity_type);
185   EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin2),
186             snapshot.activity_stack[1].origin_address);
187   EXPECT_EQ(reinterpret_cast<uintptr_t>(&lock2),
188             snapshot.activity_stack[1].data.lock.lock_address);
189 
190   tracker->PopActivity(id2);
191   ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
192   ASSERT_EQ(1U, snapshot.activity_stack_depth);
193   ASSERT_EQ(1U, snapshot.activity_stack.size());
194   EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[0].activity_type);
195   EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin1),
196             snapshot.activity_stack[0].origin_address);
197   EXPECT_EQ(11U, snapshot.activity_stack[0].data.task.sequence_id);
198 
199   tracker->PopActivity(id1);
200   ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
201   ASSERT_EQ(0U, snapshot.activity_stack_depth);
202   ASSERT_EQ(0U, snapshot.activity_stack.size());
203 }
204 
TEST_F(ActivityTrackerTest,ScopedTaskTest)205 TEST_F(ActivityTrackerTest, ScopedTaskTest) {
206   GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
207 
208   ThreadActivityTracker* tracker =
209       GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
210   ThreadActivityTracker::Snapshot snapshot;
211   ASSERT_EQ(0U, GetGlobalUserDataMemoryCacheUsed());
212 
213   ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
214   ASSERT_EQ(0U, snapshot.activity_stack_depth);
215   ASSERT_EQ(0U, snapshot.activity_stack.size());
216 
217   {
218     PendingTask task1(FROM_HERE, DoNothing());
219     ScopedTaskRunActivity activity1(task1);
220     ActivityUserData& user_data1 = activity1.user_data();
221     (void)user_data1;  // Tell compiler it's been used.
222 
223     ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
224     ASSERT_EQ(1U, snapshot.activity_stack_depth);
225     ASSERT_EQ(1U, snapshot.activity_stack.size());
226     EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[0].activity_type);
227 
228     {
229       PendingTask task2(FROM_HERE, DoNothing());
230       ScopedTaskRunActivity activity2(task2);
231       ActivityUserData& user_data2 = activity2.user_data();
232       (void)user_data2;  // Tell compiler it's been used.
233 
234       ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
235       ASSERT_EQ(2U, snapshot.activity_stack_depth);
236       ASSERT_EQ(2U, snapshot.activity_stack.size());
237       EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[1].activity_type);
238     }
239 
240     ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
241     ASSERT_EQ(1U, snapshot.activity_stack_depth);
242     ASSERT_EQ(1U, snapshot.activity_stack.size());
243     EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[0].activity_type);
244   }
245 
246   ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
247   ASSERT_EQ(0U, snapshot.activity_stack_depth);
248   ASSERT_EQ(0U, snapshot.activity_stack.size());
249   ASSERT_EQ(2U, GetGlobalUserDataMemoryCacheUsed());
250 }
251 
252 namespace {
253 
254 class SimpleLockThread : public SimpleThread {
255  public:
SimpleLockThread(const std::string & name,Lock * lock)256   SimpleLockThread(const std::string& name, Lock* lock)
257       : SimpleThread(name, Options()),
258         lock_(lock),
259         data_changed_(false),
260         is_running_(false) {}
261 
262   ~SimpleLockThread() override = default;
263 
Run()264   void Run() override {
265     ThreadActivityTracker* tracker =
266         GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
267     uint32_t pre_version = tracker->GetDataVersionForTesting();
268 
269     is_running_.store(true, std::memory_order_relaxed);
270     lock_->Acquire();
271     data_changed_ = tracker->GetDataVersionForTesting() != pre_version;
272     lock_->Release();
273     is_running_.store(false, std::memory_order_relaxed);
274   }
275 
IsRunning()276   bool IsRunning() { return is_running_.load(std::memory_order_relaxed); }
277 
WasDataChanged()278   bool WasDataChanged() { return data_changed_; };
279 
280  private:
281   Lock* lock_;
282   bool data_changed_;
283   std::atomic<bool> is_running_;
284 
285   DISALLOW_COPY_AND_ASSIGN(SimpleLockThread);
286 };
287 
288 }  // namespace
289 
TEST_F(ActivityTrackerTest,LockTest)290 TEST_F(ActivityTrackerTest, LockTest) {
291   GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
292 
293   ThreadActivityTracker* tracker =
294       GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
295   ThreadActivityTracker::Snapshot snapshot;
296   ASSERT_EQ(0U, GetGlobalUserDataMemoryCacheUsed());
297 
298   Lock lock;
299   uint32_t pre_version = tracker->GetDataVersionForTesting();
300 
301   // Check no activity when only "trying" a lock.
302   EXPECT_TRUE(lock.Try());
303   EXPECT_EQ(pre_version, tracker->GetDataVersionForTesting());
304   lock.Release();
305   EXPECT_EQ(pre_version, tracker->GetDataVersionForTesting());
306 
307   // Check no activity when acquiring a free lock.
308   SimpleLockThread t1("locker1", &lock);
309   t1.Start();
310   t1.Join();
311   EXPECT_FALSE(t1.WasDataChanged());
312 
313   // Check that activity is recorded when acquring a busy lock.
314   SimpleLockThread t2("locker2", &lock);
315   lock.Acquire();
316   t2.Start();
317   while (!t2.IsRunning())
318     PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
319   // t2 can't join until the lock is released but have to give time for t2 to
320   // actually block on the lock before releasing it or the results will not
321   // be correct.
322   PlatformThread::Sleep(TimeDelta::FromMilliseconds(200));
323   lock.Release();
324   // Now the results will be valid.
325   t2.Join();
326   EXPECT_TRUE(t2.WasDataChanged());
327 }
328 
TEST_F(ActivityTrackerTest,ExceptionTest)329 TEST_F(ActivityTrackerTest, ExceptionTest) {
330   GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
331   GlobalActivityTracker* global = GlobalActivityTracker::Get();
332 
333   ThreadActivityTracker* tracker =
334       GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
335   ThreadActivityTracker::Snapshot snapshot;
336   ASSERT_EQ(0U, GetGlobalUserDataMemoryCacheUsed());
337 
338   ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
339   ASSERT_EQ(0U, snapshot.last_exception.activity_type);
340 
341   char origin;
342   global->RecordException(&origin, 42);
343 
344   ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
345   EXPECT_EQ(Activity::ACT_EXCEPTION, snapshot.last_exception.activity_type);
346   EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin),
347             snapshot.last_exception.origin_address);
348   EXPECT_EQ(42U, snapshot.last_exception.data.exception.code);
349 }
350 
TEST_F(ActivityTrackerTest,CreateWithFileTest)351 TEST_F(ActivityTrackerTest, CreateWithFileTest) {
352   const char temp_name[] = "CreateWithFileTest";
353   ScopedTempDir temp_dir;
354   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
355   FilePath temp_file = temp_dir.GetPath().AppendASCII(temp_name);
356   const size_t temp_size = 64 << 10;  // 64 KiB
357 
358   // Create a global tracker on a new file.
359   ASSERT_FALSE(PathExists(temp_file));
360   GlobalActivityTracker::CreateWithFile(temp_file, temp_size, 0, "foo", 3);
361   GlobalActivityTracker* global = GlobalActivityTracker::Get();
362   EXPECT_EQ(std::string("foo"), global->allocator()->Name());
363   global->ReleaseTrackerForCurrentThreadForTesting();
364   delete global;
365 
366   // Create a global tracker over an existing file, replacing it. If the
367   // replacement doesn't work, the name will remain as it was first created.
368   ASSERT_TRUE(PathExists(temp_file));
369   GlobalActivityTracker::CreateWithFile(temp_file, temp_size, 0, "bar", 3);
370   global = GlobalActivityTracker::Get();
371   EXPECT_EQ(std::string("bar"), global->allocator()->Name());
372   global->ReleaseTrackerForCurrentThreadForTesting();
373   delete global;
374 }
375 
376 
377 // GlobalActivityTracker tests below.
378 
TEST_F(ActivityTrackerTest,BasicTest)379 TEST_F(ActivityTrackerTest, BasicTest) {
380   GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
381   GlobalActivityTracker* global = GlobalActivityTracker::Get();
382 
383   // Ensure the data repositories have backing store, indicated by non-zero ID.
384   EXPECT_NE(0U, global->process_data().id());
385 }
386 
387 namespace {
388 
389 class SimpleActivityThread : public SimpleThread {
390  public:
SimpleActivityThread(const std::string & name,const void * origin,Activity::Type activity,const ActivityData & data)391   SimpleActivityThread(const std::string& name,
392                        const void* origin,
393                        Activity::Type activity,
394                        const ActivityData& data)
395       : SimpleThread(name, Options()),
396         origin_(origin),
397         activity_(activity),
398         data_(data),
399         ready_(false),
400         exit_(false),
401         exit_condition_(&lock_) {}
402 
403   ~SimpleActivityThread() override = default;
404 
Run()405   void Run() override {
406     ThreadActivityTracker::ActivityId id =
407         GlobalActivityTracker::Get()
408             ->GetOrCreateTrackerForCurrentThread()
409             ->PushActivity(origin_, activity_, data_);
410 
411     {
412       AutoLock auto_lock(lock_);
413       ready_.store(true, std::memory_order_release);
414       while (!exit_.load(std::memory_order_relaxed))
415         exit_condition_.Wait();
416     }
417 
418     GlobalActivityTracker::Get()->GetTrackerForCurrentThread()->PopActivity(id);
419   }
420 
Exit()421   void Exit() {
422     AutoLock auto_lock(lock_);
423     exit_.store(true, std::memory_order_relaxed);
424     exit_condition_.Signal();
425   }
426 
WaitReady()427   void WaitReady() {
428     SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(ready_.load(std::memory_order_acquire));
429   }
430 
431  private:
432   const void* origin_;
433   Activity::Type activity_;
434   ActivityData data_;
435 
436   std::atomic<bool> ready_;
437   std::atomic<bool> exit_;
438   Lock lock_;
439   ConditionVariable exit_condition_;
440 
441   DISALLOW_COPY_AND_ASSIGN(SimpleActivityThread);
442 };
443 
444 }  // namespace
445 
TEST_F(ActivityTrackerTest,ThreadDeathTest)446 TEST_F(ActivityTrackerTest, ThreadDeathTest) {
447   GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
448   GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
449   const size_t starting_active = GetGlobalActiveTrackerCount();
450   const size_t starting_inactive = GetGlobalInactiveTrackerCount();
451 
452   SimpleActivityThread t1("t1", nullptr, Activity::ACT_TASK,
453                           ActivityData::ForTask(11));
454   t1.Start();
455   t1.WaitReady();
456   EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount());
457   EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount());
458 
459   t1.Exit();
460   t1.Join();
461   EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount());
462   EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount());
463 
464   // Start another thread and ensure it re-uses the existing memory.
465 
466   SimpleActivityThread t2("t2", nullptr, Activity::ACT_TASK,
467                           ActivityData::ForTask(22));
468   t2.Start();
469   t2.WaitReady();
470   EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount());
471   EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount());
472 
473   t2.Exit();
474   t2.Join();
475   EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount());
476   EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount());
477 }
478 
TEST_F(ActivityTrackerTest,ProcessDeathTest)479 TEST_F(ActivityTrackerTest, ProcessDeathTest) {
480   // This doesn't actually create and destroy a process. Instead, it uses for-
481   // testing interfaces to simulate data created by other processes.
482   const int64_t other_process_id = GetCurrentProcId() + 1;
483 
484   GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
485   GlobalActivityTracker* global = GlobalActivityTracker::Get();
486   ThreadActivityTracker* thread = global->GetOrCreateTrackerForCurrentThread();
487 
488   // Get callbacks for process exit.
489   global->SetProcessExitCallback(
490       Bind(&ActivityTrackerTest::HandleProcessExit, Unretained(this)));
491 
492   // Pretend than another process has started.
493   global->RecordProcessLaunch(other_process_id, FILE_PATH_LITERAL("foo --bar"));
494 
495   // Do some activities.
496   PendingTask task(FROM_HERE, DoNothing());
497   ScopedTaskRunActivity activity(task);
498   ActivityUserData& user_data = activity.user_data();
499   ASSERT_NE(0U, user_data.id());
500 
501   // Get the memory-allocator references to that data.
502   PersistentMemoryAllocator::Reference proc_data_ref =
503       global->allocator()->GetAsReference(
504           global->process_data().GetBaseAddress(),
505           GlobalActivityTracker::kTypeIdProcessDataRecord);
506   ASSERT_TRUE(proc_data_ref);
507   PersistentMemoryAllocator::Reference tracker_ref =
508       global->allocator()->GetAsReference(
509           thread->GetBaseAddress(),
510           GlobalActivityTracker::kTypeIdActivityTracker);
511   ASSERT_TRUE(tracker_ref);
512   PersistentMemoryAllocator::Reference user_data_ref =
513       global->allocator()->GetAsReference(
514           user_data.GetBaseAddress(),
515           GlobalActivityTracker::kTypeIdUserDataRecord);
516   ASSERT_TRUE(user_data_ref);
517 
518   // Make a copy of the thread-tracker state so it can be restored later.
519   const size_t tracker_size = global->allocator()->GetAllocSize(tracker_ref);
520   std::unique_ptr<char[]> tracker_copy(new char[tracker_size]);
521   memcpy(tracker_copy.get(), thread->GetBaseAddress(), tracker_size);
522 
523   // Change the objects to appear to be owned by another process. Use a "past"
524   // time so that exit-time is always later than create-time.
525   const int64_t past_stamp = Time::Now().ToInternalValue() - 1;
526   int64_t owning_id;
527   int64_t stamp;
528   ASSERT_TRUE(ActivityUserData::GetOwningProcessId(
529       global->process_data().GetBaseAddress(), &owning_id, &stamp));
530   EXPECT_NE(other_process_id, owning_id);
531   ASSERT_TRUE(ThreadActivityTracker::GetOwningProcessId(
532       thread->GetBaseAddress(), &owning_id, &stamp));
533   EXPECT_NE(other_process_id, owning_id);
534   ASSERT_TRUE(ActivityUserData::GetOwningProcessId(user_data.GetBaseAddress(),
535                                                    &owning_id, &stamp));
536   EXPECT_NE(other_process_id, owning_id);
537   global->process_data().SetOwningProcessIdForTesting(other_process_id,
538                                                       past_stamp);
539   thread->SetOwningProcessIdForTesting(other_process_id, past_stamp);
540   user_data.SetOwningProcessIdForTesting(other_process_id, past_stamp);
541   ASSERT_TRUE(ActivityUserData::GetOwningProcessId(
542       global->process_data().GetBaseAddress(), &owning_id, &stamp));
543   EXPECT_EQ(other_process_id, owning_id);
544   ASSERT_TRUE(ThreadActivityTracker::GetOwningProcessId(
545       thread->GetBaseAddress(), &owning_id, &stamp));
546   EXPECT_EQ(other_process_id, owning_id);
547   ASSERT_TRUE(ActivityUserData::GetOwningProcessId(user_data.GetBaseAddress(),
548                                                    &owning_id, &stamp));
549   EXPECT_EQ(other_process_id, owning_id);
550 
551   // Check that process exit will perform callback and free the allocations.
552   ASSERT_EQ(0, exit_id_);
553   ASSERT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecord,
554             global->allocator()->GetType(proc_data_ref));
555   ASSERT_EQ(GlobalActivityTracker::kTypeIdActivityTracker,
556             global->allocator()->GetType(tracker_ref));
557   ASSERT_EQ(GlobalActivityTracker::kTypeIdUserDataRecord,
558             global->allocator()->GetType(user_data_ref));
559   global->RecordProcessExit(other_process_id, 0);
560   EXPECT_EQ(other_process_id, exit_id_);
561   EXPECT_EQ("foo --bar", exit_command_);
562   EXPECT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecordFree,
563             global->allocator()->GetType(proc_data_ref));
564   EXPECT_EQ(GlobalActivityTracker::kTypeIdActivityTrackerFree,
565             global->allocator()->GetType(tracker_ref));
566   EXPECT_EQ(GlobalActivityTracker::kTypeIdUserDataRecordFree,
567             global->allocator()->GetType(user_data_ref));
568 
569   // Restore memory contents and types so things don't crash when doing real
570   // process clean-up.
571   memcpy(const_cast<void*>(thread->GetBaseAddress()), tracker_copy.get(),
572          tracker_size);
573   global->allocator()->ChangeType(
574       proc_data_ref, GlobalActivityTracker::kTypeIdProcessDataRecord,
575       GlobalActivityTracker::kTypeIdUserDataRecordFree, false);
576   global->allocator()->ChangeType(
577       tracker_ref, GlobalActivityTracker::kTypeIdActivityTracker,
578       GlobalActivityTracker::kTypeIdActivityTrackerFree, false);
579   global->allocator()->ChangeType(
580       user_data_ref, GlobalActivityTracker::kTypeIdUserDataRecord,
581       GlobalActivityTracker::kTypeIdUserDataRecordFree, false);
582 }
583 
584 }  // namespace debug
585 }  // namespace base
586