• 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 
PerfettoPbMsgAppendType0Field(struct PerfettoPbMsg * msg,int32_t field_id,uint64_t value)108 static inline void PerfettoPbMsgAppendType0Field(struct PerfettoPbMsg* msg,
109                                                  int32_t field_id,
110                                                  uint64_t value) {
111   uint8_t* buf_end;
112   uint8_t buf[PERFETTO_PB_VARINT_MAX_SIZE_64 + PERFETTO_PB_VARINT_MAX_SIZE_32];
113   buf_end = PerfettoPbWriteVarInt(
114       PerfettoPbMakeTag(field_id, PERFETTO_PB_WIRE_TYPE_VARINT), buf);
115   buf_end = PerfettoPbWriteVarInt(value, buf_end);
116 
117   PerfettoPbMsgAppendBytes(msg, buf,
118                            PERFETTO_STATIC_CAST(size_t, buf_end - buf));
119 }
120 
PerfettoPbMsgAppendType2Field(struct PerfettoPbMsg * msg,int32_t field_id,const uint8_t * data,size_t size)121 static inline void PerfettoPbMsgAppendType2Field(struct PerfettoPbMsg* msg,
122                                                  int32_t field_id,
123                                                  const uint8_t* data,
124                                                  size_t size) {
125   uint8_t* buf_end;
126   uint8_t buf[PERFETTO_PB_VARINT_MAX_SIZE_64 + PERFETTO_PB_VARINT_MAX_SIZE_32];
127   buf_end = PerfettoPbWriteVarInt(
128       PerfettoPbMakeTag(field_id, PERFETTO_PB_WIRE_TYPE_DELIMITED), buf);
129   buf_end =
130       PerfettoPbWriteVarInt(PERFETTO_STATIC_CAST(uint64_t, size), buf_end);
131   PerfettoPbMsgAppendBytes(msg, buf,
132                            PERFETTO_STATIC_CAST(size_t, buf_end - buf));
133 
134   PerfettoPbMsgAppendBytes(msg, data, size);
135 }
136 
PerfettoPbMsgAppendFixed32Field(struct PerfettoPbMsg * msg,int32_t field_id,uint32_t value)137 static inline void PerfettoPbMsgAppendFixed32Field(struct PerfettoPbMsg* msg,
138                                                    int32_t field_id,
139                                                    uint32_t value) {
140   uint8_t* buf_end;
141   uint8_t buf[PERFETTO_PB_VARINT_MAX_SIZE_32 + 4];
142   buf_end = PerfettoPbWriteVarInt(
143       PerfettoPbMakeTag(field_id, PERFETTO_PB_WIRE_TYPE_FIXED32), buf);
144   buf_end[0] = PERFETTO_STATIC_CAST(uint8_t, value);
145   buf_end[1] = PERFETTO_STATIC_CAST(uint8_t, value >> 8);
146   buf_end[2] = PERFETTO_STATIC_CAST(uint8_t, value >> 16);
147   buf_end[3] = PERFETTO_STATIC_CAST(uint8_t, value >> 24);
148   buf_end += 4;
149 
150   PerfettoPbMsgAppendBytes(msg, buf,
151                            PERFETTO_STATIC_CAST(size_t, buf_end - buf));
152 }
153 
PerfettoPbMsgAppendFloatField(struct PerfettoPbMsg * msg,int32_t field_id,float value)154 static inline void PerfettoPbMsgAppendFloatField(struct PerfettoPbMsg* msg,
155                                                  int32_t field_id,
156                                                  float value) {
157   uint32_t val;
158   memcpy(&val, &value, sizeof val);
159   PerfettoPbMsgAppendFixed32Field(msg, field_id, val);
160 }
161 
PerfettoPbMsgAppendFixed64Field(struct PerfettoPbMsg * msg,int32_t field_id,uint64_t value)162 static inline void PerfettoPbMsgAppendFixed64Field(struct PerfettoPbMsg* msg,
163                                                    int32_t field_id,
164                                                    uint64_t value) {
165   uint8_t* buf_end;
166   uint8_t buf[PERFETTO_PB_VARINT_MAX_SIZE_32 + 8];
167   buf_end = PerfettoPbWriteVarInt(
168       PerfettoPbMakeTag(field_id, PERFETTO_PB_WIRE_TYPE_FIXED64), buf);
169   buf_end[0] = PERFETTO_STATIC_CAST(uint8_t, value);
170   buf_end[1] = PERFETTO_STATIC_CAST(uint8_t, value >> 8);
171   buf_end[2] = PERFETTO_STATIC_CAST(uint8_t, value >> 16);
172   buf_end[3] = PERFETTO_STATIC_CAST(uint8_t, value >> 24);
173   buf_end[4] = PERFETTO_STATIC_CAST(uint8_t, value >> 32);
174   buf_end[5] = PERFETTO_STATIC_CAST(uint8_t, value >> 40);
175   buf_end[6] = PERFETTO_STATIC_CAST(uint8_t, value >> 48);
176   buf_end[7] = PERFETTO_STATIC_CAST(uint8_t, value >> 56);
177   buf_end += 8;
178 
179   PerfettoPbMsgAppendBytes(msg, buf,
180                            PERFETTO_STATIC_CAST(size_t, buf_end - buf));
181 }
182 
PerfettoPbMsgAppendDoubleField(struct PerfettoPbMsg * msg,int32_t field_id,double value)183 static inline void PerfettoPbMsgAppendDoubleField(struct PerfettoPbMsg* msg,
184                                                   int32_t field_id,
185                                                   double value) {
186   uint64_t val;
187   memcpy(&val, &value, sizeof val);
188   PerfettoPbMsgAppendFixed64Field(msg, field_id, val);
189 }
190 
PerfettoPbMsgAppendCStrField(struct PerfettoPbMsg * msg,int32_t field_id,const char * c_str)191 static inline void PerfettoPbMsgAppendCStrField(struct PerfettoPbMsg* msg,
192                                                 int32_t field_id,
193                                                 const char* c_str) {
194   PerfettoPbMsgAppendType2Field(
195       msg, field_id, PERFETTO_REINTERPRET_CAST(const uint8_t*, c_str),
196       strlen(c_str));
197 }
198 
PerfettoPbMsgBeginNested(struct PerfettoPbMsg * parent,struct PerfettoPbMsg * nested,int32_t field_id)199 static inline void PerfettoPbMsgBeginNested(struct PerfettoPbMsg* parent,
200                                             struct PerfettoPbMsg* nested,
201                                             int32_t field_id) {
202   PerfettoPbMsgAppendVarInt(
203       parent, PerfettoPbMakeTag(field_id, PERFETTO_PB_WIRE_TYPE_DELIMITED));
204 
205   PerfettoPbMsgInit(nested, parent->writer);
206   if (PERFETTO_UNLIKELY(
207           PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE >
208           PerfettoStreamWriterAvailableBytes(&parent->writer->writer))) {
209     PerfettoPbMsgPatchStack(parent);
210   }
211   nested->size_field = PERFETTO_REINTERPRET_CAST(
212       uint8_t*,
213       PerfettoStreamWriterReserveBytes(&nested->writer->writer,
214                                        PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE));
215   nested->parent = parent;
216   parent->size += PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE;
217   parent->nested = nested;
218 }
219 
220 static inline size_t PerfettoPbMsgFinalize(struct PerfettoPbMsg* msg);
221 
PerfettoPbMsgEndNested(struct PerfettoPbMsg * parent)222 static inline void PerfettoPbMsgEndNested(struct PerfettoPbMsg* parent) {
223   parent->size += PerfettoPbMsgFinalize(parent->nested);
224   parent->nested = PERFETTO_NULL;
225 }
226 
PerfettoPbMsgFinalize(struct PerfettoPbMsg * msg)227 static inline size_t PerfettoPbMsgFinalize(struct PerfettoPbMsg* msg) {
228   if (msg->nested)
229     PerfettoPbMsgEndNested(msg);
230 
231   // Write the length of the nested message a posteriori, using a leading-zero
232   // redundant varint encoding.
233   if (msg->size_field) {
234     uint32_t size_to_write;
235     size_to_write = msg->size;
236     for (size_t i = 0; i < PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE; i++) {
237       const uint8_t msb = (i < 3) ? 0x80 : 0;
238       msg->size_field[i] = (size_to_write & 0xFF) | msb;
239       size_to_write >>= 7;
240     }
241     msg->size_field = PERFETTO_NULL;
242   }
243 
244   return msg->size;
245 }
246 
247 #endif  // INCLUDE_PERFETTO_PUBLIC_PB_MSG_H_
248