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 16SELECT IMPORT('common.slices'); 17SELECT IMPORT('android.process_metadata'); 18 19-- All activity startup events. 20CREATE TABLE internal_startup_events AS 21SELECT 22 ts, 23 dur, 24 ts + dur AS ts_end, 25 STR_SPLIT(s.name, ": ", 1) AS package_name 26FROM slice s 27JOIN process_track t ON s.track_id = t.id 28JOIN process USING(upid) 29WHERE 30 s.name GLOB 'launching: *' 31 AND (process.name IS NULL OR process.name = 'system_server'); 32 33-- Gather all startup data. Populate by different sdks. 34CREATE TABLE internal_all_startups( 35 sdk STRING, 36 startup_id INTEGER BIGINT, 37 ts BIGINT, 38 ts_end BIGINT, 39 dur BIGINT, 40 package STRING, 41 startup_type STRING 42); 43 44SELECT IMPORT('android.startup.internal_startups_maxsdk28'); 45SELECT IMPORT('android.startup.internal_startups_minsdk29'); 46SELECT IMPORT('android.startup.internal_startups_minsdk33'); 47 48-- All activity startups in the trace by startup id. 49-- Populated by different scripts depending on the platform version/contents. 50-- 51-- @column id Startup id. 52-- @column ts Timestamp of startup start. 53-- @column ts_end Timestamp of startup end. 54-- @column dur Startup duration. 55-- @column package Package name. 56-- @column startup_type Startup type. 57CREATE TABLE android_startups AS 58SELECT startup_id, ts, ts_end, dur, package, startup_type FROM 59internal_all_startups WHERE ( CASE 60 WHEN SLICE_COUNT('launchingActivity#*:*') > 0 61 THEN sdk = "minsdk33" 62 WHEN SLICE_COUNT('MetricsLogger:*') > 0 63 THEN sdk = "minsdk29" 64 ELSE sdk = "maxsdk28" 65 END); 66 67-- 68-- Create startup processes 69-- 70 71-- Create a table containing only the slices which are necessary for determining 72-- whether a startup happened. 73CREATE TABLE internal_startup_indicator_slices AS 74SELECT ts, name, track_id 75FROM slice 76WHERE name IN ('bindApplication', 'activityStart', 'activityResume'); 77 78SELECT CREATE_FUNCTION( 79 'INTERNAL_STARTUP_INDICATOR_SLICE_COUNT(start_ts LONG, end_ts LONG, utid INT, name STRING)', 80 'INT', 81 ' 82 SELECT COUNT(1) 83 FROM thread_track t 84 JOIN internal_startup_indicator_slices s ON s.track_id = t.id 85 WHERE 86 t.utid = $utid AND 87 s.ts >= $start_ts AND 88 s.ts < $end_ts AND 89 s.name = $name 90 ' 91); 92 93-- Maps a startup to the set of processes that handled the activity start. 94-- 95-- The vast majority of cases should be a single process. However it is 96-- possible that the process dies during the activity startup and is respawned. 97-- 98-- @column startup_id Startup id. 99-- @column upid Upid of process on which activity started. 100-- @column startup_type Type of the startup. 101CREATE TABLE android_startup_processes AS 102-- This is intentionally a materialized query. For some reason, if we don't 103-- materialize, we end up with a query which is an order of magnitude slower :( 104WITH startup_with_type AS MATERIALIZED ( 105 SELECT 106 startup_id, 107 upid, 108 CASE 109 -- type parsed from platform event takes precedence if available 110 WHEN startup_type IS NOT NULL THEN startup_type 111 WHEN bind_app > 0 AND a_start > 0 AND a_resume > 0 THEN 'cold' 112 WHEN a_start > 0 AND a_resume > 0 THEN 'warm' 113 WHEN a_resume > 0 THEN 'hot' 114 ELSE NULL 115 END AS startup_type 116 FROM ( 117 SELECT 118 l.startup_id, 119 l.startup_type, 120 p.upid, 121 INTERNAL_STARTUP_INDICATOR_SLICE_COUNT(l.ts, l.ts_end, t.utid, 'bindApplication') AS bind_app, 122 INTERNAL_STARTUP_INDICATOR_SLICE_COUNT(l.ts, l.ts_end, t.utid, 'activityStart') AS a_start, 123 INTERNAL_STARTUP_INDICATOR_SLICE_COUNT(l.ts, l.ts_end, t.utid, 'activityResume') AS a_resume 124 FROM android_startups l 125 JOIN android_process_metadata p ON ( 126 l.package = p.package_name 127 -- If the package list data source was not enabled in the trace, nothing 128 -- will match the above constraint so also match any process whose name 129 -- is a prefix of the package name. 130 OR ( 131 (SELECT COUNT(1) = 0 FROM package_list) 132 AND p.process_name GLOB l.package || '*' 133 ) 134 ) 135 JOIN thread t ON (p.upid = t.upid AND t.is_main_thread) 136 ) 137) 138SELECT * 139FROM startup_with_type 140WHERE startup_type IS NOT NULL; 141 142 143-- Maps a startup to the set of threads on processes that handled the 144-- activity start. 145-- 146-- @column startup_id Startup id. 147-- @column ts Timestamp of start. 148-- @column dur Duration of startup. 149-- @column upid Upid of process involved in startup. 150-- @column utid Utid of the thread. 151-- @column thread_name Name of the thread. 152-- @column is_main_thread Thread is a main thread. 153CREATE VIEW android_startup_threads AS 154SELECT 155 startups.startup_id, 156 startups.ts, 157 startups.dur, 158 android_startup_processes.upid, 159 thread.utid, 160 thread.name AS thread_name, 161 thread.is_main_thread AS is_main_thread 162FROM android_startups startups 163JOIN android_startup_processes USING (startup_id) 164JOIN thread USING (upid); 165 166--- 167--- Functions 168--- 169 170-- All the slices for all startups in trace. 171-- 172-- Generally, this view should not be used. Instead, use one of the view functions related 173-- to the startup slices which are created from this table. 174-- 175-- @column startup_ts Timestamp of startup. 176-- @column startup_ts_end Timestamp of startup end. 177-- @column startup_id Startup id. 178-- @column utid UTID of thread with slice. 179-- @column thread_name Name of thread. 180-- @column is_main_thread Whether it is main thread. 181-- @column arg_set_id Arg set id. 182-- @column slice_id Slice id. 183-- @column slice_name Name of slice. 184-- @column slice_ts Timestamp of slice start. 185-- @column slice_dur Slice duration. 186CREATE VIEW android_thread_slices_for_all_startups AS 187SELECT 188 st.ts AS startup_ts, 189 st.ts + st.dur AS startup_ts_end, 190 st.startup_id, 191 st.utid, 192 st.thread_name, 193 st.is_main_thread, 194 slice.arg_set_id, 195 slice.id as slice_id, 196 slice.name AS slice_name, 197 slice.ts AS slice_ts, 198 slice.dur AS slice_dur 199FROM android_startup_threads st 200JOIN thread_track USING (utid) 201JOIN slice ON (slice.track_id = thread_track.id) 202WHERE slice.ts BETWEEN st.ts AND st.ts + st.dur; 203 204-- Given a startup id and GLOB for a slice name, returns matching slices with data. 205-- 206-- @arg startup_id INT Startup id. 207-- @arg slice_name STRING Glob of the slice. 208-- @column slice_name Name of the slice. 209-- @column slice_ts Timestamp of start of the slice. 210-- @column slice_dur Duration of the slice. 211-- @column thread_name Name of the thread with the slice. 212-- @column arg_set_id Arg set id. 213SELECT CREATE_VIEW_FUNCTION( 214 'ANDROID_SLICES_FOR_STARTUP_AND_SLICE_NAME(startup_id INT, slice_name STRING)', 215 'slice_name STRING, slice_ts INT, slice_dur INT, thread_name STRING, arg_set_id INT', 216 ' 217 SELECT slice_name, slice_ts, slice_dur, thread_name, arg_set_id 218 FROM android_thread_slices_for_all_startups 219 WHERE startup_id = $startup_id AND slice_name GLOB $slice_name 220 ' 221); 222 223-- Returns binder transaction slices for a given startup id with duration over threshold. 224-- 225-- @arg startup_id INT Startup id. 226-- @arg threshold DOUBLE Only return slices with duration over threshold. 227-- @column id Slice id. 228-- @column slice_dur Slice duration. 229-- @column thread_name Name of the thread with slice. 230-- @column process Name of the process with slice. 231-- @column arg_set_id Arg set id. 232-- @column is_main_thread Whether is main thread. 233SELECT CREATE_VIEW_FUNCTION( 234 'ANDROID_BINDER_TRANSACTION_SLICES_FOR_STARTUP(startup_id INT, threshold DOUBLE)', 235 'id INT, slice_dur INT, thread_name STRING, process STRING, arg_set_id INT, is_main_thread BOOL', 236 ' 237 SELECT slice_id as id, slice_dur, thread_name, process.name as process, s.arg_set_id, is_main_thread 238 FROM android_thread_slices_for_all_startups s 239 JOIN process ON ( 240 EXTRACT_ARG(s.arg_set_id, "destination process") = process.pid 241 ) 242 WHERE startup_id = $startup_id AND slice_name GLOB "binder transaction" AND slice_dur > $threshold 243 ' 244); 245 246-- Returns duration of startup for slice name. 247-- 248-- Sums duration of all slices of startup with provided name. 249-- 250-- @arg startup_id LONG Startup id. 251-- @arg slice_name STRING Slice name. 252-- @ret INT Sum of duration. 253SELECT CREATE_FUNCTION( 254 'ANDROID_SUM_DUR_FOR_STARTUP_AND_SLICE(startup_id LONG, slice_name STRING)', 255 'INT', 256 ' 257 SELECT SUM(slice_dur) 258 FROM android_thread_slices_for_all_startups 259 WHERE startup_id = $startup_id AND slice_name GLOB $slice_name 260 ' 261); 262 263-- Returns duration of startup for slice name on main thread. 264-- 265-- Sums duration of all slices of startup with provided name only on main thread. 266-- 267-- @arg startup_id LONG Startup id. 268-- @arg slice_name STRING Slice name. 269-- @ret INT Sum of duration. 270SELECT CREATE_FUNCTION( 271 'ANDROID_SUM_DUR_ON_MAIN_THREAD_FOR_STARTUP_AND_SLICE(startup_id LONG, slice_name STRING)', 272 'INT', 273 ' 274 SELECT SUM(slice_dur) 275 FROM android_thread_slices_for_all_startups 276 WHERE startup_id = $startup_id AND slice_name GLOB $slice_name AND is_main_thread 277 ' 278);