1// Copyright (C) 2024 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 15import m from 'mithril'; 16import {LONG, NUM, STR} from '../../trace_processor/query_result'; 17import {Trace} from '../../public/trace'; 18import {DatasetSliceTrack} from '../../components/tracks/dataset_slice_track'; 19import {SourceDataset} from '../../trace_processor/dataset'; 20import {makeColorScheme} from '../../components/colorizer'; 21import {HSLColor} from '../../base/color'; 22import {Section} from '../../widgets/section'; 23import {Tree, TreeNode} from '../../widgets/tree'; 24import {Timestamp} from '../../components/widgets/timestamp'; 25import {Time} from '../../base/time'; 26import {DetailsShell} from '../../widgets/details_shell'; 27import {GridLayout, GridLayoutColumn} from '../../widgets/grid_layout'; 28import {Spinner} from '../../widgets/spinner'; 29 30const DEPTH_TO_COLOR = [ 31 makeColorScheme(new HSLColor({h: 122, s: 39, l: 49})), 32 makeColorScheme(new HSLColor({h: 0, s: 0, l: 70})), 33 makeColorScheme(new HSLColor({h: 45, s: 100, l: 51})), 34 makeColorScheme(new HSLColor({h: 4, s: 90, l: 58})), 35 makeColorScheme(new HSLColor({h: 291, s: 64, l: 42})), 36]; 37 38const EVT_PX = 6; // Width of an event tick in pixels. 39 40export function createAndroidLogTrack(trace: Trace, uri: string) { 41 return new DatasetSliceTrack({ 42 trace, 43 uri, 44 rootTableName: 'android_logs', 45 dataset: new SourceDataset({ 46 src: ` 47 select 48 id, 49 ts, 50 prio, 51 utid, 52 tag, 53 CASE 54 WHEN prio <= 3 THEN 0 55 WHEN prio = 4 THEN 1 56 WHEN prio = 5 THEN 2 57 WHEN prio = 6 THEN 3 58 WHEN prio = 7 THEN 4 59 ELSE -1 60 END as depth 61 from android_logs 62 order by ts 63 -- android_logs aren't guaranteed to be ordered by ts, but this is a 64 -- requirements for DatasetSliceTrack's mipmap operator to work 65 -- correctly, so we must explicitly sort them above. 66 `, 67 schema: { 68 id: NUM, 69 ts: LONG, 70 prio: NUM, 71 utid: NUM, 72 depth: NUM, 73 tag: STR, 74 }, 75 }), 76 initialMaxDepth: 4, 77 colorizer: (row) => DEPTH_TO_COLOR[row.depth], 78 // It would be nice to show the message on the tooltip too, but loading a 79 // message for each event may balloon memory, so we just show the tag. 80 tooltip: (row) => [row.tag], 81 // All log events are instant events, render them as a little box rather 82 // than the default chevron. 83 instantStyle: { 84 width: EVT_PX, 85 render: (ctx, r) => ctx.fillRect(r.x, r.y, r.width, r.height), 86 }, 87 // Make rows a little more compact. 88 sliceLayout: { 89 padding: 2, 90 sliceHeight: 7, 91 }, 92 detailsPanel: (row) => { 93 // The msg is initially undefined, it'll be filled in when it loads 94 let msg: string | undefined; 95 96 // Quickly load the log message 97 trace.engine 98 .query(`select msg from android_logs where id = ${row.id}`) 99 .then((result) => { 100 const resultRow = result.maybeFirstRow({msg: STR}); 101 msg = resultRow?.msg; 102 }); 103 104 return { 105 render() { 106 return m( 107 DetailsShell, 108 { 109 title: `Android Log`, 110 }, 111 m( 112 GridLayout, 113 m( 114 GridLayoutColumn, 115 m( 116 Section, 117 {title: 'Details'}, 118 m( 119 Tree, 120 m(TreeNode, { 121 left: 'ID', 122 right: row.id, 123 }), 124 m(TreeNode, { 125 left: 'Timestamp', 126 right: m(Timestamp, {ts: Time.fromRaw(row.ts)}), 127 }), 128 m(TreeNode, { 129 left: 'Priority', 130 right: row.prio, 131 }), 132 m(TreeNode, { 133 left: 'Tag', 134 right: row.tag, 135 }), 136 m(TreeNode, { 137 left: 'Utid', 138 right: row.utid, 139 }), 140 m(TreeNode, { 141 left: 'Message', 142 right: msg ? msg : m(Spinner), 143 }), 144 ), 145 ), 146 ), 147 ), 148 ); 149 }, 150 }; 151 }, 152 }); 153} 154