Add android_boot metric

For now his computes the total time certain processes spend in
uinterruptible sleep as well as the total duration of all scheduling
slices owned by the given process.  Right now we only care about
uninterruptible sleep, but the proto is designed so that we can easily
append more fields for different scheduling states.  We pick the name
'android_boot' to make it clear that this proto can be used for future
boot related metrics.

Test: <trace_processor_shell> --run-metrics android_boot <trace>
Test: tools/diff_test_trace_processor.py <trace_processor_shell> --name-filter='.*android_boot*'
Bug: 300681738

Change-Id: I5ded2c78cdaab32cbca94bd1b9c1ef9149a32ea5
diff --git a/Android.bp b/Android.bp
index 081ab9b..617ddb5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -4589,6 +4589,7 @@
     srcs: [
         "protos/perfetto/metrics/android/android_blocking_call.proto",
         "protos/perfetto/metrics/android/android_blocking_calls_cuj_metric.proto",
+        "protos/perfetto/metrics/android/android_boot.proto",
         "protos/perfetto/metrics/android/android_frame_timeline_metric.proto",
         "protos/perfetto/metrics/android/android_sysui_notifications_blocking_calls_metric.proto",
         "protos/perfetto/metrics/android/android_trusty_workqueues.proto",
@@ -4669,6 +4670,7 @@
     srcs: [
         "protos/perfetto/metrics/android/android_blocking_call.proto",
         "protos/perfetto/metrics/android/android_blocking_calls_cuj_metric.proto",
+        "protos/perfetto/metrics/android/android_boot.proto",
         "protos/perfetto/metrics/android/android_frame_timeline_metric.proto",
         "protos/perfetto/metrics/android/android_sysui_notifications_blocking_calls_metric.proto",
         "protos/perfetto/metrics/android/android_trusty_workqueues.proto",
@@ -4732,6 +4734,7 @@
     srcs: [
         "protos/perfetto/metrics/android/android_blocking_call.proto",
         "protos/perfetto/metrics/android/android_blocking_calls_cuj_metric.proto",
+        "protos/perfetto/metrics/android/android_boot.proto",
         "protos/perfetto/metrics/android/android_frame_timeline_metric.proto",
         "protos/perfetto/metrics/android/android_sysui_notifications_blocking_calls_metric.proto",
         "protos/perfetto/metrics/android/android_trusty_workqueues.proto",
@@ -10431,6 +10434,7 @@
         "src/trace_processor/metrics/sql/android/android_batt.sql",
         "src/trace_processor/metrics/sql/android/android_binder.sql",
         "src/trace_processor/metrics/sql/android/android_blocking_calls_cuj_metric.sql",
+        "src/trace_processor/metrics/sql/android/android_boot.sql",
         "src/trace_processor/metrics/sql/android/android_camera.sql",
         "src/trace_processor/metrics/sql/android/android_camera_unagg.sql",
         "src/trace_processor/metrics/sql/android/android_cpu.sql",
diff --git a/BUILD b/BUILD
index ee2d513..71f4144 100644
--- a/BUILD
+++ b/BUILD
@@ -1994,6 +1994,7 @@
         "src/trace_processor/metrics/sql/android/android_batt.sql",
         "src/trace_processor/metrics/sql/android/android_binder.sql",
         "src/trace_processor/metrics/sql/android/android_blocking_calls_cuj_metric.sql",
+        "src/trace_processor/metrics/sql/android/android_boot.sql",
         "src/trace_processor/metrics/sql/android/android_camera.sql",
         "src/trace_processor/metrics/sql/android/android_camera_unagg.sql",
         "src/trace_processor/metrics/sql/android/android_cpu.sql",
@@ -4223,6 +4224,7 @@
     srcs = [
         "protos/perfetto/metrics/android/android_blocking_call.proto",
         "protos/perfetto/metrics/android/android_blocking_calls_cuj_metric.proto",
+        "protos/perfetto/metrics/android/android_boot.proto",
         "protos/perfetto/metrics/android/android_frame_timeline_metric.proto",
         "protos/perfetto/metrics/android/android_sysui_notifications_blocking_calls_metric.proto",
         "protos/perfetto/metrics/android/android_trusty_workqueues.proto",
diff --git a/protos/perfetto/metrics/android/BUILD.gn b/protos/perfetto/metrics/android/BUILD.gn
index 74e7a72..a2ae264 100644
--- a/protos/perfetto/metrics/android/BUILD.gn
+++ b/protos/perfetto/metrics/android/BUILD.gn
@@ -22,6 +22,7 @@
   sources = [
     "android_blocking_call.proto",
     "android_blocking_calls_cuj_metric.proto",
+    "android_boot.proto",
     "android_frame_timeline_metric.proto",
     "android_sysui_notifications_blocking_calls_metric.proto",
     "android_trusty_workqueues.proto",
diff --git a/protos/perfetto/metrics/android/android_boot.proto b/protos/perfetto/metrics/android/android_boot.proto
new file mode 100644
index 0000000..820b4e0
--- /dev/null
+++ b/protos/perfetto/metrics/android/android_boot.proto
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package perfetto.protos;
+
+// This metric computes how much time processes spend in UNINTERRUPTIBLE_SLEEP state
+message ProcessStateDurations {
+  optional int64 total_dur = 2;
+  optional int64 uninterruptible_sleep_dur = 3;
+}
+
+message AndroidBootMetric {
+  optional ProcessStateDurations system_server_durations = 1;
+  optional ProcessStateDurations systemui_durations = 2;
+  optional ProcessStateDurations launcher_durations = 3;
+  optional ProcessStateDurations gms_durations = 4;
+}
diff --git a/protos/perfetto/metrics/metrics.proto b/protos/perfetto/metrics/metrics.proto
index 94c7666..95fd3b4 100644
--- a/protos/perfetto/metrics/metrics.proto
+++ b/protos/perfetto/metrics/metrics.proto
@@ -18,6 +18,7 @@
 
 package perfetto.protos;
 
+import "protos/perfetto/metrics/android/android_boot.proto";
 import "protos/perfetto/metrics/android/android_frame_timeline_metric.proto";
 import "protos/perfetto/metrics/android/anr_metric.proto";
 import "protos/perfetto/metrics/android/batt_metric.proto";
@@ -108,7 +109,7 @@
 
 // Root message for all Perfetto-based metrics.
 //
-// Next id: 57
+// Next id: 58
 message TraceMetrics {
   reserved 4, 10, 13, 14, 16, 19;
 
@@ -263,6 +264,8 @@
   // Aggregated Android Monitor Contention metrics
   optional AndroidMonitorContentionAggMetric android_monitor_contention_agg = 56;
 
+  optional AndroidBootMetric android_boot = 57;
+
   // Demo extensions.
   extensions 450 to 499;
 
diff --git a/protos/perfetto/metrics/perfetto_merged_metrics.proto b/protos/perfetto/metrics/perfetto_merged_metrics.proto
index 70a1f52..e940682 100644
--- a/protos/perfetto/metrics/perfetto_merged_metrics.proto
+++ b/protos/perfetto/metrics/perfetto_merged_metrics.proto
@@ -105,6 +105,23 @@
 
 // End of protos/perfetto/metrics/android/android_blocking_calls_cuj_metric.proto
 
+// Begin of protos/perfetto/metrics/android/android_boot.proto
+
+// This metric computes how much time processes spend in UNINTERRUPTIBLE_SLEEP state
+message ProcessStateDurations {
+  optional int64 total_dur = 2;
+  optional int64 uninterruptible_sleep_dur = 3;
+}
+
+message AndroidBootMetric {
+  optional ProcessStateDurations system_server_durations = 1;
+  optional ProcessStateDurations systemui_durations = 2;
+  optional ProcessStateDurations launcher_durations = 3;
+  optional ProcessStateDurations gms_durations = 4;
+}
+
+// End of protos/perfetto/metrics/android/android_boot.proto
+
 // Begin of protos/perfetto/metrics/android/android_frame_timeline_metric.proto
 
 message AndroidFrameTimelineMetric {
@@ -2266,7 +2283,7 @@
 
 // Root message for all Perfetto-based metrics.
 //
-// Next id: 57
+// Next id: 58
 message TraceMetrics {
   reserved 4, 10, 13, 14, 16, 19;
 
@@ -2421,6 +2438,8 @@
   // Aggregated Android Monitor Contention metrics
   optional AndroidMonitorContentionAggMetric android_monitor_contention_agg = 56;
 
+  optional AndroidBootMetric android_boot = 57;
+
   // Demo extensions.
   extensions 450 to 499;
 
diff --git a/python/perfetto/trace_processor/metrics.descriptor b/python/perfetto/trace_processor/metrics.descriptor
index ad0d5da..926dee9 100644
--- a/python/perfetto/trace_processor/metrics.descriptor
+++ b/python/perfetto/trace_processor/metrics.descriptor
Binary files differ
diff --git a/src/trace_processor/metrics/sql/android/BUILD.gn b/src/trace_processor/metrics/sql/android/BUILD.gn
index 99223c0..6c31943 100644
--- a/src/trace_processor/metrics/sql/android/BUILD.gn
+++ b/src/trace_processor/metrics/sql/android/BUILD.gn
@@ -23,6 +23,7 @@
     "android_batt.sql",
     "android_binder.sql",
     "android_blocking_calls_cuj_metric.sql",
+    "android_boot.sql",
     "android_camera.sql",
     "android_camera_unagg.sql",
     "android_cpu.sql",
diff --git a/src/trace_processor/metrics/sql/android/android_boot.sql b/src/trace_processor/metrics/sql/android/android_boot.sql
new file mode 100644
index 0000000..46caea8
--- /dev/null
+++ b/src/trace_processor/metrics/sql/android/android_boot.sql
@@ -0,0 +1,51 @@
+--
+-- Copyright 2023 The Android Open Source Project
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+INCLUDE PERFETTO MODULE android.process_metadata;
+
+CREATE PERFETTO FUNCTION get_durations(process_name STRING)
+RETURNS TABLE(uint_sleep_dur LONG, total_dur LONG) AS
+SELECT
+    SUM(CASE WHEN thread_state.state="D" then thread_state.dur ELSE 0 END) AS uint_sleep_dur,
+    SUM(thread_state.dur) as total_dur
+FROM android_process_metadata
+INNER JOIN thread ON thread.upid=android_process_metadata.upid
+INNER JOIN thread_state ON thread.utid=thread_state.utid WHERE android_process_metadata.process_name=$process_name;
+
+DROP VIEW IF EXISTS android_boot_output;
+CREATE VIEW android_boot_output AS
+SELECT AndroidBootMetric(
+    'system_server_durations', (
+        SELECT NULL_IF_EMPTY(ProcessStateDurations(
+            'total_dur', total_dur,
+            'uninterruptible_sleep_dur', uint_sleep_dur))
+        FROM get_durations('system_server')),
+    'systemui_durations', (
+        SELECT NULL_IF_EMPTY(ProcessStateDurations(
+            'total_dur', total_dur,
+            'uninterruptible_sleep_dur', uint_sleep_dur))
+        FROM get_durations('com.android.systemui')),
+    'launcher_durations', (
+        SELECT NULL_IF_EMPTY(ProcessStateDurations(
+            'total_dur', total_dur,
+            'uninterruptible_sleep_dur', uint_sleep_dur))
+        FROM get_durations('com.google.android.apps.nexuslauncher')),
+    'gms_durations', (
+        SELECT NULL_IF_EMPTY(ProcessStateDurations(
+            'total_dur', total_dur,
+            'uninterruptible_sleep_dur', uint_sleep_dur))
+        FROM get_durations('com.google.android.gms.persistent'))
+);
diff --git a/test/data/android_boot.pftrace.sha256 b/test/data/android_boot.pftrace.sha256
new file mode 100644
index 0000000..1d9798f
--- /dev/null
+++ b/test/data/android_boot.pftrace.sha256
@@ -0,0 +1 @@
+660231895e7c1816bcbd02771fdf825917ba0540124c3fdd174c1a91470b9448
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/android/tests.py b/test/trace_processor/diff_tests/android/tests.py
index fcf165c..8bbbeb7 100644
--- a/test/trace_processor/diff_tests/android/tests.py
+++ b/test/trace_processor/diff_tests/android/tests.py
@@ -1173,3 +1173,16 @@
         /system/bin/servicemanager (0x0)
         /system/bin/storaged (0x0)
         """))
+
+  def test_android_boot(self):
+    return DiffTestBlueprint(
+        trace=DataPath('android_boot.pftrace'),
+        query=Metric('android_boot'),
+        out=TextProto(r"""
+        android_boot {
+          system_server_durations {
+            total_dur: 267193980530
+            uninterruptible_sleep_dur: 3843119529
+          }
+        }
+        """))