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