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