activity_report_extractor_unittest.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. // Copyright 2017 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. #include "components/browser_watcher/activity_report_extractor.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "base/containers/contains.h"
  8. #include "base/debug/activity_analyzer.h"
  9. #include "base/debug/activity_tracker.h"
  10. #include "base/files/file.h"
  11. #include "base/files/file_path.h"
  12. #include "base/files/memory_mapped_file.h"
  13. #include "base/files/scoped_temp_dir.h"
  14. #include "base/metrics/persistent_memory_allocator.h"
  15. #include "base/threading/platform_thread.h"
  16. #include "base/time/time.h"
  17. #include "build/build_config.h"
  18. #include "testing/gtest/include/gtest/gtest.h"
  19. #include "third_party/crashpad/crashpad/client/crash_report_database.h"
  20. namespace browser_watcher {
  21. using base::File;
  22. using base::FilePath;
  23. using base::FilePersistentMemoryAllocator;
  24. using base::MemoryMappedFile;
  25. using base::PersistentMemoryAllocator;
  26. using base::debug::ActivityData;
  27. using base::debug::ActivityTrackerMemoryAllocator;
  28. using base::debug::ActivityUserData;
  29. using base::debug::GlobalActivityAnalyzer;
  30. using base::debug::GlobalActivityTracker;
  31. using base::debug::ThreadActivityTracker;
  32. namespace {
  33. // The tracker creates some data entries internally.
  34. const size_t kInternalProcessDatums = 1;
  35. // Parameters for the activity tracking.
  36. const size_t kFileSize = 64 << 10; // 64 KiB
  37. const int kStackDepth = 6;
  38. const uint64_t kAllocatorId = 0;
  39. const char kAllocatorName[] = "PostmortemReportCollectorCollectionTest";
  40. const uint64_t kTaskSequenceNum = 42;
  41. const uintptr_t kTaskOrigin = 1000U;
  42. const uintptr_t kLockAddress = 1001U;
  43. const uintptr_t kEventAddress = 1002U;
  44. const int kThreadId = 43;
  45. const int kProcessId = 44;
  46. const int kAnotherThreadId = 45;
  47. const uint32_t kGenericId = 46U;
  48. const int32_t kGenericData = 47;
  49. } // namespace
  50. // Sets up a file backed thread tracker for direct access. A
  51. // GlobalActivityTracker is not created, meaning there is no risk of
  52. // the instrumentation interfering with the file's content.
  53. class StabilityReportExtractorThreadTrackerTest : public testing::Test {
  54. public:
  55. // Create a proper debug file.
  56. void SetUp() override {
  57. testing::Test::SetUp();
  58. // Create a file backed allocator.
  59. ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
  60. debug_file_path_ = temp_dir_.GetPath().AppendASCII("debug_file.pma");
  61. allocator_ = CreateAllocator();
  62. ASSERT_NE(nullptr, allocator_);
  63. size_t tracker_mem_size =
  64. ThreadActivityTracker::SizeForStackDepth(kStackDepth);
  65. ASSERT_GT(kFileSize, tracker_mem_size);
  66. // Create a tracker.
  67. tracker_ = CreateTracker(allocator_.get(), tracker_mem_size);
  68. ASSERT_NE(nullptr, tracker_);
  69. ASSERT_TRUE(tracker_->IsValid());
  70. }
  71. std::unique_ptr<PersistentMemoryAllocator> CreateAllocator() {
  72. // Create the memory mapped file.
  73. std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
  74. bool success = mmfile->Initialize(
  75. File(debug_file_path_, File::FLAG_CREATE | File::FLAG_READ |
  76. File::FLAG_WRITE |
  77. File::FLAG_WIN_SHARE_DELETE),
  78. {0, static_cast<int64_t>(kFileSize)},
  79. MemoryMappedFile::READ_WRITE_EXTEND);
  80. if (!success || !mmfile->IsValid())
  81. return nullptr;
  82. // Create a persistent memory allocator.
  83. if (!FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true))
  84. return nullptr;
  85. return std::make_unique<FilePersistentMemoryAllocator>(
  86. std::move(mmfile), kFileSize, kAllocatorId, kAllocatorName, false);
  87. }
  88. std::unique_ptr<ThreadActivityTracker> CreateTracker(
  89. PersistentMemoryAllocator* allocator,
  90. size_t tracker_mem_size) {
  91. // Allocate a block of memory for the tracker to use.
  92. PersistentMemoryAllocator::Reference mem_reference = allocator->Allocate(
  93. tracker_mem_size, GlobalActivityTracker::kTypeIdActivityTracker);
  94. if (mem_reference == 0U)
  95. return nullptr;
  96. // Get the memory's base address.
  97. void* mem_base = allocator->GetAsArray<char>(
  98. mem_reference, GlobalActivityTracker::kTypeIdActivityTracker,
  99. PersistentMemoryAllocator::kSizeAny);
  100. if (mem_base == nullptr)
  101. return nullptr;
  102. // Make the allocation iterable so it can be found by other processes.
  103. allocator->MakeIterable(mem_reference);
  104. return std::make_unique<ThreadActivityTracker>(mem_base, tracker_mem_size);
  105. }
  106. void PerformBasicReportValidation(const StabilityReport& report) {
  107. // One report with one thread that has the expected name and id.
  108. ASSERT_EQ(1, report.process_states_size());
  109. const ProcessState& process_state = report.process_states(0);
  110. EXPECT_EQ(base::GetCurrentProcId(), process_state.process_id());
  111. ASSERT_EQ(1, process_state.threads_size());
  112. const ThreadState& thread_state = process_state.threads(0);
  113. EXPECT_EQ(base::PlatformThread::GetName(), thread_state.thread_name());
  114. #if BUILDFLAG(IS_WIN)
  115. EXPECT_EQ(base::PlatformThread::CurrentId(), thread_state.thread_id());
  116. #elif BUILDFLAG(IS_POSIX)
  117. EXPECT_EQ(base::PlatformThread::CurrentHandle().platform_handle(),
  118. thread_state.thread_id());
  119. #endif
  120. }
  121. std::unique_ptr<GlobalActivityAnalyzer> CreateAnalyzer() {
  122. return GlobalActivityAnalyzer::CreateWithFile(debug_file_path());
  123. }
  124. private:
  125. const FilePath& debug_file_path() const { return debug_file_path_; }
  126. protected:
  127. base::ScopedTempDir temp_dir_;
  128. FilePath debug_file_path_;
  129. std::unique_ptr<PersistentMemoryAllocator> allocator_;
  130. std::unique_ptr<ThreadActivityTracker> tracker_;
  131. };
  132. TEST_F(StabilityReportExtractorThreadTrackerTest, CollectSuccess) {
  133. // Create some activity data.
  134. tracker_->PushActivity(reinterpret_cast<void*>(kTaskOrigin),
  135. base::debug::Activity::ACT_TASK_RUN,
  136. ActivityData::ForTask(kTaskSequenceNum));
  137. tracker_->PushActivity(
  138. nullptr, base::debug::Activity::ACT_LOCK_ACQUIRE,
  139. ActivityData::ForLock(reinterpret_cast<void*>(kLockAddress)));
  140. ThreadActivityTracker::ActivityId activity_id = tracker_->PushActivity(
  141. nullptr, base::debug::Activity::ACT_EVENT_WAIT,
  142. ActivityData::ForEvent(reinterpret_cast<void*>(kEventAddress)));
  143. tracker_->PushActivity(nullptr, base::debug::Activity::ACT_THREAD_JOIN,
  144. ActivityData::ForThread(kThreadId));
  145. tracker_->PushActivity(nullptr, base::debug::Activity::ACT_PROCESS_WAIT,
  146. ActivityData::ForProcess(kProcessId));
  147. tracker_->PushActivity(nullptr, base::debug::Activity::ACT_GENERIC,
  148. ActivityData::ForGeneric(kGenericId, kGenericData));
  149. // Note: this exceeds the activity stack's capacity.
  150. tracker_->PushActivity(nullptr, base::debug::Activity::ACT_THREAD_JOIN,
  151. ActivityData::ForThread(kAnotherThreadId));
  152. // Add some user data.
  153. ActivityTrackerMemoryAllocator user_data_allocator(
  154. allocator_.get(), GlobalActivityTracker::kTypeIdUserDataRecord,
  155. GlobalActivityTracker::kTypeIdUserDataRecordFree, 1024U, 10U, false);
  156. std::unique_ptr<ActivityUserData> user_data =
  157. tracker_->GetUserData(activity_id, &user_data_allocator);
  158. user_data->SetInt("some_int", 42);
  159. // Validate collection returns the expected report.
  160. StabilityReport report;
  161. ASSERT_EQ(SUCCESS, Extract(CreateAnalyzer(), &report));
  162. // Validate the report.
  163. ASSERT_NO_FATAL_FAILURE(PerformBasicReportValidation(report));
  164. const ThreadState& thread_state = report.process_states(0).threads(0);
  165. EXPECT_EQ(7, thread_state.activity_count());
  166. ASSERT_EQ(6, thread_state.activities_size());
  167. {
  168. const Activity& activity = thread_state.activities(0);
  169. EXPECT_EQ(Activity::ACT_TASK_RUN, activity.type());
  170. EXPECT_EQ(kTaskOrigin, activity.origin_address());
  171. EXPECT_EQ(kTaskSequenceNum, activity.task_sequence_id());
  172. EXPECT_EQ(0U, activity.user_data().size());
  173. }
  174. {
  175. const Activity& activity = thread_state.activities(1);
  176. EXPECT_EQ(Activity::ACT_LOCK_ACQUIRE, activity.type());
  177. EXPECT_EQ(kLockAddress, activity.lock_address());
  178. EXPECT_EQ(0U, activity.user_data().size());
  179. }
  180. {
  181. const Activity& activity = thread_state.activities(2);
  182. EXPECT_EQ(Activity::ACT_EVENT_WAIT, activity.type());
  183. EXPECT_EQ(kEventAddress, activity.event_address());
  184. ASSERT_EQ(1U, activity.user_data().size());
  185. ASSERT_TRUE(base::Contains(activity.user_data(), "some_int"));
  186. EXPECT_EQ(TypedValue::kSignedValue,
  187. activity.user_data().at("some_int").value_case());
  188. EXPECT_EQ(42, activity.user_data().at("some_int").signed_value());
  189. }
  190. {
  191. const Activity& activity = thread_state.activities(3);
  192. EXPECT_EQ(Activity::ACT_THREAD_JOIN, activity.type());
  193. EXPECT_EQ(kThreadId, activity.thread_id());
  194. EXPECT_EQ(0U, activity.user_data().size());
  195. }
  196. {
  197. const Activity& activity = thread_state.activities(4);
  198. EXPECT_EQ(Activity::ACT_PROCESS_WAIT, activity.type());
  199. EXPECT_EQ(kProcessId, activity.process_id());
  200. EXPECT_EQ(0U, activity.user_data().size());
  201. }
  202. {
  203. const Activity& activity = thread_state.activities(5);
  204. EXPECT_EQ(Activity::ACT_GENERIC, activity.type());
  205. EXPECT_EQ(kGenericId, activity.generic_id());
  206. EXPECT_EQ(kGenericData, activity.generic_data());
  207. EXPECT_EQ(0U, activity.user_data().size());
  208. }
  209. }
  210. TEST_F(StabilityReportExtractorThreadTrackerTest, CollectException) {
  211. const void* expected_pc = reinterpret_cast<void*>(0xCAFE);
  212. const void* expected_address = nullptr;
  213. const uint32_t expected_code = 42U;
  214. // Record an exception.
  215. const int64_t timestamp =
  216. base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds();
  217. tracker_->RecordExceptionActivity(expected_pc, expected_address,
  218. base::debug::Activity::ACT_EXCEPTION,
  219. ActivityData::ForException(expected_code));
  220. // Collect report and validate.
  221. StabilityReport report;
  222. ASSERT_EQ(SUCCESS, Extract(CreateAnalyzer(), &report));
  223. // Validate the presence of the exception.
  224. ASSERT_NO_FATAL_FAILURE(PerformBasicReportValidation(report));
  225. const ThreadState& thread_state = report.process_states(0).threads(0);
  226. ASSERT_TRUE(thread_state.has_exception());
  227. const Exception& exception = thread_state.exception();
  228. EXPECT_EQ(expected_code, exception.code());
  229. EXPECT_EQ(expected_pc, reinterpret_cast<void*>(exception.program_counter()));
  230. EXPECT_EQ(expected_address,
  231. reinterpret_cast<void*>(exception.exception_address()));
  232. const int64_t tolerance_us = 1000ULL;
  233. EXPECT_LE(std::abs(timestamp - exception.time()), tolerance_us);
  234. }
  235. TEST_F(StabilityReportExtractorThreadTrackerTest, CollectNoException) {
  236. // Record something.
  237. tracker_->PushActivity(reinterpret_cast<void*>(kTaskOrigin),
  238. base::debug::Activity::ACT_TASK_RUN,
  239. ActivityData::ForTask(kTaskSequenceNum));
  240. // Collect report and validate there is no exception.
  241. StabilityReport report;
  242. ASSERT_EQ(SUCCESS, Extract(CreateAnalyzer(), &report));
  243. ASSERT_NO_FATAL_FAILURE(PerformBasicReportValidation(report));
  244. const ThreadState& thread_state = report.process_states(0).threads(0);
  245. ASSERT_FALSE(thread_state.has_exception());
  246. }
  247. // Tests stability report extraction.
  248. class StabilityReportExtractorTest : public testing::Test {
  249. public:
  250. const int kMemorySize = 1 << 20; // 1MiB
  251. StabilityReportExtractorTest() {}
  252. ~StabilityReportExtractorTest() override {
  253. GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
  254. if (global_tracker) {
  255. global_tracker->ReleaseTrackerForCurrentThreadForTesting();
  256. delete global_tracker;
  257. }
  258. }
  259. void SetUp() override {
  260. testing::Test::SetUp();
  261. // Set up a debug file path.
  262. ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
  263. debug_file_path_ = temp_dir_.GetPath().AppendASCII("debug.pma");
  264. }
  265. std::unique_ptr<GlobalActivityAnalyzer> CreateAnalyzer() {
  266. return GlobalActivityAnalyzer::CreateWithFile(debug_file_path());
  267. }
  268. const FilePath& debug_file_path() { return debug_file_path_; }
  269. protected:
  270. base::ScopedTempDir temp_dir_;
  271. FilePath debug_file_path_;
  272. };
  273. TEST_F(StabilityReportExtractorTest, LogCollection) {
  274. // Record some log messages.
  275. GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL,
  276. "", 3);
  277. GlobalActivityTracker::Get()->RecordLogMessage("hello world");
  278. GlobalActivityTracker::Get()->RecordLogMessage("foo bar");
  279. // Collect the stability report.
  280. StabilityReport report;
  281. ASSERT_EQ(SUCCESS, Extract(CreateAnalyzer(), &report));
  282. // Validate the report's log content.
  283. ASSERT_EQ(2, report.log_messages_size());
  284. ASSERT_EQ("hello world", report.log_messages(0));
  285. ASSERT_EQ("foo bar", report.log_messages(1));
  286. }
  287. TEST_F(StabilityReportExtractorTest, ProcessUserDataCollection) {
  288. const char string1[] = "foo";
  289. const char string2[] = "bar";
  290. // Record some process user data.
  291. GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL,
  292. "", 3);
  293. ActivityUserData& process_data = GlobalActivityTracker::Get()->process_data();
  294. ActivityUserData::Snapshot snapshot;
  295. ASSERT_TRUE(process_data.CreateSnapshot(&snapshot));
  296. ASSERT_EQ(kInternalProcessDatums, snapshot.size());
  297. process_data.Set("raw", "foo", 3);
  298. process_data.SetString("string", "bar");
  299. process_data.SetChar("char", '9');
  300. process_data.SetInt("int", -9999);
  301. process_data.SetUint("uint", 9999);
  302. process_data.SetBool("bool", true);
  303. process_data.SetReference("ref", string1, strlen(string1));
  304. process_data.SetStringReference("sref", string2);
  305. // Collect the stability report.
  306. StabilityReport report;
  307. ASSERT_EQ(SUCCESS, Extract(CreateAnalyzer(), &report));
  308. // We expect a single process.
  309. ASSERT_EQ(1, report.process_states_size());
  310. // Validate the report contains the process' data.
  311. const auto& collected_data = report.process_states(0).data();
  312. ASSERT_EQ(kInternalProcessDatums + 8U, collected_data.size());
  313. ASSERT_TRUE(base::Contains(collected_data, "raw"));
  314. EXPECT_EQ(TypedValue::kBytesValue, collected_data.at("raw").value_case());
  315. EXPECT_EQ("foo", collected_data.at("raw").bytes_value());
  316. ASSERT_TRUE(base::Contains(collected_data, "string"));
  317. EXPECT_EQ(TypedValue::kStringValue, collected_data.at("string").value_case());
  318. EXPECT_EQ("bar", collected_data.at("string").string_value());
  319. ASSERT_TRUE(base::Contains(collected_data, "char"));
  320. EXPECT_EQ(TypedValue::kCharValue, collected_data.at("char").value_case());
  321. EXPECT_EQ("9", collected_data.at("char").char_value());
  322. ASSERT_TRUE(base::Contains(collected_data, "int"));
  323. EXPECT_EQ(TypedValue::kSignedValue, collected_data.at("int").value_case());
  324. EXPECT_EQ(-9999, collected_data.at("int").signed_value());
  325. ASSERT_TRUE(base::Contains(collected_data, "uint"));
  326. EXPECT_EQ(TypedValue::kUnsignedValue, collected_data.at("uint").value_case());
  327. EXPECT_EQ(9999U, collected_data.at("uint").unsigned_value());
  328. ASSERT_TRUE(base::Contains(collected_data, "bool"));
  329. EXPECT_EQ(TypedValue::kBoolValue, collected_data.at("bool").value_case());
  330. EXPECT_TRUE(collected_data.at("bool").bool_value());
  331. ASSERT_TRUE(base::Contains(collected_data, "ref"));
  332. EXPECT_EQ(TypedValue::kBytesReference, collected_data.at("ref").value_case());
  333. const TypedValue::Reference& ref = collected_data.at("ref").bytes_reference();
  334. EXPECT_EQ(reinterpret_cast<uintptr_t>(string1), ref.address());
  335. EXPECT_EQ(strlen(string1), static_cast<uint64_t>(ref.size()));
  336. ASSERT_TRUE(base::Contains(collected_data, "sref"));
  337. EXPECT_EQ(TypedValue::kStringReference,
  338. collected_data.at("sref").value_case());
  339. const TypedValue::Reference& sref =
  340. collected_data.at("sref").string_reference();
  341. EXPECT_EQ(reinterpret_cast<uintptr_t>(string2), sref.address());
  342. EXPECT_EQ(strlen(string2), static_cast<uint64_t>(sref.size()));
  343. }
  344. TEST_F(StabilityReportExtractorTest, ModuleCollection) {
  345. // Record some module information.
  346. GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL,
  347. "", 3);
  348. base::debug::GlobalActivityTracker::ModuleInfo module_info = {};
  349. module_info.is_loaded = true;
  350. module_info.address = 0x123456;
  351. module_info.load_time = 1111LL;
  352. module_info.size = 0x2d000;
  353. module_info.timestamp = 0xCAFECAFE;
  354. module_info.age = 1;
  355. crashpad::UUID debug_uuid;
  356. debug_uuid.InitializeFromString("11223344-5566-7788-abcd-0123456789ab");
  357. memcpy(module_info.identifier, &debug_uuid, sizeof(module_info.identifier));
  358. module_info.file = "foo";
  359. module_info.debug_file = "bar";
  360. GlobalActivityTracker::Get()->RecordModuleInfo(module_info);
  361. // Collect the stability report.
  362. StabilityReport report;
  363. ASSERT_EQ(SUCCESS, Extract(CreateAnalyzer(), &report));
  364. // Validate the report's modules content.
  365. ASSERT_EQ(1, report.process_states_size());
  366. const ProcessState& process_state = report.process_states(0);
  367. ASSERT_EQ(1, process_state.modules_size());
  368. const CodeModule collected_module = process_state.modules(0);
  369. EXPECT_EQ(module_info.address,
  370. static_cast<uintptr_t>(collected_module.base_address()));
  371. EXPECT_EQ(module_info.size, static_cast<size_t>(collected_module.size()));
  372. EXPECT_EQ(module_info.file, collected_module.code_file());
  373. EXPECT_EQ("CAFECAFE2d000", collected_module.code_identifier());
  374. EXPECT_EQ(module_info.debug_file, collected_module.debug_file());
  375. EXPECT_EQ("1122334455667788ABCD0123456789AB1",
  376. collected_module.debug_identifier());
  377. EXPECT_EQ("", collected_module.version());
  378. EXPECT_EQ(0LL, collected_module.shrink_down_delta());
  379. EXPECT_EQ(!module_info.is_loaded, collected_module.is_unloaded());
  380. }
  381. } // namespace browser_watcher