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 >>> FIELD_ID_SHIFT; 38 * 39 * // Building a tag from a field number and a wire type. 40 * int tag = (fieldNumber << 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 & WIRE_TYPE_MASK; 54 * 55 * // Building a tag from a field number and a wire type. 56 * int tag = (fieldNumber << 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