Merge "ui: Set stable to current canary" into main
diff --git a/include/perfetto/public/protos/BUILD.gn b/include/perfetto/public/protos/BUILD.gn
index cd583ad..f134d35 100644
--- a/include/perfetto/public/protos/BUILD.gn
+++ b/include/perfetto/public/protos/BUILD.gn
@@ -15,6 +15,7 @@
source_set("protos") {
sources = [
"common/builtin_clock.pzc.h",
+ "common/data_source_descriptor.pzc.h",
"config/data_source_config.pzc.h",
"config/trace_config.pzc.h",
"config/track_event/track_event_config.pzc.h",
diff --git a/include/perfetto/public/protos/common/builtin_clock.pzc.h b/include/perfetto/public/protos/common/builtin_clock.pzc.h
index 2800419..51218e4 100644
--- a/include/perfetto/public/protos/common/builtin_clock.pzc.h
+++ b/include/perfetto/public/protos/common/builtin_clock.pzc.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
#ifndef INCLUDE_PERFETTO_PUBLIC_PROTOS_COMMON_BUILTIN_CLOCK_PZC_H_
#define INCLUDE_PERFETTO_PUBLIC_PROTOS_COMMON_BUILTIN_CLOCK_PZC_H_
diff --git a/include/perfetto/public/protos/config/data_source_config.pzc.h b/include/perfetto/public/protos/config/data_source_config.pzc.h
index cd75632..718a3bc 100644
--- a/include/perfetto/public/protos/config/data_source_config.pzc.h
+++ b/include/perfetto/public/protos/config/data_source_config.pzc.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
#ifndef INCLUDE_PERFETTO_PUBLIC_PROTOS_CONFIG_DATA_SOURCE_CONFIG_PZC_H_
#define INCLUDE_PERFETTO_PUBLIC_PROTOS_CONFIG_DATA_SOURCE_CONFIG_PZC_H_
@@ -26,6 +29,7 @@
PERFETTO_PB_MSG_DECL(perfetto_protos_AndroidLogConfig);
PERFETTO_PB_MSG_DECL(perfetto_protos_AndroidPolledStateConfig);
PERFETTO_PB_MSG_DECL(perfetto_protos_AndroidPowerConfig);
+PERFETTO_PB_MSG_DECL(perfetto_protos_AndroidSdkSyspropGuardConfig);
PERFETTO_PB_MSG_DECL(perfetto_protos_AndroidSystemPropertyConfig);
PERFETTO_PB_MSG_DECL(perfetto_protos_ChromeConfig);
PERFETTO_PB_MSG_DECL(perfetto_protos_FtraceConfig);
@@ -39,6 +43,8 @@
PERFETTO_PB_MSG_DECL(perfetto_protos_PerfEventConfig);
PERFETTO_PB_MSG_DECL(perfetto_protos_ProcessStatsConfig);
PERFETTO_PB_MSG_DECL(perfetto_protos_StatsdTracingConfig);
+PERFETTO_PB_MSG_DECL(perfetto_protos_SurfaceFlingerLayersConfig);
+PERFETTO_PB_MSG_DECL(perfetto_protos_SurfaceFlingerTransactionsConfig);
PERFETTO_PB_MSG_DECL(perfetto_protos_SysStatsConfig);
PERFETTO_PB_MSG_DECL(perfetto_protos_SystemInfoConfig);
PERFETTO_PB_MSG_DECL(perfetto_protos_TestConfig);
@@ -199,6 +205,21 @@
network_packet_trace_config,
120);
PERFETTO_PB_FIELD(perfetto_protos_DataSourceConfig,
+ MSG,
+ perfetto_protos_SurfaceFlingerLayersConfig,
+ surfaceflinger_layers_config,
+ 121);
+PERFETTO_PB_FIELD(perfetto_protos_DataSourceConfig,
+ MSG,
+ perfetto_protos_SurfaceFlingerTransactionsConfig,
+ surfaceflinger_transactions_config,
+ 123);
+PERFETTO_PB_FIELD(perfetto_protos_DataSourceConfig,
+ MSG,
+ perfetto_protos_AndroidSdkSyspropGuardConfig,
+ android_sdk_sysprop_guard_config,
+ 124);
+PERFETTO_PB_FIELD(perfetto_protos_DataSourceConfig,
STRING,
const char*,
legacy_config,
diff --git a/include/perfetto/public/protos/config/trace_config.pzc.h b/include/perfetto/public/protos/config/trace_config.pzc.h
index cd14242..a2b8432 100644
--- a/include/perfetto/public/protos/config/trace_config.pzc.h
+++ b/include/perfetto/public/protos/config/trace_config.pzc.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
#ifndef INCLUDE_PERFETTO_PUBLIC_PROTOS_CONFIG_TRACE_CONFIG_PZC_H_
#define INCLUDE_PERFETTO_PUBLIC_PROTOS_CONFIG_TRACE_CONFIG_PZC_H_
@@ -21,7 +24,6 @@
#include <stdint.h>
#include "perfetto/public/pb_macros.h"
-
#include "perfetto/public/protos/common/builtin_clock.pzc.h"
PERFETTO_PB_MSG_DECL(perfetto_protos_DataSourceConfig);
@@ -36,6 +38,8 @@
PERFETTO_PB_MSG_DECL(perfetto_protos_TraceConfig_ProducerConfig);
PERFETTO_PB_MSG_DECL(perfetto_protos_TraceConfig_StatsdMetadata);
PERFETTO_PB_MSG_DECL(perfetto_protos_TraceConfig_TraceFilter);
+PERFETTO_PB_MSG_DECL(perfetto_protos_TraceConfig_TraceFilter_StringFilterChain);
+PERFETTO_PB_MSG_DECL(perfetto_protos_TraceConfig_TraceFilter_StringFilterRule);
PERFETTO_PB_MSG_DECL(perfetto_protos_TraceConfig_TriggerConfig);
PERFETTO_PB_MSG_DECL(perfetto_protos_TraceConfig_TriggerConfig_Trigger);
@@ -64,6 +68,20 @@
STATSD_LOGGING_DISABLED) = 2,
};
+PERFETTO_PB_ENUM_IN_MSG(perfetto_protos_TraceConfig_TraceFilter,
+ StringFilterPolicy){
+ PERFETTO_PB_ENUM_IN_MSG_ENTRY(perfetto_protos_TraceConfig_TraceFilter,
+ SFP_UNSPECIFIED) = 0,
+ PERFETTO_PB_ENUM_IN_MSG_ENTRY(perfetto_protos_TraceConfig_TraceFilter,
+ SFP_MATCH_REDACT_GROUPS) = 1,
+ PERFETTO_PB_ENUM_IN_MSG_ENTRY(perfetto_protos_TraceConfig_TraceFilter,
+ SFP_ATRACE_MATCH_REDACT_GROUPS) = 2,
+ PERFETTO_PB_ENUM_IN_MSG_ENTRY(perfetto_protos_TraceConfig_TraceFilter,
+ SFP_MATCH_BREAK) = 3,
+ PERFETTO_PB_ENUM_IN_MSG_ENTRY(perfetto_protos_TraceConfig_TraceFilter,
+ SFP_ATRACE_MATCH_BREAK) = 4,
+};
+
PERFETTO_PB_ENUM_IN_MSG(perfetto_protos_TraceConfig_TriggerConfig, TriggerMode){
PERFETTO_PB_ENUM_IN_MSG_ENTRY(perfetto_protos_TraceConfig_TriggerConfig,
UNSPECIFIED) = 0,
@@ -71,6 +89,8 @@
START_TRACING) = 1,
PERFETTO_PB_ENUM_IN_MSG_ENTRY(perfetto_protos_TraceConfig_TriggerConfig,
STOP_TRACING) = 2,
+ PERFETTO_PB_ENUM_IN_MSG_ENTRY(perfetto_protos_TraceConfig_TriggerConfig,
+ CLONE_SNAPSHOT) = 4,
};
PERFETTO_PB_ENUM_IN_MSG(perfetto_protos_TraceConfig_BufferConfig, FillPolicy){
@@ -214,6 +234,11 @@
compression_type,
24);
PERFETTO_PB_FIELD(perfetto_protos_TraceConfig,
+ VARINT,
+ bool,
+ compress_from_cli,
+ 37);
+PERFETTO_PB_FIELD(perfetto_protos_TraceConfig,
MSG,
perfetto_protos_TraceConfig_IncidentReportConfig,
incident_report_config,
@@ -289,6 +314,41 @@
const char*,
bytecode,
1);
+PERFETTO_PB_FIELD(perfetto_protos_TraceConfig_TraceFilter,
+ STRING,
+ const char*,
+ bytecode_v2,
+ 2);
+PERFETTO_PB_FIELD(perfetto_protos_TraceConfig_TraceFilter,
+ MSG,
+ perfetto_protos_TraceConfig_TraceFilter_StringFilterChain,
+ string_filter_chain,
+ 3);
+
+PERFETTO_PB_MSG(perfetto_protos_TraceConfig_TraceFilter_StringFilterChain);
+PERFETTO_PB_FIELD(perfetto_protos_TraceConfig_TraceFilter_StringFilterChain,
+ MSG,
+ perfetto_protos_TraceConfig_TraceFilter_StringFilterRule,
+ rules,
+ 1);
+
+PERFETTO_PB_MSG(perfetto_protos_TraceConfig_TraceFilter_StringFilterRule);
+PERFETTO_PB_FIELD(
+ perfetto_protos_TraceConfig_TraceFilter_StringFilterRule,
+ VARINT,
+ enum perfetto_protos_TraceConfig_TraceFilter_StringFilterPolicy,
+ policy,
+ 1);
+PERFETTO_PB_FIELD(perfetto_protos_TraceConfig_TraceFilter_StringFilterRule,
+ STRING,
+ const char*,
+ regex_pattern,
+ 2);
+PERFETTO_PB_FIELD(perfetto_protos_TraceConfig_TraceFilter_StringFilterRule,
+ STRING,
+ const char*,
+ atrace_payload_starts_with,
+ 3);
PERFETTO_PB_MSG(perfetto_protos_TraceConfig_IncidentReportConfig);
PERFETTO_PB_FIELD(perfetto_protos_TraceConfig_IncidentReportConfig,
@@ -331,6 +391,11 @@
trigger_mode,
1);
PERFETTO_PB_FIELD(perfetto_protos_TraceConfig_TriggerConfig,
+ VARINT,
+ bool,
+ use_clone_snapshot_if_available,
+ 5);
+PERFETTO_PB_FIELD(perfetto_protos_TraceConfig_TriggerConfig,
MSG,
perfetto_protos_TraceConfig_TriggerConfig_Trigger,
triggers,
@@ -455,6 +520,11 @@
bool,
prefer_suspend_clock_for_snapshot,
7);
+PERFETTO_PB_FIELD(perfetto_protos_TraceConfig_BuiltinDataSource,
+ VARINT,
+ bool,
+ disable_chunk_usage_histograms,
+ 8);
PERFETTO_PB_MSG(perfetto_protos_TraceConfig_DataSource);
PERFETTO_PB_FIELD(perfetto_protos_TraceConfig_DataSource,
@@ -484,5 +554,15 @@
enum perfetto_protos_TraceConfig_BufferConfig_FillPolicy,
fill_policy,
4);
+PERFETTO_PB_FIELD(perfetto_protos_TraceConfig_BufferConfig,
+ VARINT,
+ bool,
+ transfer_on_clone,
+ 5);
+PERFETTO_PB_FIELD(perfetto_protos_TraceConfig_BufferConfig,
+ VARINT,
+ bool,
+ clear_before_clone,
+ 6);
#endif // INCLUDE_PERFETTO_PUBLIC_PROTOS_CONFIG_TRACE_CONFIG_PZC_H_
diff --git a/include/perfetto/public/protos/config/track_event/track_event_config.pzc.h b/include/perfetto/public/protos/config/track_event/track_event_config.pzc.h
index 271cd24..aede7d5 100644
--- a/include/perfetto/public/protos/config/track_event/track_event_config.pzc.h
+++ b/include/perfetto/public/protos/config/track_event/track_event_config.pzc.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
#ifndef INCLUDE_PERFETTO_PUBLIC_PROTOS_CONFIG_TRACK_EVENT_TRACK_EVENT_CONFIG_PZC_H_
#define INCLUDE_PERFETTO_PUBLIC_PROTOS_CONFIG_TRACK_EVENT_TRACK_EVENT_CONFIG_PZC_H_
diff --git a/include/perfetto/public/protos/trace/interned_data/interned_data.pzc.h b/include/perfetto/public/protos/trace/interned_data/interned_data.pzc.h
index b5147a5..3c8f88a 100644
--- a/include/perfetto/public/protos/trace/interned_data/interned_data.pzc.h
+++ b/include/perfetto/public/protos/trace/interned_data/interned_data.pzc.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
#ifndef INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_INTERNED_DATA_INTERNED_DATA_PZC_H_
#define INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_INTERNED_DATA_INTERNED_DATA_PZC_H_
@@ -34,6 +37,7 @@
PERFETTO_PB_MSG_DECL(perfetto_protos_InternedString);
PERFETTO_PB_MSG_DECL(perfetto_protos_LogMessageBody);
PERFETTO_PB_MSG_DECL(perfetto_protos_Mapping);
+PERFETTO_PB_MSG_DECL(perfetto_protos_NetworkPacketContext);
PERFETTO_PB_MSG_DECL(perfetto_protos_ProfiledFrameSymbols);
PERFETTO_PB_MSG_DECL(perfetto_protos_SourceLocation);
PERFETTO_PB_MSG_DECL(perfetto_protos_UnsymbolizedSourceLocation);
@@ -144,5 +148,10 @@
perfetto_protos_InternedString,
debug_annotation_string_values,
29);
+PERFETTO_PB_FIELD(perfetto_protos_InternedData,
+ MSG,
+ perfetto_protos_NetworkPacketContext,
+ packet_context,
+ 30);
#endif // INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_INTERNED_DATA_INTERNED_DATA_PZC_H_
diff --git a/include/perfetto/public/protos/trace/test_event.pzc.h b/include/perfetto/public/protos/trace/test_event.pzc.h
index 2706934..b4e483f 100644
--- a/include/perfetto/public/protos/trace/test_event.pzc.h
+++ b/include/perfetto/public/protos/trace/test_event.pzc.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
#ifndef INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TEST_EVENT_PZC_H_
#define INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TEST_EVENT_PZC_H_
diff --git a/include/perfetto/public/protos/trace/trace.pzc.h b/include/perfetto/public/protos/trace/trace.pzc.h
index a40f46b..9625f6e 100644
--- a/include/perfetto/public/protos/trace/trace.pzc.h
+++ b/include/perfetto/public/protos/trace/trace.pzc.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
#ifndef INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TRACE_PZC_H_
#define INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TRACE_PZC_H_
diff --git a/include/perfetto/public/protos/trace/trace_packet.pzc.h b/include/perfetto/public/protos/trace/trace_packet.pzc.h
index 8c0efe4..52df003 100644
--- a/include/perfetto/public/protos/trace/trace_packet.pzc.h
+++ b/include/perfetto/public/protos/trace/trace_packet.pzc.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
#ifndef INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TRACE_PACKET_PZC_H_
#define INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TRACE_PACKET_PZC_H_
@@ -49,8 +52,10 @@
PERFETTO_PB_MSG_DECL(perfetto_protos_InitialDisplayState);
PERFETTO_PB_MSG_DECL(perfetto_protos_InodeFileMap);
PERFETTO_PB_MSG_DECL(perfetto_protos_InternedData);
+PERFETTO_PB_MSG_DECL(perfetto_protos_LayersSnapshotProto);
PERFETTO_PB_MSG_DECL(perfetto_protos_MemoryTrackerSnapshot);
PERFETTO_PB_MSG_DECL(perfetto_protos_ModuleSymbols);
+PERFETTO_PB_MSG_DECL(perfetto_protos_NetworkPacketBundle);
PERFETTO_PB_MSG_DECL(perfetto_protos_NetworkPacketEvent);
PERFETTO_PB_MSG_DECL(perfetto_protos_PackagesList);
PERFETTO_PB_MSG_DECL(perfetto_protos_PerfSample);
@@ -78,6 +83,7 @@
PERFETTO_PB_MSG_DECL(perfetto_protos_TrackDescriptor);
PERFETTO_PB_MSG_DECL(perfetto_protos_TrackEvent);
PERFETTO_PB_MSG_DECL(perfetto_protos_TrackEventRangeOfInterest);
+PERFETTO_PB_MSG_DECL(perfetto_protos_TransactionTraceEntry);
PERFETTO_PB_MSG_DECL(perfetto_protos_TranslationTable);
PERFETTO_PB_MSG_DECL(perfetto_protos_Trigger);
PERFETTO_PB_MSG_DECL(perfetto_protos_UiState);
@@ -397,11 +403,26 @@
88);
PERFETTO_PB_FIELD(perfetto_protos_TracePacket,
MSG,
+ perfetto_protos_NetworkPacketBundle,
+ network_packet_bundle,
+ 92);
+PERFETTO_PB_FIELD(perfetto_protos_TracePacket,
+ MSG,
perfetto_protos_TrackEventRangeOfInterest,
track_event_range_of_interest,
90);
PERFETTO_PB_FIELD(perfetto_protos_TracePacket,
MSG,
+ perfetto_protos_LayersSnapshotProto,
+ surfaceflinger_layers_snapshot,
+ 93);
+PERFETTO_PB_FIELD(perfetto_protos_TracePacket,
+ MSG,
+ perfetto_protos_TransactionTraceEntry,
+ surfaceflinger_transactions,
+ 94);
+PERFETTO_PB_FIELD(perfetto_protos_TracePacket,
+ MSG,
perfetto_protos_TestEvent,
for_testing,
900);
diff --git a/include/perfetto/public/protos/trace/track_event/counter_descriptor.pzc.h b/include/perfetto/public/protos/trace/track_event/counter_descriptor.pzc.h
index a5d075a..322ee8e 100644
--- a/include/perfetto/public/protos/trace/track_event/counter_descriptor.pzc.h
+++ b/include/perfetto/public/protos/trace/track_event/counter_descriptor.pzc.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
#ifndef INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TRACK_EVENT_COUNTER_DESCRIPTOR_PZC_H_
#define INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TRACK_EVENT_COUNTER_DESCRIPTOR_PZC_H_
diff --git a/include/perfetto/public/protos/trace/track_event/debug_annotation.pzc.h b/include/perfetto/public/protos/trace/track_event/debug_annotation.pzc.h
index d4152ae..3183f24 100644
--- a/include/perfetto/public/protos/trace/track_event/debug_annotation.pzc.h
+++ b/include/perfetto/public/protos/trace/track_event/debug_annotation.pzc.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
#ifndef INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TRACK_EVENT_DEBUG_ANNOTATION_PZC_H_
#define INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TRACK_EVENT_DEBUG_ANNOTATION_PZC_H_
diff --git a/include/perfetto/public/protos/trace/track_event/track_descriptor.pzc.h b/include/perfetto/public/protos/trace/track_event/track_descriptor.pzc.h
index 0069082..ee3d978 100644
--- a/include/perfetto/public/protos/trace/track_event/track_descriptor.pzc.h
+++ b/include/perfetto/public/protos/trace/track_event/track_descriptor.pzc.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
#ifndef INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TRACK_EVENT_TRACK_DESCRIPTOR_PZC_H_
#define INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TRACK_EVENT_TRACK_DESCRIPTOR_PZC_H_
@@ -65,5 +68,10 @@
perfetto_protos_CounterDescriptor,
counter,
8);
+PERFETTO_PB_FIELD(perfetto_protos_TrackDescriptor,
+ VARINT,
+ bool,
+ disallow_merging_with_system_tracks,
+ 9);
#endif // INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TRACK_EVENT_TRACK_DESCRIPTOR_PZC_H_
diff --git a/include/perfetto/public/protos/trace/track_event/track_event.pzc.h b/include/perfetto/public/protos/trace/track_event/track_event.pzc.h
index 5811154..5553376 100644
--- a/include/perfetto/public/protos/trace/track_event/track_event.pzc.h
+++ b/include/perfetto/public/protos/trace/track_event/track_event.pzc.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
#ifndef INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TRACK_EVENT_TRACK_EVENT_PZC_H_
#define INCLUDE_PERFETTO_PUBLIC_PROTOS_TRACE_TRACK_EVENT_TRACK_EVENT_PZC_H_
diff --git a/src/protozero/protoc_plugin/BUILD.gn b/src/protozero/protoc_plugin/BUILD.gn
index a628be7..b9139db 100644
--- a/src/protozero/protoc_plugin/BUILD.gn
+++ b/src/protozero/protoc_plugin/BUILD.gn
@@ -36,3 +36,14 @@
"../../../src/base",
]
}
+
+# The plugin that generates standalone C macros and function from protos
+# (xxx.pzc.h). This is used to generate the API headers of the shared library.
+perfetto_host_executable("protozero_c_plugin") {
+ sources = [ "protozero_c_plugin.cc" ]
+ deps = [
+ "../../../gn:default_deps",
+ "../../../gn:protoc_lib",
+ "../../../src/base",
+ ]
+}
diff --git a/src/protozero/protoc_plugin/protozero_c_plugin.cc b/src/protozero/protoc_plugin/protozero_c_plugin.cc
new file mode 100644
index 0000000..461b71d
--- /dev/null
+++ b/src/protozero/protoc_plugin/protozero_c_plugin.cc
@@ -0,0 +1,641 @@
+/*
+ * 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 <stdlib.h>
+
+#include <limits>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include "perfetto/ext/base/string_utils.h"
+
+namespace protozero {
+namespace {
+
+using google::protobuf::Descriptor;
+using google::protobuf::EnumDescriptor;
+using google::protobuf::EnumValueDescriptor;
+using google::protobuf::FieldDescriptor;
+using google::protobuf::FileDescriptor;
+using google::protobuf::compiler::GeneratorContext;
+using google::protobuf::io::Printer;
+using google::protobuf::io::ZeroCopyOutputStream;
+using perfetto::base::SplitString;
+using perfetto::base::StripChars;
+using perfetto::base::StripPrefix;
+using perfetto::base::StripSuffix;
+using perfetto::base::ToUpper;
+using perfetto::base::Uppercase;
+
+void Assert(bool condition) {
+ if (!condition)
+ abort();
+}
+
+struct FileDescriptorComp {
+ bool operator()(const FileDescriptor* lhs, const FileDescriptor* rhs) const {
+ int comp = lhs->name().compare(rhs->name());
+ Assert(comp != 0 || lhs == rhs);
+ return comp < 0;
+ }
+};
+
+struct DescriptorComp {
+ bool operator()(const Descriptor* lhs, const Descriptor* rhs) const {
+ int comp = lhs->full_name().compare(rhs->full_name());
+ Assert(comp != 0 || lhs == rhs);
+ return comp < 0;
+ }
+};
+
+struct EnumDescriptorComp {
+ bool operator()(const EnumDescriptor* lhs, const EnumDescriptor* rhs) const {
+ int comp = lhs->full_name().compare(rhs->full_name());
+ Assert(comp != 0 || lhs == rhs);
+ return comp < 0;
+ }
+};
+
+inline std::string ProtoStubName(const FileDescriptor* proto) {
+ return StripSuffix(proto->name(), ".proto") + ".pzc";
+}
+
+class GeneratorJob {
+ public:
+ GeneratorJob(const FileDescriptor* file, Printer* stub_h_printer)
+ : source_(file), stub_h_(stub_h_printer) {}
+
+ bool GenerateStubs() {
+ Preprocess();
+ GeneratePrologue();
+ for (const EnumDescriptor* enumeration : enums_)
+ GenerateEnumDescriptor(enumeration);
+ for (const Descriptor* message : messages_)
+ GenerateMessageDescriptor(message);
+ GenerateEpilogue();
+ return error_.empty();
+ }
+
+ void SetOption(const std::string& name, const std::string& value) {
+ if (name == "wrapper_namespace") {
+ wrapper_namespace_ = value;
+ } else if (name == "guard_strip_prefix") {
+ guard_strip_prefix_ = value;
+ } else if (name == "guard_add_prefix") {
+ guard_add_prefix_ = value;
+ } else if (name == "path_strip_prefix") {
+ path_strip_prefix_ = value;
+ } else if (name == "path_add_prefix") {
+ path_add_prefix_ = value;
+ } else if (name == "invoker") {
+ invoker_ = value;
+ } else {
+ Abort(std::string() + "Unknown plugin option '" + name + "'.");
+ }
+ }
+
+ // If generator fails to produce stubs for a particular proto definitions
+ // it finishes with undefined output and writes the first error occured.
+ const std::string& GetFirstError() const { return error_; }
+
+ private:
+ // Only the first error will be recorded.
+ void Abort(const std::string& reason) {
+ if (error_.empty())
+ error_ = reason;
+ }
+
+ // Get full name (including outer descriptors) of proto descriptor.
+ template <class T>
+ inline std::string GetDescriptorName(const T* descriptor) {
+ if (!package_.empty()) {
+ return StripPrefix(descriptor->full_name(), package_ + ".");
+ }
+ return descriptor->full_name();
+ }
+
+ // Get C++ class name corresponding to proto descriptor.
+ // Nested names are splitted by underscores. Underscores in type names aren't
+ // prohibited but not recommended in order to avoid name collisions.
+ template <class T>
+ inline std::string GetCppClassName(const T* descriptor, bool full = false) {
+ std::string name = StripChars(GetDescriptorName(descriptor), ".", '_');
+ if (full)
+ name = full_namespace_prefix_ + "_" + name;
+ return name;
+ }
+
+ const char* FieldTypeToPackedBufferType(FieldDescriptor::Type type) {
+ switch (type) {
+ case FieldDescriptor::TYPE_ENUM:
+ case FieldDescriptor::TYPE_INT32:
+ return "Int32";
+ case FieldDescriptor::TYPE_INT64:
+ return "Int64";
+ case FieldDescriptor::TYPE_UINT32:
+ return "Uint32";
+ case FieldDescriptor::TYPE_UINT64:
+ return "Uint64";
+ case FieldDescriptor::TYPE_SINT32:
+ return "Sint32";
+ case FieldDescriptor::TYPE_SINT64:
+ return "Sint64";
+ case FieldDescriptor::TYPE_FIXED32:
+ return "Fixed32";
+ case FieldDescriptor::TYPE_FIXED64:
+ return "Fixed64";
+ case FieldDescriptor::TYPE_SFIXED32:
+ return "Sfixed32";
+ case FieldDescriptor::TYPE_SFIXED64:
+ return "Sfixed64";
+ case FieldDescriptor::TYPE_FLOAT:
+ return "Float";
+ case FieldDescriptor::TYPE_DOUBLE:
+ return "Double";
+ case FieldDescriptor::TYPE_BOOL:
+ case FieldDescriptor::TYPE_STRING:
+ case FieldDescriptor::TYPE_BYTES:
+ case FieldDescriptor::TYPE_MESSAGE:
+ case FieldDescriptor::TYPE_GROUP:
+ break;
+ }
+ Abort("Unsupported packed type");
+ return "";
+ }
+ std::string FieldToCppTypeName(const FieldDescriptor* field) {
+ switch (field->type()) {
+ case FieldDescriptor::TYPE_BOOL:
+ return "bool";
+ case FieldDescriptor::TYPE_INT32:
+ return "int32_t";
+ case FieldDescriptor::TYPE_INT64:
+ return "int64_t";
+ case FieldDescriptor::TYPE_UINT32:
+ return "uint32_t";
+ case FieldDescriptor::TYPE_UINT64:
+ return "uint64_t";
+ case FieldDescriptor::TYPE_SINT32:
+ return "int32_t";
+ case FieldDescriptor::TYPE_SINT64:
+ return "int64_t";
+ case FieldDescriptor::TYPE_FIXED32:
+ return "uint32_t";
+ case FieldDescriptor::TYPE_FIXED64:
+ return "uint64_t";
+ case FieldDescriptor::TYPE_SFIXED32:
+ return "int32_t";
+ case FieldDescriptor::TYPE_SFIXED64:
+ return "int64_t";
+ case FieldDescriptor::TYPE_FLOAT:
+ return "float";
+ case FieldDescriptor::TYPE_DOUBLE:
+ return "double";
+ case FieldDescriptor::TYPE_ENUM:
+ return "enum " + GetCppClassName(field->enum_type(), true);
+ case FieldDescriptor::TYPE_STRING:
+ case FieldDescriptor::TYPE_BYTES:
+ return "const char*";
+ case FieldDescriptor::TYPE_MESSAGE:
+ return GetCppClassName(field->message_type());
+ case FieldDescriptor::TYPE_GROUP:
+ Abort("Groups not supported.");
+ return "";
+ }
+ Abort("Unrecognized FieldDescriptor::Type.");
+ return "";
+ }
+
+ void CollectDescriptors() {
+ // Collect message descriptors in DFS order.
+ std::vector<const Descriptor*> stack;
+ stack.reserve(static_cast<size_t>(source_->message_type_count()));
+ for (int i = 0; i < source_->message_type_count(); ++i)
+ stack.push_back(source_->message_type(i));
+
+ while (!stack.empty()) {
+ const Descriptor* message = stack.back();
+ stack.pop_back();
+
+ if (message->extension_count() > 0) {
+ if (message->field_count() > 0 || message->nested_type_count() > 0 ||
+ message->enum_type_count() > 0) {
+ Abort("message with extend blocks shouldn't contain anything else");
+ }
+
+ // Iterate over all fields in "extend" blocks.
+ for (int i = 0; i < message->extension_count(); ++i) {
+ const FieldDescriptor* extension = message->extension(i);
+
+ // Protoc plugin API does not group fields in "extend" blocks.
+ // As the support for extensions in protozero is limited, the code
+ // assumes that extend blocks are located inside a wrapper message and
+ // name of this message is used to group them.
+ std::string extension_name = extension->extension_scope()->name();
+ extensions_[extension_name].push_back(extension);
+ }
+ } else {
+ messages_.push_back(message);
+ for (int i = 0; i < message->nested_type_count(); ++i) {
+ stack.push_back(message->nested_type(i));
+ // Emit a forward declaration of nested message types, as the outer
+ // class will refer to them when creating type aliases.
+ referenced_messages_.insert(message->nested_type(i));
+ }
+ }
+ }
+
+ // Collect enums.
+ for (int i = 0; i < source_->enum_type_count(); ++i)
+ enums_.push_back(source_->enum_type(i));
+
+ if (source_->extension_count() > 0)
+ Abort("top-level extension blocks are not supported");
+
+ for (const Descriptor* message : messages_) {
+ for (int i = 0; i < message->enum_type_count(); ++i) {
+ enums_.push_back(message->enum_type(i));
+ }
+ }
+ }
+
+ void CollectDependencies() {
+ // Public import basically means that callers only need to import this
+ // proto in order to use the stuff publicly imported by this proto.
+ for (int i = 0; i < source_->public_dependency_count(); ++i)
+ public_imports_.insert(source_->public_dependency(i));
+
+ if (source_->weak_dependency_count() > 0)
+ Abort("Weak imports are not supported.");
+
+ // Validations. Collect public imports (of collected imports) in DFS order.
+ // Visibilty for current proto:
+ // - all imports listed in current proto,
+ // - public imports of everything imported (recursive).
+ std::vector<const FileDescriptor*> stack;
+ for (int i = 0; i < source_->dependency_count(); ++i) {
+ const FileDescriptor* imp = source_->dependency(i);
+ stack.push_back(imp);
+ if (public_imports_.count(imp) == 0) {
+ private_imports_.insert(imp);
+ }
+ }
+
+ while (!stack.empty()) {
+ const FileDescriptor* imp = stack.back();
+ stack.pop_back();
+ // Having imports under different packages leads to unnecessary
+ // complexity with namespaces.
+ if (imp->package() != package_)
+ Abort("Imported proto must be in the same package.");
+
+ for (int i = 0; i < imp->public_dependency_count(); ++i) {
+ stack.push_back(imp->public_dependency(i));
+ }
+ }
+
+ // Collect descriptors of messages and enums used in current proto.
+ // It will be used to generate necessary forward declarations and
+ // check that everything lays in the same namespace.
+ for (const Descriptor* message : messages_) {
+ for (int i = 0; i < message->field_count(); ++i) {
+ const FieldDescriptor* field = message->field(i);
+
+ if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
+ if (public_imports_.count(field->message_type()->file()) == 0) {
+ // Avoid multiple forward declarations since
+ // public imports have been already included.
+ referenced_messages_.insert(field->message_type());
+ }
+ } else if (field->type() == FieldDescriptor::TYPE_ENUM) {
+ if (public_imports_.count(field->enum_type()->file()) == 0) {
+ referenced_enums_.insert(field->enum_type());
+ }
+ }
+ }
+ }
+ }
+
+ void Preprocess() {
+ // Package name maps to a series of namespaces.
+ package_ = source_->package();
+ namespaces_ = SplitString(package_, ".");
+ if (!wrapper_namespace_.empty())
+ namespaces_.push_back(wrapper_namespace_);
+
+ full_namespace_prefix_ = "";
+ for (size_t i = 0; i < namespaces_.size(); i++) {
+ full_namespace_prefix_ += namespaces_[i];
+ if (i + 1 != namespaces_.size()) {
+ full_namespace_prefix_ += "_";
+ }
+ }
+
+ CollectDescriptors();
+ CollectDependencies();
+ }
+
+ std::string GenerateGuard() {
+ std::string guard = StripSuffix(source_->name(), ".proto");
+ guard = ToUpper(guard);
+ guard = StripChars(guard, ".-/\\", '_');
+ guard = StripPrefix(guard, guard_strip_prefix_);
+ guard = guard_add_prefix_ + guard + "_PZC_H_";
+ return guard;
+ }
+
+ // Print top header, namespaces and forward declarations.
+ void GeneratePrologue() {
+ stub_h_->Print(
+ R"(/*
+ * 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.
+ */
+
+)");
+ stub_h_->Print("// Autogenerated by the ProtoZero C compiler plugin.\n");
+ if (!invoker_.empty()) {
+ stub_h_->Print("// Invoked by $invoker$\n", "invoker", invoker_);
+ }
+ stub_h_->Print("// DO NOT EDIT.\n");
+
+ stub_h_->Print(
+ "#ifndef $guard$\n"
+ "#define $guard$\n\n"
+ "#include <stdbool.h>\n"
+ "#include <stdint.h>\n\n"
+ "#include \"perfetto/public/pb_macros.h\"\n",
+ "guard", GenerateGuard());
+
+ // Print includes for public imports and enums which cannot be forward
+ // declared.
+ std::vector<std::string> imports;
+ for (const FileDescriptor* dependency : public_imports_) {
+ imports.push_back(ProtoStubName(dependency));
+ }
+ for (const EnumDescriptor* e : referenced_enums_) {
+ if (e->file() != source_) {
+ imports.push_back(ProtoStubName(e->file()));
+ }
+ }
+
+ std::sort(imports.begin(), imports.end());
+
+ for (const std::string& imp : imports) {
+ std::string include_path = imp;
+ if (!path_strip_prefix_.empty()) {
+ include_path = StripPrefix(imp, path_strip_prefix_);
+ }
+ include_path = path_add_prefix_ + include_path;
+
+ stub_h_->Print("#include \"$name$.h\"\n", "name", include_path);
+ }
+ stub_h_->Print("\n");
+
+ // Print forward declarations.
+ for (const Descriptor* message : referenced_messages_) {
+ stub_h_->Print("PERFETTO_PB_MSG_DECL($class$);\n", "class",
+ GetCppClassName(message, true));
+ }
+
+ stub_h_->Print("\n");
+ }
+
+ void GenerateEnumDescriptor(const EnumDescriptor* enumeration) {
+ if (enumeration->containing_type()) {
+ stub_h_->Print("PERFETTO_PB_ENUM_IN_MSG($msg$, $class$){\n", "msg",
+ GetCppClassName(enumeration->containing_type(), true),
+ "class", enumeration->name());
+ } else {
+ stub_h_->Print("PERFETTO_PB_ENUM($class$){\n", "class",
+ GetCppClassName(enumeration, true));
+ }
+ stub_h_->Indent();
+
+ for (int i = 0; i < enumeration->value_count(); ++i) {
+ const EnumValueDescriptor* value = enumeration->value(i);
+ const std::string value_name = value->name();
+
+ if (enumeration->containing_type()) {
+ stub_h_->Print(
+ "PERFETTO_PB_ENUM_IN_MSG_ENTRY($msg$, $val$) = $number$,\n", "msg",
+ GetCppClassName(enumeration->containing_type(), true), "val",
+ value_name, "number", std::to_string(value->number()));
+ } else {
+ stub_h_->Print("PERFETTO_PB_ENUM_ENTRY($val$) = $number$, \n", "val",
+ full_namespace_prefix_ + "_" + value_name, "number",
+ std::to_string(value->number()));
+ }
+ }
+ stub_h_->Outdent();
+ stub_h_->Print("};\n\n");
+ }
+
+ // Packed repeated fields are encoded as a length-delimited field on the wire,
+ // where the payload is the concatenation of invidually encoded elements.
+ void GeneratePackedRepeatedFieldDescriptor(
+ const std::string& message_cpp_type,
+ const FieldDescriptor* field) {
+ std::map<std::string, std::string> setter;
+ setter["id"] = std::to_string(field->number());
+ setter["name"] = field->lowercase_name();
+ setter["class"] = message_cpp_type;
+ setter["buffer_type"] = FieldTypeToPackedBufferType(field->type());
+ stub_h_->Print(
+ setter,
+ "PERFETTO_PB_FIELD($class$, PACKED, $buffer_type$, $name$, $id$);\n");
+ }
+
+ void GenerateSimpleFieldDescriptor(const std::string& message_cpp_type,
+ const FieldDescriptor* field) {
+ std::map<std::string, std::string> setter;
+ setter["id"] = std::to_string(field->number());
+ setter["name"] = field->lowercase_name();
+ setter["ctype"] = FieldToCppTypeName(field);
+ setter["class"] = message_cpp_type;
+
+ switch (field->type()) {
+ case FieldDescriptor::TYPE_BYTES:
+ case FieldDescriptor::TYPE_STRING:
+ stub_h_->Print(
+ setter,
+ "PERFETTO_PB_FIELD($class$, STRING, const char*, $name$, $id$);\n");
+ break;
+ case FieldDescriptor::TYPE_UINT64:
+ case FieldDescriptor::TYPE_UINT32:
+ case FieldDescriptor::TYPE_INT64:
+ case FieldDescriptor::TYPE_INT32:
+ case FieldDescriptor::TYPE_BOOL:
+ case FieldDescriptor::TYPE_ENUM:
+ stub_h_->Print(
+ setter,
+ "PERFETTO_PB_FIELD($class$, VARINT, $ctype$, $name$, $id$);\n");
+ break;
+ case FieldDescriptor::TYPE_SINT64:
+ case FieldDescriptor::TYPE_SINT32:
+ stub_h_->Print(
+ setter,
+ "PERFETTO_PB_FIELD($class$, ZIGZAG, $ctype$, $name$, $id$);\n");
+ break;
+ case FieldDescriptor::TYPE_SFIXED32:
+ case FieldDescriptor::TYPE_FIXED32:
+ case FieldDescriptor::TYPE_FLOAT:
+ stub_h_->Print(
+ setter,
+ "PERFETTO_PB_FIELD($class$, FIXED32, $ctype$, $name$, $id$);\n");
+ break;
+ case FieldDescriptor::TYPE_SFIXED64:
+ case FieldDescriptor::TYPE_FIXED64:
+ case FieldDescriptor::TYPE_DOUBLE:
+ stub_h_->Print(
+ setter,
+ "PERFETTO_PB_FIELD($class$, FIXED64, $ctype$, $name$, $id$);\n");
+ break;
+ case FieldDescriptor::TYPE_MESSAGE:
+ case FieldDescriptor::TYPE_GROUP:
+ Abort("Groups not supported.");
+ break;
+ }
+ }
+
+ void GenerateNestedMessageFieldDescriptor(const std::string& message_cpp_type,
+ const FieldDescriptor* field) {
+ std::string inner_class =
+ full_namespace_prefix_ + "_" + GetCppClassName(field->message_type());
+ stub_h_->Print(
+ "PERFETTO_PB_FIELD($class$, MSG, $inner_class$, $name$, $id$);\n",
+ "class", message_cpp_type, "id", std::to_string(field->number()),
+ "name", field->lowercase_name(), "inner_class", inner_class);
+ }
+
+ void GenerateMessageDescriptor(const Descriptor* message) {
+ stub_h_->Print("PERFETTO_PB_MSG($name$);\n", "name",
+ GetCppClassName(message, true));
+
+ // Field descriptors.
+ for (int i = 0; i < message->field_count(); ++i) {
+ GenerateFieldDescriptor(GetCppClassName(message, true),
+ message->field(i));
+ }
+ stub_h_->Print("\n");
+ }
+
+ void GenerateFieldDescriptor(const std::string& message_cpp_type,
+ const FieldDescriptor* field) {
+ // GenerateFieldMetadata(message_cpp_type, field);
+ if (field->is_packed()) {
+ GeneratePackedRepeatedFieldDescriptor(message_cpp_type, field);
+ } else if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
+ GenerateSimpleFieldDescriptor(message_cpp_type, field);
+ } else {
+ GenerateNestedMessageFieldDescriptor(message_cpp_type, field);
+ }
+ }
+
+ void GenerateEpilogue() {
+ stub_h_->Print("#endif // $guard$\n", "guard", GenerateGuard());
+ }
+
+ const FileDescriptor* const source_;
+ Printer* const stub_h_;
+ std::string error_;
+
+ std::string package_;
+ std::string wrapper_namespace_;
+ std::string guard_strip_prefix_;
+ std::string guard_add_prefix_;
+ std::string path_strip_prefix_;
+ std::string path_add_prefix_;
+ std::string invoker_;
+ std::vector<std::string> namespaces_;
+ std::string full_namespace_prefix_;
+ std::vector<const Descriptor*> messages_;
+ std::vector<const EnumDescriptor*> enums_;
+ std::map<std::string, std::vector<const FieldDescriptor*>> extensions_;
+
+ // The custom *Comp comparators are to ensure determinism of the generator.
+ std::set<const FileDescriptor*, FileDescriptorComp> public_imports_;
+ std::set<const FileDescriptor*, FileDescriptorComp> private_imports_;
+ std::set<const Descriptor*, DescriptorComp> referenced_messages_;
+ std::set<const EnumDescriptor*, EnumDescriptorComp> referenced_enums_;
+};
+
+class ProtoZeroCGenerator : public google::protobuf::compiler::CodeGenerator {
+ public:
+ explicit ProtoZeroCGenerator();
+ ~ProtoZeroCGenerator() override;
+
+ // CodeGenerator implementation
+ bool Generate(const google::protobuf::FileDescriptor* file,
+ const std::string& options,
+ GeneratorContext* context,
+ std::string* error) const override;
+};
+
+ProtoZeroCGenerator::ProtoZeroCGenerator() {}
+
+ProtoZeroCGenerator::~ProtoZeroCGenerator() {}
+
+bool ProtoZeroCGenerator::Generate(const FileDescriptor* file,
+ const std::string& options,
+ GeneratorContext* context,
+ std::string* error) const {
+ const std::unique_ptr<ZeroCopyOutputStream> stub_h_file_stream(
+ context->Open(ProtoStubName(file) + ".h"));
+
+ // Variables are delimited by $.
+ Printer stub_h_printer(stub_h_file_stream.get(), '$');
+ GeneratorJob job(file, &stub_h_printer);
+
+ // Parse additional options.
+ for (const std::string& option : SplitString(options, ",")) {
+ std::vector<std::string> option_pair = SplitString(option, "=");
+ job.SetOption(option_pair[0], option_pair[1]);
+ }
+
+ if (!job.GenerateStubs()) {
+ *error = job.GetFirstError();
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+} // namespace protozero
+
+int main(int argc, char* argv[]) {
+ protozero::ProtoZeroCGenerator generator;
+ return google::protobuf::compiler::PluginMain(argc, argv, &generator);
+}
diff --git a/src/shared_lib/test/protos/library.pzc.h b/src/shared_lib/test/protos/library.pzc.h
index 9238101..94a54cd 100644
--- a/src/shared_lib/test/protos/library.pzc.h
+++ b/src/shared_lib/test/protos/library.pzc.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
#ifndef SRC_SHARED_LIB_TEST_PROTOS_LIBRARY_PZC_H_
#define SRC_SHARED_LIB_TEST_PROTOS_LIBRARY_PZC_H_
diff --git a/src/shared_lib/test/protos/library_internals/galaxies.pzc.h b/src/shared_lib/test/protos/library_internals/galaxies.pzc.h
index 0823642..1a3e0ce 100644
--- a/src/shared_lib/test/protos/library_internals/galaxies.pzc.h
+++ b/src/shared_lib/test/protos/library_internals/galaxies.pzc.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
#ifndef SRC_SHARED_LIB_TEST_PROTOS_LIBRARY_INTERNALS_GALAXIES_PZC_H_
#define SRC_SHARED_LIB_TEST_PROTOS_LIBRARY_INTERNALS_GALAXIES_PZC_H_
diff --git a/src/shared_lib/test/protos/test_messages.pzc.h b/src/shared_lib/test/protos/test_messages.pzc.h
index 5f8b6b3..5198ee7 100644
--- a/src/shared_lib/test/protos/test_messages.pzc.h
+++ b/src/shared_lib/test/protos/test_messages.pzc.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
#ifndef SRC_SHARED_LIB_TEST_PROTOS_TEST_MESSAGES_PZC_H_
#define SRC_SHARED_LIB_TEST_PROTOS_TEST_MESSAGES_PZC_H_
diff --git a/src/shared_lib/test/protos/upper_import.pzc.h b/src/shared_lib/test/protos/upper_import.pzc.h
index 37e55c6..a7f86cf 100644
--- a/src/shared_lib/test/protos/upper_import.pzc.h
+++ b/src/shared_lib/test/protos/upper_import.pzc.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
#ifndef SRC_SHARED_LIB_TEST_PROTOS_UPPER_IMPORT_PZC_H_
#define SRC_SHARED_LIB_TEST_PROTOS_UPPER_IMPORT_PZC_H_
diff --git a/tools/gen_c_protos b/tools/gen_c_protos
new file mode 100755
index 0000000..38a7491
--- /dev/null
+++ b/tools/gen_c_protos
@@ -0,0 +1,192 @@
+#!/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 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 argparse
+import filecmp
+import os
+import pathlib
+import shutil
+import subprocess
+import sys
+import tempfile
+
+SOURCE_FILES = [
+ {
+ 'files': [
+ 'protos/perfetto/common/builtin_clock.proto',
+ 'protos/perfetto/common/data_source_descriptor.proto',
+ 'protos/perfetto/config/data_source_config.proto',
+ 'protos/perfetto/config/trace_config.proto',
+ 'protos/perfetto/config/track_event/track_event_config.proto',
+ 'protos/perfetto/trace/interned_data/interned_data.proto',
+ 'protos/perfetto/trace/test_event.proto',
+ 'protos/perfetto/trace/trace.proto',
+ 'protos/perfetto/trace/trace_packet.proto',
+ 'protos/perfetto/trace/track_event/counter_descriptor.proto',
+ 'protos/perfetto/trace/track_event/debug_annotation.proto',
+ 'protos/perfetto/trace/track_event/track_descriptor.proto',
+ 'protos/perfetto/trace/track_event/track_event.proto',
+ ],
+ 'guard_strip_prefix': 'PROTOS_PERFETTO_',
+ 'guard_add_prefix':'INCLUDE_PERFETTO_PUBLIC_PROTOS_',
+ 'path_strip_prefix': 'protos/perfetto',
+ 'path_add_prefix': 'perfetto/public/protos',
+ 'include_prefix': 'include/',
+ },
+ {
+ 'files': [
+ 'src/protozero/test/example_proto/library.proto',
+ 'src/protozero/test/example_proto/library_internals/galaxies.proto',
+ 'src/protozero/test/example_proto/test_messages.proto',
+ 'src/protozero/test/example_proto/upper_import.proto',
+ ],
+ 'guard_strip_prefix': 'SRC_PROTOZERO_TEST_EXAMPLE_PROTO_',
+ 'guard_add_prefix':'SRC_SHARED_LIB_TEST_PROTOS_',
+ 'path_strip_prefix': 'src/protozero/test/example_proto',
+ 'path_add_prefix': 'src/shared_lib/test/protos',
+ },
+]
+
+ROOT_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+IS_WIN = sys.platform.startswith('win')
+
+SCRIPT_PATH = 'tools/gen_c_protos'
+
+
+def protozero_c_plugin_path(out_directory):
+ path = os.path.join(out_directory,
+ 'protozero_c_plugin') + ('.exe' if IS_WIN else '')
+ assert os.path.isfile(path)
+ return path
+
+
+def protoc_path(out_directory):
+ path = os.path.join(out_directory, 'protoc') + ('.exe' if IS_WIN else '')
+ assert os.path.isfile(path)
+ return path
+
+
+def call(cmd, *args):
+ path = os.path.join('tools', cmd)
+ command = ['python3', path] + list(args)
+ print('Running', ' '.join(command))
+ try:
+ subprocess.check_call(command, cwd=ROOT_DIR)
+ except subprocess.CalledProcessError as e:
+ assert False, 'Command: {} failed'.format(' '.join(command))
+
+
+# Reformats filename
+def clang_format(filename):
+ path = os.path.join(ROOT_DIR, 'third_party', 'clang-format',
+ 'clang-format') + ('.exe' if IS_WIN else '')
+ assert os.path.isfile(
+ path), "clang-format not found. Run tools/install-build-deps"
+ subprocess.check_call([
+ path, '--style=file:{}'.format(os.path.join(ROOT_DIR, '.clang-format')),
+ '-i', filename
+ ],
+ cwd=ROOT_DIR)
+
+
+# Transforms filename extension like the ProtoZero C plugin
+def transform_extension(filename):
+ old_suffix = ".proto"
+ new_suffix = ".pzc.h"
+ if filename.endswith(old_suffix):
+ return filename[:-len(old_suffix)] + new_suffix
+ return filename
+
+
+def generate(source, outdir, protoc_path, protozero_c_plugin_path, guard_strip_prefix, guard_add_prefix, path_strip_prefix, path_add_prefix):
+ options = {
+ 'guard_strip_prefix': guard_strip_prefix,
+ 'guard_add_prefix': guard_add_prefix,
+ 'path_strip_prefix': path_strip_prefix,
+ 'path_add_prefix': path_add_prefix,
+ 'invoker': SCRIPT_PATH,
+ }
+ serialized_options = ','.join(
+ ['{}={}'.format(name, value) for name, value in options.items()])
+ subprocess.check_call([
+ protoc_path,
+ '--proto_path=.',
+ '--plugin=protoc-gen-plugin={}'.format(protozero_c_plugin_path),
+ '--plugin_out={}:{}'.format(serialized_options, outdir),
+ source,
+ ],
+ cwd=ROOT_DIR)
+
+
+# Given filename, the path of a header generated by the ProtoZero C plugin,
+# returns the path where the header should go in the public include directory.
+# Example
+#
+# include_path_for("protos/perfetto/trace/trace.pzc.h") ==
+# "include/perfetto/public/protos/trace/trace.pzc.h"
+def include_path_for(filename):
+ return os.path.join('include', 'perfetto', 'public', 'protos',
+ *pathlib.Path(transform_extension(filename)).parts[2:])
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--check-only', action='store_true')
+ parser.add_argument('OUT')
+ args = parser.parse_args()
+ out = args.OUT
+
+ call('ninja', '-C', out, 'protoc', 'protozero_c_plugin')
+
+ try:
+ with tempfile.TemporaryDirectory() as tmpdirname:
+ for sources in SOURCE_FILES:
+ for source in sources['files']:
+ generate(source, tmpdirname, protoc_path(out), protozero_c_plugin_path(out),
+ guard_strip_prefix=sources['guard_strip_prefix'],
+ guard_add_prefix=sources['guard_add_prefix'],
+ path_strip_prefix=sources['path_strip_prefix'],
+ path_add_prefix=sources['path_add_prefix'],
+ )
+
+ tmpfilename = os.path.join(tmpdirname, transform_extension(source))
+ clang_format(tmpfilename)
+ if source.startswith(sources['path_strip_prefix']):
+ targetfilename = source[len(sources['path_strip_prefix']):]
+ else:
+ targetfilename = source
+
+ targetfilename = sources['path_add_prefix'] + targetfilename
+
+ if 'include_prefix' in sources:
+ targetfilename = os.path.join(sources['include_prefix'], targetfilename)
+ targetfilename = transform_extension(targetfilename)
+
+ if args.check_only:
+ if not filecmp.cmp(tmpfilename, targetfilename):
+ raise AssertionError('Target {} does not match', targetfilename)
+ else:
+ os.makedirs(os.path.dirname(targetfilename), exist_ok=True)
+ shutil.copyfile(tmpfilename, targetfilename)
+
+ except AssertionError as e:
+ if not str(e):
+ raise
+ print('Error: {}'.format(e))
+ return 1
+
+
+if __name__ == '__main__':
+ exit(main())
diff --git a/ui/src/base/object_utils.ts b/ui/src/base/object_utils.ts
index d8cdd38..ec662a8 100644
--- a/ui/src/base/object_utils.ts
+++ b/ui/src/base/object_utils.ts
@@ -49,3 +49,7 @@
}
return true;
}
+
+export function isString(s: unknown): s is string {
+ return typeof s === 'string' || s instanceof String;
+}
diff --git a/ui/src/common/canvas_utils.ts b/ui/src/common/canvas_utils.ts
index 71b3b76..2d09617 100644
--- a/ui/src/common/canvas_utils.ts
+++ b/ui/src/common/canvas_utils.ts
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import {isString} from '../base/object_utils';
import {globals} from '../frontend/globals';
export function cropText(str: string, charWidth: number, rectWidth: number) {
@@ -89,12 +90,20 @@
ctx.lineTo(x + width, y + 4 * triangleSize);
ctx.lineTo(x, y + height);
- const gradient = ctx.createLinearGradient(x, y, x + width, y + height);
- gradient.addColorStop(0.66, ctx.fillStyle as string);
- gradient.addColorStop(1, '#FFFFFF');
- ctx.fillStyle = gradient;
+ const fillStyle = ctx.fillStyle;
+ if (isString(fillStyle)) {
+ const gradient = ctx.createLinearGradient(x, y, x + width, y + height);
+ gradient.addColorStop(0.66, fillStyle);
+ gradient.addColorStop(1, '#FFFFFF');
+ ctx.fillStyle = gradient;
+ } else {
+ throw new Error(
+ `drawIncompleteSlice() expects fillStyle to be a simple color not ${
+ fillStyle}`);
+ }
ctx.fill();
+ ctx.fillStyle = fillStyle;
}
export function drawTrackHoverTooltip(