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