OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/debug/activity_tracker.h" | 5 #include "base/debug/activity_tracker.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/files/file.h" | 10 #include "base/files/file.h" |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
77 if (!global_tracker) | 77 if (!global_tracker) |
78 return 0; | 78 return 0; |
79 base::AutoLock autolock(global_tracker->thread_tracker_allocator_lock_); | 79 base::AutoLock autolock(global_tracker->thread_tracker_allocator_lock_); |
80 return global_tracker->thread_tracker_allocator_.cache_used(); | 80 return global_tracker->thread_tracker_allocator_.cache_used(); |
81 } | 81 } |
82 | 82 |
83 size_t GetGlobalUserDataMemoryCacheUsed() { | 83 size_t GetGlobalUserDataMemoryCacheUsed() { |
84 return GlobalActivityTracker::Get()->user_data_allocator_.cache_used(); | 84 return GlobalActivityTracker::Get()->user_data_allocator_.cache_used(); |
85 } | 85 } |
86 | 86 |
87 void HandleProcessExit(int64_t id, | |
88 int64_t stamp, | |
89 int code, | |
90 GlobalActivityTracker::ProcessPhase phase, | |
91 std::string&& command, | |
92 ActivityUserData::Snapshot&& data) { | |
93 exit_id = id; | |
94 exit_stamp = stamp; | |
95 exit_code = code; | |
96 exit_phase = phase; | |
97 exit_command = std::move(command); | |
98 exit_data = std::move(data); | |
99 } | |
100 | |
87 static void DoNothing() {} | 101 static void DoNothing() {} |
102 | |
103 int64_t exit_id = 0; | |
104 int64_t exit_stamp; | |
105 int exit_code; | |
106 GlobalActivityTracker::ProcessPhase exit_phase; | |
107 std::string exit_command; | |
108 ActivityUserData::Snapshot exit_data; | |
88 }; | 109 }; |
89 | 110 |
90 TEST_F(ActivityTrackerTest, UserDataTest) { | 111 TEST_F(ActivityTrackerTest, UserDataTest) { |
91 char buffer[256]; | 112 char buffer[256]; |
92 memset(buffer, 0, sizeof(buffer)); | 113 memset(buffer, 0, sizeof(buffer)); |
93 ActivityUserData data(buffer, sizeof(buffer)); | 114 ActivityUserData data(buffer, sizeof(buffer)); |
94 ASSERT_EQ(sizeof(buffer) - 8, data.available_); | 115 const size_t space = sizeof(buffer) - sizeof(ActivityUserData::MemoryHeader); |
116 ASSERT_EQ(space, data.available_); | |
95 | 117 |
96 data.SetInt("foo", 1); | 118 data.SetInt("foo", 1); |
97 ASSERT_EQ(sizeof(buffer) - 8 - 24, data.available_); | 119 ASSERT_EQ(space - 24, data.available_); |
manzagop (departed)
2017/03/06 21:48:41
Ah I meant you can:
space -= 24;
ASSERT_EQ(space,
| |
98 | 120 |
99 data.SetUint("b", 1U); // Small names fit beside header in a word. | 121 data.SetUint("b", 1U); // Small names fit beside header in a word. |
100 ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16, data.available_); | 122 ASSERT_EQ(space - 24 - 16, data.available_); |
101 | 123 |
102 data.Set("c", buffer, 10); | 124 data.Set("c", buffer, 10); |
103 ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24, data.available_); | 125 ASSERT_EQ(space - 24 - 16 - 24, data.available_); |
104 | 126 |
105 data.SetString("dear john", "it's been fun"); | 127 data.SetString("dear john", "it's been fun"); |
106 ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32, data.available_); | 128 ASSERT_EQ(space - 24 - 16 - 24 - 32, data.available_); |
107 | 129 |
108 data.Set("c", buffer, 20); | 130 data.Set("c", buffer, 20); |
109 ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32, data.available_); | 131 ASSERT_EQ(space - 24 - 16 - 24 - 32, data.available_); |
110 | 132 |
111 data.SetString("dear john", "but we're done together"); | 133 data.SetString("dear john", "but we're done together"); |
112 ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32, data.available_); | 134 ASSERT_EQ(space - 24 - 16 - 24 - 32, data.available_); |
113 | 135 |
114 data.SetString("dear john", "bye"); | 136 data.SetString("dear john", "bye"); |
115 ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32, data.available_); | 137 ASSERT_EQ(space - 24 - 16 - 24 - 32, data.available_); |
116 | 138 |
117 data.SetChar("d", 'x'); | 139 data.SetChar("d", 'x'); |
118 ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32 - 8, data.available_); | 140 ASSERT_EQ(space - 24 - 16 - 24 - 32 - 8, data.available_); |
119 | 141 |
120 data.SetBool("ee", true); | 142 data.SetBool("ee", true); |
121 ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32 - 8 - 16, data.available_); | 143 ASSERT_EQ(space - 24 - 16 - 24 - 32 - 8 - 16, data.available_); |
122 } | 144 } |
123 | 145 |
124 TEST_F(ActivityTrackerTest, PushPopTest) { | 146 TEST_F(ActivityTrackerTest, PushPopTest) { |
125 std::unique_ptr<ThreadActivityTracker> tracker = CreateActivityTracker(); | 147 std::unique_ptr<ThreadActivityTracker> tracker = CreateActivityTracker(); |
126 ThreadActivityTracker::Snapshot snapshot; | 148 ThreadActivityTracker::Snapshot snapshot; |
127 | 149 |
128 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); | 150 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); |
129 ASSERT_EQ(0U, snapshot.activity_stack_depth); | 151 ASSERT_EQ(0U, snapshot.activity_stack_depth); |
130 ASSERT_EQ(0U, snapshot.activity_stack.size()); | 152 ASSERT_EQ(0U, snapshot.activity_stack.size()); |
131 | 153 |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
239 GlobalActivityTracker::CreateWithFile(temp_file, temp_size, 0, "bar", 3); | 261 GlobalActivityTracker::CreateWithFile(temp_file, temp_size, 0, "bar", 3); |
240 global = GlobalActivityTracker::Get(); | 262 global = GlobalActivityTracker::Get(); |
241 EXPECT_EQ(std::string("bar"), global->allocator()->Name()); | 263 EXPECT_EQ(std::string("bar"), global->allocator()->Name()); |
242 global->ReleaseTrackerForCurrentThreadForTesting(); | 264 global->ReleaseTrackerForCurrentThreadForTesting(); |
243 delete global; | 265 delete global; |
244 } | 266 } |
245 | 267 |
246 | 268 |
247 // GlobalActivityTracker tests below. | 269 // GlobalActivityTracker tests below. |
248 | 270 |
271 TEST_F(ActivityTrackerTest, BasicTest) { | |
272 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3); | |
273 GlobalActivityTracker* global = GlobalActivityTracker::Get(); | |
274 | |
275 // Ensure the data repositories have backing store, indicated by non-zero ID. | |
276 EXPECT_NE(0U, global->process_data().id()); | |
277 EXPECT_NE(0U, global->global_data().id()); | |
278 EXPECT_NE(global->process_data().id(), global->global_data().id()); | |
279 } | |
280 | |
249 class SimpleActivityThread : public SimpleThread { | 281 class SimpleActivityThread : public SimpleThread { |
250 public: | 282 public: |
251 SimpleActivityThread(const std::string& name, | 283 SimpleActivityThread(const std::string& name, |
252 const void* origin, | 284 const void* origin, |
253 Activity::Type activity, | 285 Activity::Type activity, |
254 const ActivityData& data) | 286 const ActivityData& data) |
255 : SimpleThread(name, Options()), | 287 : SimpleThread(name, Options()), |
256 origin_(origin), | 288 origin_(origin), |
257 activity_(activity), | 289 activity_(activity), |
258 data_(data), | 290 data_(data), |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
325 t2.WaitReady(); | 357 t2.WaitReady(); |
326 EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount()); | 358 EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount()); |
327 EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount()); | 359 EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount()); |
328 | 360 |
329 t2.Exit(); | 361 t2.Exit(); |
330 t2.Join(); | 362 t2.Join(); |
331 EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount()); | 363 EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount()); |
332 EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount()); | 364 EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount()); |
333 } | 365 } |
334 | 366 |
367 TEST_F(ActivityTrackerTest, ProcessDeathTest) { | |
368 // This doesn't actually create and destroy a process. Instead, it uses for- | |
369 // testing interfaces to simulate data created by other processes. | |
370 const ProcessId other_process_id = GetCurrentProcId() + 1; | |
371 | |
372 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3); | |
373 GlobalActivityTracker* global = GlobalActivityTracker::Get(); | |
374 ThreadActivityTracker* thread = global->GetOrCreateTrackerForCurrentThread(); | |
375 | |
376 // Get callbacks for process exit. | |
377 global->SetProcessExitCallback( | |
378 Bind(&ActivityTrackerTest::HandleProcessExit, Unretained(this))); | |
379 | |
380 // Pretend than another process has started. | |
381 global->RecordProcessLaunch(other_process_id, FILE_PATH_LITERAL("foo --bar")); | |
382 | |
383 // Do some activities. | |
384 PendingTask task(FROM_HERE, base::Bind(&DoNothing)); | |
385 ScopedTaskRunActivity activity(task); | |
386 ActivityUserData& user_data = activity.user_data(); | |
387 ASSERT_NE(0U, user_data.id()); | |
388 | |
389 // Get the memory-allocator references to that data. | |
390 PersistentMemoryAllocator::Reference proc_data_ref = | |
391 global->allocator()->GetAsReference( | |
392 global->process_data().GetBaseAddress(), | |
393 GlobalActivityTracker::kTypeIdProcessDataRecord); | |
394 ASSERT_TRUE(proc_data_ref); | |
395 PersistentMemoryAllocator::Reference tracker_ref = | |
396 global->allocator()->GetAsReference( | |
397 thread->GetBaseAddress(), | |
398 GlobalActivityTracker::kTypeIdActivityTracker); | |
399 ASSERT_TRUE(tracker_ref); | |
400 PersistentMemoryAllocator::Reference user_data_ref = | |
401 global->allocator()->GetAsReference( | |
402 user_data.GetBaseAddress(), | |
403 GlobalActivityTracker::kTypeIdUserDataRecord); | |
404 ASSERT_TRUE(user_data_ref); | |
405 | |
406 // Make a copy of the thread-tracker state so it can be restored later. | |
407 const size_t tracker_size = global->allocator()->GetAllocSize(tracker_ref); | |
408 std::unique_ptr<char[]> tracker_copy(new char[tracker_size]); | |
409 memcpy(tracker_copy.get(), thread->GetBaseAddress(), tracker_size); | |
410 | |
411 // Change the objects to appear to be owned by another process. | |
412 ProcessId owning_id; | |
413 int64_t stamp; | |
414 ASSERT_TRUE(ActivityUserData::GetOwningProcessId( | |
415 global->process_data().GetBaseAddress(), &owning_id, &stamp)); | |
416 EXPECT_NE(other_process_id, owning_id); | |
417 ASSERT_TRUE(ThreadActivityTracker::GetOwningProcessId( | |
418 thread->GetBaseAddress(), &owning_id, &stamp)); | |
419 EXPECT_NE(other_process_id, owning_id); | |
420 ASSERT_TRUE(ActivityUserData::GetOwningProcessId(user_data.GetBaseAddress(), | |
421 &owning_id, &stamp)); | |
422 EXPECT_NE(other_process_id, owning_id); | |
423 global->process_data().SetOwningProcessIdForTesting(other_process_id, stamp); | |
424 thread->SetOwningProcessIdForTesting(other_process_id, stamp); | |
425 user_data.SetOwningProcessIdForTesting(other_process_id, stamp); | |
426 ASSERT_TRUE(ActivityUserData::GetOwningProcessId( | |
427 global->process_data().GetBaseAddress(), &owning_id, &stamp)); | |
428 EXPECT_EQ(other_process_id, owning_id); | |
429 ASSERT_TRUE(ThreadActivityTracker::GetOwningProcessId( | |
430 thread->GetBaseAddress(), &owning_id, &stamp)); | |
431 EXPECT_EQ(other_process_id, owning_id); | |
432 ASSERT_TRUE(ActivityUserData::GetOwningProcessId(user_data.GetBaseAddress(), | |
433 &owning_id, &stamp)); | |
434 EXPECT_EQ(other_process_id, owning_id); | |
435 | |
436 // Check that process exit will perform callback and free the allocations. | |
437 ASSERT_EQ(0, exit_id); | |
438 ASSERT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecord, | |
439 global->allocator()->GetType(proc_data_ref)); | |
440 ASSERT_EQ(GlobalActivityTracker::kTypeIdActivityTracker, | |
441 global->allocator()->GetType(tracker_ref)); | |
442 ASSERT_EQ(GlobalActivityTracker::kTypeIdUserDataRecord, | |
443 global->allocator()->GetType(user_data_ref)); | |
444 global->RecordProcessExit(other_process_id, 0); | |
445 EXPECT_EQ(other_process_id, exit_id); | |
446 EXPECT_EQ("foo --bar", exit_command); | |
447 EXPECT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecordFree, | |
448 global->allocator()->GetType(proc_data_ref)); | |
449 EXPECT_EQ(GlobalActivityTracker::kTypeIdActivityTrackerFree, | |
450 global->allocator()->GetType(tracker_ref)); | |
451 EXPECT_EQ(GlobalActivityTracker::kTypeIdUserDataRecordFree, | |
452 global->allocator()->GetType(user_data_ref)); | |
453 | |
454 // Restore memory contents and types so things don't crash when doing real | |
455 // process clean-up. | |
456 memcpy(const_cast<void*>(thread->GetBaseAddress()), tracker_copy.get(), | |
457 tracker_size); | |
458 global->allocator()->ChangeType( | |
459 proc_data_ref, GlobalActivityTracker::kTypeIdProcessDataRecord, | |
460 GlobalActivityTracker::kTypeIdUserDataRecordFree, false); | |
461 global->allocator()->ChangeType( | |
462 tracker_ref, GlobalActivityTracker::kTypeIdActivityTracker, | |
463 GlobalActivityTracker::kTypeIdActivityTrackerFree, false); | |
464 global->allocator()->ChangeType( | |
465 user_data_ref, GlobalActivityTracker::kTypeIdUserDataRecord, | |
466 GlobalActivityTracker::kTypeIdUserDataRecordFree, false); | |
467 } | |
468 | |
335 } // namespace debug | 469 } // namespace debug |
336 } // namespace base | 470 } // namespace base |
OLD | NEW |