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 ×tamp, &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