• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.TestApi;
20 
21 /**
22  * Abstract base class for both protobuf streams.
23  *
24  * Contains a set of useful constants and methods used by both
25  * ProtoOutputStream and ProtoInputStream
26  *
27  * @hide
28  */
29 @TestApi
30 public abstract class ProtoStream {
31 
32     public static final int FIELD_ID_SHIFT = 3;
33     public static final int WIRE_TYPE_MASK = (1 << FIELD_ID_SHIFT) - 1;
34     public static final int FIELD_ID_MASK = ~WIRE_TYPE_MASK;
35 
36     public static final int WIRE_TYPE_VARINT = 0;
37     public static final int WIRE_TYPE_FIXED64 = 1;
38     public static final int WIRE_TYPE_LENGTH_DELIMITED = 2;
39     public static final int WIRE_TYPE_START_GROUP = 3;
40     public static final int WIRE_TYPE_END_GROUP = 4;
41     public static final int WIRE_TYPE_FIXED32 = 5;
42 
43     /**
44      * Position of the field type in a (long) fieldId.
45      */
46     public static final int FIELD_TYPE_SHIFT = 32;
47 
48     /**
49      * Mask for the field types stored in a fieldId.  Leaves a whole
50      * byte for future expansion, even though there are currently only 17 types.
51      */
52     public static final long FIELD_TYPE_MASK = 0x0ffL << FIELD_TYPE_SHIFT;
53 
54     public static final long FIELD_TYPE_UNKNOWN = 0;
55 
56     /**
57      * The types are copied from external/protobuf/src/google/protobuf/descriptor.h directly,
58      * so no extra mapping needs to be maintained in this case.
59      */
60     public static final long FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
61     public static final long FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
62     public static final long FIELD_TYPE_INT64 = 3L << FIELD_TYPE_SHIFT;
63     public static final long FIELD_TYPE_UINT64 = 4L << FIELD_TYPE_SHIFT;
64     public static final long FIELD_TYPE_INT32 = 5L << FIELD_TYPE_SHIFT;
65     public static final long FIELD_TYPE_FIXED64 = 6L << FIELD_TYPE_SHIFT;
66     public static final long FIELD_TYPE_FIXED32 = 7L << FIELD_TYPE_SHIFT;
67     public static final long FIELD_TYPE_BOOL = 8L << FIELD_TYPE_SHIFT;
68     public static final long FIELD_TYPE_STRING = 9L << FIELD_TYPE_SHIFT;
69     //  public static final long FIELD_TYPE_GROUP = 10L << FIELD_TYPE_SHIFT; // Deprecated.
70     public static final long FIELD_TYPE_MESSAGE = 11L << FIELD_TYPE_SHIFT;
71     public static final long FIELD_TYPE_BYTES = 12L << FIELD_TYPE_SHIFT;
72     public static final long FIELD_TYPE_UINT32 = 13L << FIELD_TYPE_SHIFT;
73     public static final long FIELD_TYPE_ENUM = 14L << FIELD_TYPE_SHIFT;
74     public static final long FIELD_TYPE_SFIXED32 = 15L << FIELD_TYPE_SHIFT;
75     public static final long FIELD_TYPE_SFIXED64 = 16L << FIELD_TYPE_SHIFT;
76     public static final long FIELD_TYPE_SINT32 = 17L << FIELD_TYPE_SHIFT;
77     public static final long FIELD_TYPE_SINT64 = 18L << FIELD_TYPE_SHIFT;
78 
79     protected static final String[] FIELD_TYPE_NAMES = new String[]{
80             "Double",
81             "Float",
82             "Int64",
83             "UInt64",
84             "Int32",
85             "Fixed64",
86             "Fixed32",
87             "Bool",
88             "String",
89             "Group",  // This field is deprecated but reserved here for indexing.
90             "Message",
91             "Bytes",
92             "UInt32",
93             "Enum",
94             "SFixed32",
95             "SFixed64",
96             "SInt32",
97             "SInt64",
98     };
99 
100     //
101     // FieldId flags for whether the field is single, repeated or packed.
102     //
103     public static final int FIELD_COUNT_SHIFT = 40;
104     public static final long FIELD_COUNT_MASK = 0x0fL << FIELD_COUNT_SHIFT;
105 
106     public static final long FIELD_COUNT_UNKNOWN = 0;
107     public static final long FIELD_COUNT_SINGLE = 1L << FIELD_COUNT_SHIFT;
108     public static final long FIELD_COUNT_REPEATED = 2L << FIELD_COUNT_SHIFT;
109     public static final long FIELD_COUNT_PACKED = 5L << FIELD_COUNT_SHIFT;
110 
111 
112     /**
113      * Get the developer-usable name of a field type.
114      */
getFieldTypeString(long fieldType)115     public static String getFieldTypeString(long fieldType) {
116         int index = ((int) ((fieldType & FIELD_TYPE_MASK) >>> FIELD_TYPE_SHIFT)) - 1;
117         if (index >= 0 && index < FIELD_TYPE_NAMES.length) {
118             return FIELD_TYPE_NAMES[index];
119         } else {
120             return null;
121         }
122     }
123 
124     /**
125      * Get the developer-usable name of a field count.
126      */
getFieldCountString(long fieldCount)127     public static String getFieldCountString(long fieldCount) {
128         if (fieldCount == FIELD_COUNT_SINGLE) {
129             return "";
130         } else if (fieldCount == FIELD_COUNT_REPEATED) {
131             return "Repeated";
132         } else if (fieldCount == FIELD_COUNT_PACKED) {
133             return "Packed";
134         } else {
135             return null;
136         }
137     }
138 
139     /**
140      * Get the developer-usable name of a wire type.
141      */
getWireTypeString(int wireType)142     public static String getWireTypeString(int wireType) {
143         switch (wireType) {
144             case WIRE_TYPE_VARINT:
145                 return "Varint";
146             case WIRE_TYPE_FIXED64:
147                 return "Fixed64";
148             case WIRE_TYPE_LENGTH_DELIMITED:
149                 return "Length Delimited";
150             case WIRE_TYPE_START_GROUP:
151                 return "Start Group";
152             case WIRE_TYPE_END_GROUP:
153                 return "End Group";
154             case WIRE_TYPE_FIXED32:
155                 return "Fixed32";
156             default:
157                 return null;
158         }
159     }
160 
161     /**
162      * Get a debug string for a fieldId.
163      */
getFieldIdString(long fieldId)164     public static String getFieldIdString(long fieldId) {
165         final long fieldCount = fieldId & FIELD_COUNT_MASK;
166         String countString = getFieldCountString(fieldCount);
167         if (countString == null) {
168             countString = "fieldCount=" + fieldCount;
169         }
170         if (countString.length() > 0) {
171             countString += " ";
172         }
173 
174         final long fieldType = fieldId & FIELD_TYPE_MASK;
175         String typeString = getFieldTypeString(fieldType);
176         if (typeString == null) {
177             typeString = "fieldType=" + fieldType;
178         }
179 
180         return countString + typeString + " tag=" + ((int) fieldId)
181                 + " fieldId=0x" + Long.toHexString(fieldId);
182     }
183 
184     /**
185      * Combine a fieldId (the field keys in the proto file) and the field flags.
186      * Mostly useful for testing because the generated code contains the fieldId
187      * constants.
188      */
makeFieldId(int id, long fieldFlags)189     public static long makeFieldId(int id, long fieldFlags) {
190         return fieldFlags | (((long) id) & 0x0ffffffffL);
191     }
192 
193     //
194     // Child objects
195     //
196 
197     /**
198      * Make a token.
199      * Bits 61-63 - tag size (So we can go backwards later if the object had not data)
200      *            - 3 bits, max value 7, max value needed 5
201      * Bit  60    - true if the object is repeated (lets us require endObject or endRepeatedObject)
202      * Bits 59-51 - depth (For error checking)
203      *            - 9 bits, max value 512, when checking, value is masked (if we really
204      *              are more than 512 levels deep)
205      * Bits 32-50 - objectId (For error checking)
206      *            - 19 bits, max value 524,288. that's a lot of objects. IDs will wrap
207      *              because of the overflow, and only the tokens are compared.
208      * Bits  0-31 - offset of interest for the object.
209      */
makeToken(int tagSize, boolean repeated, int depth, int objectId, int offset)210     public static long makeToken(int tagSize, boolean repeated, int depth, int objectId,
211             int offset) {
212         return ((0x07L & (long) tagSize) << 61)
213                 | (repeated ? (1L << 60) : 0)
214                 | (0x01ffL & (long) depth) << 51
215                 | (0x07ffffL & (long) objectId) << 32
216                 | (0x0ffffffffL & (long) offset);
217     }
218 
219     /**
220      * Get the encoded tag size from the token.
221      */
getTagSizeFromToken(long token)222     public static int getTagSizeFromToken(long token) {
223         return (int) (0x7 & (token >> 61));
224     }
225 
226     /**
227      * Get whether this is a call to startObject (false) or startRepeatedObject (true).
228      */
getRepeatedFromToken(long token)229     public static boolean getRepeatedFromToken(long token) {
230         return (0x1 & (token >> 60)) != 0;
231     }
232 
233     /**
234      * Get the nesting depth of startObject calls from the token.
235      */
getDepthFromToken(long token)236     public static int getDepthFromToken(long token) {
237         return (int) (0x01ff & (token >> 51));
238     }
239 
240     /**
241      * Get the object ID from the token. The object ID is a serial number for the
242      * startObject calls that have happened on this object.  The values are truncated
243      * to 9 bits, but that is sufficient for error checking.
244      */
getObjectIdFromToken(long token)245     public static int getObjectIdFromToken(long token) {
246         return (int) (0x07ffff & (token >> 32));
247     }
248 
249     /**
250      * Get the location of the offset recorded in the token.
251      */
getOffsetFromToken(long token)252     public static int getOffsetFromToken(long token) {
253         return (int) token;
254     }
255 
256     /**
257      * Convert the object ID to the ordinal value -- the n-th call to startObject.
258      * The object IDs start at -1 and count backwards, so that the value is unlikely
259      * to alias with an actual size field that had been written.
260      */
convertObjectIdToOrdinal(int objectId)261     public static int convertObjectIdToOrdinal(int objectId) {
262         return (-1 & 0x07ffff) - objectId;
263     }
264 
265     /**
266      * Return a debugging string of a token.
267      */
token2String(long token)268     public static String token2String(long token) {
269         if (token == 0L) {
270             return "Token(0)";
271         } else {
272             return "Token(val=0x" + Long.toHexString(token)
273                     + " depth=" + getDepthFromToken(token)
274                     + " object=" + convertObjectIdToOrdinal(getObjectIdFromToken(token))
275                     + " tagSize=" + getTagSizeFromToken(token)
276                     + " offset=" + getOffsetFromToken(token)
277                     + ')';
278         }
279     }
280 }
281