xref: /aosp_15_r20/external/cronet/base/profiler/native_unwinder_android_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/profiler/native_unwinder_android.h"
6 
7 #include <sys/mman.h>
8 
9 #include <inttypes.h>
10 #include <stdio.h>  // For printf address.
11 #include <string.h>
12 #include <algorithm>
13 #include <iterator>
14 #include <vector>
15 
16 #include "base/android/build_info.h"
17 #include "base/android/jni_android.h"
18 #include "base/functional/bind.h"
19 #include "base/memory/raw_ptr.h"
20 #include "base/profiler/native_unwinder_android_map_delegate.h"
21 #include "base/profiler/native_unwinder_android_memory_regions_map_impl.h"
22 #include "base/profiler/register_context.h"
23 #include "base/profiler/stack_buffer.h"
24 #include "base/profiler/stack_copier_signal.h"
25 #include "base/profiler/stack_sampler.h"
26 #include "base/profiler/stack_sampling_profiler_java_test_util.h"
27 #include "base/profiler/stack_sampling_profiler_test_util.h"
28 #include "base/profiler/thread_delegate_posix.h"
29 #include "base/test/bind.h"
30 #include "build/build_config.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32 #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Maps.h"
33 #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Memory.h"
34 
35 extern char __executable_start;
36 
37 namespace base {
38 
39 namespace {
40 
41 // Add a MapInfo with the provided values to |maps|.
AddMapInfo(uint64_t start,uint64_t end,uint64_t offset,uint64_t flags,std::string name,const std::string & binary_build_id,unwindstack::Maps & maps)42 void AddMapInfo(uint64_t start,
43                 uint64_t end,
44                 uint64_t offset,
45                 uint64_t flags,
46                 std::string name,
47                 const std::string& binary_build_id,
48                 unwindstack::Maps& maps) {
49   maps.Add(start, end, offset, flags, name, /* load_bias = */ 0u);
50   unwindstack::MapInfo& map_info = **std::prev(maps.end());
51   map_info.SetBuildID(std::move(name));
52   map_info.set_elf_offset(map_info.offset());
53 }
54 
55 std::unique_ptr<NativeUnwinderAndroidMemoryRegionsMapImpl>
CreateMemoryRegionsMap()56 CreateMemoryRegionsMap() {
57   std::unique_ptr<NativeUnwinderAndroidMemoryRegionsMap> memory_regions_map =
58       NativeUnwinderAndroid::CreateMemoryRegionsMap();
59   std::unique_ptr<NativeUnwinderAndroidMemoryRegionsMapImpl> downcast(
60       static_cast<NativeUnwinderAndroidMemoryRegionsMapImpl*>(
61           memory_regions_map.release()));
62   return downcast;
63 }
64 
65 class NativeUnwinderAndroidMapDelegateForTesting
66     : public NativeUnwinderAndroidMapDelegate {
67  public:
NativeUnwinderAndroidMapDelegateForTesting(std::unique_ptr<NativeUnwinderAndroidMemoryRegionsMapImpl> memory_regions_map)68   explicit NativeUnwinderAndroidMapDelegateForTesting(
69       std::unique_ptr<NativeUnwinderAndroidMemoryRegionsMapImpl>
70           memory_regions_map)
71       : memory_regions_map_(std::move(memory_regions_map)) {}
72 
GetMapReference()73   NativeUnwinderAndroidMemoryRegionsMapImpl* GetMapReference() override {
74     acquire_count_++;
75     return memory_regions_map_.get();
76   }
ReleaseMapReference()77   void ReleaseMapReference() override { release_count_++; }
78 
acquire_count()79   uint32_t acquire_count() { return acquire_count_; }
release_count()80   uint32_t release_count() { return release_count_; }
81 
82  private:
83   const std::unique_ptr<NativeUnwinderAndroidMemoryRegionsMapImpl>
84       memory_regions_map_;
85 
86   uint32_t acquire_count_ = 0u;
87   uint32_t release_count_ = 0u;
88 };
89 
90 }  // namespace
91 
92 class TestStackCopierDelegate : public StackCopier::Delegate {
93  public:
OnStackCopy()94   void OnStackCopy() override {}
95 };
96 
CaptureScenario(UnwindScenario * scenario,ModuleCache * module_cache,OnceCallback<void (RegisterContext *,uintptr_t,std::vector<Frame> *)> unwind_callback)97 std::vector<Frame> CaptureScenario(
98     UnwindScenario* scenario,
99     ModuleCache* module_cache,
100     OnceCallback<void(RegisterContext*, uintptr_t, std::vector<Frame>*)>
101         unwind_callback) {
102   std::vector<Frame> sample;
103   WithTargetThread(
104       scenario,
105       BindLambdaForTesting(
106           [&](SamplingProfilerThreadToken target_thread_token) {
107             auto thread_delegate =
108                 ThreadDelegatePosix::Create(target_thread_token);
109             ASSERT_TRUE(thread_delegate);
110             auto stack_copier =
111                 std::make_unique<StackCopierSignal>(std::move(thread_delegate));
112             std::unique_ptr<StackBuffer> stack_buffer =
113                 StackSampler::CreateStackBuffer();
114 
115             RegisterContext thread_context;
116             uintptr_t stack_top;
117             TimeTicks timestamp;
118             TestStackCopierDelegate delegate;
119             bool success =
120                 stack_copier->CopyStack(stack_buffer.get(), &stack_top,
121                                         &timestamp, &thread_context, &delegate);
122             ASSERT_TRUE(success);
123 
124             sample.emplace_back(
125                 RegisterContextInstructionPointer(&thread_context),
126                 module_cache->GetModuleForAddress(
127                     RegisterContextInstructionPointer(&thread_context)));
128 
129             std::move(unwind_callback).Run(&thread_context, stack_top, &sample);
130           }));
131 
132   return sample;
133 }
134 
135 // TODO(https://crbug.com/1147315): After fix, re-enable on all ASAN bots.
136 #if defined(ADDRESS_SANITIZER)
137 #define MAYBE_PlainFunction DISABLED_PlainFunction
138 #else
139 #define MAYBE_PlainFunction PlainFunction
140 #endif
141 // Checks that the expected information is present in sampled frames.
TEST(NativeUnwinderAndroidTest,MAYBE_PlainFunction)142 TEST(NativeUnwinderAndroidTest, MAYBE_PlainFunction) {
143   const auto sdk_version = base::android::BuildInfo::GetInstance()->sdk_int();
144   if (sdk_version < base::android::SDK_VERSION_NOUGAT) {
145     GTEST_SKIP();
146   }
147 
148   UnwindScenario scenario(BindRepeating(&CallWithPlainFunction));
149   NativeUnwinderAndroidMapDelegateForTesting map_delegate(
150       CreateMemoryRegionsMap());
151 
152   ModuleCache module_cache;
153   auto unwinder = std::make_unique<NativeUnwinderAndroid>(
154       0, &map_delegate, /*is_java_name_hashing_enabled=*/false);
155 
156   unwinder->Initialize(&module_cache);
157   std::vector<Frame> sample =
158       CaptureScenario(&scenario, &module_cache,
159                       BindLambdaForTesting([&](RegisterContext* thread_context,
160                                                uintptr_t stack_top,
161                                                std::vector<Frame>* sample) {
162                         ASSERT_TRUE(unwinder->CanUnwindFrom(sample->back()));
163                         UnwindResult result = unwinder->TryUnwind(
164                             thread_context, stack_top, sample);
165                         EXPECT_EQ(UnwindResult::kCompleted, result);
166                       }));
167 
168   // Check that all the modules are valid.
169   for (const auto& frame : sample)
170     EXPECT_NE(nullptr, frame.module);
171 
172   // The stack should contain a full unwind.
173   ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
174                                scenario.GetSetupFunctionAddressRange(),
175                                scenario.GetOuterFunctionAddressRange()});
176 }
177 
178 // TODO(https://crbug.com/1147315): After fix, re-enable on all ASAN bots.
179 #if defined(ADDRESS_SANITIZER)
180 #define MAYBE_Alloca DISABLED_Alloca
181 #else
182 #define MAYBE_Alloca Alloca
183 #endif
184 // Checks that the unwinder handles stacks containing dynamically-allocated
185 // stack memory.
TEST(NativeUnwinderAndroidTest,MAYBE_Alloca)186 TEST(NativeUnwinderAndroidTest, MAYBE_Alloca) {
187   const auto sdk_version = base::android::BuildInfo::GetInstance()->sdk_int();
188   if (sdk_version < base::android::SDK_VERSION_NOUGAT) {
189     GTEST_SKIP();
190   }
191 
192   UnwindScenario scenario(BindRepeating(&CallWithAlloca));
193 
194   NativeUnwinderAndroidMapDelegateForTesting map_delegate(
195       CreateMemoryRegionsMap());
196 
197   ModuleCache module_cache;
198   auto unwinder = std::make_unique<NativeUnwinderAndroid>(
199       0, &map_delegate, /*is_java_name_hashing_enabled=*/false);
200 
201   unwinder->Initialize(&module_cache);
202   std::vector<Frame> sample =
203       CaptureScenario(&scenario, &module_cache,
204                       BindLambdaForTesting([&](RegisterContext* thread_context,
205                                                uintptr_t stack_top,
206                                                std::vector<Frame>* sample) {
207                         ASSERT_TRUE(unwinder->CanUnwindFrom(sample->back()));
208                         UnwindResult result = unwinder->TryUnwind(
209                             thread_context, stack_top, sample);
210                         EXPECT_EQ(UnwindResult::kCompleted, result);
211                       }));
212 
213   // Check that all the modules are valid.
214   for (const auto& frame : sample)
215     EXPECT_NE(nullptr, frame.module);
216 
217   // The stack should contain a full unwind.
218   ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
219                                scenario.GetSetupFunctionAddressRange(),
220                                scenario.GetOuterFunctionAddressRange()});
221 }
222 
223 // TODO(https://crbug.com/1147315): After fix, re-enable on all ASAN bots.
224 #if defined(ADDRESS_SANITIZER)
225 #define MAYBE_OtherLibrary DISABLED_OtherLibrary
226 #else
227 #define MAYBE_OtherLibrary OtherLibrary
228 #endif
229 // Checks that a stack that runs through another library produces a stack with
230 // the expected functions.
TEST(NativeUnwinderAndroidTest,MAYBE_OtherLibrary)231 TEST(NativeUnwinderAndroidTest, MAYBE_OtherLibrary) {
232   const auto sdk_version = base::android::BuildInfo::GetInstance()->sdk_int();
233   if (sdk_version < base::android::SDK_VERSION_NOUGAT) {
234     GTEST_SKIP();
235   }
236 
237   NativeLibrary other_library = LoadOtherLibrary();
238   UnwindScenario scenario(
239       BindRepeating(&CallThroughOtherLibrary, Unretained(other_library)));
240 
241   NativeUnwinderAndroidMapDelegateForTesting map_delegate(
242       CreateMemoryRegionsMap());
243   ModuleCache module_cache;
244   auto unwinder = std::make_unique<NativeUnwinderAndroid>(
245       0, &map_delegate, /*is_java_name_hashing_enabled=*/false);
246 
247   unwinder->Initialize(&module_cache);
248   std::vector<Frame> sample =
249       CaptureScenario(&scenario, &module_cache,
250                       BindLambdaForTesting([&](RegisterContext* thread_context,
251                                                uintptr_t stack_top,
252                                                std::vector<Frame>* sample) {
253                         ASSERT_TRUE(unwinder->CanUnwindFrom(sample->back()));
254                         UnwindResult result = unwinder->TryUnwind(
255                             thread_context, stack_top, sample);
256                         EXPECT_EQ(UnwindResult::kCompleted, result);
257                       }));
258 
259   // The stack should contain a full unwind.
260   ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
261                                scenario.GetSetupFunctionAddressRange(),
262                                scenario.GetOuterFunctionAddressRange()});
263 }
264 
265 // Check that unwinding is interrupted for excluded modules.
TEST(NativeUnwinderAndroidTest,ExcludeOtherLibrary)266 TEST(NativeUnwinderAndroidTest, ExcludeOtherLibrary) {
267   NativeLibrary other_library = LoadOtherLibrary();
268   UnwindScenario scenario(
269       BindRepeating(&CallThroughOtherLibrary, Unretained(other_library)));
270 
271   NativeUnwinderAndroidMapDelegateForTesting map_delegate(
272       CreateMemoryRegionsMap());
273   ModuleCache module_cache;
274   unwindstack::MapInfo* other_library_map =
275       map_delegate.GetMapReference()
276           ->maps()
277           ->Find(GetAddressInOtherLibrary(other_library))
278           .get();
279   ASSERT_NE(nullptr, other_library_map);
280   auto unwinder = std::make_unique<NativeUnwinderAndroid>(
281       other_library_map->start(), &map_delegate,
282       /*is_java_name_hashing_enabled=*/false);
283   unwinder->Initialize(&module_cache);
284 
285   std::vector<Frame> sample =
286       CaptureScenario(&scenario, &module_cache,
287                       BindLambdaForTesting([&](RegisterContext* thread_context,
288                                                uintptr_t stack_top,
289                                                std::vector<Frame>* sample) {
290                         ASSERT_TRUE(unwinder->CanUnwindFrom(sample->back()));
291                         EXPECT_EQ(UnwindResult::kUnrecognizedFrame,
292                                   unwinder->TryUnwind(thread_context, stack_top,
293                                                       sample));
294                         EXPECT_FALSE(unwinder->CanUnwindFrom(sample->back()));
295                       }));
296 
297   ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange()});
298   ExpectStackDoesNotContain(sample, {scenario.GetSetupFunctionAddressRange(),
299                                      scenario.GetOuterFunctionAddressRange()});
300 }
301 
302 // Check that unwinding can be resumed after an incomplete unwind.
303 #if defined(ADDRESS_SANITIZER)
304 // TODO(https://crbug.com/1147315): Fix, re-enable.
305 #define MAYBE_ResumeUnwinding DISABLED_ResumeUnwinding
306 #else
307 #define MAYBE_ResumeUnwinding ResumeUnwinding
308 #endif
TEST(NativeUnwinderAndroidTest,MAYBE_ResumeUnwinding)309 TEST(NativeUnwinderAndroidTest, MAYBE_ResumeUnwinding) {
310   NativeLibrary other_library = LoadOtherLibrary();
311   UnwindScenario scenario(
312       BindRepeating(&CallThroughOtherLibrary, Unretained(other_library)));
313 
314   NativeUnwinderAndroidMapDelegateForTesting map_delegate(
315       CreateMemoryRegionsMap());
316 
317   // Several unwinders are used to unwind different portion of the stack. Since
318   // only 1 unwinder can be registered as a module provider, each unwinder uses
319   // a distinct ModuleCache. This tests that NativeUnwinderAndroid can pick up
320   // from a state in the middle of the stack. This emulates having
321   // NativeUnwinderAndroid work with other unwinders, but doesn't reproduce what
322   // happens in production.
323   ModuleCache module_cache_for_all;
324   auto unwinder_for_all = std::make_unique<NativeUnwinderAndroid>(
325       0, &map_delegate, /*is_java_name_hashing_enabled=*/false);
326   unwinder_for_all->Initialize(&module_cache_for_all);
327 
328   ModuleCache module_cache_for_native;
329   auto unwinder_for_native = std::make_unique<NativeUnwinderAndroid>(
330       reinterpret_cast<uintptr_t>(&__executable_start), &map_delegate,
331       /*is_java_name_hashing_enabled=*/false);
332   unwinder_for_native->Initialize(&module_cache_for_native);
333 
334   ModuleCache module_cache_for_chrome;
335   unwindstack::MapInfo* other_library_map =
336       map_delegate.GetMapReference()
337           ->maps()
338           ->Find(GetAddressInOtherLibrary(other_library))
339           .get();
340   ASSERT_NE(nullptr, other_library_map);
341   auto unwinder_for_chrome = std::make_unique<NativeUnwinderAndroid>(
342       other_library_map->start(), &map_delegate,
343       /*is_java_name_hashing_enabled=*/false);
344   unwinder_for_chrome->Initialize(&module_cache_for_chrome);
345 
346   std::vector<Frame> sample = CaptureScenario(
347       &scenario, &module_cache_for_native,
348       BindLambdaForTesting([&](RegisterContext* thread_context,
349                                uintptr_t stack_top,
350                                std::vector<Frame>* sample) {
351         // |unwinder_for_native| unwinds through native frames, but stops at
352         // chrome frames. It might not contain SampleAddressRange.
353         ASSERT_TRUE(unwinder_for_native->CanUnwindFrom(sample->back()));
354         EXPECT_EQ(
355             UnwindResult::kUnrecognizedFrame,
356             unwinder_for_native->TryUnwind(thread_context, stack_top, sample));
357         EXPECT_FALSE(unwinder_for_native->CanUnwindFrom(sample->back()));
358 
359         ExpectStackDoesNotContain(*sample,
360                                   {scenario.GetSetupFunctionAddressRange(),
361                                    scenario.GetOuterFunctionAddressRange()});
362         size_t prior_stack_size = sample->size();
363 
364         // |unwinder_for_chrome| unwinds through Chrome frames, but stops at
365         // |other_library|. It won't contain SetupFunctionAddressRange.
366         ASSERT_TRUE(unwinder_for_chrome->CanUnwindFrom(sample->back()));
367         EXPECT_EQ(
368             UnwindResult::kUnrecognizedFrame,
369             unwinder_for_chrome->TryUnwind(thread_context, stack_top, sample));
370         EXPECT_FALSE(unwinder_for_chrome->CanUnwindFrom(sample->back()));
371         EXPECT_LT(prior_stack_size, sample->size());
372         ExpectStackContains(*sample, {scenario.GetWaitForSampleAddressRange()});
373         ExpectStackDoesNotContain(*sample,
374                                   {scenario.GetSetupFunctionAddressRange(),
375                                    scenario.GetOuterFunctionAddressRange()});
376 
377         // |unwinder_for_all| should complete unwinding through all frames.
378         ASSERT_TRUE(unwinder_for_all->CanUnwindFrom(sample->back()));
379         EXPECT_EQ(
380             UnwindResult::kCompleted,
381             unwinder_for_all->TryUnwind(thread_context, stack_top, sample));
382       }));
383 
384   // The stack should contain a full unwind.
385   ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
386                                scenario.GetSetupFunctionAddressRange(),
387                                scenario.GetOuterFunctionAddressRange()});
388 }
389 
390 // Checks that java frames can be unwound through.
TEST(NativeUnwinderAndroidTest,JavaFunction)391 TEST(NativeUnwinderAndroidTest, JavaFunction) {
392   auto* build_info = base::android::BuildInfo::GetInstance();
393   const auto sdk_version = build_info->sdk_int();
394 
395   // Skip this test on anything Android O or earlier, because Java unwinding
396   // fails on these.
397   if (sdk_version <= base::android::SDK_VERSION_OREO) {
398     GTEST_SKIP();
399   }
400 
401   UnwindScenario scenario(base::BindRepeating(callWithJavaFunction));
402 
403   NativeUnwinderAndroidMapDelegateForTesting map_delegate(
404       CreateMemoryRegionsMap());
405 
406   ModuleCache module_cache;
407   auto unwinder = std::make_unique<NativeUnwinderAndroid>(
408       0, &map_delegate, /*is_java_name_hashing_enabled=*/false);
409 
410   unwinder->Initialize(&module_cache);
411   std::vector<Frame> sample =
412       CaptureScenario(&scenario, &module_cache,
413                       BindLambdaForTesting([&](RegisterContext* thread_context,
414                                                uintptr_t stack_top,
415                                                std::vector<Frame>* sample) {
416                         ASSERT_TRUE(unwinder->CanUnwindFrom(sample->back()));
417                         UnwindResult result = unwinder->TryUnwind(
418                             thread_context, stack_top, sample);
419                         EXPECT_EQ(UnwindResult::kCompleted, result);
420                       }));
421 
422   // Check that all the modules are valid.
423   for (const auto& frame : sample)
424     EXPECT_NE(nullptr, frame.module);
425 
426   // The stack should contain a full unwind.
427   ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
428                                scenario.GetSetupFunctionAddressRange(),
429                                scenario.GetOuterFunctionAddressRange()});
430 }
431 
TEST(NativeUnwinderAndroidTest,UnwindStackMemoryTest)432 TEST(NativeUnwinderAndroidTest, UnwindStackMemoryTest) {
433   std::vector<uint8_t> input = {1, 2, 3, 4, 5};
434   uintptr_t begin = reinterpret_cast<uintptr_t>(input.data());
435   uintptr_t end = reinterpret_cast<uintptr_t>(input.data() + input.size());
436   UnwindStackMemoryAndroid memory(begin, end);
437 
438   const auto check_read_fails = [&](uintptr_t addr, size_t size) {
439     std::vector<uint8_t> output(size);
440     EXPECT_EQ(0U, memory.Read(addr, output.data(), size));
441   };
442   const auto check_read_succeeds = [&](uintptr_t addr, size_t size) {
443     std::vector<uint8_t> output(size);
444     EXPECT_EQ(size, memory.Read(addr, output.data(), size));
445     EXPECT_EQ(
446         0, memcmp(reinterpret_cast<const uint8_t*>(addr), output.data(), size));
447   };
448 
449   check_read_fails(begin - 1, 1);
450   check_read_fails(begin - 1, 2);
451   check_read_fails(end, 1);
452   check_read_fails(end, 2);
453   check_read_fails(end - 1, 2);
454 
455   check_read_succeeds(begin, 1);
456   check_read_succeeds(begin, 5);
457   check_read_succeeds(end - 1, 1);
458 }
459 
460 // Checks the debug basename is the whole name for a non-ELF module.
TEST(NativeUnwinderAndroidTest,ModuleDebugBasenameForNonElf)461 TEST(NativeUnwinderAndroidTest, ModuleDebugBasenameForNonElf) {
462   auto maps = std::make_unique<unwindstack::Maps>();
463 
464   AddMapInfo(0x1000u, 0x2000u, 0u, PROT_READ | PROT_EXEC, "[foo / bar]", {0xAA},
465              *maps);
466 
467   ModuleCache module_cache;
468 
469   std::unique_ptr<NativeUnwinderAndroidMemoryRegionsMapImpl>
470       memory_regions_map = CreateMemoryRegionsMap();
471   memory_regions_map->SetMapsForTesting(std::move(maps));
472   NativeUnwinderAndroidMapDelegateForTesting map_delegate(
473       std::move(memory_regions_map));
474   auto unwinder = std::make_unique<NativeUnwinderAndroid>(
475       0, &map_delegate, /*is_java_name_hashing_enabled=*/false);
476   unwinder->Initialize(&module_cache);
477 
478   const ModuleCache::Module* module = module_cache.GetModuleForAddress(0x1000u);
479 
480   ASSERT_TRUE(module);
481   EXPECT_EQ("[foo / bar]", module->GetDebugBasename().value());
482 }
483 
484 // Checks that modules are only created for executable memory regions.
TEST(NativeUnwinderAndroidTest,ModulesCreatedOnlyForExecutableRegions)485 TEST(NativeUnwinderAndroidTest, ModulesCreatedOnlyForExecutableRegions) {
486   auto maps = std::make_unique<unwindstack::Maps>();
487   AddMapInfo(0x1000u, 0x2000u, 0u, PROT_READ | PROT_EXEC, "[a]", {0xAA}, *maps);
488   AddMapInfo(0x2000u, 0x3000u, 0u, PROT_READ, "[b]", {0xAB}, *maps);
489   AddMapInfo(0x3000u, 0x4000u, 0u, PROT_READ | PROT_EXEC, "[c]", {0xAC}, *maps);
490 
491   std::unique_ptr<NativeUnwinderAndroidMemoryRegionsMapImpl>
492       memory_regions_map = CreateMemoryRegionsMap();
493   memory_regions_map->SetMapsForTesting(std::move(maps));
494   NativeUnwinderAndroidMapDelegateForTesting map_delegate(
495       std::move(memory_regions_map));
496   ModuleCache module_cache;
497   auto unwinder = std::make_unique<NativeUnwinderAndroid>(
498       0, &map_delegate, /*is_java_name_hashing_enabled=*/false);
499   unwinder->Initialize(&module_cache);
500 
501   const ModuleCache::Module* module1 =
502       module_cache.GetModuleForAddress(0x1000u);
503   const ModuleCache::Module* module2 =
504       module_cache.GetModuleForAddress(0x2000u);
505   const ModuleCache::Module* module3 =
506       module_cache.GetModuleForAddress(0x3000u);
507 
508   ASSERT_TRUE(module1);
509   EXPECT_EQ(0x1000u, module1->GetBaseAddress());
510   EXPECT_EQ(nullptr, module2);
511   ASSERT_TRUE(module3);
512   EXPECT_EQ(0x3000u, module3->GetBaseAddress());
513 }
514 
TEST(NativeUnwinderAndroidTest,AcquireAndReleaseMemoryRegionsMapThroughMapDelegate)515 TEST(NativeUnwinderAndroidTest,
516      AcquireAndReleaseMemoryRegionsMapThroughMapDelegate) {
517   NativeUnwinderAndroidMapDelegateForTesting map_delegate(
518       CreateMemoryRegionsMap());
519 
520   {
521     ModuleCache module_cache;
522     auto unwinder = std::make_unique<NativeUnwinderAndroid>(
523         0, &map_delegate, /*is_java_name_hashing_enabled=*/false);
524     unwinder->Initialize(&module_cache);
525     EXPECT_EQ(1u, map_delegate.acquire_count());
526     EXPECT_EQ(0u, map_delegate.release_count());
527   }
528 
529   EXPECT_EQ(1u, map_delegate.acquire_count());
530   EXPECT_EQ(1u, map_delegate.release_count());
531 }
532 
533 }  // namespace base
534