1#!/usr/bin/env python 2# 3# Copyright (C) 2018 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17"""Tests for the native_heapdump_viewer script.""" 18 19import native_heapdump_viewer 20import os 21import sys 22import tempfile 23import unittest 24 25class NativeHeapdumpViewerTest(unittest.TestCase): 26 _tmp_file_name = None 27 28 def CreateTmpFile(self, contents): 29 fd, self._tmp_file_name = tempfile.mkstemp() 30 os.write(fd, contents.encode()) 31 os.close(fd) 32 return self._tmp_file_name 33 34 def tearDown(self): 35 if self._tmp_file_name: 36 try: 37 os.unlink(self._tmp_file_name) 38 except Exception: 39 print("Failed to delete %s" % (heap)) 40 41class GetNumFieldValidTest(NativeHeapdumpViewerTest): 42 _map_data = """ 43MAPS 441000-10000 r-xp 00000000 fd:00 495 /data/does_not_exist.so 45END 46""" 47 48 _heap_num_field_valid_version10 = """ 49Android Native Heap Dump v1.0 50 51Total memory: 33800 52Allocation records: 13 53Backtrace size: 16 54 55z 1 sz 1000 num 4 bt 1000 2000 3000 56z 1 sz 2000 num 6 bt 1100 2100 3100 57z 0 sz 1200 num 1 bt 1200 2200 3200 58z 0 sz 8300 num 2 bt 1300 2300 3300 59""" 60 61 _heap_num_field_invalid_version10 = """ 62Android Native Heap Dump v1.0 63 64Total memory: 12500 65Allocation records: 4 66Backtrace size: 16 67 68z 1 sz 1000 num 16 bt 1000 2000 3000 69z 1 sz 2000 num 16 bt 1100 2100 3100 70z 0 sz 1200 num 16 bt 1200 2200 3200 71z 0 sz 8300 num 16 bt 1300 2300 3300 72""" 73 74 _heap_data = """ 75 76Total memory: 200000 77Allocation records: 64 78Backtrace size: 16 79 80z 1 sz 1000 num 16 bt 1000 2000 3000 81z 1 sz 2000 num 16 bt 1100 2100 3100 82z 0 sz 1200 num 16 bt 1200 2200 3200 83z 0 sz 8300 num 16 bt 1300 2300 3300 84""" 85 86 def test_version10_valid(self): 87 heap = self.CreateTmpFile(self._heap_num_field_valid_version10 + self._map_data) 88 self.assertTrue(native_heapdump_viewer.GetNumFieldValid(heap)) 89 90 def test_version10_invalid(self): 91 heap = self.CreateTmpFile(self._heap_num_field_invalid_version10 + self._map_data) 92 self.assertFalse(native_heapdump_viewer.GetNumFieldValid(heap)) 93 94 def test_version11_valid(self): 95 heap = self.CreateTmpFile("Android Native Heap Dump v1.1" + self._heap_data + self._map_data) 96 self.assertTrue(native_heapdump_viewer.GetNumFieldValid(heap)) 97 98 def test_version12_valid(self): 99 heap = self.CreateTmpFile("Android Native Heap Dump v1.2" + self._heap_data + self._map_data) 100 self.assertTrue(native_heapdump_viewer.GetNumFieldValid(heap)) 101 102class ParseNativeHeapTest(NativeHeapdumpViewerTest): 103 _backtrace_data = """ 104z 1 sz 1000 num 4 bt 1000 2000 3000 105z 0 sz 8300 num 5 bt 1300 2300 3300 106""" 107 108 109 def test_backtrace_num_field_valid(self): 110 heap = self.CreateTmpFile(self._backtrace_data) 111 backtraces, mapppings = native_heapdump_viewer.ParseNativeHeap(heap, False, True, "") 112 self.assertTrue(backtraces) 113 self.assertEqual(2, len(backtraces)) 114 115 self.assertFalse(backtraces[0].is_zygote) 116 self.assertEqual(1000, backtraces[0].size) 117 self.assertEqual(4, backtraces[0].num_allocs) 118 self.assertEqual([0x1000, 0x2000, 0x3000], backtraces[0].frames) 119 120 self.assertTrue(backtraces[1].is_zygote) 121 self.assertEqual(8300, backtraces[1].size) 122 self.assertEqual(5, backtraces[1].num_allocs) 123 self.assertEqual([0x1300, 0x2300, 0x3300], backtraces[1].frames) 124 125 def test_backtrace_num_field_invalid(self): 126 heap = self.CreateTmpFile(self._backtrace_data) 127 backtraces, mapppings = native_heapdump_viewer.ParseNativeHeap(heap, False, False, "") 128 self.assertTrue(backtraces) 129 self.assertEqual(2, len(backtraces)) 130 131 self.assertFalse(backtraces[0].is_zygote) 132 self.assertEqual(1000, backtraces[0].size) 133 self.assertEqual(1, backtraces[0].num_allocs) 134 self.assertEqual([0x1000, 0x2000, 0x3000], backtraces[0].frames) 135 136 self.assertTrue(backtraces[1].is_zygote) 137 self.assertEqual(8300, backtraces[1].size) 138 self.assertEqual(1, backtraces[1].num_allocs) 139 self.assertEqual([0x1300, 0x2300, 0x3300], backtraces[1].frames) 140 141 def test_backtrace_reverse_field_valid(self): 142 heap = self.CreateTmpFile(self._backtrace_data) 143 backtraces, mapppings = native_heapdump_viewer.ParseNativeHeap(heap, True, True, "") 144 self.assertTrue(backtraces) 145 self.assertEqual(2, len(backtraces)) 146 147 self.assertFalse(backtraces[0].is_zygote) 148 self.assertEqual(1000, backtraces[0].size) 149 self.assertEqual(4, backtraces[0].num_allocs) 150 self.assertEqual([0x3000, 0x2000, 0x1000], backtraces[0].frames) 151 152 self.assertTrue(backtraces[1].is_zygote) 153 self.assertEqual(8300, backtraces[1].size) 154 self.assertEqual(5, backtraces[1].num_allocs) 155 self.assertEqual([0x3300, 0x2300, 0x1300], backtraces[1].frames) 156 157 def test_mappings(self): 158 map_data = """ 159MAPS 1601000-4000 r-xp 00000000 fd:00 495 /system/lib64/libc.so 1616000-8000 r-xp 00000000 fd:00 495 162a000-f000 r-xp 0000b000 fd:00 495 /system/lib64/libutils.so 163END 164""" 165 166 heap = self.CreateTmpFile(map_data) 167 backtraces, mappings = native_heapdump_viewer.ParseNativeHeap(heap, True, True, "") 168 169 self.assertTrue(mappings) 170 self.assertEqual(2, len(mappings)) 171 172 self.assertEqual(0x1000, mappings[0].start) 173 self.assertEqual(0x4000, mappings[0].end) 174 self.assertEqual(0, mappings[0].offset) 175 self.assertEqual("/system/lib64/libc.so", mappings[0].name) 176 177 self.assertEqual(0xa000, mappings[1].start) 178 self.assertEqual(0xf000, mappings[1].end) 179 self.assertEqual(0xb000, mappings[1].offset) 180 self.assertEqual("/system/lib64/libutils.so", mappings[1].name) 181 182if __name__ == '__main__': 183 unittest.main(verbosity=2) 184