1-- 2-- Copyright 2024 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 16INCLUDE PERFETTO MODULE counters.intervals; 17 18INCLUDE PERFETTO MODULE android.battery.charging_states; 19 20INCLUDE PERFETTO MODULE android.screen_state; 21 22INCLUDE PERFETTO MODULE intervals.intersect; 23 24CREATE PERFETTO TABLE _job_states AS 25SELECT 26 t.id AS track_id, 27 s.ts, 28 s.id AS slice_id, 29 extract_arg(arg_set_id, 'scheduled_job_state_changed.job_name') AS job_name, 30 extract_arg(arg_set_id, 'scheduled_job_state_changed.attribution_node[0].uid') AS uid, 31 extract_arg(arg_set_id, 'scheduled_job_state_changed.state') AS state, 32 extract_arg(arg_set_id, 'scheduled_job_state_changed.internal_stop_reason') AS internal_stop_reason, 33 extract_arg(arg_set_id, 'scheduled_job_state_changed.public_stop_reason') AS public_stop_reason, 34 extract_arg(arg_set_id, 'scheduled_job_state_changed.effective_priority') AS effective_priority, 35 extract_arg(arg_set_id, 'scheduled_job_state_changed.has_battery_not_low_constraint') AS has_battery_not_low_constraint, 36 extract_arg(arg_set_id, 'scheduled_job_state_changed.has_charging_constraint') AS has_charging_constraint, 37 extract_arg(arg_set_id, 'scheduled_job_state_changed.has_connectivity_constraint') AS has_connectivity_constraint, 38 extract_arg(arg_set_id, 'scheduled_job_state_changed.has_content_trigger_constraint') AS has_content_trigger_constraint, 39 extract_arg(arg_set_id, 'scheduled_job_state_changed.has_deadline_constraint') AS has_deadline_constraint, 40 extract_arg(arg_set_id, 'scheduled_job_state_changed.has_idle_constraint') AS has_idle_constraint, 41 extract_arg(arg_set_id, 'scheduled_job_state_changed.has_storage_not_low_constraint') AS has_storage_not_low_constraint, 42 extract_arg(arg_set_id, 'scheduled_job_state_changed.has_timing_delay_constraint') AS has_timing_delay_constraint, 43 extract_arg(arg_set_id, 'scheduled_job_state_changed.is_prefetch') = 1 AS is_prefetch, 44 extract_arg(arg_set_id, 'scheduled_job_state_changed.is_requested_expedited_job') AS is_requested_expedited_job, 45 extract_arg(arg_set_id, 'scheduled_job_state_changed.is_running_as_expedited_job') AS is_running_as_expedited_job, 46 extract_arg(arg_set_id, 'scheduled_job_state_changed.job_id') AS job_id, 47 extract_arg(arg_set_id, 'scheduled_job_state_changed.num_previous_attempts') AS num_previous_attempts, 48 extract_arg(arg_set_id, 'scheduled_job_state_changed.requested_priority') AS requested_priority, 49 extract_arg(arg_set_id, 'scheduled_job_state_changed.standby_bucket') AS standby_bucket, 50 extract_arg(arg_set_id, 'scheduled_job_state_changed.is_periodic') AS is_periodic, 51 extract_arg(arg_set_id, 'scheduled_job_state_changed.is_periodic') AS has_flex_constraint, 52 extract_arg(arg_set_id, 'scheduled_job_state_changed.is_requested_as_user_initiated_job') AS is_requested_as_user_initiated_job, 53 extract_arg(arg_set_id, 'scheduled_job_state_changed.is_running_as_user_initiated_job') AS is_running_as_user_initiated_job, 54 extract_arg(arg_set_id, 'scheduled_job_state_changed.deadline_ms') AS deadline_ms, 55 extract_arg(arg_set_id, 'scheduled_job_state_changed.job_start_latency_ms') AS job_start_latency_ms, 56 extract_arg(arg_set_id, 'scheduled_job_state_changed.num_uncompleted_work_items') AS num_uncompleted_work_items, 57 extract_arg(arg_set_id, 'scheduled_job_state_changed.proc_state') AS proc_state 58FROM track AS t 59JOIN slice AS s 60 ON ( 61 s.track_id = t.id 62 ) 63WHERE 64 t.name = 'Statsd Atoms' AND s.name = 'scheduled_job_state_changed'; 65 66CREATE PERFETTO TABLE _job_started AS 67WITH 68 cte AS ( 69 SELECT 70 *, 71 lead(state, 1) OVER (PARTITION BY uid, job_name, job_id ORDER BY uid, job_name, job_id, ts) AS lead_state, 72 lead(ts, 1, trace_end()) OVER (PARTITION BY uid, job_name, job_id ORDER BY uid, job_name, job_id, ts) AS ts_lead, 73 --- Filter out statsd lossy issue. 74 lead(ts, 1) OVER (PARTITION BY uid, job_name, job_id ORDER BY uid, job_name, job_id, ts) IS NULL AS is_end_slice, 75 lead(internal_stop_reason, 1, 'INTERNAL_STOP_REASON_UNKNOWN') OVER (PARTITION BY uid, job_name, job_id ORDER BY uid, job_name, job_id, ts) AS lead_internal_stop_reason, 76 lead(public_stop_reason, 1, 'PUBLIC_STOP_REASON_UNKNOWN') OVER (PARTITION BY uid, job_name, job_id ORDER BY uid, job_name, job_id, ts) AS lead_public_stop_reason 77 FROM _job_states 78 WHERE 79 state != 'CANCELLED' 80 ) 81SELECT 82 -- Job name is based on whether the tag and/or namespace are present: 83 -- 1. Both tag and namespace are present: @<namespace>@<tag>:<package name> 84 -- 2. Only tag is present: <tag>:<package name> 85 -- 3. Only namespace is present: @<namespace>@<package name>/<class name> 86 CASE 87 WHEN substr(job_name, 1, 1) = '@' 88 THEN CASE 89 WHEN substr(str_split(job_name, '/', 1), 1, 3) = 'com' 90 THEN str_split(job_name, '/', 1) 91 ELSE str_split(str_split(job_name, '/', 0), '@', 2) 92 END 93 ELSE str_split(job_name, '/', 0) 94 END AS package_name, 95 CASE 96 WHEN substr(job_name, 1, 1) = '@' 97 THEN str_split(job_name, '@', 1) 98 ELSE str_split(job_name, '/', 1) 99 END AS job_namespace, 100 ts_lead - ts AS dur, 101 iif(lead_state = 'SCHEDULED', TRUE, FALSE) AS is_rescheduled, 102 * 103FROM cte 104WHERE 105 is_end_slice = FALSE 106 AND ( 107 ts_lead - ts 108 ) > 0 109 AND state = 'STARTED' 110 AND lead_state IN ('FINISHED', 'SCHEDULED'); 111 112CREATE PERFETTO TABLE _charging_screen_states AS 113SELECT 114 row_number() OVER () AS id, 115 ii.ts, 116 ii.dur, 117 c.charging_state, 118 s.screen_state 119FROM _interval_intersect!( 120 (android_charging_states, android_screen_state), 121 () 122) AS ii 123JOIN android_charging_states AS c 124 ON c.id = ii.id_0 125JOIN android_screen_state AS s 126 ON s.id = ii.id_1; 127 128-- This table returns constraint changes that a 129-- job will go through in a single trace. 130-- 131-- Values in this table are derived from the the `ScheduledJobStateChanged` 132-- atom. This table differs from the 133-- `android_job_scheduler_with_screen_charging_states` in this module 134-- (`android.job_scheduler_states`) by only having job constraint information. 135-- 136-- See documentation for the `android_job_scheduler_with_screen_charging_states` 137-- for how tables in this module differ from `android_job_scheduler_events` 138-- table in the `android.job_scheduler` module and how to populate this table. 139CREATE PERFETTO TABLE android_job_scheduler_states ( 140 -- Unique identifier for job scheduler state. 141 id ID, 142 -- Timestamp of job state slice. 143 ts TIMESTAMP, 144 -- Duration of job state slice. 145 dur DURATION, 146 -- Id of the slice. 147 slice_id JOINID(slice.id), 148 -- Name of the job (as named by the app). 149 job_name STRING, 150 -- Uid associated with job. 151 uid LONG, 152 -- Id of job (assigned by app for T- builds and system generated in U+ 153 -- builds). 154 job_id LONG, 155 -- Package that the job belongs (ex: associated app). 156 package_name STRING, 157 -- Namespace of job. 158 job_namespace STRING, 159 -- Priority at which JobScheduler ran the job. 160 effective_priority LONG, 161 -- True if app requested job should run when the device battery is not low. 162 has_battery_not_low_constraint BOOL, 163 -- True if app requested job should run when the device is charging. 164 has_charging_constraint BOOL, 165 -- True if app requested job should run when device has connectivity. 166 has_connectivity_constraint BOOL, 167 -- True if app requested job should run when there is a content trigger. 168 has_content_trigger_constraint BOOL, 169 -- True if app requested there is a deadline by which the job should run. 170 has_deadline_constraint BOOL, 171 -- True if app requested job should run when device is idle. 172 has_idle_constraint BOOL, 173 -- True if app requested job should run when device storage is not low. 174 has_storage_not_low_constraint BOOL, 175 -- True if app requested job has a timing delay. 176 has_timing_delay_constraint BOOL, 177 -- True if app requested job should run within hours of app launch. 178 is_prefetch BOOL, 179 -- True if app requested that the job is run as an expedited job. 180 is_requested_expedited_job BOOL, 181 -- The job is run as an expedited job. 182 is_running_as_expedited_job BOOL, 183 -- Number of previous attempts at running job. 184 num_previous_attempts TIMESTAMP, 185 -- The requested priority at which the job should run. 186 requested_priority LONG, 187 -- The job's standby bucket (one of: Active, Working Set, Frequent, Rare, 188 -- Never, Restricted, Exempt). 189 standby_bucket STRING, 190 -- Job should run in intervals. 191 is_periodic BOOL, 192 -- True if the job should run as a flex job. 193 has_flex_constraint BOOL, 194 -- True is app has requested that a job be run as a user initiated job. 195 is_requested_as_user_initiated_job BOOL, 196 -- True if job is running as a user initiated job. 197 is_running_as_user_initiated_job BOOL, 198 -- Deadline that job has requested and valid if has_deadline_constraint is 199 -- true. 200 deadline_ms LONG, 201 -- The latency in ms between when a job is scheduled and when it actually 202 -- starts. 203 job_start_latency_ms LONG, 204 -- Number of uncompleted job work items. 205 num_uncompleted_work_items LONG, 206 -- Process state of the process responsible for running the job. 207 proc_state STRING, 208 -- Internal stop reason for a job. 209 internal_stop_reason STRING, 210 -- Public stop reason for a job. 211 public_stop_reason STRING 212) AS 213SELECT 214 row_number() OVER (ORDER BY ts) AS id, 215 ts, 216 dur, 217 slice_id, 218 job_name, 219 uid, 220 job_id, 221 package_name, 222 job_namespace, 223 effective_priority, 224 has_battery_not_low_constraint, 225 has_charging_constraint, 226 has_connectivity_constraint, 227 has_content_trigger_constraint, 228 has_deadline_constraint, 229 has_idle_constraint, 230 has_storage_not_low_constraint, 231 has_timing_delay_constraint, 232 is_prefetch, 233 is_requested_expedited_job, 234 is_running_as_expedited_job, 235 num_previous_attempts, 236 requested_priority, 237 standby_bucket, 238 is_periodic, 239 has_flex_constraint, 240 is_requested_as_user_initiated_job, 241 is_running_as_user_initiated_job, 242 deadline_ms, 243 job_start_latency_ms, 244 num_uncompleted_work_items, 245 proc_state, 246 lead_internal_stop_reason AS internal_stop_reason, 247 lead_public_stop_reason AS public_stop_reason 248FROM _job_started; 249 250-- This table returns the constraint, charging, 251-- and screen state changes that a job will go through 252-- in a single trace. 253-- 254-- Values from this table are derived from 255-- the `ScheduledJobStateChanged` atom. This differs from the 256-- `android_job_scheduler_events` table in the `android.job_scheduler` module 257-- which is derived from ATrace the system server category 258-- (`atrace_categories: "ss"`). 259-- 260-- This also differs from the `android_job_scheduler_states` in this module 261-- (`android.job_scheduler_states`) by providing charging and screen state 262-- changes. 263-- 264-- To populate this table, enable the Statsd Tracing Config with the 265-- ATOM_SCHEDULED_JOB_STATE_CHANGED push atom id. 266-- https://perfetto.dev/docs/reference/trace-config-proto#StatsdTracingConfig 267-- 268-- This table is preferred over `android_job_scheduler_events` 269-- since it contains more information and should be used whenever 270-- `ATOM_SCHEDULED_JOB_STATE_CHANGED` is available in a trace. 271CREATE PERFETTO TABLE android_job_scheduler_with_screen_charging_states ( 272 -- Timestamp of job. 273 ts TIMESTAMP, 274 -- Duration of slice in ns. 275 dur DURATION, 276 -- Id of the slice. 277 slice_id JOINID(slice.id), 278 -- Name of the job (as named by the app). 279 job_name STRING, 280 -- Id of job (assigned by app for T- builds and system generated in U+ 281 -- builds). 282 job_id LONG, 283 -- Uid associated with job. 284 uid LONG, 285 -- Duration of entire job in ns. 286 job_dur DURATION, 287 -- Package that the job belongs (ex: associated app). 288 package_name STRING, 289 -- Namespace of job. 290 job_namespace STRING, 291 -- Device charging state during job (one of: Charging, Discharging, Not charging, 292 -- Full, Unknown). 293 charging_state STRING, 294 -- Device screen state during job (one of: Screen off, Screen on, Always-on display 295 -- (doze), Unknown). 296 screen_state STRING, 297 -- Priority at which JobScheduler ran the job. 298 effective_priority LONG, 299 -- True if app requested job should run when the device battery is not low. 300 has_battery_not_low_constraint BOOL, 301 -- True if app requested job should run when the device is charging. 302 has_charging_constraint BOOL, 303 -- True if app requested job should run when device has connectivity. 304 has_connectivity_constraint BOOL, 305 -- True if app requested job should run when there is a content trigger. 306 has_content_trigger_constraint BOOL, 307 -- True if app requested there is a deadline by which the job should run. 308 has_deadline_constraint BOOL, 309 -- True if app requested job should run when device is idle. 310 has_idle_constraint BOOL, 311 -- True if app requested job should run when device storage is not low. 312 has_storage_not_low_constraint BOOL, 313 -- True if app requested job has a timing delay. 314 has_timing_delay_constraint BOOL, 315 -- True if app requested job should run within hours of app launch. 316 is_prefetch BOOL, 317 -- True if app requested that the job is run as an expedited job. 318 is_requested_expedited_job BOOL, 319 -- The job is run as an expedited job. 320 is_running_as_expedited_job BOOL, 321 -- Number of previous attempts at running job. 322 num_previous_attempts TIMESTAMP, 323 -- The requested priority at which the job should run. 324 requested_priority LONG, 325 -- The job's standby bucket (one of: Active, Working Set, Frequent, Rare, 326 -- Never, Restricted, Exempt). 327 standby_bucket STRING, 328 -- Job should run in intervals. 329 is_periodic BOOL, 330 -- True if the job should run as a flex job. 331 has_flex_constraint BOOL, 332 -- True is app has requested that a job be run as a user initiated job. 333 is_requested_as_user_initiated_job BOOL, 334 -- True if job is running as a user initiated job. 335 is_running_as_user_initiated_job BOOL, 336 -- Deadline that job has requested and valid if has_deadline_constraint is 337 -- true. 338 deadline_ms LONG, 339 -- The latency in ms between when a job is scheduled and when it actually 340 -- starts. 341 job_start_latency_ms LONG, 342 -- Number of uncompleted job work items. 343 num_uncompleted_work_items LONG, 344 -- Process state of the process responsible for running the job. 345 proc_state STRING, 346 -- Internal stop reason for a job. 347 internal_stop_reason STRING, 348 -- Public stop reason for a job. 349 public_stop_reason STRING 350) AS 351SELECT 352 ii.ts, 353 ii.dur, 354 js.slice_id, 355 js.job_name || '_' || js.job_id AS job_name, 356 js.uid, 357 js.job_id, 358 js.dur AS job_dur, 359 js.package_name, 360 js.job_namespace, 361 c.charging_state, 362 c.screen_state, 363 js.effective_priority, 364 js.has_battery_not_low_constraint, 365 js.has_charging_constraint, 366 js.has_connectivity_constraint, 367 js.has_content_trigger_constraint, 368 js.has_deadline_constraint, 369 js.has_idle_constraint, 370 js.has_storage_not_low_constraint, 371 js.has_timing_delay_constraint, 372 js.is_prefetch, 373 js.is_requested_expedited_job, 374 js.is_running_as_expedited_job, 375 js.num_previous_attempts, 376 js.requested_priority, 377 js.standby_bucket, 378 js.is_periodic, 379 js.has_flex_constraint, 380 js.is_requested_as_user_initiated_job, 381 js.is_running_as_user_initiated_job, 382 js.deadline_ms, 383 js.job_start_latency_ms, 384 js.num_uncompleted_work_items, 385 js.proc_state, 386 js.internal_stop_reason, 387 js.public_stop_reason 388FROM _interval_intersect!( 389 (_charging_screen_states, 390 android_job_scheduler_states), 391 () 392 ) AS ii 393JOIN _charging_screen_states AS c 394 ON c.id = ii.id_0 395JOIN android_job_scheduler_states AS js 396 ON js.id = ii.id_1; 397