[stdlib]: Add an android service module
Added a detailed service bindings table. We connect the client process
making the binding to the server process getting bound using the binder
txns orchestrated through the system_server.
We also special case bindings from system_server itself.
Test: tools/diff_test_trace_processor.py out/android/trace_processor_shell --name-filter '.*service_binding.*'
Change-Id: I9180ab33ac7cefee7fa2e2559b0e7fc819354043
diff --git a/Android.bp b/Android.bp
index 9611c03..03a8547 100644
--- a/Android.bp
+++ b/Android.bp
@@ -11968,6 +11968,7 @@
"src/trace_processor/perfetto_sql/stdlib/android/network_packets.sql",
"src/trace_processor/perfetto_sql/stdlib/android/process_metadata.sql",
"src/trace_processor/perfetto_sql/stdlib/android/screenshots.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/services.sql",
"src/trace_processor/perfetto_sql/stdlib/android/slices.sql",
"src/trace_processor/perfetto_sql/stdlib/android/startup/startup_events.sql",
"src/trace_processor/perfetto_sql/stdlib/android/startup/startups.sql",
diff --git a/BUILD b/BUILD
index 70ad1f7..dde29af 100644
--- a/BUILD
+++ b/BUILD
@@ -2272,6 +2272,7 @@
"src/trace_processor/perfetto_sql/stdlib/android/network_packets.sql",
"src/trace_processor/perfetto_sql/stdlib/android/process_metadata.sql",
"src/trace_processor/perfetto_sql/stdlib/android/screenshots.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/services.sql",
"src/trace_processor/perfetto_sql/stdlib/android/slices.sql",
"src/trace_processor/perfetto_sql/stdlib/android/statsd.sql",
"src/trace_processor/perfetto_sql/stdlib/android/thread.sql",
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn
index ffd1350..62ba544 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn
@@ -33,6 +33,7 @@
"network_packets.sql",
"process_metadata.sql",
"screenshots.sql",
+ "services.sql",
"slices.sql",
"statsd.sql",
"thread.sql",
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/services.sql b/src/trace_processor/perfetto_sql/stdlib/android/services.sql
new file mode 100644
index 0000000..2a4afd3
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/android/services.sql
@@ -0,0 +1,155 @@
+--
+-- Copyright 2024 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 common.slices;
+INCLUDE PERFETTO MODULE android.binder;
+INCLUDE PERFETTO MODULE graphs.search;
+
+-- Details of all Service#onBind dispatched events.
+CREATE PERFETTO VIEW _bind_dispatch
+AS
+WITH
+ next_sibling AS MATERIALIZED (
+ SELECT *
+ FROM
+ graph_next_sibling!(
+ (
+ SELECT id AS node_id, parent_id AS node_parent_id, ts AS sort_key
+ FROM slice
+ WHERE dur = 0
+ )
+ )
+ ),
+ service AS (
+ SELECT
+ next_slice.id,
+ next_slice.ts,
+ next_slice.dur,
+ next_slice.name,
+ slice.utid,
+ slice.name AS bind_seq_name
+ FROM next_sibling
+ JOIN thread_slice slice
+ ON slice.id = next_sibling.node_id
+ JOIN slice next_slice
+ ON next_slice.id = next_sibling.next_node_id
+ )
+ SELECT
+ id,
+ ts,
+ dur,
+ utid,
+ CAST(STR_SPLIT(STR_SPLIT(bind_seq_name, 'bindSeq=', 1), ' ', 0) AS INT) AS bind_seq
+FROM service
+WHERE bind_seq_name GLOB 'requestServiceBinding*' AND name = 'binder transaction async';
+
+-- Details of all Service#onBind received events.
+CREATE PERFETTO VIEW _bind_receive
+AS
+SELECT
+ id,
+ ts,
+ dur,
+ track_id,
+ REPLACE(STR_SPLIT(STR_SPLIT(name, 'token=', 1), ' ', 0), 'ServiceRecord{', '') AS token,
+ STR_SPLIT(STR_SPLIT(name, 'act=', 1), ' ', 0) AS act,
+ STR_SPLIT(STR_SPLIT(name, 'cmp=', 1), ' ', 0) AS cmp,
+ STR_SPLIT(STR_SPLIT(name, 'flg=', 1), ' ', 0) AS flg,
+ CAST(STR_SPLIT(STR_SPLIT(name, 'bindSeq=', 1), '}', 0) AS INT) AS bind_seq
+FROM slice
+WHERE name GLOB 'serviceBind:*';
+
+-- All service bindings from client app to server app.
+CREATE PERFETTO TABLE android_service_bindings(
+ -- OOM score of client process making the binding.
+ client_oom_score INT,
+ -- Name of client process making the binding.
+ client_process STRING,
+ -- Name of client thread making the binding.
+ client_thread STRING,
+ -- Pid of client process making the binding.
+ client_pid INT,
+ -- Tid of client process making the binding.
+ client_tid INT,
+ -- Upid of client process making the binding.
+ client_upid INT,
+ -- Utid of client thread making the binding.
+ client_utid INT,
+ -- Timestamp the client process made the request.
+ client_ts INT,
+ -- Duration of the client binding request.
+ client_dur INT,
+ -- OOM score of server process getting bound to.
+ server_oom_score INT,
+ -- Name of server process getting bound to
+ server_process STRING,
+ -- Name of server thread getting bound to.
+ server_thread STRING,
+ -- Pid of server process getting bound to.
+ server_pid INT,
+ -- Tid of server process getting bound to.
+ server_tid INT,
+ -- Upid of server process getting bound to.
+ server_upid INT,
+ -- Utid of server process getting bound to.
+ server_utid INT,
+ -- Timestamp the server process got bound to.
+ server_ts INT,
+ -- Duration of the server process handling the binding.
+ server_dur INT,
+ -- Unique binder identifier for the Service binding.
+ token STRING,
+ -- Intent action name for the service binding.
+ act STRING,
+ -- Intent component name for the service binding.
+ cmp STRING,
+ -- Intent flag for the service binding.
+ flg STRING,
+ -- Monotonically increasing id for the service binding.
+ bind_seq INT)
+AS
+SELECT
+ COALESCE(client_binder.client_oom_score, server_binder.client_oom_score) AS client_oom_score,
+ COALESCE(client_binder.client_process, server_binder.client_process) AS client_process,
+ COALESCE(client_binder.client_thread, server_binder.client_thread) AS client_thread,
+ COALESCE(client_binder.client_pid, server_binder.client_pid) AS client_pid,
+ COALESCE(client_binder.client_tid, server_binder.client_tid) AS client_tid,
+ COALESCE(client_binder.client_upid, server_binder.client_upid) AS client_upid,
+ COALESCE(client_binder.client_utid, server_binder.client_utid) AS client_utid,
+ COALESCE(client_binder.client_ts, server_binder.client_ts) AS client_ts,
+ COALESCE(client_binder.client_dur, server_binder.client_dur) AS client_dur,
+ server_binder.server_oom_score,
+ server_binder.server_process,
+ server_binder.server_thread,
+ server_binder.server_pid,
+ server_binder.server_tid,
+ server_binder.server_upid,
+ server_binder.server_utid,
+ receive.ts AS server_ts,
+ receive.dur AS server_dur,
+ receive.token,
+ receive.act,
+ receive.cmp,
+ receive.flg,
+ receive.bind_seq
+FROM _bind_dispatch dispatch
+JOIN _bind_receive receive
+ ON dispatch.bind_seq = receive.bind_seq
+LEFT JOIN android_binder_txns server_binder
+ ON server_binder.binder_txn_id = dispatch.id
+LEFT JOIN ancestor_slice(dispatch.id) anc ON anc.depth = 0
+LEFT JOIN android_binder_txns client_binder
+ ON client_binder.server_ts = anc.ts AND dispatch.utid = client_binder.server_utid;
diff --git a/src/trace_processor/perfetto_sql/stdlib/graphs/search.sql b/src/trace_processor/perfetto_sql/stdlib/graphs/search.sql
index 05cec80..6d9bf00 100644
--- a/src/trace_processor/perfetto_sql/stdlib/graphs/search.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/graphs/search.sql
@@ -67,3 +67,35 @@
$start_node_id
) dt
);
+
+-- Computes the next sibling node in a directed graph. The next node under a parent node
+-- is determined by on the |sort_key|, which should be unique for every node under a parent.
+-- The order of the next sibling is undefined if the |sort_key| is not unique.
+--
+-- Example usage:
+--
+-- -- Compute the next sibling:
+-- SELECT *
+-- FROM graph_next_sibling!(
+-- (
+-- SELECT
+-- id AS node_id,
+-- parent_id AS node_parent_id,
+-- ts AS sort_key
+-- FROM slice
+-- )
+-- );
+-- ```
+CREATE PERFETTO MACRO graph_next_sibling(
+ -- A table/view/subquery corresponding to a directed graph for which to find the next sibling.
+ -- This table must have the columns "node_id", "node_parent_id" and "sort_key".
+ graph_table TableOrSubquery
+)
+-- The returned table has the schema (node_id UINT32, next_node_id UINT32).
+-- |node_id| is the id of the node from the input graph and |next_node_id|
+-- is the id of the node which is its next sibling.
+RETURNS TableOrSubquery AS
+(
+ SELECT node_id, lead(node_id) OVER (PARTITION BY node_parent_id ORDER BY sort_key) AS next_node_id
+ FROM $graph_table
+);
diff --git a/test/trace_processor/diff_tests/stdlib/android/tests.py b/test/trace_processor/diff_tests/stdlib/android/tests.py
index 402fdcc..63a92ca 100644
--- a/test/trace_processor/diff_tests/stdlib/android/tests.py
+++ b/test/trace_processor/diff_tests/stdlib/android/tests.py
@@ -1160,4 +1160,47 @@
out=Csv("""
"pid","ts","dur"
8361,588092720937,576298685
+ """))
+
+ def test_service_bindings(self):
+ return DiffTestBlueprint(
+ trace=DataPath('post_boot_trace.atr'),
+ query="""
+ INCLUDE PERFETTO MODULE android.services;
+ SELECT
+ client_oom_score,
+ client_process,
+ client_thread,
+ client_pid,
+ client_tid,
+ client_ts,
+ client_dur,
+ server_oom_score,
+ server_process,
+ server_thread,
+ server_tid,
+ server_pid,
+ server_ts,
+ server_dur,
+ token,
+ act,
+ cmp,
+ flg,
+ bind_seq
+ FROM android_service_bindings
+ ORDER BY client_tid, client_ts
+ LIMIT 10
+ """,
+ out=Csv("""
+ "client_oom_score","client_process","client_thread","client_pid","client_tid","client_ts","client_dur","server_oom_score","server_process","server_thread","server_tid","server_pid","server_ts","server_dur","token","act","cmp","flg","bind_seq"
+ -900,"system_server","system_server",7288,7288,577830735575,0,0,"android.ext.services","binder:7732_3",7764,7732,577866081720,9755069,"android.os.BinderProxy@a0dc800","android.service.notification.NotificationAssistantService","android.ext.services/.notification.Assistant","[NULL]",21
+ -900,"system_server","eduling.default",7288,7366,579204777498,0,0,"com.android.dialer","binder:8075_2",8097,8075,579207718770,13090141,"android.os.BinderProxy@9a28fdf","[NULL]","com.android.dialer/com.android.voicemail.impl.StatusCheckJobService","0x4",29
+ -900,"system_server","eduling.default",7288,7366,580022869386,0,0,"com.android.imsserviceentitlement","binder:8647_1",8667,8647,580027477378,1982139,"android.os.BinderProxy@27f8e83","[NULL]","com.android.imsserviceentitlement/.fcm.FcmRegistrationService","0x4",35
+ -900,"system_server","StorageManagerS",7288,7397,587754918358,0,-700,"com.android.providers.media.module","binder:8294_1",8327,8294,587757305854,2691423,"android.os.BinderProxy@73b68b5","[NULL]","com.android.providers.media.module/com.android.providers.media.fuse.ExternalStorageServiceImpl","[NULL]",44
+ -800,"com.android.systemui","ndroid.systemui",7493,7493,572995972978,8071106,-800,"com.android.systemui","binder:7493_4",7682,7493,573131280194,17181314,"android.os.BinderProxy@1c2ac60","android.service.wallpaper.WallpaperService","com.android.systemui/.wallpapers.ImageWallpaper","[NULL]",14
+ -800,"com.android.systemui","ndroid.systemui",7493,7493,572995972978,8071106,-800,"com.android.systemui","binder:7493_4",7682,7493,577000518511,6977972,"android.os.BinderProxy@b18137","[NULL]","com.android.systemui/.keyguard.KeyguardService","0x100",15
+ -800,"com.android.networkstack.process","rkstack.process",7610,7610,571078334504,7552850,-800,"com.android.networkstack.process","binder:7610_1",7633,7610,571090652307,74610898,"android.os.BinderProxy@ee1090b","android.net.INetworkStackConnector","com.android.networkstack/com.android.server.NetworkStackService","[NULL]",2
+ -800,"com.android.networkstack.process","rkstack.process",7610,7610,571078334504,7552850,-800,"com.android.networkstack.process","binder:7610_1",7633,7610,571489537275,1570460,"android.os.BinderProxy@a0dc800","android.net.ITetheringConnector","com.android.networkstack.tethering/.TetheringService","[NULL]",3
+ 0,"com.android.bluetooth","droid.bluetooth",7639,7639,571248973750,9874358,-700,"com.android.bluetooth","binder:7639_2",7672,7639,571871169647,6460322,"android.os.BinderProxy@7482132","android.bluetooth.IBluetooth","com.android.bluetooth/.btservice.AdapterService","[NULL]",4
+ -700,"com.android.bluetooth","droid.bluetooth",7639,7639,572342110044,4874276,-700,"com.android.bluetooth","binder:7639_2",7672,7639,572466393291,1404185,"android.os.BinderProxy@ce5a6fc","android.media.browse.MediaBrowserService","com.android.bluetooth/.avrcpcontroller.BluetoothMediaBrowserService","[NULL]",10
"""))
diff --git a/test/trace_processor/diff_tests/stdlib/graphs/search_tests.py b/test/trace_processor/diff_tests/stdlib/graphs/search_tests.py
index 093b021..1e3b96b 100644
--- a/test/trace_processor/diff_tests/stdlib/graphs/search_tests.py
+++ b/test/trace_processor/diff_tests/stdlib/graphs/search_tests.py
@@ -131,3 +131,25 @@
"L","D"
"R","[NULL]"
"""))
+
+ def test_next_sibling(self):
+ return DiffTestBlueprint(
+ trace=DataPath('counters.json'),
+ query="""
+ INCLUDE PERFETTO MODULE graphs.search;
+
+ CREATE PERFETTO TABLE foo AS
+ SELECT 1 AS node_id, 0 AS node_parent_id, 1 AS sort_key
+ UNION ALL
+ SELECT 2 AS node_id, 1 AS node_parent_id, 2 AS sort_key
+ UNION ALL
+ SELECT 3 AS node_id, 1 AS node_parent_id, 1 AS sort_key;
+
+ SELECT * FROM graph_next_sibling!(foo);
+ """,
+ out=Csv("""
+ "node_id","next_node_id"
+ 1,"[NULL]"
+ 3,2
+ 2,"[NULL]"
+ """))