• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef INCLUDE_PERFETTO_PUBLIC_PB_MSG_H_
18 #define INCLUDE_PERFETTO_PUBLIC_PB_MSG_H_
19 
20 #include <assert.h>
21 #include <stdint.h>
22 #include <string.h>
23 
24 #include "perfetto/public/abi/stream_writer_abi.h"
25 #include "perfetto/public/compiler.h"
26 #include "perfetto/public/pb_utils.h"
27 #include "perfetto/public/stream_writer.h"
28 
29 // The number of bytes reserved by this implementation to encode a protobuf type
30 // 2 field size as var-int. Keep this in sync with kMessageLengthFieldSize in
31 // proto_utils.h.
32 #define PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE 4
33 
34 // Points to the memory used by a `PerfettoPbMsg` for writing.
35 struct PerfettoPbMsgWriter {
36   struct PerfettoStreamWriter writer;
37 };
38 
39 struct PerfettoPbMsg {
40   // Pointer to a non-aligned pre-reserved var-int slot of
41   // PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE bytes. If not NULL,
42   // protozero_length_buf_finalize() will write the size of proto-encoded
43   // message in the pointed memory region.
44   uint8_t* size_field;
45 
46   // Current size of the buffer.
47   uint32_t size;
48 
49   struct PerfettoPbMsgWriter* writer;
50 
51   struct PerfettoPbMsg* nested;
52   struct PerfettoPbMsg* parent;
53 };
54 
PerfettoPbMsgInit(struct PerfettoPbMsg * msg,struct PerfettoPbMsgWriter * writer)55 static inline void PerfettoPbMsgInit(struct PerfettoPbMsg* msg,
56                                      struct PerfettoPbMsgWriter* writer) {
57   msg->size_field = PERFETTO_NULL;
58   msg->size = 0;
59   msg->writer = writer;
60   msg->nested = PERFETTO_NULL;
61   msg->parent = PERFETTO_NULL;
62 }
63 
PerfettoPbMsgPatch(struct PerfettoPbMsg * msg)64 static inline void PerfettoPbMsgPatch(struct PerfettoPbMsg* msg) {
65   static_assert(
66       PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE == PERFETTO_STREAM_WRITER_PATCH_SIZE,
67       "PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE doesn't match patch size");
68   msg->size_field =
69       PerfettoStreamWriterAnnotatePatch(&msg->writer->writer, msg->size_field);
70 }
71 
PerfettoPbMsgPatchStack(struct PerfettoPbMsg * msg)72 static inline void PerfettoPbMsgPatchStack(struct PerfettoPbMsg* msg) {
73   uint8_t* const cur_range_end = msg->writer->writer.end;
74   uint8_t* const cur_range_begin = msg->writer->writer.begin;
75   while (msg && cur_range_begin <= msg->size_field &&
76          msg->size_field < cur_range_end) {
77     PerfettoPbMsgPatch(msg);
78     msg = msg->parent;
79   }
80 }
81 
PerfettoPbMsgAppendBytes(struct PerfettoPbMsg * msg,const uint8_t * begin,size_t size)82 static inline void PerfettoPbMsgAppendBytes(struct PerfettoPbMsg* msg,
83                                             const uint8_t* begin,
84                                             size_t size) {
85   if (PERFETTO_UNLIKELY(
86           size > PerfettoStreamWriterAvailableBytes(&msg->writer->writer))) {
87     PerfettoPbMsgPatchStack(msg);
88   }
89   PerfettoStreamWriterAppendBytes(&msg->writer->writer, begin, size);
90   msg->size += size;
91 }
92 
PerfettoPbMsgAppendByte(struct PerfettoPbMsg * msg,uint8_t value)93 static inline void PerfettoPbMsgAppendByte(struct PerfettoPbMsg* msg,
94                                            uint8_t value) {
95   PerfettoPbMsgAppendBytes(msg, &value, 1);
96 }
97 
PerfettoPbMsgAppendVarInt(struct PerfettoPbMsg * msg,uint64_t value)98 static inline void PerfettoPbMsgAppendVarInt(struct PerfettoPbMsg* msg,
99                                              uint64_t value) {
100   uint8_t* buf_end;
101   uint8_t buf[PERFETTO_PB_VARINT_MAX_SIZE_64];
102   buf_end = PerfettoPbWriteVarInt(value, buf);
103 
104   PerfettoPbMsgAppendBytes(msg, buf,
105                            PERFETTO_STATIC_CAST(size_t, buf_end - buf));
106 }
107 
PerfettoPbMsgAppendFixed64(struct PerfettoPbMsg * msg,uint64_t value)108 static inline void PerfettoPbMsgAppendFixed64(struct PerfettoPbMsg* msg,
109                                               uint64_t value) {
110   uint8_t buf[8];
111   PerfettoPbWriteFixed64(value, buf);
112 
113   PerfettoPbMsgAppendBytes(msg, buf, 8);
114 }
115 
PerfettoPbMsgAppendFixed32(struct PerfettoPbMsg * msg,uint32_t value)116 static inline void PerfettoPbMsgAppendFixed32(struct PerfettoPbMsg* msg,
117                                               uint32_t value) {
118   uint8_t buf[4];
119   PerfettoPbWriteFixed32(value, buf);
120 
121   PerfettoPbMsgAppendBytes(msg, buf, 4);
122 }
123 
PerfettoPbMsgAppendType0Field(struct PerfettoPbMsg * msg,int32_t field_id,uint64_t value)124 static inline void PerfettoPbMsgAppendType0Field(struct PerfettoPbMsg* msg,
125                                                  int32_t field_id,
126                                                  uint64_t value) {
127   uint8_t* buf_end;
128   uint8_t buf[PERFETTO_PB_VARINT_MAX_SIZE_64 + PERFETTO_PB_VARINT_MAX_SIZE_32];
129   buf_end = PerfettoPbWriteVarInt(
130       PerfettoPbMakeTag(field_id, PERFETTO_PB_WIRE_TYPE_VARINT), buf);
131   buf_end = PerfettoPbWriteVarInt(value, buf_end);
132 
133   PerfettoPbMsgAppendBytes(msg, buf,
134                            PERFETTO_STATIC_CAST(size_t, buf_end - buf));
135 }
136 
PerfettoPbMsgAppendType2Field(struct PerfettoPbMsg * msg,int32_t field_id,const uint8_t * data,size_t size)137 static inline void PerfettoPbMsgAppendType2Field(struct PerfettoPbMsg* msg,
138                                                  int32_t field_id,
139                                                  const uint8_t* data,
140                                                  size_t size) {
141   uint8_t* buf_end;
142   uint8_t buf[PERFETTO_PB_VARINT_MAX_SIZE_64 + PERFETTO_PB_VARINT_MAX_SIZE_32];
143   buf_end = PerfettoPbWriteVarInt(
144       PerfettoPbMakeTag(field_id, PERFETTO_PB_WIRE_TYPE_DELIMITED), buf);
145   buf_end =
146       PerfettoPbWriteVarInt(PERFETTO_STATIC_CAST(uint64_t, size), buf_end);
147   PerfettoPbMsgAppendBytes(msg, buf,
148                            PERFETTO_STATIC_CAST(size_t, buf_end - buf));
149 
150   PerfettoPbMsgAppendBytes(msg, data, size);
151 }
152 
PerfettoPbMsgAppendFixed32Field(struct PerfettoPbMsg * msg,int32_t field_id,uint32_t value)153 static inline void PerfettoPbMsgAppendFixed32Field(struct PerfettoPbMsg* msg,
154                                                    int32_t field_id,
155                                                    uint32_t value) {
156   uint8_t* buf_end;
157   uint8_t buf[PERFETTO_PB_VARINT_MAX_SIZE_32 + 4];
158   buf_end = PerfettoPbWriteVarInt(
159       PerfettoPbMakeTag(field_id, PERFETTO_PB_WIRE_TYPE_FIXED32), buf);
160   buf_end = PerfettoPbWriteFixed32(value, buf_end);
161 
162   PerfettoPbMsgAppendBytes(msg, buf,
163                            PERFETTO_STATIC_CAST(size_t, buf_end - buf));
164 }
165 
PerfettoPbMsgAppendFloatField(struct PerfettoPbMsg * msg,int32_t field_id,float value)166 static inline void PerfettoPbMsgAppendFloatField(struct PerfettoPbMsg* msg,
167                                                  int32_t field_id,
168                                                  float value) {
169   uint32_t val;
170   memcpy(&val, &value, sizeof val);
171   PerfettoPbMsgAppendFixed32Field(msg, field_id, val);
172 }
173 
PerfettoPbMsgAppendFixed64Field(struct PerfettoPbMsg * msg,int32_t field_id,uint64_t value)174 static inline void PerfettoPbMsgAppendFixed64Field(struct PerfettoPbMsg* msg,
175                                                    int32_t field_id,
176                                                    uint64_t value) {
177   uint8_t* buf_end;
178   uint8_t buf[PERFETTO_PB_VARINT_MAX_SIZE_32 + 8];
179   buf_end = PerfettoPbWriteVarInt(
180       PerfettoPbMakeTag(field_id, PERFETTO_PB_WIRE_TYPE_FIXED64), buf);
181   buf_end = PerfettoPbWriteFixed64(value, buf_end);
182 
183   PerfettoPbMsgAppendBytes(msg, buf,
184                            PERFETTO_STATIC_CAST(size_t, buf_end - buf));
185 }
186 
PerfettoPbMsgAppendDoubleField(struct PerfettoPbMsg * msg,int32_t field_id,double value)187 static inline void PerfettoPbMsgAppendDoubleField(struct PerfettoPbMsg* msg,
188                                                   int32_t field_id,
189                                                   double value) {
190   uint64_t val;
191   memcpy(&val, &value, sizeof val);
192   PerfettoPbMsgAppendFixed64Field(msg, field_id, val);
193 }
194 
PerfettoPbMsgAppendCStrField(struct PerfettoPbMsg * msg,int32_t field_id,const char * c_str)195 static inline void PerfettoPbMsgAppendCStrField(struct PerfettoPbMsg* msg,
196                                                 int32_t field_id,
197                                                 const char* c_str) {
198   PerfettoPbMsgAppendType2Field(
199       msg, field_id, PERFETTO_REINTERPRET_CAST(const uint8_t*, c_str),
200       strlen(c_str));
201 }
202 
PerfettoPbMsgBeginNested(struct PerfettoPbMsg * parent,struct PerfettoPbMsg * nested,int32_t field_id)203 static inline void PerfettoPbMsgBeginNested(struct PerfettoPbMsg* parent,
204                                             struct PerfettoPbMsg* nested,
205                                             int32_t field_id) {
206   PerfettoPbMsgAppendVarInt(
207       parent, PerfettoPbMakeTag(field_id, PERFETTO_PB_WIRE_TYPE_DELIMITED));
208 
209   PerfettoPbMsgInit(nested, parent->writer);
210   if (PERFETTO_UNLIKELY(
211           PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE >
212           PerfettoStreamWriterAvailableBytes(&parent->writer->writer))) {
213     PerfettoPbMsgPatchStack(parent);
214   }
215   nested->size_field = PERFETTO_REINTERPRET_CAST(
216       uint8_t*,
217       PerfettoStreamWriterReserveBytes(&nested->writer->writer,
218                                        PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE));
219   nested->parent = parent;
220   parent->size += PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE;
221   parent->nested = nested;
222 }
223 
224 static inline size_t PerfettoPbMsgFinalize(struct PerfettoPbMsg* msg);
225 
PerfettoPbMsgEndNested(struct PerfettoPbMsg * parent)226 static inline void PerfettoPbMsgEndNested(struct PerfettoPbMsg* parent) {
227   parent->size += PerfettoPbMsgFinalize(parent->nested);
228   parent->nested = PERFETTO_NULL;
229 }
230 
PerfettoPbMsgFinalize(struct PerfettoPbMsg * msg)231 static inline size_t PerfettoPbMsgFinalize(struct PerfettoPbMsg* msg) {
232   if (msg->nested)
233     PerfettoPbMsgEndNested(msg);
234 
235   // Write the length of the nested message a posteriori, using a leading-zero
236   // redundant varint encoding.
237   if (msg->size_field) {
238     uint32_t size_to_write;
239     size_to_write = msg->size;
240     for (size_t i = 0; i < PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE; i++) {
241       const uint8_t msb = (i < 3) ? 0x80 : 0;
242       msg->size_field[i] = (size_to_write & 0xFF) | msb;
243       size_to_write >>= 7;
244     }
245     msg->size_field = PERFETTO_NULL;
246   }
247 
248   return msg->size;
249 }
250 
251 #endif  // INCLUDE_PERFETTO_PUBLIC_PB_MSG_H_
252