Skip to content

Commit 278e400

Browse files
committed
ui: Add remaining Ahat heap analysis views
Add allocations, objects, object detail, rooted, bitmap gallery, strings, and search views. Expand query layer with instance detail, field extraction, bitmap pixel decoding, and download helpers. Change-Id: I4d85f0ce2fa65e71e4da6a4a5fbc42b5ec16b413
1 parent 08ad279 commit 278e400

File tree

12 files changed

+2947
-13
lines changed

12 files changed

+2947
-13
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright (C) 2026 The Android Open Source Project
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
export function downloadBlob(name: string, data: Uint8Array): void {
16+
const blob = new Blob([data], {type: 'application/octet-stream'});
17+
const url = URL.createObjectURL(blob);
18+
const a = document.createElement('a');
19+
a.href = url;
20+
a.download = name;
21+
a.click();
22+
URL.revokeObjectURL(url);
23+
}

ui/src/plugins/com.android.Ahat/heap_dump_page.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ import {
2929
} from './nav_state';
3030
import * as queries from './queries';
3131
import OverviewView from './views/overview_view';
32+
import RootedView from './views/rooted_view';
33+
import ObjectView from './views/object_view';
34+
import SearchView from './views/search_view';
35+
import ObjectsView from './views/objects_view';
36+
import BitmapGalleryView from './views/bitmap_gallery_view';
37+
import AllocationsView from './views/allocations_view';
38+
import StringsView from './views/strings_view';
3239

3340
// ─── Content View Router ──────────────────────────────────────────────────────
3441

@@ -40,8 +47,38 @@ function renderContentView(
4047
switch (state.view) {
4148
case 'overview':
4249
return m(OverviewView, {overview, name: 'Heap Dump', navigate});
43-
default:
44-
return m(OverviewView, {overview, name: 'Heap Dump', navigate});
50+
case 'allocations':
51+
return m(AllocationsView, {
52+
engine,
53+
navigate,
54+
heaps: overview.heaps,
55+
params: state.params,
56+
});
57+
case 'rooted':
58+
return m(RootedView, {engine, heaps: overview.heaps, navigate});
59+
case 'object':
60+
return m(ObjectView, {
61+
engine,
62+
heaps: overview.heaps,
63+
navigate,
64+
params: state.params,
65+
});
66+
case 'objects':
67+
return m(ObjectsView, {engine, navigate, params: state.params});
68+
case 'search':
69+
return m(SearchView, {
70+
engine,
71+
navigate,
72+
initialQuery: state.params.q,
73+
});
74+
case 'bitmaps':
75+
return m(BitmapGalleryView, {engine, navigate});
76+
case 'strings':
77+
return m(StringsView, {
78+
engine,
79+
navigate,
80+
initialQuery: state.params.q,
81+
});
4582
}
4683
}
4784

ui/src/plugins/com.android.Ahat/index.ts

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {SidebarManager} from '../../public/sidebar';
2020
import {NUM} from '../../trace_processor/query_result';
2121
import {HeapDumpPage} from './heap_dump_page';
2222
import {nav} from './nav_state';
23+
import {resetBitmapDumpDataCache} from './queries';
2324

2425
let sidebarManager: SidebarManager;
2526

@@ -49,15 +50,41 @@ export default class implements PerfettoPlugin {
4950

5051
HeapDumpPage.engine = ctx.engine;
5152
HeapDumpPage.hasHeapData = true;
53+
resetBitmapDumpDataCache();
5254

53-
ctx.trash.use(
54-
sidebarManager.addMenuItem({
55-
section: 'ahat',
56-
text: 'Overview',
57-
href: '#!/ahat',
58-
icon: 'dashboard',
59-
cssClass: () => (nav.view === 'overview' ? 'ah-sidebar-active' : ''),
60-
}),
61-
);
55+
const viewItems = [
56+
{label: 'Overview', subpage: '', view: 'overview', icon: 'dashboard'},
57+
{
58+
label: 'Allocations',
59+
subpage: 'allocations',
60+
view: 'allocations',
61+
icon: 'bar_chart',
62+
},
63+
{
64+
label: 'Rooted',
65+
subpage: 'rooted',
66+
view: 'rooted',
67+
icon: 'account_tree',
68+
},
69+
{label: 'Bitmaps', subpage: 'bitmaps', view: 'bitmaps', icon: 'image'},
70+
{
71+
label: 'Strings',
72+
subpage: 'strings',
73+
view: 'strings',
74+
icon: 'text_fields',
75+
},
76+
{label: 'Search', subpage: 'search', view: 'search', icon: 'search'},
77+
];
78+
for (const v of viewItems) {
79+
ctx.trash.use(
80+
sidebarManager.addMenuItem({
81+
section: 'ahat',
82+
text: v.label,
83+
href: v.subpage ? `#!/ahat/${v.subpage}` : '#!/ahat',
84+
icon: v.icon,
85+
cssClass: () => (nav.view === v.view ? 'ah-sidebar-active' : ''),
86+
}),
87+
);
88+
}
6289
}
6390
}

0 commit comments

Comments
 (0)