1-- 2-- Copyright 2023 The Android Open Source Project 3-- 4-- Licensed under the Apache License, Version 2.0 (the "License"); 5-- you may not use this file except in compliance with the License. 6-- You may obtain a copy of the License at 7-- 8-- https://www.apache.org/licenses/LICENSE-2.0 9-- 10-- Unless required by applicable law or agreed to in writing, software 11-- distributed under the License is distributed on an "AS IS" BASIS, 12-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13-- See the License for the specific language governing permissions and 14-- limitations under the License. 15 16-- Converts a battery_stats counter value to human readable string. 17CREATE PERFETTO FUNCTION android_battery_stats_counter_to_string( 18 -- The counter track name (e.g. 'battery_stats.audio'). 19 track STRING, 20 -- The counter value. 21 value DOUBLE 22) 23-- The human-readable name for the counter value. 24RETURNS STRING AS 25SELECT 26 CASE 27 WHEN ( 28 $track = "battery_stats.wifi_scan" 29 OR $track = "battery_stats.wifi_radio" 30 OR $track = "battery_stats.mobile_radio" 31 OR $track = "battery_stats.audio" 32 OR $track = "battery_stats.video" 33 OR $track = "battery_stats.camera" 34 OR $track = "battery_stats.power_save" 35 OR $track = "battery_stats.phone_in_call" 36 ) 37 THEN CASE $value WHEN 0 THEN "inactive" WHEN 1 THEN "active" ELSE "unknown" END 38 WHEN $track = "battery_stats.wifi" 39 THEN CASE $value WHEN 0 THEN "off" WHEN 1 THEN "on" ELSE "unknown" END 40 WHEN $track = "battery_stats.phone_state" 41 THEN CASE $value 42 WHEN 0 43 THEN "in" 44 WHEN 1 45 THEN "out" 46 WHEN 2 47 THEN "emergency" 48 WHEN 3 49 THEN "off" 50 ELSE "unknown" 51 END 52 WHEN ( 53 $track = "battery_stats.phone_signal_strength" 54 OR $track = "battery_stats.wifi_signal_strength" 55 ) 56 THEN CASE $value 57 WHEN 0 58 THEN "0/4" 59 WHEN 1 60 THEN "1/4" 61 WHEN 2 62 THEN "2/4" 63 WHEN 3 64 THEN "3/4" 65 WHEN 4 66 THEN "4/4" 67 ELSE "unknown" 68 END 69 WHEN $track = "battery_stats.wifi_suppl" 70 THEN CASE $value 71 WHEN 0 72 THEN "invalid" 73 WHEN 1 74 THEN "disconnected" 75 WHEN 2 76 THEN "disabled" 77 WHEN 3 78 THEN "inactive" 79 WHEN 4 80 THEN "scanning" 81 WHEN 5 82 THEN "authenticating" 83 WHEN 6 84 THEN "associating" 85 WHEN 7 86 THEN "associated" 87 WHEN 8 88 THEN "4-way-handshake" 89 WHEN 9 90 THEN "group-handshake" 91 WHEN 10 92 THEN "completed" 93 WHEN 11 94 THEN "dormant" 95 WHEN 12 96 THEN "uninitialized" 97 ELSE "unknown" 98 END 99 WHEN $track = "battery_stats.data_conn" 100 THEN CASE $value 101 WHEN 0 102 THEN "Out of service" 103 WHEN 1 104 THEN "2.5G (GPRS)" 105 WHEN 2 106 THEN "2.7G (EDGE)" 107 WHEN 3 108 THEN "3G (UMTS)" 109 WHEN 4 110 THEN "3G (CDMA)" 111 WHEN 5 112 THEN "3G (EVDO Rel 0)" 113 WHEN 6 114 THEN "3G (EVDO Rev A)" 115 WHEN 7 116 THEN "3G (LXRTT)" 117 WHEN 8 118 THEN "3.5G (HSDPA)" 119 WHEN 9 120 THEN "3.5G (HSUPA)" 121 WHEN 10 122 THEN "3.5G (HSPA)" 123 WHEN 11 124 THEN "2G (IDEN)" 125 WHEN 12 126 THEN "3G (EVDO Rev B)" 127 WHEN 13 128 THEN "4G (LTE)" 129 WHEN 14 130 THEN "3.5G (eHRPD)" 131 WHEN 15 132 THEN "3.7G (HSPA+)" 133 WHEN 16 134 THEN "2G (GSM)" 135 WHEN 17 136 THEN "3G (TD SCDMA)" 137 WHEN 18 138 THEN "Wifi calling (IWLAN)" 139 WHEN 19 140 THEN "4.5G (LTE CA)" 141 WHEN 20 142 THEN "5G (NR)" 143 WHEN 21 144 THEN "Emergency calls only" 145 WHEN 22 146 THEN "Other" 147 ELSE "unknown" 148 END 149 ELSE cast_string!($value) 150 END; 151 152-- View of human readable battery stats counter-based states. These are recorded 153-- by BatteryStats as a bitmap where each 'category' has a unique value at any 154-- given time. 155CREATE PERFETTO VIEW android_battery_stats_state ( 156 -- Start of the new barrary state. 157 ts TIMESTAMP, 158 -- The duration the state was active, -1 for incomplete slices. 159 dur DURATION, 160 -- The same as `dur`, but extends to trace end for incomplete slices. 161 safe_dur DURATION, 162 -- The name of the counter track. 163 track_name STRING, 164 -- The counter value as a number. 165 value LONG, 166 -- The counter value as a human-readable string. 167 value_name STRING 168) AS 169SELECT 170 ts, 171 coalesce(lead(ts) OVER (PARTITION BY name ORDER BY ts) - ts, -1) AS dur, 172 lead(ts, 1, trace_end()) OVER (PARTITION BY name ORDER BY ts) - ts AS safe_dur, 173 name AS track_name, 174 cast_int!(value) AS value, 175 android_battery_stats_counter_to_string(name, value) AS value_name 176FROM counter 177JOIN counter_track 178 ON counter.track_id = counter_track.id 179WHERE 180 counter_track.name GLOB 'battery_stats.*'; 181 182-- View of slices derived from battery_stats events. Battery stats records all 183-- events as instants, however some may indicate whether something started or 184-- stopped with a '+' or '-' prefix. Events such as jobs, top apps, foreground 185-- apps or long wakes include these details and allow drawing slices between 186-- instant events found in a trace. 187-- 188-- For example, we may see an event like the following on 'battery_stats.top': 189-- 190-- -top=10215:"com.google.android.apps.nexuslauncher" 191-- 192-- This view will find the associated start ('+top') with the matching suffix 193-- (everything after the '=') to construct a slice. It computes the timestamp 194-- and duration from the events and extract the details as follows: 195-- 196-- track_name='battery_stats.top' 197-- str_value='com.google.android.apps.nexuslauncher' 198-- int_value=10215 199CREATE PERFETTO VIEW android_battery_stats_event_slices ( 200 -- Start of a new battery state. 201 ts TIMESTAMP, 202 -- The duration the state was active, -1 for incomplete slices. 203 dur DURATION, 204 -- The same as `dur`, but extends to trace end for incomplete slices. 205 safe_dur DURATION, 206 -- The name of the counter track. 207 track_name STRING, 208 -- String value. 209 str_value STRING, 210 -- Int value. 211 int_value LONG 212) AS 213WITH 214 event_markers AS ( 215 SELECT 216 ts, 217 track.name AS track_name, 218 str_split(slice.name, '=', 1) AS key, 219 substr(slice.name, 1, 1) = '+' AS start 220 FROM slice 221 JOIN track 222 ON slice.track_id = track.id 223 WHERE 224 track_name GLOB 'battery_stats.*' AND substr(slice.name, 1, 1) IN ('+', '-') 225 ), 226 with_neighbors AS ( 227 SELECT 228 *, 229 lag(ts) OVER (PARTITION BY track_name, key ORDER BY ts) AS last_ts, 230 lead(ts) OVER (PARTITION BY track_name, key ORDER BY ts) AS next_ts 231 FROM event_markers 232 ), 233 -- Note: query performance depends on the ability to push down filters on 234 -- the track_name. It would be more clear below to have two queries and union 235 -- them, but doing so prevents push down through the above window functions. 236 event_spans AS ( 237 SELECT 238 track_name, 239 key, 240 iif(start, ts, trace_start()) AS ts, 241 iif(start, next_ts, ts) AS end_ts 242 FROM with_neighbors 243 -- For the majority of events, we take the `start` event and compute the dur 244 -- based on next_ts. In the off chance we get an end event with no prior 245 -- start (matched by the second half of this where), we can create an event 246 -- starting from the beginning of the trace ending at the current event. 247 WHERE 248 ( 249 start OR last_ts IS NULL 250 ) 251 ) 252SELECT 253 ts, 254 coalesce(end_ts - ts, -1) AS dur, 255 coalesce(end_ts, trace_end()) - ts AS safe_dur, 256 track_name, 257 str_split(key, '"', 1) AS str_value, 258 cast_int!(str_split(key, ':', 0)) AS int_value 259FROM event_spans; 260