1 /*
2  * Copyright (C) 2018 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 package android.util.proto;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 
22 /**
23  * Base utility class for protobuf streams.
24  *
25  * Contains a set of constants and methods used in generated code for
26  * {@link ProtoOutputStream}.
27  *
28  * @hide
29  */
30 public class ProtoStream {
31 
32     /**
33      * Number of bits to shift the field number to form a tag.
34      *
35      * <pre>
36      * // Reading a field number from a tag.
37      * int fieldNumber = tag &gt;&gt;&gt; FIELD_ID_SHIFT;
38      *
39      * // Building a tag from a field number and a wire type.
40      * int tag = (fieldNumber &lt;&lt; FIELD_ID_SHIFT) | wireType;
41      * </pre>
42      *
43      * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
44      * Encoding</a>
45      */
46     public static final int FIELD_ID_SHIFT = 3;
47 
48     /**
49      * Mask to select the wire type from a tag.
50      *
51      * <pre>
52      * // Reading a wire type from a tag.
53      * int wireType = tag &amp; WIRE_TYPE_MASK;
54      *
55      * // Building a tag from a field number and a wire type.
56      * int tag = (fieldNumber &lt;&lt; FIELD_ID_SHIFT) | wireType;
57      * </pre>
58      *
59      * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
60      * Encoding</a>
61      */
62     public static final int WIRE_TYPE_MASK = (1 << FIELD_ID_SHIFT) - 1;
63 
64     /**
65      * Mask to select the field id from a tag.
66      * @hide (not used by anything, and not actually useful, because you also want
67      * to shift when you mask the field id).
68      */
69     public static final int FIELD_ID_MASK = ~WIRE_TYPE_MASK;
70 
71     /**
72      * Varint wire type code.
73      *
74      * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
75      * Encoding</a>
76      */
77     public static final int WIRE_TYPE_VARINT = 0;
78 
79     /**
80      * Fixed64 wire type code.
81      *
82      * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
83      * Encoding</a>
84      */
85     public static final int WIRE_TYPE_FIXED64 = 1;
86 
87     /**
88      * Length delimited wire type code.
89      *
90      * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
91      * Encoding</a>
92      */
93     public static final int WIRE_TYPE_LENGTH_DELIMITED = 2;
94 
95     /**
96      * Start group wire type code.
97      *
98      * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
99      * Encoding</a>
100      */
101     public static final int WIRE_TYPE_START_GROUP = 3;
102 
103     /**
104      * End group wire type code.
105      *
106      * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
107      * Encoding</a>
108      */
109     public static final int WIRE_TYPE_END_GROUP = 4;
110 
111     /**
112      * Fixed32 wire type code.
113      *
114      * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
115      * Encoding</a>
116      */
117     public static final int WIRE_TYPE_FIXED32 = 5;
118 
119     /**
120      * Position of the field type in a (long) fieldId.
121      */
122     public static final int FIELD_TYPE_SHIFT = 32;
123 
124     /**
125      * Mask for the field types stored in a fieldId.  Leaves a whole
126      * byte for future expansion, even though there are currently only 17 types.
127      */
128     public static final long FIELD_TYPE_MASK = 0x0ffL << FIELD_TYPE_SHIFT;
129 
130     /**
131      * Not a real wire type.
132      * @hide
133      */
134     public static final long FIELD_TYPE_UNKNOWN = 0;
135 
136 
137     /*
138      * The FIELD_TYPE_ constants are copied from
139      * external/protobuf/src/google/protobuf/descriptor.h directly, so no
140      * extra mapping needs to be maintained in this case.
141      */
142 
143     /**
144      * Field type code for double fields. Used to build constants in generated
145      * code for use with the {@link ProtoOutputStream#write(long, double)
146      * ProtoOutputStream.write(long, double)} method.
147      */
148     public static final long FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
149 
150     /**
151      * Field type code for float fields. Used to build constants in generated
152      * code for use with the {@link ProtoOutputStream#write(long, float)
153      * ProtoOutputStream.write(long, float)} method.
154      */
155     public static final long FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
156 
157     /**
158      * Field type code for int64 fields. Used to build constants in generated
159      * code for use with the {@link ProtoOutputStream#write(long, long)
160      * ProtoOutputStream.write(long, long)} method.
161      */
162     public static final long FIELD_TYPE_INT64 = 3L << FIELD_TYPE_SHIFT;
163 
164     /**
165      * Field type code for uint64 fields. Used to build constants in generated
166      * code for use with the {@link ProtoOutputStream#write(long, long)
167      * ProtoOutputStream.write(long, long)} method.
168      */
169     public static final long FIELD_TYPE_UINT64 = 4L << FIELD_TYPE_SHIFT;
170 
171     /**
172      * Field type code for int32 fields. Used to build constants in generated
173      * code for use with the {@link ProtoOutputStream#write(long, int)
174      * ProtoOutputStream.write(long, int)} method.
175      */
176     public static final long FIELD_TYPE_INT32 = 5L << FIELD_TYPE_SHIFT;
177 
178     /**
179      * Field type code for fixed64 fields. Used to build constants in generated
180      * code for use with the {@link ProtoOutputStream#write(long, long)
181      * ProtoOutputStream.write(long, long)} method.
182      */
183     public static final long FIELD_TYPE_FIXED64 = 6L << FIELD_TYPE_SHIFT;
184 
185     /**
186      * Field type code for fixed32 fields. Used to build constants in generated
187      * code for use with the {@link ProtoOutputStream#write(long, int)
188      * ProtoOutputStream.write(long, int)} method.
189      */
190 
191     /**
192      * Field type code for fixed32 fields. Used to build constants in generated
193      * code for use with the {@link ProtoOutputStream#write(long, int)
194      * ProtoOutputStream.write(long, int)} method.
195      */
196     public static final long FIELD_TYPE_FIXED32 = 7L << FIELD_TYPE_SHIFT;
197 
198     /**
199      * Field type code for bool fields. Used to build constants in generated
200      * code for use with the {@link ProtoOutputStream#write(long, boolean)
201      * ProtoOutputStream.write(long, boolean)} method.
202      */
203     public static final long FIELD_TYPE_BOOL = 8L << FIELD_TYPE_SHIFT;
204 
205     /**
206      * Field type code for string fields. Used to build constants in generated
207      * code for use with the {@link ProtoOutputStream#write(long, String)
208      * ProtoOutputStream.write(long, String)} method.
209      */
210     public static final long FIELD_TYPE_STRING = 9L << FIELD_TYPE_SHIFT;
211 
212     //  public static final long FIELD_TYPE_GROUP = 10L << FIELD_TYPE_SHIFT; // Deprecated.
213 
214     /**
215      * Field type code for message fields. Used to build constants in generated
216      * code for use with the {@link ProtoOutputStream#start(long)
217      * ProtoOutputStream.start(long)} method.
218      */
219     public static final long FIELD_TYPE_MESSAGE = 11L << FIELD_TYPE_SHIFT;
220 
221     /**
222      * Field type code for bytes fields. Used to build constants in generated
223      * code for use with the {@link ProtoOutputStream#write(long, byte[])
224      * ProtoOutputStream.write(long, byte[])} method.
225      */
226     public static final long FIELD_TYPE_BYTES = 12L << FIELD_TYPE_SHIFT;
227 
228     /**
229      * Field type code for uint32 fields. Used to build constants in generated
230      * code for use with the {@link ProtoOutputStream#write(long, int)
231      * ProtoOutputStream.write(long, int)} method.
232      */
233     public static final long FIELD_TYPE_UINT32 = 13L << FIELD_TYPE_SHIFT;
234 
235     /**
236      * Field type code for enum fields. Used to build constants in generated
237      * code for use with the {@link ProtoOutputStream#write(long, int)
238      * ProtoOutputStream.write(long, int)} method.
239      */
240     public static final long FIELD_TYPE_ENUM = 14L << FIELD_TYPE_SHIFT;
241 
242     /**
243      * Field type code for sfixed32 fields. Used to build constants in generated
244      * code for use with the {@link ProtoOutputStream#write(long, int)
245      * ProtoOutputStream.write(long, int)} method.
246      */
247     public static final long FIELD_TYPE_SFIXED32 = 15L << FIELD_TYPE_SHIFT;
248 
249     /**
250      * Field type code for sfixed64 fields. Used to build constants in generated
251      * code for use with the {@link ProtoOutputStream#write(long, long)
252      * ProtoOutputStream.write(long, long)} method.
253      */
254     public static final long FIELD_TYPE_SFIXED64 = 16L << FIELD_TYPE_SHIFT;
255 
256     /**
257      * Field type code for sint32 fields. Used to build constants in generated
258      * code for use with the {@link ProtoOutputStream#write(long, int)
259      * ProtoOutputStream.write(long, int)} method.
260      */
261     public static final long FIELD_TYPE_SINT32 = 17L << FIELD_TYPE_SHIFT;
262 
263     /**
264      * Field type code for sint64 fields. Used to build constants in generated
265      * code for use with the {@link ProtoOutputStream#write(long, long)
266      * ProtoOutputStream.write(long, long)} method.
267      */
268     public static final long FIELD_TYPE_SINT64 = 18L << FIELD_TYPE_SHIFT;
269 
270     private static final @NonNull String[] FIELD_TYPE_NAMES = new String[]{
271             "Double",
272             "Float",
273             "Int64",
274             "UInt64",
275             "Int32",
276             "Fixed64",
277             "Fixed32",
278             "Bool",
279             "String",
280             "Group",  // This field is deprecated but reserved here for indexing.
281             "Message",
282             "Bytes",
283             "UInt32",
284             "Enum",
285             "SFixed32",
286             "SFixed64",
287             "SInt32",
288             "SInt64",
289     };
290 
291     //
292     // FieldId flags for whether the field is single, repeated or packed.
293     //
294     /**
295      * Bit offset for building a field id to be used with a
296      * <code>{@link ProtoOutputStream}.write(...)</code>.
297      *
298      * @see #FIELD_COUNT_MASK
299      * @see #FIELD_COUNT_UNKNOWN
300      * @see #FIELD_COUNT_SINGLE
301      * @see #FIELD_COUNT_REPEATED
302      * @see #FIELD_COUNT_PACKED
303      */
304     public static final int FIELD_COUNT_SHIFT = 40;
305 
306     /**
307      * Bit mask for selecting the field count when reading a field id that
308      * is used with a <code>{@link ProtoOutputStream}.write(...)</code> method.
309      *
310      * @see #FIELD_COUNT_SHIFT
311      * @see #FIELD_COUNT_MASK
312      * @see #FIELD_COUNT_UNKNOWN
313      * @see #FIELD_COUNT_SINGLE
314      * @see #FIELD_COUNT_REPEATED
315      * @see #FIELD_COUNT_PACKED
316      * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
317      * Encoding</a>
318      */
319     public static final long FIELD_COUNT_MASK = 0x0fL << FIELD_COUNT_SHIFT;
320 
321     /**
322      * Unknown field count, encoded into a field id used with a
323      * <code>{@link ProtoOutputStream}.write(...)</code> method.
324      *
325      * @see #FIELD_COUNT_SHIFT
326      * @see #FIELD_COUNT_MASK
327      * @see #FIELD_COUNT_SINGLE
328      * @see #FIELD_COUNT_REPEATED
329      * @see #FIELD_COUNT_PACKED
330      * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
331      * Encoding</a>
332      */
333     public static final long FIELD_COUNT_UNKNOWN = 0;
334 
335     /**
336      * Single field count, encoded into a field id used with a
337      * <code>{@link ProtoOutputStream}.write(...)</code> method.
338      *
339      * @see #FIELD_COUNT_SHIFT
340      * @see #FIELD_COUNT_MASK
341      * @see #FIELD_COUNT_UNKNOWN
342      * @see #FIELD_COUNT_REPEATED
343      * @see #FIELD_COUNT_PACKED
344      * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
345      * Encoding</a>
346      */
347     public static final long FIELD_COUNT_SINGLE = 1L << FIELD_COUNT_SHIFT;
348 
349     /**
350      * Repeated field count, encoded into a field id used with a
351      * <code>{@link ProtoOutputStream}.write(...)</code> method.
352      *
353      * @see #FIELD_COUNT_SHIFT
354      * @see #FIELD_COUNT_MASK
355      * @see #FIELD_COUNT_UNKNOWN
356      * @see #FIELD_COUNT_SINGLE
357      * @see #FIELD_COUNT_PACKED
358      * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
359      * Encoding</a>
360      */
361     public static final long FIELD_COUNT_REPEATED = 2L << FIELD_COUNT_SHIFT;
362 
363     /**
364      * Repeated packed field count, encoded into a field id used with a
365      * <code>{@link ProtoOutputStream}.write(...)</code> method.
366      *
367      * @see #FIELD_COUNT_SHIFT
368      * @see #FIELD_COUNT_MASK
369      * @see #FIELD_COUNT_UNKNOWN
370      * @see #FIELD_COUNT_SINGLE
371      * @see #FIELD_COUNT_REPEATED
372      * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
373      * Encoding</a>
374      */
375     public static final long FIELD_COUNT_PACKED = 5L << FIELD_COUNT_SHIFT;
376 
377 
378     /**
379      * Get the developer-usable name of a field type.
380      */
getFieldTypeString(long fieldType)381     public static @Nullable String getFieldTypeString(long fieldType) {
382         int index = ((int) ((fieldType & FIELD_TYPE_MASK) >>> FIELD_TYPE_SHIFT)) - 1;
383         if (index >= 0 && index < FIELD_TYPE_NAMES.length) {
384             return FIELD_TYPE_NAMES[index];
385         } else {
386             return null;
387         }
388     }
389 
390     /**
391      * Get the developer-usable name of a field count.
392      */
getFieldCountString(long fieldCount)393     public static @Nullable String getFieldCountString(long fieldCount) {
394         if (fieldCount == FIELD_COUNT_SINGLE) {
395             return "";
396         } else if (fieldCount == FIELD_COUNT_REPEATED) {
397             return "Repeated";
398         } else if (fieldCount == FIELD_COUNT_PACKED) {
399             return "Packed";
400         } else {
401             return null;
402         }
403     }
404 
405     /**
406      * Get the developer-usable name of a wire type.
407      */
getWireTypeString(int wireType)408     public static @Nullable String getWireTypeString(int wireType) {
409         switch (wireType) {
410             case WIRE_TYPE_VARINT:
411                 return "Varint";
412             case WIRE_TYPE_FIXED64:
413                 return "Fixed64";
414             case WIRE_TYPE_LENGTH_DELIMITED:
415                 return "Length Delimited";
416             case WIRE_TYPE_START_GROUP:
417                 return "Start Group";
418             case WIRE_TYPE_END_GROUP:
419                 return "End Group";
420             case WIRE_TYPE_FIXED32:
421                 return "Fixed32";
422             default:
423                 return null;
424         }
425     }
426 
427     /**
428      * Get a debug string for a fieldId.
429      */
getFieldIdString(long fieldId)430     public static @NonNull String getFieldIdString(long fieldId) {
431         final long fieldCount = fieldId & FIELD_COUNT_MASK;
432         String countString = getFieldCountString(fieldCount);
433         if (countString == null) {
434             countString = "fieldCount=" + fieldCount;
435         }
436         if (countString.length() > 0) {
437             countString += " ";
438         }
439 
440         final long fieldType = fieldId & FIELD_TYPE_MASK;
441         String typeString = getFieldTypeString(fieldType);
442         if (typeString == null) {
443             typeString = "fieldType=" + fieldType;
444         }
445 
446         return countString + typeString + " tag=" + ((int) fieldId)
447                 + " fieldId=0x" + Long.toHexString(fieldId);
448     }
449 
450     /**
451      * Combine a fieldId (the field keys in the proto file) and the field flags.
452      * Mostly useful for testing because the generated code contains the fieldId
453      * constants.
454      */
makeFieldId(int id, long fieldFlags)455     public static long makeFieldId(int id, long fieldFlags) {
456         return fieldFlags | (((long) id) & 0x0ffffffffL);
457     }
458 
459     //
460     // Child objects
461     //
462 
463     /**
464      * Make a token.
465      * Bits 61-63 - tag size (So we can go backwards later if the object had not data)
466      *            - 3 bits, max value 7, max value needed 5
467      * Bit  60    - true if the object is repeated (lets us require endObject or endRepeatedObject)
468      * Bits 59-51 - depth (For error checking)
469      *            - 9 bits, max value 512, when checking, value is masked (if we really
470      *              are more than 512 levels deep)
471      * Bits 32-50 - objectId (For error checking)
472      *            - 19 bits, max value 524,288. that's a lot of objects. IDs will wrap
473      *              because of the overflow, and only the tokens are compared.
474      * Bits  0-31 - offset of interest for the object.
475      */
makeToken(int tagSize, boolean repeated, int depth, int objectId, int offset)476     public static long makeToken(int tagSize, boolean repeated, int depth, int objectId,
477             int offset) {
478         return ((0x07L & (long) tagSize) << 61)
479                 | (repeated ? (1L << 60) : 0)
480                 | (0x01ffL & (long) depth) << 51
481                 | (0x07ffffL & (long) objectId) << 32
482                 | (0x0ffffffffL & (long) offset);
483     }
484 
485     /**
486      * Get the encoded tag size from the token.
487      *
488      * @hide
489      */
getTagSizeFromToken(long token)490     public static int getTagSizeFromToken(long token) {
491         return (int) (0x7 & (token >> 61));
492     }
493 
494     /**
495      * Get whether the token has the repeated bit set to true or false
496      *
497      * @hide
498      */
getRepeatedFromToken(long token)499     public static boolean getRepeatedFromToken(long token) {
500         return (0x1 & (token >> 60)) != 0;
501     }
502 
503     /**
504      * Get the nesting depth from the token.
505      *
506      * @hide
507      */
getDepthFromToken(long token)508     public static int getDepthFromToken(long token) {
509         return (int) (0x01ff & (token >> 51));
510     }
511 
512     /**
513      * Get the object ID from the token.
514      *
515      * <p>The object ID is a serial number for the
516      * startObject calls that have happened on this object.  The values are truncated
517      * to 9 bits, but that is sufficient for error checking.
518      *
519      * @hide
520      */
getObjectIdFromToken(long token)521     public static int getObjectIdFromToken(long token) {
522         return (int) (0x07ffff & (token >> 32));
523     }
524 
525     /**
526      * Get the location of the offset recorded in the token.
527      *
528      * @hide
529      */
getOffsetFromToken(long token)530     public static int getOffsetFromToken(long token) {
531         return (int) token;
532     }
533 
534     /**
535      * Convert the object ID to the ordinal value -- the n-th call to startObject.
536      *
537      * <p>The object IDs start at -1 and count backwards, so that the value is unlikely
538      * to alias with an actual size field that had been written.
539      *
540      * @hide
541      */
convertObjectIdToOrdinal(int objectId)542     public static int convertObjectIdToOrdinal(int objectId) {
543         return (-1 & 0x07ffff) - objectId;
544     }
545 
546     /**
547      * Return a debugging string of a token.
548      */
token2String(long token)549     public static @NonNull String token2String(long token) {
550         if (token == 0L) {
551             return "Token(0)";
552         } else {
553             return "Token(val=0x" + Long.toHexString(token)
554                     + " depth=" + getDepthFromToken(token)
555                     + " object=" + convertObjectIdToOrdinal(getObjectIdFromToken(token))
556                     + " tagSize=" + getTagSizeFromToken(token)
557                     + " offset=" + getOffsetFromToken(token)
558                     + ')';
559         }
560     }
561 
562     /**
563      * @hide
564      */
ProtoStream()565     protected ProtoStream() {}
566 }
567