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