Merge "Remove '.details-panel button' ruleset"
diff --git a/BUILD b/BUILD
index 9b50375..49778a3 100644
--- a/BUILD
+++ b/BUILD
@@ -3824,6 +3824,7 @@
],
deps = [
":protos_perfetto_common_protos",
+ ":protos_perfetto_trace_android_protos",
":protos_perfetto_trace_gpu_protos",
":protos_perfetto_trace_profiling_protos",
":protos_perfetto_trace_track_event_protos",
@@ -3835,6 +3836,7 @@
name = "protos_perfetto_trace_interned_data_zero",
deps = [
":protos_perfetto_common_zero",
+ ":protos_perfetto_trace_android_zero",
":protos_perfetto_trace_gpu_zero",
":protos_perfetto_trace_interned_data_protos",
":protos_perfetto_trace_profiling_zero",
diff --git a/protos/perfetto/config/android/network_trace_config.proto b/protos/perfetto/config/android/network_trace_config.proto
index f58f280..ad5196b 100644
--- a/protos/perfetto/config/android/network_trace_config.proto
+++ b/protos/perfetto/config/android/network_trace_config.proto
@@ -27,4 +27,28 @@
// The minimum polling rate is 100ms (values below this are ignored).
// Introduced in Android 14 (U).
optional uint32 poll_ms = 1;
+
+ // The aggregation_threshold is the number of packets at which an event will
+ // switch from per-packet details to aggregate details. For example, a value
+ // of 50 means that if a particular event (grouped by the unique combinations
+ // of metadata fields: {interface, direction, uid, etc}) has fewer than 50
+ // packets, the exact timestamp and length are recorded for each packet. If
+ // there were 50 or more packets in an event, it would only record the total
+ // duration, packets, and length. A value of zero or unspecified will always
+ /// record per-packet details. A value of 1 always records aggregate details.
+ optional uint32 aggregation_threshold = 2;
+
+ // Specifies the maximum number of packet contexts to intern at a time. This
+ // prevents the interning table from growing too large and controls whether
+ // interning is enabled or disabled (a value of zero disables interning and
+ // is the default). When a data sources interning table reaches this amount,
+ // packet contexts will be inlined into NetworkPacketEvents.
+ optional uint32 intern_limit = 3;
+
+ // The following fields specify whether certain fields should be dropped from
+ // the output. Dropping fields improves normalization results, reduces the
+ // size of the interning table, and slightly reduces event size.
+ optional bool drop_local_port = 4;
+ optional bool drop_remote_port = 5;
+ optional bool drop_tcp_flags = 6;
}
diff --git a/protos/perfetto/config/perfetto_config.proto b/protos/perfetto/config/perfetto_config.proto
index 2504541..3673dd0 100644
--- a/protos/perfetto/config/perfetto_config.proto
+++ b/protos/perfetto/config/perfetto_config.proto
@@ -430,6 +430,30 @@
// The minimum polling rate is 100ms (values below this are ignored).
// Introduced in Android 14 (U).
optional uint32 poll_ms = 1;
+
+ // The aggregation_threshold is the number of packets at which an event will
+ // switch from per-packet details to aggregate details. For example, a value
+ // of 50 means that if a particular event (grouped by the unique combinations
+ // of metadata fields: {interface, direction, uid, etc}) has fewer than 50
+ // packets, the exact timestamp and length are recorded for each packet. If
+ // there were 50 or more packets in an event, it would only record the total
+ // duration, packets, and length. A value of zero or unspecified will always
+ /// record per-packet details. A value of 1 always records aggregate details.
+ optional uint32 aggregation_threshold = 2;
+
+ // Specifies the maximum number of packet contexts to intern at a time. This
+ // prevents the interning table from growing too large and controls whether
+ // interning is enabled or disabled (a value of zero disables interning and
+ // is the default). When a data sources interning table reaches this amount,
+ // packet contexts will be inlined into NetworkPacketEvents.
+ optional uint32 intern_limit = 3;
+
+ // The following fields specify whether certain fields should be dropped from
+ // the output. Dropping fields improves normalization results, reduces the
+ // size of the interning table, and slightly reduces event size.
+ optional bool drop_local_port = 4;
+ optional bool drop_remote_port = 5;
+ optional bool drop_tcp_flags = 6;
}
// End of protos/perfetto/config/android/network_trace_config.proto
diff --git a/protos/perfetto/metrics/android/android_frame_timeline_metric.proto b/protos/perfetto/metrics/android/android_frame_timeline_metric.proto
index d0f4d50..0ae9ec6 100644
--- a/protos/perfetto/metrics/android/android_frame_timeline_metric.proto
+++ b/protos/perfetto/metrics/android/android_frame_timeline_metric.proto
@@ -39,12 +39,14 @@
optional double frame_dur_ms_p90 = 15;
optional double frame_dur_ms_p95 = 16;
optional double frame_dur_ms_p99 = 17;
+ optional int64 dropped_frames = 18;
reserved 1, 2;
}
optional int64 total_frames = 4;
optional int64 missed_app_frames = 5;
+ optional int64 dropped_frames = 6;
repeated ProcessBreakdown process = 2;
diff --git a/protos/perfetto/metrics/perfetto_merged_metrics.proto b/protos/perfetto/metrics/perfetto_merged_metrics.proto
index 4db6c88..b4956f8 100644
--- a/protos/perfetto/metrics/perfetto_merged_metrics.proto
+++ b/protos/perfetto/metrics/perfetto_merged_metrics.proto
@@ -68,12 +68,14 @@
optional double frame_dur_ms_p90 = 15;
optional double frame_dur_ms_p95 = 16;
optional double frame_dur_ms_p99 = 17;
+ optional int64 dropped_frames = 18;
reserved 1, 2;
}
optional int64 total_frames = 4;
optional int64 missed_app_frames = 5;
+ optional int64 dropped_frames = 6;
repeated ProcessBreakdown process = 2;
diff --git a/protos/perfetto/trace/android/frame_timeline_event.proto b/protos/perfetto/trace/android/frame_timeline_event.proto
index bee0bc7..f1f0df8 100644
--- a/protos/perfetto/trace/android/frame_timeline_event.proto
+++ b/protos/perfetto/trace/android/frame_timeline_event.proto
@@ -42,6 +42,7 @@
JANK_BUFFER_STUFFING = 128;
JANK_UNKNOWN = 256;
JANK_SF_STUFFING = 512;
+ JANK_DROPPED = 1024;
};
// Specifies how a frame was presented on screen w.r.t. timing.
diff --git a/protos/perfetto/trace/android/network_trace.proto b/protos/perfetto/trace/android/network_trace.proto
index d1c43a2..5fcd28b 100644
--- a/protos/perfetto/trace/android/network_trace.proto
+++ b/protos/perfetto/trace/android/network_trace.proto
@@ -33,7 +33,9 @@
// The name of the interface if available (e.g. 'rmnet0').
optional string interface = 2;
- // The length of the packet in bytes (wire_size - L2_header_size).
+ // The length of the packet in bytes (wire_size - L2_header_size). Ignored
+ // when using NetworkPacketEvent as the ctx in either NetworkPacketBundle or
+ // NetworkPacketContext.
optional uint32 length = 3;
// The Linux user id associated with the packet's socket.
@@ -54,3 +56,36 @@
// The remote udp/tcp port of the packet.
optional uint32 remote_port = 9;
}
+
+// NetworkPacketBundle bundles one or more packets sharing the same attributes.
+message NetworkPacketBundle {
+ oneof packet_context {
+ // The intern id for looking up the associated packet context.
+ uint64 iid = 1;
+
+ // The inlined context for events in this bundle.
+ NetworkPacketEvent ctx = 2;
+ }
+
+ // The timestamp of the i-th packet encoded as the nanoseconds since the
+ // enclosing TracePacket's timestamp.
+ repeated uint64 packet_timestamps = 3 [packed = true];
+
+ // The length of the i-th packet in bytes (wire_size - L2_header_size).
+ repeated uint32 packet_lengths = 4 [packed = true];
+
+ // Total number of packets in the bundle (when above aggregation_threshold).
+ optional uint32 total_packets = 5;
+
+ // Duration between first and last packet (when above aggregation_threshold).
+ optional uint64 total_duration = 6;
+
+ // Total packet length in bytes (when above aggregation_threshold).
+ optional uint64 total_length = 7;
+}
+
+// An internable packet context.
+message NetworkPacketContext {
+ optional uint64 iid = 1;
+ optional NetworkPacketEvent ctx = 2;
+}
diff --git a/protos/perfetto/trace/interned_data/BUILD.gn b/protos/perfetto/trace/interned_data/BUILD.gn
index 580bb5b..66436c5 100644
--- a/protos/perfetto/trace/interned_data/BUILD.gn
+++ b/protos/perfetto/trace/interned_data/BUILD.gn
@@ -17,6 +17,7 @@
perfetto_proto_library("@TYPE@") {
sources = [ "interned_data.proto" ]
deps = [
+ "../android:@TYPE@",
"../gpu:@TYPE@",
"../profiling:@TYPE@",
"../track_event:@TYPE@",
diff --git a/protos/perfetto/trace/interned_data/interned_data.proto b/protos/perfetto/trace/interned_data/interned_data.proto
index 59103a7..9b6db47 100644
--- a/protos/perfetto/trace/interned_data/interned_data.proto
+++ b/protos/perfetto/trace/interned_data/interned_data.proto
@@ -16,6 +16,7 @@
syntax = "proto2";
+import "protos/perfetto/trace/android/network_trace.proto";
import "protos/perfetto/trace/gpu/gpu_render_stage_event.proto";
import "protos/perfetto/trace/track_event/chrome_histogram_sample.proto";
import "protos/perfetto/trace/track_event/debug_annotation.proto";
@@ -53,7 +54,7 @@
// emitted proactively in advance of referring to them in later packets.
//
// Next reserved id: 8 (up to 15).
-// Next id: 30.
+// Next id: 31.
message InternedData {
// TODO(eseckler): Replace iid fields inside interned messages with
// map<iid, message> type fields in InternedData.
@@ -114,4 +115,7 @@
// Interned string values in the DebugAnnotation proto.
repeated InternedString debug_annotation_string_values = 29;
+
+ // Interned packet context for android.network_packets.
+ repeated NetworkPacketContext packet_context = 30;
}
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 29d22c9..7dc8589 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -430,6 +430,30 @@
// The minimum polling rate is 100ms (values below this are ignored).
// Introduced in Android 14 (U).
optional uint32 poll_ms = 1;
+
+ // The aggregation_threshold is the number of packets at which an event will
+ // switch from per-packet details to aggregate details. For example, a value
+ // of 50 means that if a particular event (grouped by the unique combinations
+ // of metadata fields: {interface, direction, uid, etc}) has fewer than 50
+ // packets, the exact timestamp and length are recorded for each packet. If
+ // there were 50 or more packets in an event, it would only record the total
+ // duration, packets, and length. A value of zero or unspecified will always
+ /// record per-packet details. A value of 1 always records aggregate details.
+ optional uint32 aggregation_threshold = 2;
+
+ // Specifies the maximum number of packet contexts to intern at a time. This
+ // prevents the interning table from growing too large and controls whether
+ // interning is enabled or disabled (a value of zero disables interning and
+ // is the default). When a data sources interning table reaches this amount,
+ // packet contexts will be inlined into NetworkPacketEvents.
+ optional uint32 intern_limit = 3;
+
+ // The following fields specify whether certain fields should be dropped from
+ // the output. Dropping fields improves normalization results, reduces the
+ // size of the interning table, and slightly reduces event size.
+ optional bool drop_local_port = 4;
+ optional bool drop_remote_port = 5;
+ optional bool drop_tcp_flags = 6;
}
// End of protos/perfetto/config/android/network_trace_config.proto
@@ -3489,6 +3513,7 @@
JANK_BUFFER_STUFFING = 128;
JANK_UNKNOWN = 256;
JANK_SF_STUFFING = 512;
+ JANK_DROPPED = 1024;
};
// Specifies how a frame was presented on screen w.r.t. timing.
@@ -3707,7 +3732,9 @@
// The name of the interface if available (e.g. 'rmnet0').
optional string interface = 2;
- // The length of the packet in bytes (wire_size - L2_header_size).
+ // The length of the packet in bytes (wire_size - L2_header_size). Ignored
+ // when using NetworkPacketEvent as the ctx in either NetworkPacketBundle or
+ // NetworkPacketContext.
optional uint32 length = 3;
// The Linux user id associated with the packet's socket.
@@ -3729,6 +3756,39 @@
optional uint32 remote_port = 9;
}
+// NetworkPacketBundle bundles one or more packets sharing the same attributes.
+message NetworkPacketBundle {
+ oneof packet_context {
+ // The intern id for looking up the associated packet context.
+ uint64 iid = 1;
+
+ // The inlined context for events in this bundle.
+ NetworkPacketEvent ctx = 2;
+ }
+
+ // The timestamp of the i-th packet encoded as the nanoseconds since the
+ // enclosing TracePacket's timestamp.
+ repeated uint64 packet_timestamps = 3 [packed = true];
+
+ // The length of the i-th packet in bytes (wire_size - L2_header_size).
+ repeated uint32 packet_lengths = 4 [packed = true];
+
+ // Total number of packets in the bundle (when above aggregation_threshold).
+ optional uint32 total_packets = 5;
+
+ // Duration between first and last packet (when above aggregation_threshold).
+ optional uint64 total_duration = 6;
+
+ // Total packet length in bytes (when above aggregation_threshold).
+ optional uint64 total_length = 7;
+}
+
+// An internable packet context.
+message NetworkPacketContext {
+ optional uint64 iid = 1;
+ optional NetworkPacketEvent ctx = 2;
+}
+
// End of protos/perfetto/trace/android/network_trace.proto
// Begin of protos/perfetto/trace/android/packages_list.proto
@@ -9898,7 +9958,7 @@
// emitted proactively in advance of referring to them in later packets.
//
// Next reserved id: 8 (up to 15).
-// Next id: 30.
+// Next id: 31.
message InternedData {
// TODO(eseckler): Replace iid fields inside interned messages with
// map<iid, message> type fields in InternedData.
@@ -9959,6 +10019,9 @@
// Interned string values in the DebugAnnotation proto.
repeated InternedString debug_annotation_string_values = 29;
+
+ // Interned packet context for android.network_packets.
+ repeated NetworkPacketContext packet_context = 30;
}
// End of protos/perfetto/trace/interned_data/interned_data.proto
@@ -11803,7 +11866,7 @@
// See the [Buffers and Dataflow](/docs/concepts/buffers.md) doc for details.
//
// Next reserved id: 14 (up to 15).
-// Next id: 92.
+// Next id: 93.
message TracePacket {
// The timestamp of the TracePacket.
// By default this timestamps refers to the trace clock (CLOCK_BOOTTIME on
@@ -11912,6 +11975,9 @@
// Represents a single packet sent or received by the network.
NetworkPacketEvent network_packet = 88;
+ // Represents one or more packets sent or received by the network.
+ NetworkPacketBundle network_packet_bundle = 92;
+
// The "range of interest" for track events. See the message definition
// comments for more details.
TrackEventRangeOfInterest track_event_range_of_interest = 90;
diff --git a/protos/perfetto/trace/trace_packet.proto b/protos/perfetto/trace/trace_packet.proto
index c5c2de5..bb20291 100644
--- a/protos/perfetto/trace/trace_packet.proto
+++ b/protos/perfetto/trace/trace_packet.proto
@@ -94,7 +94,7 @@
// See the [Buffers and Dataflow](/docs/concepts/buffers.md) doc for details.
//
// Next reserved id: 14 (up to 15).
-// Next id: 92.
+// Next id: 93.
message TracePacket {
// The timestamp of the TracePacket.
// By default this timestamps refers to the trace clock (CLOCK_BOOTTIME on
@@ -203,6 +203,9 @@
// Represents a single packet sent or received by the network.
NetworkPacketEvent network_packet = 88;
+ // Represents one or more packets sent or received by the network.
+ NetworkPacketBundle network_packet_bundle = 92;
+
// The "range of interest" for track events. See the message definition
// comments for more details.
TrackEventRangeOfInterest track_event_range_of_interest = 90;
diff --git a/python/perfetto/trace_processor/metrics.descriptor b/python/perfetto/trace_processor/metrics.descriptor
index bf8b56e..ffc882c 100644
--- a/python/perfetto/trace_processor/metrics.descriptor
+++ b/python/perfetto/trace_processor/metrics.descriptor
Binary files differ
diff --git a/python/perfetto/trace_processor/protos.py b/python/perfetto/trace_processor/protos.py
index 4d0c40e..ea13297 100644
--- a/python/perfetto/trace_processor/protos.py
+++ b/python/perfetto/trace_processor/protos.py
@@ -43,6 +43,8 @@
def create_message_factory(message_type):
message_desc = self.descriptor_pool.FindMessageTypeByName(message_type)
+ if hasattr(message_factory, 'GetMessageClass'):
+ return message_factory.GetMessageClass(message_desc)
return message_factory.MessageFactory().GetPrototype(message_desc)
# Create proto messages to correctly communicate with the RPC API by sending
diff --git a/src/trace_processor/importers/proto/frame_timeline_event_parser.cc b/src/trace_processor/importers/proto/frame_timeline_event_parser.cc
index 6a7faf3..0b3e84e 100644
--- a/src/trace_processor/importers/proto/frame_timeline_event_parser.cc
+++ b/src/trace_processor/importers/proto/frame_timeline_event_parser.cc
@@ -82,6 +82,8 @@
jank_reasons.emplace_back("Unknown Jank");
if (jank_type & FrameTimelineEvent::JANK_SF_STUFFING)
jank_reasons.emplace_back("SurfaceFlinger Stuffing");
+ if (jank_type & FrameTimelineEvent::JANK_DROPPED)
+ jank_reasons.emplace_back("Dropped Frame");
std::string jank_str(
std::accumulate(jank_reasons.begin(), jank_reasons.end(), std::string(),
diff --git a/src/trace_processor/metrics/sql/android/android_frame_timeline_metric.sql b/src/trace_processor/metrics/sql/android/android_frame_timeline_metric.sql
index 44a55a2..40285e6 100644
--- a/src/trace_processor/metrics/sql/android/android_frame_timeline_metric.sql
+++ b/src/trace_processor/metrics/sql/android/android_frame_timeline_metric.sql
@@ -30,7 +30,9 @@
SUM(jank_type GLOB '*App Deadline Missed*'
OR jank_type GLOB '*SurfaceFlinger*'
OR jank_type GLOB '*Prediction Error*'
- OR jank_type GLOB '*Display HAL*') AS missed_frames,
+ OR jank_type GLOB '*Display HAL*'
+ OR jank_type GLOB '*Dropped Frame*') AS missed_frames,
+ SUM(jank_type GLOB '*Dropped Frame*') AS dropped_frames,
CAST(PERCENTILE(dur, 50) AS INTEGER) AS frame_dur_p50,
CAST(PERCENTILE(dur, 90) AS INTEGER) AS frame_dur_p90,
CAST(PERCENTILE(dur, 95) AS INTEGER) AS frame_dur_p95,
@@ -53,6 +55,7 @@
AndroidFrameTimelineMetric(
'total_frames', SUM(total_frames),
'missed_app_frames', SUM(missed_app_frames),
+ 'dropped_frames', SUM(dropped_frames),
'process', (
SELECT
RepeatedField(
@@ -67,6 +70,7 @@
'frame_dur_p50', frame_dur_p50,
'frame_dur_p90', frame_dur_p90,
'frame_dur_p95', frame_dur_p95,
- 'frame_dur_p99', frame_dur_p99))
+ 'frame_dur_p99', frame_dur_p99,
+ 'dropped_frames', dropped_frames))
FROM android_frame_timeline_metric_per_process))
FROM android_frame_timeline_metric_per_process;
diff --git a/test/cts/heapprofd_java_test_cts.cc b/test/cts/heapprofd_java_test_cts.cc
index 40c4aa6..6435f76 100644
--- a/test/cts/heapprofd_java_test_cts.cc
+++ b/test/cts/heapprofd_java_test_cts.cc
@@ -146,10 +146,13 @@
helper.StartTracing(trace_config);
StartAppActivity(app_name, "JavaOomActivity", "target.app.running", &task_runner,
/*delay_ms=*/100);
+ task_runner.RunUntilCheckpoint("target.app.running", 10000 /*ms*/);
- helper.WaitForTracingDisabled();
- helper.ReadData();
- helper.WaitForReadData();
+ if (SupportsOomHeapDump()) {
+ helper.WaitForTracingDisabled();
+ helper.ReadData();
+ helper.WaitForReadData();
+ }
PERFETTO_CHECK(IsAppRunning(app_name));
StopApp(app_name, "new.app.stopped", &task_runner);
diff --git a/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256 b/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
index d51b12b..56eb2c2 100644
--- a/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
+++ b/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
@@ -1 +1 @@
-01cee2096f54717e22e8b662477bb3eb55490eca01f1e092e96f998d13696b21
\ No newline at end of file
+6559e421403a5417246d436f86d352aab868a66fd850240589d771bb6f8bf267
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256 b/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
index d4896f7..0556f9d 100644
--- a/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
+++ b/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
@@ -1 +1 @@
-2e4095665abc92e5b8f1c25a47689af0a0f7af349375e5831f405e18b23fffd8
\ No newline at end of file
+55d04a3a8c16c9afe3298def1cbf8939a3508023f6da2f0b6777427764fdff24
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256 b/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
index 341e2ce..43932c6 100644
--- a/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
@@ -1 +1 @@
-9df3bd84fdafacbc874214e876624606f4abe55ecbaaa82d3ffbf8d7f0619cce
\ No newline at end of file
+ff165563554a298ef54a9bf1acfcfff80ca09bf869412cd17c22eaa3d73ebd53
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
index 259f7be..e342913 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
@@ -1 +1 @@
-ab33f88f300df74195d963b0e0f827e9c637716a558cfb42952ea00b727c52b5
\ No newline at end of file
+5799b74804912156abf653b05c3e57598bf8c7719c257567eb9a58689f5fef29
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
index 0937e8c..9ce11d7 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
@@ -1 +1 @@
-28e6f5a2f066b5dc1c192b9b4386d08f99e532d5c8e6981cbb00f3a521c336a4
\ No newline at end of file
+44a5f57e15b33c714daad868c40ac379b3d0be06e64dba685e8ba36fde4426e3
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
index 3f65312..956fa6a 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
@@ -1 +1 @@
-61624a8c55db10d0a387100294b8a8b1191bc542f8f4da28a1d0447024689df0
\ No newline at end of file
+a6a3d22d4a437774e6aa555fa046bda49f2ff3d9ddca2eda0e2da96115bd98d7
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha256
index 3e6d116..e0d079f 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha256
@@ -1 +1 @@
-1ce5977375a3c459f0834c1e8114564e7fcb2c03f8e504e4c7558d62019338e5
\ No newline at end of file
+2650426962c62983041501bbd8fd2cad33d4c7734e859ae132885ed1e8f2d305
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha256
index 1c4c4a1..e5613f6 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha256
@@ -1 +1 @@
-f1e10b381882081846e9df1b024e8ad992fa470f0ce137b6fa90e0f0641d8c39
\ No newline at end of file
+94b7078e2c9452112262c365f841b4d504f89f79e745c871316e4235a31caaf9
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha256
index 5863d55..b69e976 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha256
@@ -1 +1 @@
-f3c0069c0ef9643552081835fd06c972b87448b7df5ac538a4d3e213a437bcb1
\ No newline at end of file
+5a0015c3a57443dae62ec68acea089c1dc186c040ea0cb31e2bfbb98213379f8
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha256
index e70add7..fb257d9 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha256
@@ -1 +1 @@
-04b6ed7959eef3625b2d25d9daa68e7caea3f8ad4846234a45a6c264aebc8e47
\ No newline at end of file
+656dd0f321a2b0d81728ef6144d6d27b86d2a355d212eae82a07723f8bb51363
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha256
index d66c5dd..f5eea2d 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha256
@@ -1 +1 @@
-e1eaeed835b30f5e575a17c922de4179bc320c5564160af276ced725903795ba
\ No newline at end of file
+1bd377e966ca2a42963f5d0ab22d30aaba00e11c7e56c534010bfd3e27d4066e
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha256 b/test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha256
index ac9f60e..d3a37c5 100644
--- a/test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha256
@@ -1 +1 @@
-08b1014ccc25e1bad77cccdc58545e212f804f51a75bf6cef233a33cbd835fac
\ No newline at end of file
+111744f4975530816a265893e4eb5213db59be514208e98424061b9aae622806
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
index 01fb381..f52a7cf 100644
--- a/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
@@ -1 +1 @@
-7fa091fa3b7613ea388d12d59501ff6af5eb618bc113d8cc09dee86aee65eb20
\ No newline at end of file
+219f53dbacd26b4e2535b6bc581e2d3face7949546b5a53d52b75ce4d7e2d7e9
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256 b/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256
index c9480fb..9f21de4 100644
--- a/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256
@@ -1 +1 @@
-b5bedbda51c728c7b058ee17c83be9536bcd85770ed2b0c3a3d305aea42b5078
\ No newline at end of file
+13537f7a1c55c131307413033086ff478db706a5f974d801bf3edadd02334d1d
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha256 b/test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha256
index d733f51..96f9dbd 100644
--- a/test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha256
@@ -1 +1 @@
-d1687347903fbe76615507eac353b0afdd7b1db2d3a8b58aa037b6a1016d3b7f
\ No newline at end of file
+956051d915faf570c30e8c596421d99da77276d130a077eb583425ab43e4dced
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
index 4ead93a..0d59eb4 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
@@ -1 +1 @@
-ad3a36f843c2b04d2acd7529036f32fdd4c91a5162ce0ce3502bdf27382bd463
\ No newline at end of file
+6c73b73c0e57e071143bf9030b38b9bd88409c3748640c1ebbef22f9c2e38c0c
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
index 01fb381..f52a7cf 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
@@ -1 +1 @@
-7fa091fa3b7613ea388d12d59501ff6af5eb618bc113d8cc09dee86aee65eb20
\ No newline at end of file
+219f53dbacd26b4e2535b6bc581e2d3face7949546b5a53d52b75ce4d7e2d7e9
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
index 4ead93a..0d59eb4 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
@@ -1 +1 @@
-ad3a36f843c2b04d2acd7529036f32fdd4c91a5162ce0ce3502bdf27382bd463
\ No newline at end of file
+6c73b73c0e57e071143bf9030b38b9bd88409c3748640c1ebbef22f9c2e38c0c
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
index 3c37919..88aa4ba 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
@@ -1 +1 @@
-cc6799a71bce86cd5c3b657182a99999337bda963c54a96b36b811051f5309dd
\ No newline at end of file
+1a4de1eb1aafa874a275174348fddd726364b1bfa05fd7179cab5fa4cffa36df
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha256
index 45218a3..36df905 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha256
@@ -1 +1 @@
-48f3843a740514558a711104b8fa156d613c7141fb1021941fd95e1806b0deff
\ No newline at end of file
+b2d299ac7e4695ef8ae62e84595efe5fef03c426b34122680af5ebe8ffe52589
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256
index 2723dae..fdbf575 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256
@@ -1 +1 @@
-006f0866f8dbf0181034b3d730627481787a04031a005dd6f0224ccfe30110d7
\ No newline at end of file
+4d52c4eaed29cacf5bf71bb6743b7b6556f6021c7a98d0b4d5beed11bf734b84
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
index 01fb381..f52a7cf 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
@@ -1 +1 @@
-7fa091fa3b7613ea388d12d59501ff6af5eb618bc113d8cc09dee86aee65eb20
\ No newline at end of file
+219f53dbacd26b4e2535b6bc581e2d3face7949546b5a53d52b75ce4d7e2d7e9
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
index 4ead93a..0d59eb4 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
@@ -1 +1 @@
-ad3a36f843c2b04d2acd7529036f32fdd4c91a5162ce0ce3502bdf27382bd463
\ No newline at end of file
+6c73b73c0e57e071143bf9030b38b9bd88409c3748640c1ebbef22f9c2e38c0c
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
index 4ead93a..0d59eb4 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
@@ -1 +1 @@
-ad3a36f843c2b04d2acd7529036f32fdd4c91a5162ce0ce3502bdf27382bd463
\ No newline at end of file
+6c73b73c0e57e071143bf9030b38b9bd88409c3748640c1ebbef22f9c2e38c0c
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/performance/frame_timeline_metric.out b/test/trace_processor/diff_tests/performance/frame_timeline_metric.out
index a121e82..1a06b3c 100644
--- a/test/trace_processor/diff_tests/performance/frame_timeline_metric.out
+++ b/test/trace_processor/diff_tests/performance/frame_timeline_metric.out
@@ -1,6 +1,7 @@
android_frame_timeline_metric {
- total_frames: 5
+ total_frames: 6
missed_app_frames: 3
+ dropped_frames: 1
process {
process {
@@ -16,6 +17,7 @@
frame_dur_p90: 33
frame_dur_p95: 33
frame_dur_p99: 33
+ dropped_frames: 0
}
process {
@@ -32,21 +34,23 @@
frame_dur_p90: 16
frame_dur_p95: 16
frame_dur_p99: 16
+ dropped_frames: 0
}
process {
process {
name: "process3"
}
- total_frames: 1
- missed_frames: 1
+ total_frames: 2
+ missed_frames: 2
missed_app_frames: 0
missed_sf_frames: 1
- frame_dur_max: 4
- frame_dur_avg: 4
- frame_dur_p50: 4
+ frame_dur_max: 5
+ frame_dur_avg: 2
+ frame_dur_p50: 2
frame_dur_p90: 4
frame_dur_p95: 4
frame_dur_p99: 4
+ dropped_frames: 1
}
}
diff --git a/test/trace_processor/diff_tests/performance/frame_timeline_metric.py b/test/trace_processor/diff_tests/performance/frame_timeline_metric.py
index b499eb4..17639a3 100755
--- a/test/trace_processor/diff_tests/performance/frame_timeline_metric.py
+++ b/test/trace_processor/diff_tests/performance/frame_timeline_metric.py
@@ -30,6 +30,7 @@
JANK_BUFFER_STUFFING = 128
JANK_UNKNOWN = 256
JANK_SF_STUFFING = 512
+ JANK_DROPPED = 1024
class PresentType:
@@ -123,5 +124,17 @@
gpu_composition=0,
jank_type=JankType.JANK_SF_CPU_DEADLINE_MISSED,
prediction_type=PredictionType.PREDICTION_VALID)
-trace.add_frame_end_event(ts=85, cookie=15)
+trace.add_actual_surface_frame_start_event(
+ ts=90,
+ cookie=15,
+ token=8,
+ display_frame_token=9,
+ pid=1003,
+ layer_name="Layer1",
+ present_type=PresentType.PRESENT_DROPPED,
+ on_time_finish=0,
+ gpu_composition=0,
+ jank_type=JankType.JANK_DROPPED,
+ prediction_type=PredictionType.PREDICTION_VALID)
+trace.add_frame_end_event(ts=95, cookie=15)
sys.stdout.buffer.write(trace.trace.SerializeToString())
diff --git a/tools/gen_amalgamated_sql.py b/tools/gen_amalgamated_sql.py
index 1ac0ab0..a726002 100755
--- a/tools/gen_amalgamated_sql.py
+++ b/tools/gen_amalgamated_sql.py
@@ -64,8 +64,10 @@
};
'''
-def filename_to_variable(filename):
- return "k" + "".join([x.capitalize() for x in filename.split("_")])
+
+def filename_to_variable(filename: str):
+ return "k" + "".join(
+ [x.capitalize() for x in filename.replace(os.path.sep, '_').split("_")])
def main():
@@ -114,8 +116,7 @@
# Create the C++ variable for each SQL file.
for path, sql in sql_outputs.items():
- name = os.path.basename(path)
- variable = filename_to_variable(os.path.splitext(name)[0])
+ variable = filename_to_variable(os.path.splitext(path)[0])
output.write('\nconst char {}[] = '.format(variable))
# MSVC doesn't like string literals that are individually longer than 16k.
# However it's still fine "if" "we" "concatenate" "many" "of" "them".
@@ -135,8 +136,7 @@
# Create mapping of filename to variable name for each variable.
output.write("\nconst FileToSql kFileToSql[] = {")
for path in sql_outputs.keys():
- name = os.path.basename(path)
- variable = filename_to_variable(os.path.splitext(name)[0])
+ variable = filename_to_variable(os.path.splitext(path)[0])
# This is for Windows which has \ as a path separator.
path = path.replace("\\", "/")
diff --git a/ui/src/assets/analyze_page.scss b/ui/src/assets/analyze_page.scss
index 4a700a3..fbe9bab 100644
--- a/ui/src/assets/analyze_page.scss
+++ b/ui/src/assets/analyze_page.scss
@@ -15,6 +15,8 @@
.analyze-page {
overflow-y: auto;
overflow-x: hidden;
+ display: grid;
+ grid-template-rows: auto auto 1fr;
.query-input {
width: 100%;
background-color: #111;
@@ -29,5 +31,6 @@
padding: 0.5em;
overflow: auto;
resize: vertical;
+ outline: none;
}
}
diff --git a/ui/src/assets/common.scss b/ui/src/assets/common.scss
index 9e26d09..82a9569 100644
--- a/ui/src/assets/common.scss
+++ b/ui/src/assets/common.scss
@@ -12,12 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+@import "widgets/theme";
@import "typefaces";
@import "fonts";
:root {
- --sidebar-width: 256px;
- --topbar-height: 48px;
+ --sidebar-width: 230px;
+ --topbar-height: 44px;
--monospace-font: "Roboto Mono", monospace;
--track-shell-width: 250px;
--track-border-color: #00000025;
@@ -51,7 +52,7 @@
overflow-wrap: break-word;
font-family: "Roboto Condensed", sans-serif;
font-weight: 300;
- letter-spacing: -0.25px;
+ letter-spacing: -0.5px;
}
* {
@@ -175,12 +176,13 @@
grid-area: alerts;
background-color: #f2f2f2;
> div {
- font-family: "Raleway", sans-serif;
+ font-family: "Roboto", sans-serif;
font-weight: 400;
letter-spacing: 0.25px;
padding: 1rem;
display: flex;
justify-content: space-between;
+ align-items: center;
button {
width: 24px;
height: 24px;
@@ -377,7 +379,7 @@
.track-shell {
@include transition();
- padding-left: 10px;
+ padding-left: 5px;
display: grid;
cursor: grab;
grid-template-areas: "title buttons";
@@ -408,7 +410,7 @@
.chip {
background-color: #bed6ff;
- border-radius: 3px;
+ border-radius: $pf-border-radius;
font-size: smaller;
padding: 0 0.1rem;
margin-left: 1ch;
@@ -441,6 +443,7 @@
display: flex;
height: 100%;
align-items: center;
+ justify-content: center;
&:hover {
background-color: #ebeef9;
@@ -469,6 +472,7 @@
}
.details-panel-container {
+ box-shadow: #0000003b 0px 0px 3px 1px;
position: relative;
overflow-x: hidden;
overflow-y: auto;
@@ -533,7 +537,7 @@
}
.overview-timeline {
- height: 100px;
+ height: 70px;
}
.time-axis-panel {
diff --git a/ui/src/assets/details.scss b/ui/src/assets/details.scss
index c1d112e..00919b8 100644
--- a/ui/src/assets/details.scss
+++ b/ui/src/assets/details.scss
@@ -41,14 +41,14 @@
padding: 3px 10px 0 10px;
margin-top: 3px;
font-size: 13px;
- border-radius: 5px 5px 0 0;
- background-color: hsla(0, 0%, 75%, 1);
- border-top: solid 1px hsla(0, 0%, 75%, 1);
- border-left: solid 1px hsla(0, 0%, 75%, 1);
+ border-radius: 3px 3px 0 0;
+ background-color: #0000000f;
border-right: solid 1px hsla(0, 0%, 75%, 1);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
+ z-index: 5;
+ box-shadow: #0000003b 0px 0px 3px 1px;
&[active] {
background-color: white;
@@ -62,6 +62,10 @@
cursor: pointer;
background-color: hsla(0, 0%, 85%, 1);
}
+
+ &:nth-child(1) {
+ margin-left: 3px;
+ }
}
}
diff --git a/ui/src/assets/flags_page.scss b/ui/src/assets/flags_page.scss
index a23c60f..d65b678 100644
--- a/ui/src/assets/flags_page.scss
+++ b/ui/src/assets/flags_page.scss
@@ -12,31 +12,34 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+@import "widgets/theme";
+
.flags-page {
overflow-y: scroll;
}
.flags-content {
- max-width: 90ch;
+ max-width: 100ch;
width: 60%;
margin: 0 auto;
padding: 3rem;
display: grid;
- grid-row-gap: 1rem;
h1 {
font-size: larger;
+ margin: 1rem 1rem;
}
button {
background: none;
border: 1px solid rgb(218, 220, 224);
- border-radius: 3px;
+ border-radius: $pf-border-radius;
color: rgb(25, 103, 210);
font-size: 0.8125rem;
padding: 8px 12px;
cursor: pointer;
font-weight: 500;
+ margin: 3px 0.5rem;
}
}
@@ -45,9 +48,9 @@
grid-template:
"title control" auto
"description control" auto / 1fr auto;
-
- row-gap: 0.5rem;
- align-content: center;
+ row-gap: 0.3rem;
+ padding: 1rem 1rem;
+ align-items: center;
select {
grid-area: control;
@@ -70,3 +73,8 @@
font-size: smaller;
}
}
+
+.flag-widget:nth-child(2n+1) {
+ background-color: #0000000a;
+}
+
diff --git a/ui/src/assets/hiring_banner.scss b/ui/src/assets/hiring_banner.scss
index a6807df..3e3b46d 100644
--- a/ui/src/assets/hiring_banner.scss
+++ b/ui/src/assets/hiring_banner.scss
@@ -1,5 +1,5 @@
.hiring-banner {
- font-family: "Raleway", sans-serif;
+ font-family: "Roboto", sans-serif;
font-size: 12px;
background: #db4634;
box-shadow: 0 0 3px rgba(0, 0, 0, 30%);
diff --git a/ui/src/assets/home_page.scss b/ui/src/assets/home_page.scss
index 4d3f5a8..f421b83 100644
--- a/ui/src/assets/home_page.scss
+++ b/ui/src/assets/home_page.scss
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+@import "widgets/theme";
+
.home-page {
text-align: center;
align-items: center;
@@ -31,15 +33,15 @@
font-size: 60px;
margin: 25px;
text-align: center;
- font-family: "Raleway", sans-serif;
- font-weight: 100;
+ font-family: "Roboto", sans-serif;
+ font-weight: 400;
color: #333;
}
.channel-select {
font-family: "Roboto", sans-serif;
font-size: 1.2rem;
- font-weight: 200;
+ font-weight: 400;
margin-top: 3em;
--chan-width: 100px;
--chan-num: 2;
@@ -69,7 +71,7 @@
padding: 0;
position: relative;
background-color: hsl(218, 8%, 30%);
- border-radius: 3px;
+ border-radius: $pf-border-radius;
box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.4);
border: 0;
width: calc(var(--chan-width) * var(--chan-num));
@@ -88,7 +90,7 @@
z-index: 2;
text-transform: uppercase;
font-size: 16px;
- font-family: "Raleway";
+ font-family: "Roboto";
font-weight: 400;
letter-spacing: 0.3px;
}
@@ -106,7 +108,7 @@
left: 0;
z-index: 1;
border-radius: inherit;
- @include transition();
+ @include transition(0.2s);
}
.home-page-reload {
@@ -114,7 +116,7 @@
opacity: 0;
color: #da4534;
font-weight: 400;
- @include transition();
+ @include transition(0.2s);
&.show {
opacity: 1;
}
@@ -126,7 +128,7 @@
grid-area: footer;
text-decoration: none;
font-family: "Roboto", sans-serif;
- font-weight: 200;
+ font-weight: 400;
color: #333;
font-size: 15px;
}
diff --git a/ui/src/assets/metrics_page.scss b/ui/src/assets/metrics_page.scss
index 3ed881c..1487e34 100644
--- a/ui/src/assets/metrics_page.scss
+++ b/ui/src/assets/metrics_page.scss
@@ -12,9 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+@import "widgets/theme";
+
.metrics-page {
padding: 30px;
- font-family: "Raleway", sans-serif;
+ font-family: "Roboto", sans-serif;
overflow-y: auto;
.metric-run-button {
@@ -23,12 +25,12 @@
border-radius: 4px;
padding: 5px 10px;
font-weight: bold;
- font-family: "Raleway";
+ font-family: "Roboto";
}
select {
margin: 10px;
- font-family: "Raleway";
+ font-family: "Roboto";
font-size: 1em;
border: 1px solid black;
background-color: #eee;
@@ -39,7 +41,7 @@
padding: 20px;
font-family: "Roboto Mono";
line-height: 1.5em;
- border-radius: 5px;
+ border-radius: $pf-border-radius;
overflow-x: auto;
&.metric-error {
color: #ef6c00;
diff --git a/ui/src/assets/modal.scss b/ui/src/assets/modal.scss
index 76d3cea..ee575f0 100644
--- a/ui/src/assets/modal.scss
+++ b/ui/src/assets/modal.scss
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+@import "widgets/theme";
+
// The opacity changes are only transitional. Once the `modalFadeOut` animation
// reaches the end, the Mithril component that renders .modal-backdrop
// (and .modal-dialog) is fully destroyed and removed from the DOM.
@@ -57,7 +59,6 @@
.modal-dialog {
position: absolute;
z-index: 100;
- border: 1px solid #333;
background-color: #fff;
margin: auto;
min-width: 25vw;
@@ -65,7 +66,7 @@
padding: 30px;
max-width: 90vw;
max-height: 90vh;
- border-radius: 4px;
+ border-radius: $pf-border-radius;
overflow-y: auto;
top: 50%;
left: 50%;
@@ -86,7 +87,7 @@
h2 {
margin-top: 0;
margin-bottom: 0;
- font-family: "Raleway", sans-serif;
+ font-family: "Roboto", sans-serif;
font-weight: 600;
font-size: 1.25rem;
line-height: 1.25;
diff --git a/ui/src/assets/perfetto.scss b/ui/src/assets/perfetto.scss
index cb3c14e..5e72a03 100644
--- a/ui/src/assets/perfetto.scss
+++ b/ui/src/assets/perfetto.scss
@@ -32,3 +32,4 @@
@import "widgets/empty_state";
@import "widgets/anchor";
@import "widgets/popup";
+@import "widgets/multiselect";
diff --git a/ui/src/assets/record.scss b/ui/src/assets/record.scss
index 529e57e..43cf635 100644
--- a/ui/src/assets/record.scss
+++ b/ui/src/assets/record.scss
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+@import "widgets/theme";
+
:root {
--record-text-color: #333;
}
@@ -30,7 +32,7 @@
max-width: 900px;
min-height: 500px;
margin: auto;
- border-radius: 5px;
+ border-radius: $pf-border-radius;
box-shadow: 0 1px 2px 0 #aaa, 0 1px 3px 1px #eee;
background-color: #fff;
display: grid;
@@ -53,7 +55,7 @@
height: 100%;
text-align: center;
padding: 180px 30px;
- font-family: "Raleway", sans-serif;
+ font-family: "Roboto", sans-serif;
font-size: 25px;
}
}
@@ -72,8 +74,6 @@
flex-direction: row;
.logo-wrapping {
- border-radius: 50%;
- background-color: #f0f0f0;
width: 150px;
height: 150px;
display: inline-block;
@@ -81,7 +81,7 @@
align-self: center;
i.material-icons {
- color: #0000ff;
+ color: #16161d;
font-size: 150px;
}
}
@@ -127,7 +127,7 @@
input[type="text"] {
flex-grow: 1;
- border-radius: 4px;
+ border-radius: $pf-border-radius;
border: 1px solid #dcdcdc;
padding: 3px;
margin: 0 10px;
@@ -169,7 +169,7 @@
.record-modal-button,
.record-modal-button-high {
- border-radius: 0.25rem;
+ border-radius: $pf-border-radius;
border-style: none;
border-width: 0;
}
@@ -234,7 +234,7 @@
margin: 10px;
text-align: center;
background-color: #eee;
- font-family: "Raleway", sans-serif;
+ font-family: "Roboto", sans-serif;
font-size: 17px;
@media (max-width: 1280px) {
font-size: 1.6vw;
@@ -366,7 +366,7 @@
padding: 0 1em;
font-size: 15px;
letter-spacing: 0.5px;
- font-family: "Raleway", sans-serif;
+ font-family: "Roboto", sans-serif;
font-weight: 600;
color: #666;
display: grid;
@@ -378,12 +378,10 @@
i {
margin: auto;
- border-radius: 100%;
font-size: 32px;
width: 38px;
height: 38px;
padding: 3px;
- background: #eee;
grid-area: icon;
}
@@ -476,7 +474,7 @@
margin-right: 10px;
text-align: center;
justify-items: center;
- font-family: "Raleway", sans-serif;
+ font-family: "Roboto", sans-serif;
padding: 7px;
&:hover:enabled {
@@ -542,7 +540,7 @@
}
&::placeholder {
color: #b4b7ba;
- font-family: "Raleway", sans-serif;
+ font-family: "Roboto", sans-serif;
font-weight: 400;
}
}
@@ -564,7 +562,7 @@
> header {
text-align: center;
- font-family: "Raleway", sans-serif;
+ font-family: "Roboto", sans-serif;
font-size: 20px;
padding: 15px 10px;
color: #333;
@@ -801,7 +799,7 @@
margin: 5px;
text-align: center;
background-color: #eee;
- font-family: "Raleway", sans-serif;
+ font-family: "Roboto", sans-serif;
font-size: 20px;
@media (max-width: 1280px) {
font-size: 1.6vw;
@@ -1175,7 +1173,7 @@
text-align: center;
margin: 3px;
background-color: #eee;
- font-family: "Raleway", sans-serif;
+ font-family: "Roboto", sans-serif;
flex-grow: 1;
font-size: 17px;
@media (max-width: 1280px) {
@@ -1202,7 +1200,7 @@
border-radius: 10px;
text-align: center;
justify-items: center;
- font-family: "Raleway", sans-serif;
+ font-family: "Roboto", sans-serif;
padding: 7px;
background-color: hsl(88, 50%, 67%);
diff --git a/ui/src/assets/sidebar.scss b/ui/src/assets/sidebar.scss
index b0a7092..6fedf61 100644
--- a/ui/src/assets/sidebar.scss
+++ b/ui/src/assets/sidebar.scss
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+@import "widgets/theme";
+
.sidebar {
--sidebar-padding-bottom: 40px;
--sidebar-timing: 0.15s;
@@ -38,11 +40,11 @@
height: var(--topbar-height);
line-height: var(--topbar-height);
vertical-align: middle;
- padding: 0 20px;
+ padding: 0 12px;
color: #fff;
overflow: visible;
.brand {
- height: 40px;
+ height: 36px;
margin-top: 4px;
}
&::before {
@@ -54,7 +56,7 @@
position: absolute;
font-size: 10px;
line-height: 10px;
- font-family: "Raleway", sans-serif;
+ font-family: "Roboto", sans-serif;
left: 155px;
top: 7px;
}
@@ -121,17 +123,15 @@
cursor: pointer;
> h1,
> h2 {
- font-family: "Raleway", sans-serif;
letter-spacing: 0.25px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
- margin: 0 24px;
+ margin: 0 12px;
}
> h1 {
color: #fff;
font-size: 15px;
- font-weight: 500;
}
> h2 {
@include transition();
@@ -189,10 +189,8 @@
a {
line-height: 24px;
font-size: 14px;
- font-weight: 400;
- font-family: "Raleway", sans-serif;
letter-spacing: 0.5px;
- padding: 5px 24px;
+ padding: 4px 12px;
text-decoration: none;
display: block;
&.pending {
@@ -225,6 +223,7 @@
}
.material-icons {
margin-right: 10px;
+ font-size: 20px
}
&:hover {
background-color: #373f4b;
@@ -265,13 +264,19 @@
}
> .dbg-info-square {
+ font-family: "Roboto Condensed", sans-serif;
width: 24px;
- height: 22px;
- line-height: 22px;
+ height: 24px;
+ line-height: 24px;
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+
margin: 1px 0;
background: #12161b;
color: #4e71b3;
- border-radius: 5px;
+ border-radius: $pf-border-radius;
font-size: 12px;
text-align: center;
&.green {
diff --git a/ui/src/assets/topbar.scss b/ui/src/assets/topbar.scss
index 561c9364..7742b5a 100644
--- a/ui/src/assets/topbar.scss
+++ b/ui/src/assets/topbar.scss
@@ -11,6 +11,9 @@
// 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.
+
+@import "widgets/theme";
+
@mixin omnibox-width() {
width: 90%;
max-width: 600px;
@@ -22,7 +25,7 @@
z-index: 3;
overflow: visible;
background-color: hsl(215, 1%, 95%);
- box-shadow: 0 -3px 14px 2px #bbb;
+ box-shadow: 0px 1px 2px 1px #00000026;
min-height: var(--topbar-height);
display: flex;
justify-content: center;
@@ -33,7 +36,7 @@
display: grid;
grid-template-areas: "icon input stepthrough";
grid-template-columns: 34px auto max-content;
- border-radius: 20px;
+ border-radius: $pf-border-radius;
background-color: #fcfcfc;
border: 0;
line-height: 34px;
@@ -83,14 +86,14 @@
}
&.message-mode {
background-color: hsl(0, 0%, 89%);
- border-radius: 4px;
+ border-radius: $pf-border-radius;
input::placeholder {
font-weight: 400;
font-family: var(--monospace-font);
color: hsl(213, 40%, 50%);
}
&:before {
- content: "bubble_chart";
+ content: "info";
}
}
.stepthrough {
diff --git a/ui/src/assets/trace_info_page.scss b/ui/src/assets/trace_info_page.scss
index 69baaaf..3846b7a 100644
--- a/ui/src/assets/trace_info_page.scss
+++ b/ui/src/assets/trace_info_page.scss
@@ -36,7 +36,7 @@
}
h2 {
- font-family: "Raleway", sans-serif;
+ font-family: "Roboto", sans-serif;
font-weight: 400;
letter-spacing: 0.25px;
font-size: 2rem;
diff --git a/ui/src/assets/typefaces.scss b/ui/src/assets/typefaces.scss
index d0c4b82..02ef5e8 100644
--- a/ui/src/assets/typefaces.scss
+++ b/ui/src/assets/typefaces.scss
@@ -1,27 +1,5 @@
/* latin */
@font-face {
- font-family: "Raleway";
- font-style: normal;
- font-weight: 100;
- src: url(assets/Raleway-Thin.woff2) format("woff2");
- unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
- U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
- U+FEFF, U+FFFD;
-}
-
-/* latin */
-@font-face {
- font-family: "Raleway";
- font-style: normal;
- font-weight: 400;
- src: url(assets/Raleway-Regular.woff2) format("woff2");
- unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
- U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
- U+FEFF, U+FFFD;
-}
-
-/* latin */
-@font-face {
font-family: "Roboto";
font-style: normal;
font-weight: 100;
diff --git a/ui/src/assets/widgets/empty_state.scss b/ui/src/assets/widgets/empty_state.scss
index 46ab9bc..081bca9 100644
--- a/ui/src/assets/widgets/empty_state.scss
+++ b/ui/src/assets/widgets/empty_state.scss
@@ -23,7 +23,7 @@
& > i {
margin: auto;
- font-size: 5em; // Size of the icon is relative to the font size
+ font-size: 5em; // Size of the icon is relative to the font size.
color: $pf-minimal-foreground;
margin-bottom: 10px;
}
@@ -31,6 +31,14 @@
.pf-empty-state-header {
margin-bottom: 10px;
color: $pf-minimal-foreground;
+ text-align: center;
+
+ // Limit width to the size of the container and use no wrap & elipsis to
+ // stop the size getting out of control.
+ max-width: 100%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
.pf-empty-state-detail {
diff --git a/ui/src/assets/widgets/multiselect.scss b/ui/src/assets/widgets/multiselect.scss
new file mode 100644
index 0000000..c751d3a
--- /dev/null
+++ b/ui/src/assets/widgets/multiselect.scss
@@ -0,0 +1,56 @@
+// 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.
+
+// Generic list with y-overflow, move me to a common file if we want to reuse.
+.pf-list {
+ overflow-y: auto;
+}
+
+.pf-multiselect-popup {
+ font-family: $pf-font;
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ width: 280px;
+ max-height: 300px;
+ & > .pf-search-bar {
+ margin-bottom: 8px;
+ display: flex;
+ & > .pf-search-box {
+ flex-grow: 1;
+ }
+ }
+ .pf-multiselect-item {
+ display: block; // Put each item on a new line
+ margin-top: 5px;
+ }
+ .pf-multiselect-header {
+ align-items: baseline;
+ display: flex;
+ position: sticky;
+ top: 0;
+ font-size: 1em;
+ background-color: white;
+ z-index: 1;
+ font-size: 0.75em;
+ border-bottom: solid 1px $pf-minimal-foreground;
+ & > span {
+ margin-right: auto;
+ }
+ }
+ .pf-multiselect-container {
+ position: relative;
+ margin-bottom: 16px;
+ }
+}
diff --git a/ui/src/assets/widgets/theme.scss b/ui/src/assets/widgets/theme.scss
index 3902dc4..2a49642 100644
--- a/ui/src/assets/widgets/theme.scss
+++ b/ui/src/assets/widgets/theme.scss
@@ -15,7 +15,7 @@
// Standard theme settings for widgets
$pf-font: "Roboto Condensed", sans-serif;
-$pf-border-radius: 3px;
+$pf-border-radius: 2px;
$pf-anim-timing: 250ms cubic-bezier(0.4, 0, 0.2, 1);
// Here we describe two colour schemes: primary and minimal
diff --git a/ui/src/common/protos.ts b/ui/src/common/protos.ts
index 1fa770d..9443a00 100644
--- a/ui/src/common/protos.ts
+++ b/ui/src/common/protos.ts
@@ -25,6 +25,8 @@
import ChromeConfig = protos.perfetto.protos.ChromeConfig;
import TrackEventConfig = protos.perfetto.protos.TrackEventConfig;
import ConsumerPort = protos.perfetto.protos.ConsumerPort;
+import NetworkPacketTraceConfig =
+ protos.perfetto.protos.NetworkPacketTraceConfig;
import NativeContinuousDumpConfig =
protos.perfetto.protos.HeapprofdConfig.ContinuousDumpConfig;
import JavaContinuousDumpConfig =
@@ -112,6 +114,7 @@
JavaHprofConfig,
MeminfoCounters,
NativeContinuousDumpConfig,
+ NetworkPacketTraceConfig,
ProcessStatsConfig,
PerfettoMetatrace,
ReadBuffersRequest,
diff --git a/ui/src/common/recordingV2/recording_config_utils.ts b/ui/src/common/recordingV2/recording_config_utils.ts
index 6a329b3..2840b3c 100644
--- a/ui/src/common/recordingV2/recording_config_utils.ts
+++ b/ui/src/common/recordingV2/recording_config_utils.ts
@@ -28,6 +28,7 @@
JavaHprofConfig,
MeminfoCounters,
NativeContinuousDumpConfig,
+ NetworkPacketTraceConfig,
ProcessStatsConfig,
SysStatsConfig,
TraceConfig,
@@ -368,6 +369,25 @@
}
}
+ if (uiCfg.androidNetworkTracing) {
+ if (targetInfo.targetType !== 'CHROME') {
+ const net = new TraceConfig.DataSource();
+ net.config = new DataSourceConfig();
+ net.config.name = 'android.network_packets';
+ net.config.networkPacketTraceConfig = new NetworkPacketTraceConfig();
+ net.config.networkPacketTraceConfig.pollMs =
+ uiCfg.androidNetworkTracingPollMs;
+ protoCfg.dataSources.push(net);
+
+ // Record package info so that Perfetto can display the package name for
+ // network packet events based on the event uid.
+ const pkg = new TraceConfig.DataSource();
+ pkg.config = new DataSourceConfig();
+ pkg.config.name = 'android.packages_list';
+ protoCfg.dataSources.push(pkg);
+ }
+ }
+
if (uiCfg.chromeLogs) {
chromeCategories.add('log');
}
diff --git a/ui/src/controller/record_config_types.ts b/ui/src/controller/record_config_types.ts
index fc306b2..a23acfd 100644
--- a/ui/src/controller/record_config_types.ts
+++ b/ui/src/controller/record_config_types.ts
@@ -53,6 +53,8 @@
androidLogBuffers: arrayOf(str()),
androidFrameTimeline: bool(),
androidGameInterventionList: bool(),
+ androidNetworkTracing: bool(),
+ androidNetworkTracingPollMs: num(250),
cpuCoarse: bool(),
cpuCoarsePollMs: num(1000),
diff --git a/ui/src/controller/track_decider.ts b/ui/src/controller/track_decider.ts
index b577210..543c87c 100644
--- a/ui/src/controller/track_decider.ts
+++ b/ui/src/controller/track_decider.ts
@@ -93,7 +93,7 @@
const KERNEL_WAKELOCK_GROUP = 'Kernel wakelocks';
const NETWORK_TRACK_REGEX = new RegExp('^.* (Received|Transmitted)( KB)?$');
const NETWORK_TRACK_GROUP = 'Networking';
-const ENTITY_RESIDENCY_REGEX = new RegExp('^Entity residency: (.*)$');
+const ENTITY_RESIDENCY_REGEX = new RegExp('^Entity residency:');
const ENTITY_RESIDENCY_GROUP = 'Entity residency';
// Sets the default 'scale' for counter tracks. If the regex matches
@@ -632,17 +632,11 @@
}
}
- async groupTracksByRegex(
- regex: RegExp, groupName: string,
- renameToCapturingGroup?: number): Promise<void> {
+ async groupTracksByRegex(regex: RegExp, groupName: string): Promise<void> {
let groupUuid = undefined;
for (const track of this.tracksToAdd) {
- const matches = regex.exec(track.name);
- if (matches !== null) {
- if (renameToCapturingGroup) {
- track.name = matches[renameToCapturingGroup];
- }
+ if (regex.test(track.name)) {
if (groupUuid === undefined) {
groupUuid = uuidv4();
}
@@ -1695,7 +1689,7 @@
await this.groupTracksByRegex(KERNEL_WAKELOCK_REGEX, KERNEL_WAKELOCK_GROUP);
await this.groupTracksByRegex(NETWORK_TRACK_REGEX, NETWORK_TRACK_GROUP);
await this.groupTracksByRegex(
- ENTITY_RESIDENCY_REGEX, ENTITY_RESIDENCY_GROUP, 1);
+ ENTITY_RESIDENCY_REGEX, ENTITY_RESIDENCY_GROUP);
// Pre-group all kernel "threads" (actually processes) if this is a linux
// system trace. Below, addProcessTrackGroups will skip them due to an
diff --git a/ui/src/frontend/icons.ts b/ui/src/frontend/icons.ts
index 0725a41..d30ba54 100644
--- a/ui/src/frontend/icons.ts
+++ b/ui/src/frontend/icons.ts
@@ -20,3 +20,10 @@
export const EXPAND_UP = 'expand_less';
export const PIN = 'push_pin';
+
+export const LIBRARY_ADD_CHECK = 'library_add_check';
+
+export const SELECT_ALL = 'select_all';
+export const DESELECT = 'deselect';
+
+export const STAR = 'star';
diff --git a/ui/src/frontend/metrics_page.ts b/ui/src/frontend/metrics_page.ts
index 1eabd99..606236f 100644
--- a/ui/src/frontend/metrics_page.ts
+++ b/ui/src/frontend/metrics_page.ts
@@ -17,6 +17,7 @@
import {Actions} from '../common/actions';
import {globals} from './globals';
import {createPage} from './pages';
+import {Button} from './widgets/button';
function getCurrSelectedMetric() {
const {availableMetrics, selectedIndex} = globals.state.metrics;
@@ -64,9 +65,10 @@
},
availableMetrics.map(
(metric) => m('option', {value: metric, key: metric}, metric))),
- m('button.metric-run-button',
- {onclick: () => globals.dispatch(Actions.requestSelectedMetric({}))},
- 'Run'),
+ m(Button, {
+ onclick: () => globals.dispatch(Actions.requestSelectedMetric({})),
+ label: 'Run',
+ }),
]);
}
}
diff --git a/ui/src/frontend/notes_panel.ts b/ui/src/frontend/notes_panel.ts
index 295c893..52cec48 100644
--- a/ui/src/frontend/notes_panel.ts
+++ b/ui/src/frontend/notes_panel.ts
@@ -232,7 +232,7 @@
const prevBaseline = ctx.textBaseline;
ctx.textBaseline = 'alphabetic';
// Adjust height for icon font.
- ctx.font = '24px Material Icons';
+ ctx.font = '24px Material Symbols Sharp';
ctx.fillStyle = color;
ctx.strokeStyle = color;
// The ligatures have padding included that means the icon is not drawn
diff --git a/ui/src/frontend/overview_timeline_panel.ts b/ui/src/frontend/overview_timeline_panel.ts
index adc06d9..2e351f3 100644
--- a/ui/src/frontend/overview_timeline_panel.ts
+++ b/ui/src/frontend/overview_timeline_panel.ts
@@ -34,7 +34,7 @@
import {TimeScale} from './time_scale';
export class OverviewTimelinePanel extends Panel {
- private static HANDLE_SIZE_PX = 7;
+ private static HANDLE_SIZE_PX = 5;
private width = 0;
private gesture?: DragGestureHandler;
@@ -79,7 +79,7 @@
renderCanvas(ctx: CanvasRenderingContext2D, size: PanelSize) {
if (this.width === undefined) return;
if (this.timeScale === undefined) return;
- const headerHeight = 25;
+ const headerHeight = 20;
const tracksHeight = size.height - headerHeight;
const timeSpan = new TimeSpan(0, this.totTime.duration);
@@ -147,18 +147,18 @@
ctx.fillRect(vizEndPx, headerHeight, 1, tracksHeight);
const hbarWidth = OverviewTimelinePanel.HANDLE_SIZE_PX;
- const hbarDivisionFactor = 3.5;
+ const hbarHeight = tracksHeight * 0.4;
// Draw handlebar
ctx.fillRect(
vizStartPx - Math.floor(hbarWidth / 2) - 1,
headerHeight,
hbarWidth,
- tracksHeight / hbarDivisionFactor);
+ hbarHeight);
ctx.fillRect(
vizEndPx - Math.floor(hbarWidth / 2),
headerHeight,
hbarWidth,
- tracksHeight / hbarDivisionFactor);
+ hbarHeight);
}
private onMouseMove(e: MouseEvent) {
diff --git a/ui/src/frontend/query_history.ts b/ui/src/frontend/query_history.ts
index e2e503c..a50627a 100644
--- a/ui/src/frontend/query_history.ts
+++ b/ui/src/frontend/query_history.ts
@@ -17,6 +17,8 @@
import {Actions} from '../common/actions';
import {globals} from './globals';
+import {STAR} from './icons';
+
import {
arrayOf,
bool,
@@ -60,15 +62,17 @@
return m(
'.history-item',
m('.history-item-buttons',
- m('button',
- {
- onclick: () => {
- queryHistoryStorage.setStarred(
- vnode.attrs.index, !vnode.attrs.entry.starred);
- globals.rafScheduler.scheduleFullRedraw();
+ m(
+ 'button',
+ {
+ onclick: () => {
+ queryHistoryStorage.setStarred(
+ vnode.attrs.index, !vnode.attrs.entry.starred);
+ globals.rafScheduler.scheduleFullRedraw();
+ },
},
- },
- m(Icon, {icon: 'star', filled: vnode.attrs.entry.starred})),
+ m(Icon, {icon: STAR, filled: vnode.attrs.entry.starred}),
+ ),
m('button',
{
onclick: () => {
diff --git a/ui/src/frontend/record_page.ts b/ui/src/frontend/record_page.ts
index d142ee6..d6d574a 100644
--- a/ui/src/frontend/record_page.ts
+++ b/ui/src/frontend/record_page.ts
@@ -711,7 +711,7 @@
m('.sub', 'Buffer mode, size and duration'))),
m('a[href="#!/record/instructions"]',
m(`li${routePage === 'instructions' ? '.active' : ''}`,
- m('i.material-icons.rec', 'fiber_manual_record'),
+ m('i.material-icons-filled.rec', 'fiber_manual_record'),
m('.title', 'Recording command'),
m('.sub', 'Manually record trace'))),
PERSIST_CONFIG_FLAG.get() ?
diff --git a/ui/src/frontend/record_page_v2.ts b/ui/src/frontend/record_page_v2.ts
index 105411d..70ab452 100644
--- a/ui/src/frontend/record_page_v2.ts
+++ b/ui/src/frontend/record_page_v2.ts
@@ -466,7 +466,7 @@
m('.sub', 'Buffer mode, size and duration'))),
m('a[href="#!/record/instructions"]',
m(`li${routePage === 'instructions' ? '.active' : ''}`,
- m('i.material-icons.rec', 'fiber_manual_record'),
+ m('i.material-icons-filled.rec', 'fiber_manual_record'),
m('.title', 'Recording command'),
m('.sub', 'Manually record trace'))),
PERSIST_CONFIG_FLAG.get() ?
diff --git a/ui/src/frontend/recording/android_settings.ts b/ui/src/frontend/recording/android_settings.ts
index 2536a69..7f9a6e5 100644
--- a/ui/src/frontend/recording/android_settings.ts
+++ b/ui/src/frontend/recording/android_settings.ts
@@ -21,6 +21,8 @@
DropdownAttrs,
Probe,
ProbeAttrs,
+ Slider,
+ SliderAttrs,
Textarea,
TextareaAttrs,
Toggle,
@@ -172,6 +174,23 @@
Requires Android 13 (T) or above.`,
setEnabled: (cfg, val) => cfg.androidGameInterventionList = val,
isEnabled: (cfg) => cfg.androidGameInterventionList,
- } as ProbeAttrs));
+ } as ProbeAttrs),
+ m(Probe,
+ {
+ title: 'Network Tracing',
+ img: '',
+ descr: `Records detailed information on network packets.
+ Requires Android 14 (U) or above.`,
+ setEnabled: (cfg, val) => cfg.androidNetworkTracing = val,
+ isEnabled: (cfg) => cfg.androidNetworkTracing,
+ } as ProbeAttrs,
+ m(Slider, {
+ title: 'Poll interval',
+ cssClass: '.thin',
+ values: [100, 250, 500, 1000, 2500],
+ unit: 'ms',
+ set: (cfg, val) => cfg.androidNetworkTracingPollMs = val,
+ get: (cfg) => cfg.androidNetworkTracingPollMs,
+ } as SliderAttrs)));
}
}
diff --git a/ui/src/frontend/recording/reset_target_modal.ts b/ui/src/frontend/recording/reset_target_modal.ts
index a50cce8..5e34c7b 100644
--- a/ui/src/frontend/recording/reset_target_modal.ts
+++ b/ui/src/frontend/recording/reset_target_modal.ts
@@ -69,7 +69,6 @@
m('.logo-wrapping', m('i.material-icons', 'usb')),
m('.record-modal-description',
m('h3', 'Android device over WebUSB'),
- m('h4', 'JustWorks from the browser with one click'),
m('text',
'Android developers: this option cannot co-operate ' +
'with the adb host on your machine. Only one entity between ' +
diff --git a/ui/src/frontend/track_panel.ts b/ui/src/frontend/track_panel.ts
index b76eeed..0aa518a 100644
--- a/ui/src/frontend/track_panel.ts
+++ b/ui/src/frontend/track_panel.ts
@@ -245,7 +245,7 @@
'.track',
{
style: {
- height: `${Math.max(24, attrs.track.getHeight())}px`,
+ height: `${Math.max(18, attrs.track.getHeight())}px`,
},
id: 'track_' + attrs.trackState.id,
},
diff --git a/ui/src/frontend/widgets/checkbox.ts b/ui/src/frontend/widgets/checkbox.ts
index e9fa7d9..34a8eb8 100644
--- a/ui/src/frontend/widgets/checkbox.ts
+++ b/ui/src/frontend/widgets/checkbox.ts
@@ -25,16 +25,25 @@
// events will be fired.
// Defaults to false.
disabled?: boolean;
+ // Extra classes
+ classes?: string|string[];
// Remaining attributes forwarded to the underlying HTML <label>.
[htmlAttrs: string]: any;
}
export class Checkbox implements m.ClassComponent<CheckboxAttrs> {
view({attrs}: m.CVnode<CheckboxAttrs>) {
- const {label, checked, disabled = false, ...htmlAttrs} = attrs;
+ const {
+ label,
+ checked,
+ disabled = false,
+ classes: extraClasses,
+ ...htmlAttrs
+ } = attrs;
const classes = classNames(
disabled && 'pf-disabled',
+ extraClasses,
);
// The default checkbox is removed and an entirely new one created inside
diff --git a/ui/src/frontend/widgets/multiselect.ts b/ui/src/frontend/widgets/multiselect.ts
new file mode 100644
index 0000000..84c788b
--- /dev/null
+++ b/ui/src/frontend/widgets/multiselect.ts
@@ -0,0 +1,233 @@
+// 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.
+
+import * as m from 'mithril';
+import {globals} from '../globals';
+import {DESELECT, SELECT_ALL} from '../icons';
+import {Button} from './button';
+import {Checkbox} from './checkbox';
+import {EmptyState} from './empty_state';
+import {Popup, PopupPosition} from './popup';
+import {TextInput} from './text_input';
+
+export interface Option {
+ // The ID is used to indentify this option, and is used in callbacks.
+ id: string;
+ // This is the name displayed and used for searching.
+ name: string;
+ // Whether the option is selected or not.
+ checked: boolean;
+}
+
+export interface MultiSelectDiff {
+ id: string;
+ checked: boolean;
+}
+
+export interface MultiSelectAttrs {
+ icon?: string;
+ label: string;
+ options: Option[];
+ onChange?: (diffs: MultiSelectDiff[]) => void;
+ repeatCheckedItemsAtTop?: boolean;
+ showNumSelected?: boolean;
+ popupPosition?: PopupPosition;
+}
+
+// A component which shows a list of items with checkboxes, allowing the user to
+// select from the list which ones they want to be selected.
+// Also provides search functionality.
+// This component is entirely controlled and callbacks must be supplied for when
+// the selected items changes, and when the search term changes.
+// There is an optional boolean flag to enable repeating the selected items at
+// the top of the list for easy access - defaults to false.
+export class MultiSelect implements m.ClassComponent<MultiSelectAttrs> {
+ private searchText: string = '';
+ view({attrs}: m.CVnode<MultiSelectAttrs>) {
+ const {
+ icon,
+ popupPosition = PopupPosition.Auto,
+ } = attrs;
+
+ return m(
+ Popup,
+ {
+ trigger: m(Button, {label: this.labelText(attrs), icon}),
+ position: popupPosition,
+ },
+ this.renderPopup(attrs),
+ );
+ }
+
+ private labelText(attrs: MultiSelectAttrs): string {
+ const {
+ options,
+ showNumSelected,
+ label,
+ } = attrs;
+
+ if (showNumSelected) {
+ const numSelected = options.filter(({checked}) => checked).length;
+ return `${label} (${numSelected} selected)`;
+ } else {
+ return label;
+ }
+ }
+
+ private renderPopup(attrs: MultiSelectAttrs) {
+ const {
+ options,
+ } = attrs;
+
+ const filteredItems = options.filter(({name}) => {
+ return name.toLowerCase().includes(this.searchText.toLowerCase());
+ });
+
+ return m(
+ '.pf-multiselect-popup',
+ this.renderSearchBox(),
+ this.renderListOfItems(attrs, filteredItems),
+ );
+ }
+
+ private renderListOfItems(attrs: MultiSelectAttrs, options: Option[]) {
+ const {
+ repeatCheckedItemsAtTop,
+ onChange = () => {},
+ } = attrs;
+ const allChecked = options.every(({checked}) => checked);
+ const anyChecked = options.some(({checked}) => checked);
+
+ if (options.length === 0) {
+ return m(EmptyState, {
+ header: `No results for '${this.searchText}'`,
+ });
+ } else {
+ return [m(
+ '.pf-list',
+ repeatCheckedItemsAtTop && anyChecked &&
+ m(
+ '.pf-multiselect-container',
+ m(
+ '.pf-multiselect-header',
+ m('span',
+ this.searchText === '' ? 'Selected' :
+ `Selected (Filtered)`),
+ m(Button, {
+ label: 'Clear All',
+ icon: DESELECT,
+ minimal: true,
+ onclick: () => {
+ const diffs =
+ options.filter(({checked}) => checked)
+ .map(({id}) => ({id, checked: false}));
+ onChange(diffs);
+ globals.rafScheduler.scheduleFullRedraw();
+ },
+ disabled: !anyChecked,
+ }),
+ ),
+ this.renderOptions(
+ attrs, options.filter(({checked}) => checked)),
+ ),
+ m(
+ '.pf-multiselect-container',
+ m(
+ '.pf-multiselect-header',
+ m('span',
+ this.searchText === '' ? 'Options' : `Options (Filtered)`),
+ m(Button, {
+ label: 'Select All',
+ icon: SELECT_ALL,
+ minimal: true,
+ onclick: () => {
+ const diffs = options.filter(({checked}) => !checked)
+ .map(({id}) => ({id, checked: true}));
+ onChange(diffs);
+ globals.rafScheduler.scheduleFullRedraw();
+ },
+ disabled: allChecked,
+ }),
+ m(Button, {
+ label: 'Select None',
+ icon: DESELECT,
+ minimal: true,
+ onclick: () => {
+ const diffs = options.filter(({checked}) => checked)
+ .map(({id}) => ({id, checked: false}));
+ onChange(diffs);
+ globals.rafScheduler.scheduleFullRedraw();
+ },
+ disabled: !anyChecked,
+ }),
+ ),
+ this.renderOptions(attrs, options),
+ ),
+ )];
+ }
+ }
+
+ private renderSearchBox() {
+ return m(
+ '.pf-search-bar',
+ m(TextInput, {
+ oninput: (event: Event) => {
+ const eventTarget = event.target as HTMLTextAreaElement;
+ this.searchText = eventTarget.value;
+ globals.rafScheduler.scheduleFullRedraw();
+ },
+ value: this.searchText,
+ placeholder: 'Search...',
+ extraClasses: 'pf-search-box',
+ }),
+ this.renderClearButton(),
+ );
+ }
+
+ private renderClearButton() {
+ if (this.searchText != '') {
+ return m(Button, {
+ onclick: () => {
+ this.searchText = '';
+ globals.rafScheduler.scheduleFullRedraw();
+ },
+ label: '',
+ icon: 'close',
+ minimal: true,
+ });
+ } else {
+ return null;
+ }
+ }
+
+ private renderOptions(attrs: MultiSelectAttrs, options: Option[]) {
+ const {
+ onChange = () => {},
+ } = attrs;
+
+ return options.map((item) => {
+ const {checked, name, id} = item;
+ return m(Checkbox, {
+ label: name,
+ key: id, // Prevents transitions jumping between items when searching
+ checked,
+ classes: 'pf-multiselect-item',
+ onchange: () => {
+ onChange([{id, checked: !checked}]);
+ globals.rafScheduler.scheduleFullRedraw();
+ },
+ });
+ });
+ }
+}
diff --git a/ui/src/frontend/widgets/text_input.ts b/ui/src/frontend/widgets/text_input.ts
index cd5f7e8..326dcd2 100644
--- a/ui/src/frontend/widgets/text_input.ts
+++ b/ui/src/frontend/widgets/text_input.ts
@@ -13,9 +13,11 @@
// limitations under the License.
import * as m from 'mithril';
+import {classNames} from '../classnames';
export interface TextInputAttrs {
[htmlAttrs: string]: any;
+ extraClasses?: string|string[];
}
// For now, this component is just a simple wrapper around a plain old input
@@ -25,6 +27,8 @@
// become more apparent.
export class TextInput implements m.ClassComponent<TextInputAttrs> {
view({attrs}: m.CVnode<TextInputAttrs>) {
- return m('input.pf-text-input', attrs);
+ const {extraClasses = '', ...htmlAttrs} = attrs;
+ const classes = classNames(extraClasses);
+ return m('input.pf-text-input', {class: classes, ...htmlAttrs});
}
}
diff --git a/ui/src/frontend/widgets_page.ts b/ui/src/frontend/widgets_page.ts
index 0a946cc..054ad6d 100644
--- a/ui/src/frontend/widgets_page.ts
+++ b/ui/src/frontend/widgets_page.ts
@@ -17,16 +17,35 @@
import {Anchor} from './anchor';
import {classNames} from './classnames';
import {globals} from './globals';
+import {LIBRARY_ADD_CHECK} from './icons';
import {createPage} from './pages';
import {TableShowcase} from './tables/table_showcase';
import {Button} from './widgets/button';
import {Checkbox} from './widgets/checkbox';
import {EmptyState} from './widgets/empty_state';
import {Icon} from './widgets/icon';
+import {MultiSelect, MultiSelectDiff} from './widgets/multiselect';
import {Popup, PopupPosition} from './widgets/popup';
import {Portal} from './widgets/portal';
import {TextInput} from './widgets/text_input';
+const options: {[key: string]: boolean} = {
+ foobar: false,
+ foo: false,
+ bar: false,
+ baz: false,
+ qux: false,
+ quux: false,
+ corge: false,
+ grault: false,
+ garply: false,
+ waldo: false,
+ fred: false,
+ plugh: false,
+ xyzzy: false,
+ thud: false,
+};
+
function PortalButton() {
let portalOpen = false;
@@ -338,6 +357,34 @@
m(WidgetShowcase, {
renderWidget: (opts) => m(Icon, {icon: 'star', ...opts}),
initialOpts: {filled: false},
- }));
+ }),
+ m('h2', 'MultiSelect'),
+ m(WidgetShowcase, {
+ renderWidget: ({icon, ...rest}) => m(MultiSelect, {
+ options: Object.entries(options).map(([key, value]) => {
+ return {
+ id: key,
+ name: key,
+ checked: value,
+ };
+ }),
+ popupPosition: PopupPosition.Top,
+ label: 'Multi Select',
+ icon: icon ? LIBRARY_ADD_CHECK : undefined,
+ onChange: (diffs: MultiSelectDiff[]) => {
+ diffs.forEach(({id, checked}) => {
+ options[id] = checked;
+ });
+ globals.rafScheduler.scheduleFullRedraw();
+ },
+ ...rest,
+ }),
+ initialOpts: {
+ icon: true,
+ showNumSelected: true,
+ repeatCheckedItemsAtTop: true,
+ },
+ }),
+ );
},
});
diff --git a/ui/src/tracks/chrome_slices/index.ts b/ui/src/tracks/chrome_slices/index.ts
index 00c475a..23f9a5e 100644
--- a/ui/src/tracks/chrome_slices/index.ts
+++ b/ui/src/tracks/chrome_slices/index.ts
@@ -29,7 +29,7 @@
export const SLICE_TRACK_KIND = 'ChromeSliceTrack';
const SLICE_HEIGHT = 18;
-const TRACK_PADDING = 4;
+const TRACK_PADDING = 2;
const CHEVRON_WIDTH_PX = 10;
const HALF_CHEVRON_WIDTH_PX = CHEVRON_WIDTH_PX / 2;
const INNER_CHEVRON_OFFSET = -3;
diff --git a/ui/src/tracks/thread_state/index.ts b/ui/src/tracks/thread_state/index.ts
index 475d8b1..3713999 100644
--- a/ui/src/tracks/thread_state/index.ts
+++ b/ui/src/tracks/thread_state/index.ts
@@ -167,8 +167,8 @@
}
}
-const MARGIN_TOP = 4;
-const RECT_HEIGHT = 14;
+const MARGIN_TOP = 3;
+const RECT_HEIGHT = 12;
const EXCESS_WIDTH = 10;
class ThreadStateTrack extends Track<Config, Data> {