1-- 2-- Copyright 2019 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-- 16DROP VIEW IF EXISTS battery_view; 17CREATE VIEW battery_view AS 18SELECT 19 all_ts.ts as ts, 20 current_avg_ua, 21 capacity_percent, 22 charge_uah, 23 current_ua 24FROM ( 25 SELECT distinct(ts) AS ts 26 FROM counter c 27 JOIN counter_track t on c.track_id = t.id 28 WHERE name LIKE 'batt.%' 29) AS all_ts 30LEFT JOIN ( 31 SELECT ts, value AS current_avg_ua 32 FROM counter c 33 JOIN counter_track t on c.track_id = t.id 34 WHERE name='batt.current.avg_ua' 35) USING(ts) 36LEFT JOIN ( 37 SELECT ts, value AS capacity_percent 38 FROM counter c 39 JOIN counter_track t on c.track_id = t.id 40 WHERE name='batt.capacity_pct' 41) USING(ts) 42LEFT JOIN ( 43 SELECT ts, value AS charge_uah 44 FROM counter c 45 JOIN counter_track t on c.track_id = t.id 46 WHERE name='batt.charge_uah' 47) USING(ts) 48LEFT JOIN ( 49 SELECT ts, value AS current_ua 50 FROM counter c 51 JOIN counter_track t on c.track_id = t.id 52 WHERE name='batt.current_ua' 53) USING(ts) 54ORDER BY ts; 55 56DROP TABLE IF EXISTS android_batt_wakelocks_merged; 57CREATE TABLE android_batt_wakelocks_merged AS 58SELECT 59 MIN(ts) AS ts, 60 MAX(ts_end) AS ts_end 61FROM ( 62 SELECT 63 *, 64 SUM(new_group) OVER (ORDER BY ts) AS group_id 65 FROM ( 66 SELECT 67 ts, 68 ts + dur AS ts_end, 69 -- There is a new group if there was a gap before this wakelock. 70 -- i.e. the max end timestamp of all preceding wakelocks is before 71 -- the start timestamp of this one. 72 -- The null check is for the first row which is always a new group. 73 IFNULL( 74 MAX(ts + dur) OVER ( 75 ORDER BY ts 76 ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING 77 ) < ts, 78 true 79 ) AS new_group 80 FROM slice 81 WHERE slice.name LIKE 'WakeLock %' AND dur != -1 82 ) 83) 84GROUP BY group_id; 85 86-- Different device kernels log different actions when suspending. This table 87-- tells us the action that straddles the actual suspend period. 88DROP TABLE IF EXISTS device_action_mapping; 89CREATE TABLE device_action_mapping (device TEXT, action TEXT); 90INSERT INTO device_action_mapping VALUES 91('blueline', 'timekeeping_freeze'), 92('crosshatch', 'timekeeping_freeze'), 93('bonito', 'timekeeping_freeze'), 94('sargo', 'timekeeping_freeze'), 95('coral', 'timekeeping_freeze'), 96('flame', 'timekeeping_freeze'), 97('sunfish', 'timekeeping_freeze'), 98('redfin', 'syscore_resume'), 99('bramble', 'syscore_resume'); 100 101DROP TABLE IF EXISTS device_action; 102CREATE TABLE device_action AS 103SELECT action 104FROM device_action_mapping dam 105WHERE EXISTS ( 106 SELECT 1 FROM metadata 107 WHERE name = 'android_build_fingerprint' AND str_value LIKE '%' || dam.device || '%'); 108 109DROP TABLE IF EXISTS suspend_slice_; 110CREATE TABLE suspend_slice_ AS 111-- Traces from after b/70292203 was fixed have the action string so just look 112-- for it. 113SELECT 114 ts, 115 dur, 116 true as trustworthy 117FROM ( 118 SELECT 119 ts, 120 LEAD(ts) OVER (ORDER BY ts, start DESC) - ts AS dur, 121 start 122 FROM ( 123 SELECT 124 ts, 125 EXTRACT_ARG(arg_set_id, 'action') AS action, 126 EXTRACT_ARG(arg_set_id, 'start') AS start 127 FROM raw 128 WHERE name = 'suspend_resume' 129 ) JOIN device_action USING(action) 130) 131WHERE start = 1 132UNION ALL 133-- Traces from before b/70292203 was fixed (approx Nov 2020) do not have the 134-- action string so we do some convoluted pattern matching that mostly works. 135-- TODO(simonmacm) remove this when enough time has passed (mid 2021?) 136SELECT 137 ts, 138 dur, 139 false as trustworthy 140FROM ( 141 SELECT 142 ts, 143 ts - lag(ts) OVER w AS lag_dur, 144 lead(ts) OVER w - ts AS dur, 145 action, 146 start, 147 event, 148 lag(start) OVER w AS lag_start, 149 lag(event) OVER w AS lag_event, 150 lag(start, 2) OVER w AS lag_2_start, 151 lag(event, 2) OVER w AS lag_2_event, 152 lead(start) OVER w AS lead_start, 153 lead(event) OVER w AS lead_event, 154 lead(start, 2) OVER w AS lead_2_start, 155 lead(event, 2) OVER w AS lead_2_event 156 FROM ( 157 SELECT 158 ts, 159 EXTRACT_ARG(arg_set_id, 'action') AS action, 160 EXTRACT_ARG(arg_set_id, 'start') AS start, 161 EXTRACT_ARG(arg_set_id, 'val') AS event 162 FROM raw 163 WHERE name = 'suspend_resume' 164 ) 165 WINDOW w AS (ORDER BY ts) 166) 167WHERE action IS NULL AND ( 168-- We want to find the start and end events with action='timekeeping_freeze'. 169-- In practice, these events often show up in a sequence like the following: 170-- start = 1, event = 1 [string would have been 'machine_suspend'] 171-- start = 1, event = (any) [string would have been 'timekeeping_freeze'] * 172-- 173-- (sleep happens here) 174-- 175-- start = 0, event = (any) [string would have been 'timekeeping_freeze'] 176-- start = 0, event = 1 [string would have been 'machine_suspend'] 177-- 178-- So we look for this pattern of start and event, anchored on the event marked 179-- with "*". 180 ( 181 lag_start = 1 AND lag_event = 1 182 AND start = 1 183 AND lead_start = 0 184 AND lead_2_start = 0 AND lead_2_event = 1 185 ) 186-- Or in newer kernels we seem to have a very different pattern. We can take 187-- advantage of that fact that we get several events with identical timestamp 188-- just before sleeping (normally this never happens): 189-- gap = 0, start = 1, event = 3 190-- gap = 0, start = 0, event = 3 191-- gap = 0, start = 1, event = 0 192-- 193-- (sleep happens here) 194-- 195-- gap = (any), start = 0, event = 0 196 OR ( 197 lag_dur = 0 198 AND lead_start = 0 AND lead_event = 0 199 AND start = 1 AND event = 0 200 AND lag_start = 0 AND lag_event = 3 201 AND lag_2_start = 1 AND lag_2_event = 3 202 ) 203); 204 205DROP TABLE device_action_mapping; 206DROP TABLE device_action; 207 208SELECT RUN_METRIC('android/global_counter_span_view.sql', 209 'table_name', 'screen_state', 210 'counter_name', 'ScreenState'); 211 212DROP TABLE IF EXISTS screen_state_span_with_suspend; 213CREATE VIRTUAL TABLE screen_state_span_with_suspend 214 USING span_join(screen_state_span, suspend_slice_); 215 216DROP VIEW IF EXISTS android_batt_event; 217CREATE VIEW android_batt_event AS 218SELECT 219 ts, 220 dur, 221 'Suspended' AS slice_name, 222 'Suspend / resume' AS track_name, 223 'slice' AS track_type 224FROM suspend_slice_; 225 226DROP VIEW IF EXISTS android_batt_output; 227CREATE VIEW android_batt_output AS 228SELECT AndroidBatteryMetric( 229 'battery_counters', ( 230 SELECT RepeatedField( 231 AndroidBatteryMetric_BatteryCounters( 232 'timestamp_ns', ts, 233 'charge_counter_uah', charge_uah, 234 'capacity_percent', capacity_percent, 235 'current_ua', current_ua, 236 'current_avg_ua', current_avg_ua 237 ) 238 ) 239 FROM battery_view 240 ), 241 'battery_aggregates', ( 242 SELECT NULL_IF_EMPTY(AndroidBatteryMetric_BatteryAggregates( 243 'total_screen_off_ns', 244 SUM(CASE WHEN state = 1.0 AND tbl = 'total' THEN dur ELSE 0 END), 245 'total_screen_on_ns', 246 SUM(CASE WHEN state = 2.0 AND tbl = 'total' THEN dur ELSE 0 END), 247 'total_screen_doze_ns', 248 SUM(CASE WHEN state = 3.0 AND tbl = 'total' THEN dur ELSE 0 END), 249 'sleep_ns', 250 (SELECT SUM(dur) FROM suspend_slice_), 251 'sleep_screen_off_ns', 252 SUM(CASE WHEN state = 1.0 AND tbl = 'sleep' THEN dur ELSE 0 END), 253 'sleep_screen_on_ns', 254 SUM(CASE WHEN state = 2.0 AND tbl = 'sleep' THEN dur ELSE 0 END), 255 'sleep_screen_doze_ns', 256 SUM(CASE WHEN state = 3.0 AND tbl = 'sleep' THEN dur ELSE 0 END), 257 'total_wakelock_ns', 258 (SELECT SUM(ts_end - ts) FROM android_batt_wakelocks_merged) 259 )) 260 FROM ( 261 SELECT dur, screen_state_val AS state, 'total' AS tbl 262 FROM screen_state_span 263 UNION ALL 264 SELECT dur, screen_state_val AS state, 'sleep' AS tbl 265 FROM screen_state_span_with_suspend 266 ) 267 ), 268 'suspend_period', ( 269 SELECT RepeatedField( 270 AndroidBatteryMetric_SuspendPeriod( 271 'timestamp_ns', ts, 272 'duration_ns', dur 273 ) 274 ) 275 FROM suspend_slice_ 276 WHERE trustworthy 277 ) 278); 279