Add transition trace processor
Test: tools/ninja -C out/linux_clang_release && tools/diff_test_trace_processor.py ./out/linux_clang_release/trace_processor_shell --name-filter ShellTransitions
Bug: 309630341
Change-Id: I70dcbd421133572a4d36f9d025bf1d67ac208b99
diff --git a/Android.bp b/Android.bp
index 144e1e1..6288761 100644
--- a/Android.bp
+++ b/Android.bp
@@ -11258,6 +11258,8 @@
filegroup {
name: "perfetto_src_trace_processor_importers_proto_winscope_full",
srcs: [
+ "src/trace_processor/importers/proto/winscope/shell_transitions_parser.cc",
+ "src/trace_processor/importers/proto/winscope/shell_transitions_tracker.cc",
"src/trace_processor/importers/proto/winscope/surfaceflinger_layers_parser.cc",
"src/trace_processor/importers/proto/winscope/surfaceflinger_transactions_parser.cc",
"src/trace_processor/importers/proto/winscope/winscope_args_parser.cc",
diff --git a/BUILD b/BUILD
index c1d990d..49824c7 100644
--- a/BUILD
+++ b/BUILD
@@ -1576,6 +1576,10 @@
perfetto_filegroup(
name = "src_trace_processor_importers_proto_winscope_full",
srcs = [
+ "src/trace_processor/importers/proto/winscope/shell_transitions_parser.cc",
+ "src/trace_processor/importers/proto/winscope/shell_transitions_parser.h",
+ "src/trace_processor/importers/proto/winscope/shell_transitions_tracker.cc",
+ "src/trace_processor/importers/proto/winscope/shell_transitions_tracker.h",
"src/trace_processor/importers/proto/winscope/surfaceflinger_layers_parser.cc",
"src/trace_processor/importers/proto/winscope/surfaceflinger_layers_parser.h",
"src/trace_processor/importers/proto/winscope/surfaceflinger_transactions_parser.cc",
diff --git a/src/trace_processor/importers/common/args_tracker.h b/src/trace_processor/importers/common/args_tracker.h
index 4751fef..2a3a8b5 100644
--- a/src/trace_processor/importers/common/args_tracker.h
+++ b/src/trace_processor/importers/common/args_tracker.h
@@ -139,6 +139,12 @@
context_->storage->mutable_surfaceflinger_transactions_table(), id);
}
+ BoundInserter AddArgsTo(tables::WindowManagerShellTransitionsTable::Id id) {
+ return AddArgsTo(
+ context_->storage->mutable_window_manager_shell_transitions_table(),
+ id);
+ }
+
BoundInserter AddArgsTo(MetadataId id) {
auto* table = context_->storage->mutable_metadata_table();
uint32_t row = *table->id().IndexOf(id);
diff --git a/src/trace_processor/importers/proto/winscope/BUILD.gn b/src/trace_processor/importers/proto/winscope/BUILD.gn
index 2d48f0c..7b04e85 100644
--- a/src/trace_processor/importers/proto/winscope/BUILD.gn
+++ b/src/trace_processor/importers/proto/winscope/BUILD.gn
@@ -16,30 +16,35 @@
source_set("full") {
sources = [
+ "shell_transitions_parser.cc",
+ "shell_transitions_parser.h",
+ "shell_transitions_tracker.cc",
+ "shell_transitions_tracker.h",
"surfaceflinger_layers_parser.cc",
"surfaceflinger_layers_parser.h",
"surfaceflinger_transactions_parser.cc",
"surfaceflinger_transactions_parser.h",
- "winscope_args_parser.h",
"winscope_args_parser.cc",
+ "winscope_args_parser.h",
"winscope_module.cc",
"winscope_module.h",
]
deps = [
":gen_cc_winscope_descriptor",
+ "../:proto_importer_module",
"../../../../../gn:default_deps",
- "../../../../../protos/perfetto/trace/android:zero",
"../../../../../protos/perfetto/trace:zero",
+ "../../../../../protos/perfetto/trace/android:zero",
"../../../storage",
"../../../tables",
"../../../types",
"../../common",
"../../common:parser_types",
- "../:proto_importer_module",
]
}
perfetto_cc_proto_descriptor("gen_cc_winscope_descriptor") {
descriptor_name = "winscope.descriptor"
- descriptor_target = "../../../../../protos/perfetto/trace/android:winscope_descriptor"
+ descriptor_target =
+ "../../../../../protos/perfetto/trace/android:winscope_descriptor"
}
diff --git a/src/trace_processor/importers/proto/winscope/shell_transitions_parser.cc b/src/trace_processor/importers/proto/winscope/shell_transitions_parser.cc
new file mode 100644
index 0000000..aee9118
--- /dev/null
+++ b/src/trace_processor/importers/proto/winscope/shell_transitions_parser.cc
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#include "src/trace_processor/importers/proto/winscope/shell_transitions_parser.h"
+#include "src/trace_processor/importers/proto/winscope/shell_transitions_tracker.h"
+
+#include "protos/perfetto/trace/android/shell_transition.pbzero.h"
+#include "src/trace_processor/importers/common/args_tracker.h"
+#include "src/trace_processor/importers/proto/winscope/winscope.descriptor.h"
+#include "src/trace_processor/importers/proto/winscope/winscope_args_parser.h"
+#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+ShellTransitionsParser::ShellTransitionsParser(TraceProcessorContext* context)
+ : context_(context), args_parser_{pool_} {
+ pool_.AddFromFileDescriptorSet(kWinscopeDescriptor.data(),
+ kWinscopeDescriptor.size());
+}
+
+void ShellTransitionsParser::Parse(int64_t, protozero::ConstBytes blob) {
+ protos::pbzero::ShellTransition::Decoder transition(blob);
+
+ auto row_id =
+ ShellTransitionsTracker::GetOrCreate(context_)->InternTransition(
+ transition.id());
+
+ auto* window_manager_shell_transitions_table =
+ context_->storage->mutable_window_manager_shell_transitions_table();
+ auto row = window_manager_shell_transitions_table->FindById(row_id).value();
+
+ if (transition.has_dispatch_time_ns()) {
+ row.set_ts(transition.dispatch_time_ns());
+ }
+
+ auto inserter = context_->args_tracker->AddArgsTo(row_id);
+ WinscopeArgsParser writer(inserter, *context_->storage.get());
+ base::Status status = args_parser_.ParseMessage(
+ blob, kShellTransitionsProtoName, nullptr /* parse all fields */, writer);
+
+ if (!status.ok()) {
+ context_->storage->IncrementStats(
+ stats::winscope_shell_transitions_parse_errors);
+ }
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/winscope/shell_transitions_parser.h b/src/trace_processor/importers/proto/winscope/shell_transitions_parser.h
new file mode 100644
index 0000000..2150e00
--- /dev/null
+++ b/src/trace_processor/importers/proto/winscope/shell_transitions_parser.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_WINSCOPE_SHELL_TRANSITIONS_PARSER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_WINSCOPE_SHELL_TRANSITIONS_PARSER_H_
+
+#include "src/trace_processor/util/descriptors.h"
+#include "src/trace_processor/util/proto_to_args_parser.h"
+
+namespace perfetto {
+
+namespace trace_processor {
+
+class TraceProcessorContext;
+
+class ShellTransitionsParser {
+ public:
+ explicit ShellTransitionsParser(TraceProcessorContext*);
+ void Parse(int64_t timestamp, protozero::ConstBytes);
+
+ private:
+ static constexpr auto* kShellTransitionsProtoName =
+ ".perfetto.protos.ShellTransition";
+
+ TraceProcessorContext* const context_;
+ DescriptorPool pool_;
+ util::ProtoToArgsParser args_parser_;
+};
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_WINSCOPE_SHELL_TRANSITIONS_PARSER_H_
diff --git a/src/trace_processor/importers/proto/winscope/shell_transitions_tracker.cc b/src/trace_processor/importers/proto/winscope/shell_transitions_tracker.cc
new file mode 100644
index 0000000..6025d91
--- /dev/null
+++ b/src/trace_processor/importers/proto/winscope/shell_transitions_tracker.cc
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#include "shell_transitions_tracker.h"
+#include "perfetto/ext/base/crash_keys.h"
+#include "src/trace_processor/importers/common/process_tracker.h"
+#include "src/trace_processor/storage/metadata.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+
+namespace perfetto {
+namespace trace_processor {
+ShellTransitionsTracker::ShellTransitionsTracker(TraceProcessorContext* context)
+ : context_(context) {}
+
+ShellTransitionsTracker::~ShellTransitionsTracker() = default;
+
+tables::WindowManagerShellTransitionsTable::Id
+ShellTransitionsTracker::InternTransition(int32_t transition_id) {
+ auto pos = transition_id_to_row_mapping_.find(transition_id);
+ if (pos != transition_id_to_row_mapping_.end()) {
+ return pos->second;
+ }
+
+ auto* window_manager_shell_transitions_table =
+ context_->storage->mutable_window_manager_shell_transitions_table();
+
+ tables::WindowManagerShellTransitionsTable::Row row;
+ row.transition_id = transition_id;
+ auto row_id = window_manager_shell_transitions_table->Insert(row).id;
+
+ transition_id_to_row_mapping_.insert({transition_id, row_id});
+
+ return row_id;
+}
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/winscope/shell_transitions_tracker.h b/src/trace_processor/importers/proto/winscope/shell_transitions_tracker.h
new file mode 100644
index 0000000..07ef736
--- /dev/null
+++ b/src/trace_processor/importers/proto/winscope/shell_transitions_tracker.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_WINSCOPE_SHELL_TRANSITIONS_TRACKER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_WINSCOPE_SHELL_TRANSITIONS_TRACKER_H_
+
+#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+// Tracks information in the transition table.
+class ShellTransitionsTracker : public Destructible {
+ public:
+ explicit ShellTransitionsTracker(TraceProcessorContext*);
+ virtual ~ShellTransitionsTracker() override;
+
+ static ShellTransitionsTracker* GetOrCreate(TraceProcessorContext* context) {
+ if (!context->shell_transitions_tracker) {
+ context->shell_transitions_tracker.reset(
+ new ShellTransitionsTracker(context));
+ }
+ return static_cast<ShellTransitionsTracker*>(
+ context->shell_transitions_tracker.get());
+ }
+
+ tables::WindowManagerShellTransitionsTable::Id InternTransition(
+ int32_t transition_id);
+
+ private:
+ TraceProcessorContext* context_;
+ std::unordered_map<int32_t, tables::WindowManagerShellTransitionsTable::Id>
+ transition_id_to_row_mapping_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_WINSCOPE_SHELL_TRANSITIONS_TRACKER_H_
diff --git a/src/trace_processor/importers/proto/winscope/winscope_module.cc b/src/trace_processor/importers/proto/winscope/winscope_module.cc
index de9e224..e4d9c0e 100644
--- a/src/trace_processor/importers/proto/winscope/winscope_module.cc
+++ b/src/trace_processor/importers/proto/winscope/winscope_module.cc
@@ -23,11 +23,13 @@
WinscopeModule::WinscopeModule(TraceProcessorContext* context)
: surfaceflinger_layers_parser_(context),
- surfaceflinger_transactions_parser_(context) {
+ surfaceflinger_transactions_parser_(context),
+ shell_transitions_parser_(context) {
RegisterForField(TracePacket::kSurfaceflingerLayersSnapshotFieldNumber,
context);
RegisterForField(TracePacket::kSurfaceflingerTransactionsFieldNumber,
context);
+ RegisterForField(TracePacket::kShellTransitionFieldNumber, context);
}
void WinscopeModule::ParseTracePacketData(const TracePacket::Decoder& decoder,
@@ -43,6 +45,9 @@
surfaceflinger_transactions_parser_.Parse(
timestamp, decoder.surfaceflinger_transactions());
return;
+ case TracePacket::kShellTransitionFieldNumber:
+ shell_transitions_parser_.Parse(timestamp, decoder.shell_transition());
+ return;
}
}
diff --git a/src/trace_processor/importers/proto/winscope/winscope_module.h b/src/trace_processor/importers/proto/winscope/winscope_module.h
index d9428d0..fffe42c 100644
--- a/src/trace_processor/importers/proto/winscope/winscope_module.h
+++ b/src/trace_processor/importers/proto/winscope/winscope_module.h
@@ -21,6 +21,7 @@
#include "perfetto/base/build_config.h"
#include "src/trace_processor/importers/common/parser_types.h"
#include "src/trace_processor/importers/proto/proto_importer_module.h"
+#include "src/trace_processor/importers/proto/winscope/shell_transitions_parser.h"
#include "src/trace_processor/importers/proto/winscope/surfaceflinger_layers_parser.h"
#include "src/trace_processor/importers/proto/winscope/surfaceflinger_transactions_parser.h"
@@ -41,6 +42,7 @@
private:
SurfaceFlingerLayersParser surfaceflinger_layers_parser_;
SurfaceFlingerTransactionsParser surfaceflinger_transactions_parser_;
+ ShellTransitionsParser shell_transitions_parser_;
};
} // namespace trace_processor
diff --git a/src/trace_processor/storage/stats.h b/src/trace_processor/storage/stats.h
index d583632..1e40489 100644
--- a/src/trace_processor/storage/stats.h
+++ b/src/trace_processor/storage/stats.h
@@ -262,6 +262,11 @@
kSingle, kInfo, kAnalysis, \
"SurfaceFlinger transactions packet has unknown fields, which results " \
"in some arguments missing. You may need a newer version of trace " \
+ "processor to parse them."), \
+ F(winscope_shell_transitions_parse_errors, \
+ kSingle, kInfo, kAnalysis, \
+ "Shell transition packet has unknown fields, which results " \
+ "in some arguments missing. You may need a newer version of trace " \
"processor to parse them.")
// clang-format on
diff --git a/src/trace_processor/storage/trace_storage.h b/src/trace_processor/storage/trace_storage.h
index e75233e..b9413b0 100644
--- a/src/trace_processor/storage/trace_storage.h
+++ b/src/trace_processor/storage/trace_storage.h
@@ -738,6 +738,15 @@
return &surfaceflinger_transactions_table_;
}
+ const tables::WindowManagerShellTransitionsTable&
+ window_manager_shell_transitions_table() const {
+ return window_manager_shell_transitions_table_;
+ }
+ tables::WindowManagerShellTransitionsTable*
+ mutable_window_manager_shell_transitions_table() {
+ return &window_manager_shell_transitions_table_;
+ }
+
const tables::ExperimentalProtoPathTable& experimental_proto_path_table()
const {
return experimental_proto_path_table_;
@@ -995,6 +1004,8 @@
tables::SurfaceFlingerLayerTable surfaceflinger_layer_table_{&string_pool_};
tables::SurfaceFlingerTransactionsTable surfaceflinger_transactions_table_{
&string_pool_};
+ tables::WindowManagerShellTransitionsTable
+ window_manager_shell_transitions_table_{&string_pool_};
tables::ExperimentalProtoPathTable experimental_proto_path_table_{
&string_pool_};
diff --git a/src/trace_processor/tables/table_destructors.cc b/src/trace_processor/tables/table_destructors.cc
index 16981fa..e22a56e 100644
--- a/src/trace_processor/tables/table_destructors.cc
+++ b/src/trace_processor/tables/table_destructors.cc
@@ -120,6 +120,8 @@
default;
SurfaceFlingerLayerTable::~SurfaceFlingerLayerTable() = default;
SurfaceFlingerTransactionsTable::~SurfaceFlingerTransactionsTable() = default;
+WindowManagerShellTransitionsTable::~WindowManagerShellTransitionsTable() =
+ default;
} // namespace tables
diff --git a/src/trace_processor/tables/winscope_tables.py b/src/trace_processor/tables/winscope_tables.py
index 22f2080..5391c96 100644
--- a/src/trace_processor/tables/winscope_tables.py
+++ b/src/trace_processor/tables/winscope_tables.py
@@ -60,16 +60,36 @@
C('arg_set_id', CppUint32()),
],
tabledoc=TableDoc(
- doc='SurfaceFlinger transactions. Each row contains a set of transactions that SurfaceFlinger committed together.',
+ doc='SurfaceFlinger transactions. Each row contains a set of ' +
+ 'transactions that SurfaceFlinger committed together.',
group='Winscope',
columns={
'ts': 'Timestamp of the transactions commit',
'arg_set_id': 'Extra args parsed from the proto message',
}))
+WINDOW_MANAGER_SHELL_TRANSITIONS_TABLE = Table(
+ python_module=__file__,
+ class_name='WindowManagerShellTransitionsTable',
+ sql_name='window_manager_shell_transitions',
+ columns=[
+ C('ts', CppInt64()),
+ C('transition_id', CppInt64()),
+ C('arg_set_id', CppUint32()),
+ ],
+ tabledoc=TableDoc(
+ doc='Window Manager Shell Transitions',
+ group='Winscope',
+ columns={
+ 'ts': 'The timestamp the transition started playing',
+ 'transition_id': 'The id of the transition',
+ 'arg_set_id': 'Extra args parsed from the proto message',
+ }))
+
# Keep this list sorted.
ALL_TABLES = [
SURFACE_FLINGER_LAYERS_SNAPSHOT_TABLE,
SURFACE_FLINGER_LAYER_TABLE,
SURFACE_FLINGER_TRANSACTIONS_TABLE,
+ WINDOW_MANAGER_SHELL_TRANSITIONS_TABLE,
]
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 6c3b209..8ddff77 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -855,6 +855,8 @@
RegisterStaticTable(storage->surfaceflinger_layer_table());
RegisterStaticTable(storage->surfaceflinger_transactions_table());
+ RegisterStaticTable(storage->window_manager_shell_transitions_table());
+
RegisterStaticTable(storage->metadata_table());
RegisterStaticTable(storage->cpu_table());
RegisterStaticTable(storage->cpu_freq_table());
diff --git a/src/trace_processor/types/trace_processor_context.h b/src/trace_processor/types/trace_processor_context.h
index c2644ee..1eb16e4 100644
--- a/src/trace_processor/types/trace_processor_context.h
+++ b/src/trace_processor/types/trace_processor_context.h
@@ -123,6 +123,7 @@
std::unique_ptr<Destructible> i2c_tracker; // I2CTracker
std::unique_ptr<Destructible> perf_data_tracker; // PerfDataTracker
std::unique_ptr<Destructible> content_analyzer;
+ std::unique_ptr<Destructible> shell_transitions_tracker;
// These fields are trace readers which will be called by |forwarding_parser|
// once the format of the trace is discovered. They are placed here as they
diff --git a/test/trace_processor/diff_tests/include_index.py b/test/trace_processor/diff_tests/include_index.py
index 28c5abd..f1aed96 100644
--- a/test/trace_processor/diff_tests/include_index.py
+++ b/test/trace_processor/diff_tests/include_index.py
@@ -51,6 +51,7 @@
from diff_tests.parser.android.tests_games import AndroidGames
from diff_tests.parser.android.tests_surfaceflinger_layers import SurfaceFlingerLayers
from diff_tests.parser.android.tests_surfaceflinger_transactions import SurfaceFlingerTransactions
+from diff_tests.parser.android.tests_shell_transitions import ShellTransitions
from diff_tests.parser.android_fs.tests import AndroidFs
from diff_tests.parser.atrace.tests import Atrace
from diff_tests.parser.atrace.tests_error_handling import AtraceErrorHandling
@@ -170,6 +171,8 @@
'SurfaceFlingerLayers').fetch(),
*SurfaceFlingerTransactions(index_path, 'parser/android',
'SurfaceFlingerTransactions').fetch(),
+ *ShellTransitions(index_path, 'parser/android',
+ 'ShellTransitions').fetch(),
*TrackEvent(index_path, 'parser/track_event', 'TrackEvent').fetch(),
*TranslatedArgs(index_path, 'parser/translated_args',
'TranslatedArgs').fetch(),
diff --git a/test/trace_processor/diff_tests/parser/android/shell_transitions.textproto b/test/trace_processor/diff_tests/parser/android/shell_transitions.textproto
new file mode 100644
index 0000000..b92eb39
--- /dev/null
+++ b/test/trace_processor/diff_tests/parser/android/shell_transitions.textproto
@@ -0,0 +1,167 @@
+packet {
+ trusted_uid: 1000
+ trusted_packet_sequence_id: 2
+ previous_packet_dropped: true
+ trusted_pid: 1305
+ first_packet_on_sequence: true
+ shell_transition {
+ id: 7
+ create_time_ns: 76799049027
+ send_time_ns: 76875395422
+ start_transaction_id: 5604932321952
+ finish_transaction_id: 5604932321954
+ }
+}
+packet {
+ trusted_uid: 1000
+ trusted_packet_sequence_id: 2
+ trusted_pid: 1305
+ shell_transition {
+ id: 10
+ create_time_ns: 77854865352
+ send_time_ns: 77894307328
+ start_transaction_id: 5604932322158
+ finish_transaction_id: 5604932322159
+ }
+}
+packet {
+ trusted_uid: 1000
+ trusted_packet_sequence_id: 2
+ trusted_pid: 1305
+ shell_transition {
+ id: 11
+ create_time_ns: 82498121051
+ send_time_ns: 82535513345
+ start_transaction_id: 5604932322346
+ finish_transaction_id: 5604932322347
+ }
+}
+packet {
+ trusted_uid: 1000
+ trusted_packet_sequence_id: 3
+ previous_packet_dropped: true
+ trusted_pid: 1305
+ first_packet_on_sequence: true
+ shell_transition {
+ id: 8
+ create_time_ns: 76955664017
+ send_time_ns: 77277756832
+ start_transaction_id: 5604932322028
+ finish_transaction_id: 5604932322029
+ }
+}
+packet {
+ trusted_uid: 1000
+ trusted_packet_sequence_id: 4
+ previous_packet_dropped: true
+ trusted_pid: 1305
+ first_packet_on_sequence: true
+ shell_transition {
+ id: 7
+ starting_window_remove_time_ns: 77706603918
+ }
+}
+packet {
+ trusted_uid: 1000
+ trusted_packet_sequence_id: 5
+ previous_packet_dropped: true
+ trusted_pid: 1305
+ first_packet_on_sequence: true
+ shell_transition {
+ id: 9
+ create_time_ns: 77825423417
+ send_time_ns: 77843436723
+ start_transaction_id: 5604932322137
+ finish_transaction_id: 5604932322138
+ }
+}
+packet {
+ trusted_uid: 1000
+ trusted_packet_sequence_id: 5
+ trusted_pid: 1305
+ shell_transition {
+ id: 9
+ finish_time_ns: 77873935462
+ }
+}
+packet {
+ trusted_uid: 1000
+ trusted_packet_sequence_id: 5
+ trusted_pid: 1305
+ shell_transition {
+ id: 10
+ finish_time_ns: 78621610429
+ }
+}
+packet {
+ trusted_uid: 10241
+ trusted_packet_sequence_id: 6
+ previous_packet_dropped: true
+ trusted_pid: 2528
+ first_packet_on_sequence: true
+ shell_transition {
+ id: 7
+ dispatch_time_ns: 76879063147
+ handler: 2
+ }
+}
+packet {
+ trusted_uid: 10241
+ trusted_packet_sequence_id: 6
+ trusted_pid: 2528
+ shell_transition {
+ id: 8
+ merge_time_ns: 77278725500
+ merge_target: 7
+ }
+}
+packet {
+ trusted_uid: 10241
+ trusted_packet_sequence_id: 6
+ trusted_pid: 2528
+ shell_transition {
+ id: 8
+ dispatch_time_ns: 77320527177
+ handler: 3
+ }
+}
+packet {
+ trusted_uid: 10241
+ trusted_packet_sequence_id: 6
+ trusted_pid: 2528
+ shell_transition {
+ id: 9
+ dispatch_time_ns: 77876414832
+ handler: 3
+ }
+}
+packet {
+ trusted_uid: 10241
+ trusted_packet_sequence_id: 6
+ trusted_pid: 2528
+ shell_transition {
+ id: 10
+ dispatch_time_ns: 77899001013
+ handler: 4
+ }
+}
+packet {
+ trusted_uid: 10241
+ trusted_packet_sequence_id: 6
+ trusted_pid: 2528
+ shell_transition {
+ id: 11
+ dispatch_time_ns: 82536817137
+ handler: 2
+ }
+}
+packet {
+ trusted_uid: 10241
+ trusted_packet_sequence_id: 6
+ trusted_pid: 2528
+ shell_transition {
+ id: 12
+ merge_time_ns: 82697060749
+ merge_target: 11
+ }
+}
diff --git a/test/trace_processor/diff_tests/parser/android/shell_transitions_simple_merge.textproto b/test/trace_processor/diff_tests/parser/android/shell_transitions_simple_merge.textproto
new file mode 100644
index 0000000..6c9cb65
--- /dev/null
+++ b/test/trace_processor/diff_tests/parser/android/shell_transitions_simple_merge.textproto
@@ -0,0 +1,62 @@
+packet {
+ trusted_uid: 1000
+ trusted_packet_sequence_id: 2
+ previous_packet_dropped: true
+ trusted_pid: 1336
+ first_packet_on_sequence: true
+ shell_transition {
+ id: 15
+ create_time_ns: 2187614568227
+ send_time_ns: 2187671767120
+ start_transaction_id: 5738076308937
+ finish_transaction_id: 5738076308938
+ type: 1
+ targets {
+ mode: 1
+ layer_id: 244
+ window_id: 219481253
+ flags: 0
+ }
+ targets {
+ mode: 4
+ layer_id: 47
+ window_id: 54474511
+ flags: 1
+ }
+ flags: 0
+ }
+}
+packet {
+ trusted_uid: 1000
+ trusted_packet_sequence_id: 3
+ previous_packet_dropped: true
+ trusted_pid: 1336
+ first_packet_on_sequence: true
+ shell_transition {
+ id: 15
+ finish_time_ns: 2188195968659
+ }
+}
+packet {
+ trusted_uid: 1000
+ trusted_packet_sequence_id: 5
+ previous_packet_dropped: true
+ trusted_pid: 1336
+ first_packet_on_sequence: true
+ shell_transition {
+ id: 15
+ starting_window_remove_time_ns: 2188652838898
+ }
+}
+packet {
+ trusted_uid: 10225
+ trusted_packet_sequence_id: 12
+ previous_packet_dropped: true
+ trusted_pid: 3981
+ first_packet_on_sequence: true
+ shell_transition {
+ id: 15
+ dispatch_time_ns: 2187673373973
+ handler: 2
+ }
+}
diff --git a/test/trace_processor/diff_tests/parser/android/tests_shell_transitions.py b/test/trace_processor/diff_tests/parser/android/tests_shell_transitions.py
new file mode 100644
index 0000000..31af5f7
--- /dev/null
+++ b/test/trace_processor/diff_tests/parser/android/tests_shell_transitions.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+# 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 a
+#
+# 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.
+
+from python.generators.diff_tests.testing import Path
+from python.generators.diff_tests.testing import Csv
+from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import TestSuite
+
+
+class ShellTransitions(TestSuite):
+
+ def test_has_expected_transition_rows(self):
+ return DiffTestBlueprint(
+ trace=Path('shell_transitions.textproto'),
+ query="""
+ SELECT
+ id, transition_id
+ FROM
+ window_manager_shell_transitions;
+ """,
+ out=Csv("""
+ "id","transition_id"
+ 0,7
+ 1,10
+ 2,11
+ 3,8
+ 4,9
+ 5,12
+ """))
+
+ def test_has_expected_transition_args(self):
+ return DiffTestBlueprint(
+ trace=Path('shell_transitions_simple_merge.textproto'),
+ query="""
+ SELECT
+ args.key, args.display_value
+ FROM
+ window_manager_shell_transitions JOIN args ON window_manager_shell_transitions.arg_set_id = args.arg_set_id
+ WHERE window_manager_shell_transitions.transition_id = 15
+ ORDER BY args.key;
+ """,
+ out=Csv("""
+ "key","display_value"
+ "create_time_ns","2187614568227"
+ "dispatch_time_ns","2187673373973"
+ "finish_time_ns","2188195968659"
+ "finish_transaction_id","5738076308938"
+ "flags","0"
+ "handler","2"
+ "id","15"
+ "send_time_ns","2187671767120"
+ "start_transaction_id","5738076308937"
+ "starting_window_remove_time_ns","2188652838898"
+ "targets[0].flags","0"
+ "targets[0].layer_id","244"
+ "targets[0].mode","1"
+ "targets[0].window_id","219481253"
+ "targets[1].flags","1"
+ "targets[1].layer_id","47"
+ "targets[1].mode","4"
+ "targets[1].window_id","54474511"
+ "type","1"
+ """))