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 
5 #include "services/resource_coordinator/memory_instrumentation/coordinator_impl.h"
6 
7 #include "base/bind.h"
8 #include "base/run_loop.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/test/gmock_callback_support.h"
11 #include "base/test/task_environment.h"
12 #include "base/test/trace_event_analyzer.h"
13 #include "base/threading/platform_thread.h"
14 #include "base/time/time.h"
15 #include "base/trace_event/memory_dump_request_args.h"
16 #include "build/build_config.h"
17 #include "mojo/public/cpp/bindings/interface_request.h"
18 #include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 
22 using base::test::RunOnceClosure;
23 using ::testing::_;
24 using ::testing::AllOf;
25 using ::testing::Contains;
26 using ::testing::Eq;
27 using ::testing::Field;
28 using ::testing::Invoke;
29 using ::testing::IsEmpty;
30 using ::testing::Ne;
31 using ::testing::NiceMock;
32 using ::testing::NotNull;
33 using ::testing::Pointee;
34 using ::testing::Property;
35 using ::testing::Return;
36 using ::testing::UnorderedElementsAre;
37 
38 using GetVmRegionsForHeapProfilerCallback = memory_instrumentation::
39     CoordinatorImpl::GetVmRegionsForHeapProfilerCallback;
40 using RequestGlobalMemoryDumpAndAppendToTraceCallback = memory_instrumentation::
41     CoordinatorImpl::RequestGlobalMemoryDumpAndAppendToTraceCallback;
42 using RequestGlobalMemoryDumpCallback =
43     memory_instrumentation::CoordinatorImpl::RequestGlobalMemoryDumpCallback;
44 using RequestGlobalMemoryDumpForPidCallback = memory_instrumentation::
45     CoordinatorImpl::RequestGlobalMemoryDumpForPidCallback;
46 using base::trace_event::MemoryAllocatorDump;
47 using base::trace_event::MemoryDumpArgs;
48 using base::trace_event::MemoryDumpLevelOfDetail;
49 using base::trace_event::MemoryDumpManager;
50 using base::trace_event::MemoryDumpRequestArgs;
51 using base::trace_event::MemoryDumpType;
52 using base::trace_event::ProcessMemoryDump;
53 using base::trace_event::TraceLog;
54 using memory_instrumentation::mojom::GlobalMemoryDump;
55 using memory_instrumentation::mojom::GlobalMemoryDumpPtr;
56 
57 namespace memory_instrumentation {
58 
59 class FakeCoordinatorImpl : public CoordinatorImpl {
60  public:
61   FakeCoordinatorImpl() = default;
62   ~FakeCoordinatorImpl() override = default;
63 
64   MOCK_CONST_METHOD0(ComputePidToServiceNamesMap,
65                      std::map<base::ProcessId, std::vector<std::string>>());
66 };
67 
68 class CoordinatorImplTest : public testing::Test {
69  public:
70   CoordinatorImplTest() = default;
71 
SetUp()72   void SetUp() override {
73     coordinator_.reset(new NiceMock<FakeCoordinatorImpl>);
74   }
75 
TearDown()76   void TearDown() override { coordinator_.reset(); }
77 
RegisterClientProcess(mojo::PendingReceiver<mojom::Coordinator> receiver,mojo::PendingRemote<mojom::ClientProcess> client_process,mojom::ProcessType process_type,base::ProcessId pid)78   void RegisterClientProcess(
79       mojo::PendingReceiver<mojom::Coordinator> receiver,
80       mojo::PendingRemote<mojom::ClientProcess> client_process,
81       mojom::ProcessType process_type,
82       base::ProcessId pid) {
83     coordinator_->RegisterClientProcess(
84         std::move(receiver), std::move(client_process), process_type, pid,
85         /*service_name=*/base::nullopt);
86   }
87 
RequestGlobalMemoryDump(RequestGlobalMemoryDumpCallback callback)88   void RequestGlobalMemoryDump(RequestGlobalMemoryDumpCallback callback) {
89     RequestGlobalMemoryDump(
90         MemoryDumpType::SUMMARY_ONLY, MemoryDumpLevelOfDetail::BACKGROUND,
91         MemoryDumpDeterminism::NONE, {}, std::move(callback));
92   }
93 
RequestGlobalMemoryDump(MemoryDumpType dump_type,MemoryDumpLevelOfDetail level_of_detail,MemoryDumpDeterminism determinism,const std::vector<std::string> & allocator_dump_names,RequestGlobalMemoryDumpCallback callback)94   void RequestGlobalMemoryDump(
95       MemoryDumpType dump_type,
96       MemoryDumpLevelOfDetail level_of_detail,
97       MemoryDumpDeterminism determinism,
98       const std::vector<std::string>& allocator_dump_names,
99       RequestGlobalMemoryDumpCallback callback) {
100     coordinator_->RequestGlobalMemoryDump(dump_type, level_of_detail,
101                                           determinism, allocator_dump_names,
102                                           std::move(callback));
103   }
104 
RequestGlobalMemoryDumpForPid(base::ProcessId pid,const std::vector<std::string> & allocator_dump_names,RequestGlobalMemoryDumpForPidCallback callback)105   void RequestGlobalMemoryDumpForPid(
106       base::ProcessId pid,
107       const std::vector<std::string>& allocator_dump_names,
108       RequestGlobalMemoryDumpForPidCallback callback) {
109     coordinator_->RequestGlobalMemoryDumpForPid(pid, allocator_dump_names,
110                                                 std::move(callback));
111   }
112 
RequestGlobalMemoryDumpAndAppendToTrace(RequestGlobalMemoryDumpAndAppendToTraceCallback callback)113   void RequestGlobalMemoryDumpAndAppendToTrace(
114       RequestGlobalMemoryDumpAndAppendToTraceCallback callback) {
115     coordinator_->RequestGlobalMemoryDumpAndAppendToTrace(
116         MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::DETAILED,
117         MemoryDumpDeterminism::NONE, std::move(callback));
118   }
119 
GetVmRegionsForHeapProfiler(const std::vector<base::ProcessId> & pids,GetVmRegionsForHeapProfilerCallback callback)120   void GetVmRegionsForHeapProfiler(
121       const std::vector<base::ProcessId>& pids,
122       GetVmRegionsForHeapProfilerCallback callback) {
123     coordinator_->GetVmRegionsForHeapProfiler(pids, std::move(callback));
124   }
125 
ReduceCoordinatorClientProcessTimeout()126   void ReduceCoordinatorClientProcessTimeout() {
127     coordinator_->set_client_process_timeout(
128         base::TimeDelta::FromMilliseconds(5));
129   }
130 
131  protected:
132   std::unique_ptr<NiceMock<FakeCoordinatorImpl>> coordinator_;
133 
134   base::test::SingleThreadTaskEnvironment task_environment_{
135       base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME};
136 };
137 
138 class MockClientProcess : public mojom::ClientProcess {
139  public:
MockClientProcess(CoordinatorImplTest * test_coordinator)140   MockClientProcess(CoordinatorImplTest* test_coordinator)
141       : MockClientProcess(test_coordinator,
142                           base::GetCurrentProcId(),
143                           mojom::ProcessType::OTHER) {}
144 
MockClientProcess(CoordinatorImplTest * test_coordinator,base::ProcessId pid,mojom::ProcessType process_type)145   MockClientProcess(CoordinatorImplTest* test_coordinator,
146                     base::ProcessId pid,
147                     mojom::ProcessType process_type) {
148     // Register to the coordinator.
149     mojo::Remote<mojom::Coordinator> remote_coordinator;
150     mojo::PendingRemote<mojom::ClientProcess> client_process;
151     receiver_.Bind(client_process.InitWithNewPipeAndPassReceiver());
152     test_coordinator->RegisterClientProcess(
153         remote_coordinator.BindNewPipeAndPassReceiver(),
154         std::move(client_process), process_type, pid);
155 
156     ON_CALL(*this, RequestChromeMemoryDumpMock(_, _))
157         .WillByDefault(Invoke([pid](const MemoryDumpRequestArgs& args,
158                                     RequestChromeMemoryDumpCallback& callback) {
159           MemoryDumpArgs dump_args{MemoryDumpLevelOfDetail::DETAILED};
160           auto pmd = std::make_unique<ProcessMemoryDump>(dump_args);
161           auto* mad = pmd->CreateAllocatorDump(
162               "malloc", base::trace_event::MemoryAllocatorDumpGuid(pid));
163           mad->AddScalar(MemoryAllocatorDump::kNameSize,
164                          MemoryAllocatorDump::kUnitsBytes, 1024);
165 
166           std::move(callback).Run(true, args.dump_guid, std::move(pmd));
167         }));
168 
169     ON_CALL(*this, RequestOSMemoryDumpMock(_, _, _))
170         .WillByDefault(Invoke([](mojom::MemoryMapOption,
171                                  const std::vector<base::ProcessId> pids,
172                                  RequestOSMemoryDumpCallback& callback) {
173           base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
174           std::move(callback).Run(true, std::move(results));
175         }));
176   }
177 
178   ~MockClientProcess() override = default;
179 
180   // TODO(crbug.com/729950): Remove non const reference here once GMock is
181   // updated to support move-only types.
182   MOCK_METHOD2(RequestChromeMemoryDumpMock,
183                void(const MemoryDumpRequestArgs& args,
184                     RequestChromeMemoryDumpCallback& callback));
185   MOCK_METHOD3(RequestOSMemoryDumpMock,
186                void(mojom::MemoryMapOption option,
187                     const std::vector<base::ProcessId>& args,
188                     RequestOSMemoryDumpCallback& callback));
189 
RequestChromeMemoryDump(const MemoryDumpRequestArgs & args,RequestChromeMemoryDumpCallback callback)190   void RequestChromeMemoryDump(
191       const MemoryDumpRequestArgs& args,
192       RequestChromeMemoryDumpCallback callback) override {
193     RequestChromeMemoryDumpMock(args, callback);
194   }
RequestOSMemoryDump(mojom::MemoryMapOption option,const std::vector<base::ProcessId> & args,RequestOSMemoryDumpCallback callback)195   void RequestOSMemoryDump(mojom::MemoryMapOption option,
196                            const std::vector<base::ProcessId>& args,
197                            RequestOSMemoryDumpCallback callback) override {
198     RequestOSMemoryDumpMock(option, args, callback);
199   }
200 
201  private:
202   mojo::Receiver<mojom::ClientProcess> receiver_{this};
203 };
204 
205 class MockGlobalMemoryDumpCallback {
206  public:
207   MockGlobalMemoryDumpCallback() = default;
208   MOCK_METHOD2(OnCall, void(bool, GlobalMemoryDump*));
209 
Run(bool success,GlobalMemoryDumpPtr ptr)210   void Run(bool success, GlobalMemoryDumpPtr ptr) {
211     OnCall(success, ptr.get());
212   }
213 
Get()214   RequestGlobalMemoryDumpCallback Get() {
215     return base::BindRepeating(&MockGlobalMemoryDumpCallback::Run,
216                                base::Unretained(this));
217   }
218 };
219 
220 class MockGlobalMemoryDumpAndAppendToTraceCallback {
221  public:
222   MockGlobalMemoryDumpAndAppendToTraceCallback() = default;
223   MOCK_METHOD2(OnCall, void(bool, uint64_t));
224 
Run(bool success,uint64_t dump_guid)225   void Run(bool success, uint64_t dump_guid) { OnCall(success, dump_guid); }
226 
Get()227   RequestGlobalMemoryDumpAndAppendToTraceCallback Get() {
228     return base::BindRepeating(
229         &MockGlobalMemoryDumpAndAppendToTraceCallback::Run,
230         base::Unretained(this));
231   }
232 };
233 
234 class MockGetVmRegionsForHeapProfilerCallback {
235  public:
236   MockGetVmRegionsForHeapProfilerCallback() = default;
237   MOCK_METHOD1(OnCall,
238                void(const base::flat_map<base::ProcessId,
239                                          std::vector<mojom::VmRegionPtr>>&));
240 
Run(base::flat_map<base::ProcessId,std::vector<mojom::VmRegionPtr>> results)241   void Run(base::flat_map<base::ProcessId, std::vector<mojom::VmRegionPtr>>
242                results) {
243     OnCall(results);
244   }
245 
Get()246   GetVmRegionsForHeapProfilerCallback Get() {
247     return base::BindRepeating(&MockGetVmRegionsForHeapProfilerCallback::Run,
248                                base::Unretained(this));
249   }
250 };
251 
GetFakeAddrForVmRegion(int pid,int region_index)252 uint64_t GetFakeAddrForVmRegion(int pid, int region_index) {
253   return 0x100000ul * pid * (region_index + 1);
254 }
255 
GetFakeSizeForVmRegion(int pid,int region_index)256 uint64_t GetFakeSizeForVmRegion(int pid, int region_index) {
257   return 4096 * pid * (region_index + 1);
258 }
259 
FillRawOSDump(int pid)260 mojom::RawOSMemDumpPtr FillRawOSDump(int pid) {
261   mojom::RawOSMemDumpPtr raw_os_dump = mojom::RawOSMemDump::New();
262   raw_os_dump->platform_private_footprint =
263       mojom::PlatformPrivateFootprint::New();
264   raw_os_dump->resident_set_kb = pid;
265   for (int i = 0; i < 3; i++) {
266     mojom::VmRegionPtr vm_region = mojom::VmRegion::New();
267     vm_region->start_address = GetFakeAddrForVmRegion(pid, i);
268     vm_region->size_in_bytes = GetFakeSizeForVmRegion(pid, i);
269     raw_os_dump->memory_maps.push_back(std::move(vm_region));
270   }
271   return raw_os_dump;
272 }
273 
274 // Tests that the global dump is acked even in absence of clients.
TEST_F(CoordinatorImplTest,NoClients)275 TEST_F(CoordinatorImplTest, NoClients) {
276   MockGlobalMemoryDumpCallback callback;
277   EXPECT_CALL(callback, OnCall(true, NotNull()));
278   RequestGlobalMemoryDump(callback.Get());
279 }
280 
281 // Nominal behavior: several clients contributing to the global dump.
TEST_F(CoordinatorImplTest,SeveralClients)282 TEST_F(CoordinatorImplTest, SeveralClients) {
283   base::RunLoop run_loop;
284 
285   NiceMock<MockClientProcess> client_process_1(this, 1,
286                                                mojom::ProcessType::BROWSER);
287   NiceMock<MockClientProcess> client_process_2(this);
288 
289   EXPECT_CALL(client_process_1, RequestChromeMemoryDumpMock(_, _)).Times(1);
290   EXPECT_CALL(client_process_2, RequestChromeMemoryDumpMock(_, _)).Times(1);
291 
292   MockGlobalMemoryDumpCallback callback;
293   EXPECT_CALL(callback, OnCall(true, NotNull()))
294       .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
295   RequestGlobalMemoryDump(callback.Get());
296   run_loop.Run();
297 }
298 
299 // Issuing two requests will cause the second one to be queued.
TEST_F(CoordinatorImplTest,QueuedRequest)300 TEST_F(CoordinatorImplTest, QueuedRequest) {
301   base::RunLoop run_loop;
302 
303   // This variable to be static as the lambda below has to convert to a function
304   // pointer rather than a functor.
305   static base::test::SingleThreadTaskEnvironment* task_environment = nullptr;
306   task_environment = &task_environment_;
307 
308   NiceMock<MockClientProcess> client_process_1(this, 1,
309                                                mojom::ProcessType::BROWSER);
310   NiceMock<MockClientProcess> client_process_2(this);
311 
312   // Each request will invoke on both processes.
313   EXPECT_CALL(client_process_1, RequestChromeMemoryDumpMock(_, _)).Times(2);
314   EXPECT_CALL(client_process_2, RequestChromeMemoryDumpMock(_, _))
315       .Times(2)
316       .WillRepeatedly(Invoke(
317           [](const MemoryDumpRequestArgs& args,
318              MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
319             // Skip the wall clock time-ticks forward to make sure start_time
320             // is strictly increasing.
321             task_environment->FastForwardBy(
322                 base::TimeDelta::FromMilliseconds(10));
323             MemoryDumpArgs dump_args{MemoryDumpLevelOfDetail::DETAILED};
324             auto pmd = std::make_unique<ProcessMemoryDump>(dump_args);
325             std::move(callback).Run(true, args.dump_guid, std::move(pmd));
326           }));
327 
328   MockGlobalMemoryDumpCallback callback1;
329   MockGlobalMemoryDumpCallback callback2;
330 
331   // Verify that the start time of subsequent dumps is monotonically
332   // increasing.
333   base::TimeTicks before = base::TimeTicks::Now();
334   base::TimeTicks first_dump_time;
335   EXPECT_CALL(callback1, OnCall(true, NotNull()))
336       .WillOnce(Invoke([&](bool success, GlobalMemoryDump* global_dump) {
337         EXPECT_LE(before, global_dump->start_time);
338         first_dump_time = global_dump->start_time;
339       }));
340   EXPECT_CALL(callback2, OnCall(true, NotNull()))
341       .WillOnce(Invoke([&](bool success, GlobalMemoryDump* global_dump) {
342         EXPECT_LT(before, global_dump->start_time);
343         EXPECT_LT(first_dump_time, global_dump->start_time);
344         run_loop.Quit();
345       }));
346   RequestGlobalMemoryDump(callback1.Get());
347   RequestGlobalMemoryDump(callback2.Get());
348   run_loop.Run();
349 }
350 
TEST_F(CoordinatorImplTest,MissingChromeDump)351 TEST_F(CoordinatorImplTest, MissingChromeDump) {
352   base::RunLoop run_loop;
353 
354   NiceMock<MockClientProcess> client_process(this, 1,
355                                              mojom::ProcessType::BROWSER);
356 
357   EXPECT_CALL(client_process, RequestChromeMemoryDumpMock(_, _))
358       .WillOnce(Invoke(
359           [](const MemoryDumpRequestArgs& args,
360              MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
361             MemoryDumpArgs dump_args{MemoryDumpLevelOfDetail::DETAILED};
362             auto pmd = std::make_unique<ProcessMemoryDump>(dump_args);
363             std::move(callback).Run(true, args.dump_guid, std::move(pmd));
364           }));
365 
366   MockGlobalMemoryDumpCallback callback;
367   EXPECT_CALL(
368       callback,
369       OnCall(true, Pointee(Field(&mojom::GlobalMemoryDump::process_dumps,
370                                  IsEmpty()))))
371       .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
372   RequestGlobalMemoryDump(callback.Get());
373   run_loop.Run();
374 }
375 
TEST_F(CoordinatorImplTest,MissingOsDump)376 TEST_F(CoordinatorImplTest, MissingOsDump) {
377   base::RunLoop run_loop;
378 
379   NiceMock<MockClientProcess> client_process(this, 1,
380                                              mojom::ProcessType::BROWSER);
381 
382   EXPECT_CALL(client_process, RequestOSMemoryDumpMock(_, _, _))
383       .WillOnce(Invoke(
384           [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
385              MockClientProcess::RequestOSMemoryDumpCallback& callback) {
386             base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
387             std::move(callback).Run(true, std::move(results));
388           }));
389 
390   MockGlobalMemoryDumpCallback callback;
391   EXPECT_CALL(
392       callback,
393       OnCall(true, Pointee(Field(&mojom::GlobalMemoryDump::process_dumps,
394                                  IsEmpty()))))
395       .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
396   RequestGlobalMemoryDump(callback.Get());
397   run_loop.Run();
398 }
399 
TEST_F(CoordinatorImplTest,TimeOutStuckChild)400 TEST_F(CoordinatorImplTest, TimeOutStuckChild) {
401   base::RunLoop run_loop;
402 
403   // |stuck_callback| should be destroyed after |client_process| or mojo
404   // will complain about the callback being destoyed before the binding.
405   MockClientProcess::RequestChromeMemoryDumpCallback stuck_callback;
406   NiceMock<MockClientProcess> client_process(this, 1,
407                                              mojom::ProcessType::BROWSER);
408 
409   // Store a reference to the callback passed to RequestChromeMemoryDump
410   // to emulate "stuck" behaviour.
411   EXPECT_CALL(client_process, RequestChromeMemoryDumpMock(_, _))
412       .WillOnce(Invoke(
413           [&stuck_callback](
414               const MemoryDumpRequestArgs&,
415               MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
416             stuck_callback = std::move(callback);
417           }));
418 
419   MockGlobalMemoryDumpCallback callback;
420   EXPECT_CALL(
421       callback,
422       OnCall(false, Pointee(Field(&mojom::GlobalMemoryDump::process_dumps,
423                                   IsEmpty()))))
424       .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
425   ReduceCoordinatorClientProcessTimeout();
426   RequestGlobalMemoryDump(callback.Get());
427   run_loop.Run();
428 }
429 
TEST_F(CoordinatorImplTest,TimeOutStuckChildMultiProcess)430 TEST_F(CoordinatorImplTest, TimeOutStuckChildMultiProcess) {
431   base::RunLoop run_loop;
432 
433   static constexpr base::ProcessId kBrowserPid = 1;
434   static constexpr base::ProcessId kRendererPid = 2;
435 
436   // |stuck_callback| should be destroyed after |renderer_client| or mojo
437   // will complain about the callback being destoyed before the binding.
438   MockClientProcess::RequestChromeMemoryDumpCallback stuck_callback;
439   MockClientProcess browser_client(this, kBrowserPid,
440                                    mojom::ProcessType::BROWSER);
441   MockClientProcess renderer_client(this, kRendererPid,
442                                     mojom::ProcessType::RENDERER);
443 
444 // This ifdef is here to match the sandboxing behavior of the client.
445 // On Linux, all memory dumps come from the browser client. On all other
446 // platforms, they are expected to come from each individual client.
447 #if defined(OS_LINUX)
448   EXPECT_CALL(browser_client,
449               RequestOSMemoryDumpMock(
450                   _, AllOf(Contains(kBrowserPid), Contains(kRendererPid)), _))
451       .WillOnce(Invoke(
452           [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
453              MockClientProcess::RequestOSMemoryDumpCallback& callback) {
454             base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
455             results[kBrowserPid] = FillRawOSDump(kBrowserPid);
456             results[kRendererPid] = FillRawOSDump(kRendererPid);
457             std::move(callback).Run(true, std::move(results));
458           }));
459   EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, _, _)).Times(0);
460 #else
461   EXPECT_CALL(browser_client, RequestOSMemoryDumpMock(_, Contains(0), _))
462       .WillOnce(Invoke(
463           [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
464              MockClientProcess::RequestOSMemoryDumpCallback& callback) {
465             base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
466             results[0] = FillRawOSDump(kBrowserPid);
467             std::move(callback).Run(true, std::move(results));
468           }));
469   EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, Contains(0), _))
470       .WillOnce(Invoke(
471           [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
472              MockClientProcess::RequestOSMemoryDumpCallback& callback) {
473             base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
474             results[0] = FillRawOSDump(kRendererPid);
475             std::move(callback).Run(true, std::move(results));
476           }));
477 #endif  // defined(OS_LINUX)
478 
479   // Make the browser respond correctly but pretend the renderer is "stuck"
480   // by storing a callback.
481   EXPECT_CALL(renderer_client, RequestChromeMemoryDumpMock(_, _))
482       .WillOnce(Invoke(
483           [&stuck_callback](
484               const MemoryDumpRequestArgs&,
485               MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
486             stuck_callback = std::move(callback);
487           }));
488 
489   MockGlobalMemoryDumpCallback callback;
490   EXPECT_CALL(callback, OnCall(false, _))
491       .WillOnce(
492           Invoke([&run_loop](bool success, GlobalMemoryDump* global_dump) {
493             EXPECT_EQ(1U, global_dump->process_dumps.size());
494             run_loop.Quit();
495           }));
496   ReduceCoordinatorClientProcessTimeout();
497   RequestGlobalMemoryDump(callback.Get());
498   run_loop.Run();
499 }
500 
501 // Tests that a global dump is completed even if a client disconnects (e.g. due
502 // to a crash) while a global dump is happening.
TEST_F(CoordinatorImplTest,ClientCrashDuringGlobalDump)503 TEST_F(CoordinatorImplTest, ClientCrashDuringGlobalDump) {
504   base::RunLoop run_loop;
505 
506   auto client_process_1 = std::make_unique<NiceMock<MockClientProcess>>(
507       this, 1, mojom::ProcessType::BROWSER);
508   auto client_process_2 = std::make_unique<NiceMock<MockClientProcess>>(this);
509 
510   // One of the client processes dies after a global dump is requested and
511   // before it receives the corresponding process dump request. The coordinator
512   // should detect that one of its clients is disconnected and claim the global
513   // dump attempt has failed.
514 
515   // Whichever client is called first destroys the other client.
516   ON_CALL(*client_process_1, RequestChromeMemoryDumpMock(_, _))
517       .WillByDefault(Invoke(
518           [&client_process_2](
519               const MemoryDumpRequestArgs& args,
520               MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
521             client_process_2.reset();
522             std::move(callback).Run(true, args.dump_guid, nullptr);
523           }));
524   ON_CALL(*client_process_2, RequestChromeMemoryDumpMock(_, _))
525       .WillByDefault(Invoke(
526           [&client_process_1](
527               const MemoryDumpRequestArgs& args,
528               MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
529             client_process_1.reset();
530             std::move(callback).Run(true, args.dump_guid, nullptr);
531           }));
532 
533   MockGlobalMemoryDumpCallback callback;
534   EXPECT_CALL(callback, OnCall(false, NotNull()))
535       .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
536   RequestGlobalMemoryDump(callback.Get());
537   run_loop.Run();
538 }
539 
540 // Like ClientCrashDuringGlobalDump but covers the case of having only one
541 // client. Regression testing for crbug.com/742265.
TEST_F(CoordinatorImplTest,SingleClientCrashDuringGlobalDump)542 TEST_F(CoordinatorImplTest, SingleClientCrashDuringGlobalDump) {
543   base::RunLoop run_loop;
544 
545   auto client_process = std::make_unique<NiceMock<MockClientProcess>>(
546       this, 1, mojom::ProcessType::BROWSER);
547 
548   ON_CALL(*client_process, RequestChromeMemoryDumpMock(_, _))
549       .WillByDefault(Invoke(
550           [&client_process](
551               const MemoryDumpRequestArgs& args,
552               MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
553             // The dtor here will cause mojo to post an UnregisterClient call to
554             // the coordinator.
555             client_process.reset();
556             std::move(callback).Run(true, args.dump_guid, nullptr);
557           }));
558 
559   MockGlobalMemoryDumpCallback callback;
560   EXPECT_CALL(callback, OnCall(false, NotNull()))
561       .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
562   RequestGlobalMemoryDump(callback.Get());
563   run_loop.Run();
564 }
565 
TEST_F(CoordinatorImplTest,GlobalMemoryDumpStruct)566 TEST_F(CoordinatorImplTest, GlobalMemoryDumpStruct) {
567   base::RunLoop run_loop;
568 
569   MockClientProcess browser_client(this, 1, mojom::ProcessType::BROWSER);
570   MockClientProcess renderer_client(this, 2, mojom::ProcessType::RENDERER);
571 
572   EXPECT_CALL(browser_client, RequestChromeMemoryDumpMock(_, _))
573       .WillOnce(Invoke([](const MemoryDumpRequestArgs& args,
574                           MockClientProcess::RequestChromeMemoryDumpCallback&
575                               callback) {
576         MemoryDumpArgs dump_args{MemoryDumpLevelOfDetail::DETAILED};
577         auto pmd = std::make_unique<ProcessMemoryDump>(dump_args);
578         auto* size = MemoryAllocatorDump::kNameSize;
579         auto* bytes = MemoryAllocatorDump::kUnitsBytes;
580         const uint32_t kB = 1024;
581 
582         pmd->CreateAllocatorDump("malloc",
583                                  base::trace_event::MemoryAllocatorDumpGuid(1))
584             ->AddScalar(size, bytes, 1 * kB);
585         pmd->CreateAllocatorDump("malloc/ignored")
586             ->AddScalar(size, bytes, 99 * kB);
587 
588         pmd->CreateAllocatorDump("blink_gc")->AddScalar(size, bytes, 2 * kB);
589         pmd->CreateAllocatorDump("blink_gc/ignored")
590             ->AddScalar(size, bytes, 99 * kB);
591 
592         pmd->CreateAllocatorDump("v8/foo")->AddScalar(size, bytes, 1 * kB);
593         pmd->CreateAllocatorDump("v8/bar")->AddScalar(size, bytes, 2 * kB);
594         pmd->CreateAllocatorDump("v8")->AddScalar(size, bytes, 99 * kB);
595 
596         // All the 99 KB values here are expected to be ignored.
597         pmd->CreateAllocatorDump("partition_alloc")
598             ->AddScalar(size, bytes, 99 * kB);
599         pmd->CreateAllocatorDump("partition_alloc/allocated_objects")
600             ->AddScalar(size, bytes, 99 * kB);
601         pmd->CreateAllocatorDump("partition_alloc/allocated_objects/ignored")
602             ->AddScalar(size, bytes, 99 * kB);
603         pmd->CreateAllocatorDump("partition_alloc/partitions")
604             ->AddScalar(size, bytes, 99 * kB);
605         pmd->CreateAllocatorDump("partition_alloc/partitions/not_ignored_1")
606             ->AddScalar(size, bytes, 2 * kB);
607         pmd->CreateAllocatorDump("partition_alloc/partitions/not_ignored_2")
608             ->AddScalar(size, bytes, 2 * kB);
609 
610         std::move(callback).Run(true, args.dump_guid, std::move(pmd));
611       }));
612   EXPECT_CALL(renderer_client, RequestChromeMemoryDumpMock(_, _))
613       .WillOnce(Invoke(
614           [](const MemoryDumpRequestArgs& args,
615              MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
616             MemoryDumpArgs dump_args{MemoryDumpLevelOfDetail::DETAILED};
617             auto pmd = std::make_unique<ProcessMemoryDump>(dump_args);
618             auto* mad = pmd->CreateAllocatorDump(
619                 "malloc", base::trace_event::MemoryAllocatorDumpGuid(2));
620             mad->AddScalar(MemoryAllocatorDump::kNameSize,
621                            MemoryAllocatorDump::kUnitsBytes, 1024 * 2);
622             std::move(callback).Run(true, args.dump_guid, std::move(pmd));
623           }));
624 #if defined(OS_LINUX)
625   EXPECT_CALL(browser_client,
626               RequestOSMemoryDumpMock(_, AllOf(Contains(1), Contains(2)), _))
627       .WillOnce(Invoke(
628           [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
629              MockClientProcess::RequestOSMemoryDumpCallback& callback) {
630             base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
631             results[1] = mojom::RawOSMemDump::New();
632             results[1]->resident_set_kb = 1;
633             results[1]->platform_private_footprint =
634                 mojom::PlatformPrivateFootprint::New();
635             results[2] = mojom::RawOSMemDump::New();
636             results[2]->platform_private_footprint =
637                 mojom::PlatformPrivateFootprint::New();
638             results[2]->resident_set_kb = 2;
639             std::move(callback).Run(true, std::move(results));
640           }));
641   EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, _, _)).Times(0);
642 #else
643   EXPECT_CALL(browser_client, RequestOSMemoryDumpMock(_, Contains(0), _))
644       .WillOnce(Invoke(
645           [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
646              MockClientProcess::RequestOSMemoryDumpCallback& callback) {
647             base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
648             results[0] = mojom::RawOSMemDump::New();
649             results[0]->platform_private_footprint =
650                 mojom::PlatformPrivateFootprint::New();
651             results[0]->resident_set_kb = 1;
652             std::move(callback).Run(true, std::move(results));
653           }));
654   EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, Contains(0), _))
655       .WillOnce(Invoke(
656           [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
657              MockClientProcess::RequestOSMemoryDumpCallback& callback) {
658             base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
659             results[0] = mojom::RawOSMemDump::New();
660             results[0]->platform_private_footprint =
661                 mojom::PlatformPrivateFootprint::New();
662             results[0]->resident_set_kb = 2;
663             std::move(callback).Run(true, std::move(results));
664           }));
665 #endif  // defined(OS_LINUX)
666 
667   MockGlobalMemoryDumpCallback callback;
668   EXPECT_CALL(callback, OnCall(true, NotNull()))
669       .WillOnce(Invoke([&run_loop](bool success,
670                                    GlobalMemoryDump* global_dump) {
671         EXPECT_TRUE(success);
672         EXPECT_EQ(2U, global_dump->process_dumps.size());
673         mojom::ProcessMemoryDumpPtr browser_dump = nullptr;
674         mojom::ProcessMemoryDumpPtr renderer_dump = nullptr;
675         for (mojom::ProcessMemoryDumpPtr& dump : global_dump->process_dumps) {
676           if (dump->process_type == mojom::ProcessType::BROWSER) {
677             browser_dump = std::move(dump);
678           } else if (dump->process_type == mojom::ProcessType::RENDERER) {
679             renderer_dump = std::move(dump);
680           }
681         }
682 
683         EXPECT_EQ(browser_dump->os_dump->resident_set_kb, 1u);
684         EXPECT_EQ(renderer_dump->os_dump->resident_set_kb, 2u);
685         run_loop.Quit();
686       }));
687 
688   RequestGlobalMemoryDump(callback.Get());
689   run_loop.Run();
690 }
691 
TEST_F(CoordinatorImplTest,VmRegionsForHeapProfiler)692 TEST_F(CoordinatorImplTest, VmRegionsForHeapProfiler) {
693   base::RunLoop run_loop;
694   // Not using a constexpr base::ProcessId because std:unordered_map<>
695   // and friends makes it too easy to accidentally odr-use this variable
696   // causing all sorts of compiler-toolchain divergent fun when trying
697   // to decide of the lambda capture is necessary.
698   static constexpr base::ProcessId kBrowserPid = 1;
699   static constexpr base::ProcessId kRendererPid = 2;
700 
701   MockClientProcess browser_client(this, kBrowserPid,
702                                    mojom::ProcessType::BROWSER);
703   MockClientProcess renderer_client(this, kRendererPid,
704                                     mojom::ProcessType::RENDERER);
705 
706 // This ifdef is here to match the sandboxing behavior of the client.
707 // On Linux, all memory dumps come from the browser client. On all other
708 // platforms, they are expected to come from each individual client.
709 #if defined(OS_LINUX)
710   EXPECT_CALL(browser_client,
711               RequestOSMemoryDumpMock(
712                   _, AllOf(Contains(kBrowserPid), Contains(kRendererPid)), _))
713       .WillOnce(Invoke(
714           [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
715              MockClientProcess::RequestOSMemoryDumpCallback& callback) {
716             base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
717             results[kBrowserPid] = FillRawOSDump(kBrowserPid);
718             results[kRendererPid] = FillRawOSDump(kRendererPid);
719             std::move(callback).Run(true, std::move(results));
720           }));
721   EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, _, _)).Times(0);
722 #else
723   EXPECT_CALL(browser_client, RequestOSMemoryDumpMock(_, Contains(0), _))
724       .WillOnce(Invoke(
725           [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
726              MockClientProcess::RequestOSMemoryDumpCallback& callback) {
727             base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
728             results[0] = FillRawOSDump(kBrowserPid);
729             std::move(callback).Run(true, std::move(results));
730           }));
731   EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, Contains(0), _))
732       .WillOnce(Invoke(
733           [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
734              MockClientProcess::RequestOSMemoryDumpCallback& callback) {
735             base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
736             results[0] = FillRawOSDump(kRendererPid);
737             std::move(callback).Run(true, std::move(results));
738           }));
739 #endif  // defined(OS_LINUX)
740 
741   MockGetVmRegionsForHeapProfilerCallback callback;
742   EXPECT_CALL(callback, OnCall(_))
743       .WillOnce(Invoke(
744           [&run_loop](
745               const base::flat_map<base::ProcessId,
746                                    std::vector<mojom::VmRegionPtr>>& results) {
747             ASSERT_EQ(2U, results.size());
748 
749             auto browser_it = results.find(kBrowserPid);
750             ASSERT_TRUE(browser_it != results.end());
751             auto renderer_it = results.find(kRendererPid);
752             ASSERT_TRUE(renderer_it != results.end());
753 
754             const std::vector<mojom::VmRegionPtr>& browser_mmaps =
755                 browser_it->second;
756             ASSERT_EQ(3u, browser_mmaps.size());
757             for (int i = 0; i < 3; i++) {
758               EXPECT_EQ(GetFakeAddrForVmRegion(kBrowserPid, i),
759                         browser_mmaps[i]->start_address);
760             }
761 
762             const std::vector<mojom::VmRegionPtr>& renderer_mmaps =
763                 renderer_it->second;
764             ASSERT_EQ(3u, renderer_mmaps.size());
765             for (int i = 0; i < 3; i++) {
766               EXPECT_EQ(GetFakeAddrForVmRegion(kRendererPid, i),
767                         renderer_mmaps[i]->start_address);
768             }
769             run_loop.Quit();
770           }));
771 
772   std::vector<base::ProcessId> pids;
773   pids.push_back(kBrowserPid);
774   pids.push_back(kRendererPid);
775   GetVmRegionsForHeapProfiler(pids, callback.Get());
776   run_loop.Run();
777 }
778 
779 // RequestGlobalMemoryDump, as opposite to RequestGlobalMemoryDumpAndAddToTrace,
780 // shouldn't add anything into the trace
TEST_F(CoordinatorImplTest,DumpsArentAddedToTraceUnlessRequested)781 TEST_F(CoordinatorImplTest, DumpsArentAddedToTraceUnlessRequested) {
782   using trace_analyzer::Query;
783 
784   base::RunLoop run_loop;
785 
786   NiceMock<MockClientProcess> client_process(this, 1,
787                                              mojom::ProcessType::BROWSER);
788 
789   EXPECT_CALL(client_process, RequestChromeMemoryDumpMock(_, _))
790       .WillOnce(Invoke(
791           [](const MemoryDumpRequestArgs& args,
792              MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
793             MemoryDumpArgs dump_args{MemoryDumpLevelOfDetail::DETAILED};
794             auto pmd = std::make_unique<ProcessMemoryDump>(dump_args);
795             std::move(callback).Run(true, args.dump_guid, std::move(pmd));
796           }));
797 
798   MockGlobalMemoryDumpCallback callback;
799   EXPECT_CALL(
800       callback,
801       OnCall(true, Pointee(Field(&mojom::GlobalMemoryDump::process_dumps,
802                                  IsEmpty()))))
803       .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
804 
805   trace_analyzer::Start(MemoryDumpManager::kTraceCategory);
806   RequestGlobalMemoryDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
807                           MemoryDumpLevelOfDetail::DETAILED,
808                           MemoryDumpDeterminism::NONE, {}, callback.Get());
809   run_loop.Run();
810   auto analyzer = trace_analyzer::Stop();
811 
812   trace_analyzer::TraceEventVector events;
813   analyzer->FindEvents(
814       trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_MEMORY_DUMP),
815       &events);
816 
817   ASSERT_EQ(0u, events.size());
818 }
819 
TEST_F(CoordinatorImplTest,DumpsAreAddedToTraceWhenRequested)820 TEST_F(CoordinatorImplTest, DumpsAreAddedToTraceWhenRequested) {
821   using trace_analyzer::Query;
822 
823   base::RunLoop run_loop;
824 
825   NiceMock<MockClientProcess> client_process(this, 1,
826                                              mojom::ProcessType::BROWSER);
827   EXPECT_CALL(client_process, RequestChromeMemoryDumpMock(_, _))
828       .WillOnce(Invoke(
829           [](const MemoryDumpRequestArgs& args,
830              MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
831             MemoryDumpArgs dump_args{MemoryDumpLevelOfDetail::DETAILED};
832             auto pmd = std::make_unique<ProcessMemoryDump>(dump_args);
833             std::move(callback).Run(true, args.dump_guid, std::move(pmd));
834           }));
835 
836   MockGlobalMemoryDumpAndAppendToTraceCallback callback;
837   EXPECT_CALL(callback, OnCall(true, Ne(0ul)))
838       .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
839 
840   trace_analyzer::Start(MemoryDumpManager::kTraceCategory);
841   RequestGlobalMemoryDumpAndAppendToTrace(callback.Get());
842   run_loop.Run();
843   auto analyzer = trace_analyzer::Stop();
844 
845   trace_analyzer::TraceEventVector events;
846   analyzer->FindEvents(
847       trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_MEMORY_DUMP),
848       &events);
849 
850   ASSERT_EQ(1u, events.size());
851   ASSERT_TRUE(trace_analyzer::CountMatches(
852       events, trace_analyzer::Query::EventNameIs(MemoryDumpTypeToString(
853                   MemoryDumpType::EXPLICITLY_TRIGGERED))));
854 }
855 
TEST_F(CoordinatorImplTest,DumpByPidSuccess)856 TEST_F(CoordinatorImplTest, DumpByPidSuccess) {
857   static constexpr base::ProcessId kBrowserPid = 1;
858   static constexpr base::ProcessId kRendererPid = 2;
859   static constexpr base::ProcessId kGpuPid = 3;
860 
861   NiceMock<MockClientProcess> client_process_1(this, kBrowserPid,
862                                                mojom::ProcessType::BROWSER);
863   NiceMock<MockClientProcess> client_process_2(this, kRendererPid,
864                                                mojom::ProcessType::RENDERER);
865   NiceMock<MockClientProcess> client_process_3(this, kGpuPid,
866                                                mojom::ProcessType::GPU);
867 
868 // This ifdef is here to match the sandboxing behavior of the client.
869 // On Linux, all memory dumps come from the browser client. On all other
870 // platforms, they are expected to come from each individual client.
871 #if defined(OS_LINUX)
872   EXPECT_CALL(client_process_1, RequestOSMemoryDumpMock(_, _, _))
873       .WillOnce(Invoke(
874           [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
875              MockClientProcess::RequestOSMemoryDumpCallback& callback) {
876             base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
877             results[kBrowserPid] = FillRawOSDump(kBrowserPid);
878             std::move(callback).Run(true, std::move(results));
879           }))
880       .WillOnce(Invoke(
881           [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
882              MockClientProcess::RequestOSMemoryDumpCallback& callback) {
883             base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
884             results[kRendererPid] = FillRawOSDump(kRendererPid);
885             std::move(callback).Run(true, std::move(results));
886           }))
887       .WillOnce(Invoke(
888           [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
889              MockClientProcess::RequestOSMemoryDumpCallback& callback) {
890             base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
891             results[kGpuPid] = FillRawOSDump(kGpuPid);
892             std::move(callback).Run(true, std::move(results));
893           }));
894 #else
895   EXPECT_CALL(client_process_1, RequestOSMemoryDumpMock(_, Contains(0), _))
896       .WillOnce(Invoke(
897           [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
898              MockClientProcess::RequestOSMemoryDumpCallback& callback) {
899             base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
900             results[0] = FillRawOSDump(kBrowserPid);
901             std::move(callback).Run(true, std::move(results));
902           }));
903   EXPECT_CALL(client_process_2, RequestOSMemoryDumpMock(_, Contains(0), _))
904       .WillOnce(Invoke(
905           [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
906              MockClientProcess::RequestOSMemoryDumpCallback& callback) {
907             base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
908             results[0] = FillRawOSDump(kRendererPid);
909             std::move(callback).Run(true, std::move(results));
910           }));
911   EXPECT_CALL(client_process_3, RequestOSMemoryDumpMock(_, Contains(0), _))
912       .WillOnce(Invoke(
913           [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
914              MockClientProcess::RequestOSMemoryDumpCallback& callback) {
915             base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
916             results[0] = FillRawOSDump(kGpuPid);
917             std::move(callback).Run(true, std::move(results));
918           }));
919 #endif  // defined(OS_LINUX)
920 
921   base::RunLoop run_loop;
922 
923   MockGlobalMemoryDumpCallback callback;
924   EXPECT_CALL(callback, OnCall(true, Ne(nullptr)))
925       .WillOnce(Invoke([](bool success, GlobalMemoryDump* global_dump) {
926         EXPECT_EQ(1U, global_dump->process_dumps.size());
927         EXPECT_EQ(global_dump->process_dumps[0]->pid, kBrowserPid);
928       }))
929       .WillOnce(Invoke([](bool success, GlobalMemoryDump* global_dump) {
930         EXPECT_EQ(1U, global_dump->process_dumps.size());
931         EXPECT_EQ(global_dump->process_dumps[0]->pid, kRendererPid);
932       }))
933       .WillOnce(
934           Invoke([&run_loop](bool success, GlobalMemoryDump* global_dump) {
935             EXPECT_EQ(1U, global_dump->process_dumps.size());
936             EXPECT_EQ(global_dump->process_dumps[0]->pid, kGpuPid);
937             run_loop.Quit();
938           }));
939 
940   RequestGlobalMemoryDumpForPid(kBrowserPid, {}, callback.Get());
941   RequestGlobalMemoryDumpForPid(kRendererPid, {}, callback.Get());
942   RequestGlobalMemoryDumpForPid(kGpuPid, {}, callback.Get());
943   run_loop.Run();
944 }
945 
TEST_F(CoordinatorImplTest,DumpByPidFailure)946 TEST_F(CoordinatorImplTest, DumpByPidFailure) {
947   NiceMock<MockClientProcess> client_process_1(this, 1,
948                                                mojom::ProcessType::BROWSER);
949 
950   base::RunLoop run_loop;
951 
952   MockGlobalMemoryDumpCallback callback;
953   EXPECT_CALL(callback, OnCall(false, nullptr))
954       .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
955 
956   RequestGlobalMemoryDumpForPid(2, {}, callback.Get());
957   run_loop.Run();
958 }
959 
960 }  // namespace memory_instrumentation
961