1 /* 2 * Copyright 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 androidx.versionedparcelable; 18 19 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX; 20 21 import android.os.BadParcelableException; 22 import android.os.Bundle; 23 import android.os.IBinder; 24 import android.os.IInterface; 25 import android.os.NetworkOnMainThreadException; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 import android.util.Size; 29 import android.util.SizeF; 30 import android.util.SparseBooleanArray; 31 32 import androidx.annotation.RequiresApi; 33 import androidx.annotation.RestrictTo; 34 import androidx.collection.ArrayMap; 35 import androidx.collection.ArraySet; 36 import androidx.collection.SimpleArrayMap; 37 38 import org.jspecify.annotations.NonNull; 39 import org.jspecify.annotations.Nullable; 40 41 import java.io.ByteArrayInputStream; 42 import java.io.ByteArrayOutputStream; 43 import java.io.IOException; 44 import java.io.ObjectInputStream; 45 import java.io.ObjectOutputStream; 46 import java.io.ObjectStreamClass; 47 import java.io.Serializable; 48 import java.lang.reflect.InvocationTargetException; 49 import java.lang.reflect.Method; 50 import java.util.ArrayList; 51 import java.util.Collection; 52 import java.util.List; 53 import java.util.Map; 54 import java.util.Set; 55 56 /** 57 */ 58 @RestrictTo(LIBRARY_GROUP_PREFIX) 59 public abstract class VersionedParcel { 60 61 private static final @NonNull String TAG = "VersionedParcel"; 62 63 // These constants cannot change once shipped. 64 private static final int EX_SECURITY = -1; 65 private static final int EX_BAD_PARCELABLE = -2; 66 private static final int EX_ILLEGAL_ARGUMENT = -3; 67 private static final int EX_NULL_POINTER = -4; 68 private static final int EX_ILLEGAL_STATE = -5; 69 private static final int EX_NETWORK_MAIN_THREAD = -6; 70 private static final int EX_UNSUPPORTED_OPERATION = -7; 71 private static final int EX_PARCELABLE = -9; 72 73 private static final int TYPE_VERSIONED_PARCELABLE = 1; 74 private static final int TYPE_PARCELABLE = 2; 75 private static final int TYPE_SERIALIZABLE = 3; 76 private static final int TYPE_STRING = 4; 77 private static final int TYPE_BINDER = 5; 78 private static final int TYPE_INTEGER = 7; 79 private static final int TYPE_FLOAT = 8; 80 81 final @NonNull SimpleArrayMap<String, Method> mReadCache; 82 final @NonNull SimpleArrayMap<String, Method> mWriteCache; 83 final @NonNull SimpleArrayMap<String, Class<?>> mParcelizerCache; 84 VersionedParcel( @onNull SimpleArrayMap<String, Method> readCache, @NonNull SimpleArrayMap<String, Method> writeCache, @NonNull SimpleArrayMap<String, Class<?>> parcelizerCache )85 VersionedParcel( 86 @NonNull SimpleArrayMap<String, Method> readCache, 87 @NonNull SimpleArrayMap<String, Method> writeCache, 88 @NonNull SimpleArrayMap<String, Class<?>> parcelizerCache 89 ) { 90 mReadCache = readCache; 91 mWriteCache = writeCache; 92 mParcelizerCache = parcelizerCache; 93 } 94 95 /** 96 * Whether this VersionedParcel is serializing into a stream and will not accept Parcelables. 97 */ isStream()98 public boolean isStream() { 99 return false; 100 } 101 102 /** 103 * Closes the last field when done parceling. 104 */ closeField()105 protected abstract void closeField(); 106 107 /** 108 * Create a sub-parcel to be used for a child VersionedParcelable 109 */ createSubParcel()110 protected abstract @NonNull VersionedParcel createSubParcel(); 111 112 /** 113 * Write a byte array into the parcel. 114 * 115 * @param b Bytes to place into the parcel. 116 */ writeByteArray(byte @Nullable [] b)117 protected abstract void writeByteArray(byte @Nullable [] b); 118 119 /** 120 * Write a byte array into the parcel. 121 * 122 * @param b Bytes to place into the parcel. 123 * @param offset Index of first byte to be written. 124 * @param len Number of bytes to write. 125 */ writeByteArray(byte @Nullable [] b, int offset, int len)126 protected abstract void writeByteArray(byte @Nullable [] b, int offset, int len); 127 128 /** 129 * Write a CharSequence into the parcel. 130 */ writeCharSequence(@ullable CharSequence charSequence)131 protected abstract void writeCharSequence(@Nullable CharSequence charSequence); 132 133 /** 134 * Write an integer value into the parcel at the current dataPosition(), 135 * growing dataCapacity() if needed. 136 */ writeInt(int val)137 protected abstract void writeInt(int val); 138 139 /** 140 * Write a long integer value into the parcel at the current dataPosition(), 141 * growing dataCapacity() if needed. 142 */ writeLong(long val)143 protected abstract void writeLong(long val); 144 145 /** 146 * Write a floating point value into the parcel at the current 147 * dataPosition(), growing dataCapacity() if needed. 148 */ writeFloat(float val)149 protected abstract void writeFloat(float val); 150 151 /** 152 * Write a double precision floating point value into the parcel at the 153 * current dataPosition(), growing dataCapacity() if needed. 154 */ writeDouble(double val)155 protected abstract void writeDouble(double val); 156 157 /** 158 * Write a string value into the parcel at the current dataPosition(), 159 * growing dataCapacity() if needed. 160 */ writeString(@ullable String val)161 protected abstract void writeString(@Nullable String val); 162 163 /** 164 * Write an object into the parcel at the current dataPosition(), 165 * growing dataCapacity() if needed. 166 */ writeStrongBinder(@ullable IBinder val)167 protected abstract void writeStrongBinder(@Nullable IBinder val); 168 169 /** 170 * Flatten the name of the class of the VersionedParcelable and its contents 171 * into the parcel. 172 * 173 * @param p The VersionedParcelable object to be written. 174 * {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}. 175 */ writeParcelable(@ullable Parcelable p)176 protected abstract void writeParcelable(@Nullable Parcelable p); 177 178 /** 179 * Write a boolean value into the parcel at the current dataPosition(), 180 * growing dataCapacity() if needed. 181 */ writeBoolean(boolean val)182 protected abstract void writeBoolean(boolean val); 183 184 /** 185 * Write an object into the parcel at the current dataPosition(), 186 * growing dataCapacity() if needed. 187 */ writeStrongInterface(@ullable IInterface val)188 protected abstract void writeStrongInterface(@Nullable IInterface val); 189 190 /** 191 * Flatten a Bundle into the parcel at the current dataPosition(), 192 * growing dataCapacity() if needed. 193 */ writeBundle(@ullable Bundle val)194 protected abstract void writeBundle(@Nullable Bundle val); 195 196 /** 197 * Read an integer value from the parcel at the current dataPosition(). 198 */ readInt()199 protected abstract int readInt(); 200 201 /** 202 * Read a long integer value from the parcel at the current dataPosition(). 203 */ readLong()204 protected abstract long readLong(); 205 206 /** 207 * Read a floating point value from the parcel at the current 208 * dataPosition(). 209 */ readFloat()210 protected abstract float readFloat(); 211 212 /** 213 * Read a double precision floating point value from the parcel at the 214 * current dataPosition(). 215 */ readDouble()216 protected abstract double readDouble(); 217 218 /** 219 * Read a string value from the parcel at the current dataPosition(). 220 */ readString()221 protected abstract @Nullable String readString(); 222 223 /** 224 * Read an object from the parcel at the current dataPosition(). 225 */ readStrongBinder()226 protected abstract @Nullable IBinder readStrongBinder(); 227 228 /** 229 * Read a byte[] object from the parcel. 230 */ readByteArray()231 protected abstract byte @Nullable [] readByteArray(); 232 233 /** 234 * Read a CharSequence from the parcel 235 */ readCharSequence()236 protected abstract @Nullable CharSequence readCharSequence(); 237 238 /** 239 */ 240 @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) readParcelable()241 protected abstract <T extends Parcelable> @Nullable T readParcelable(); 242 243 /** 244 * Read and return a new Bundle object from the parcel at the current 245 * dataPosition(). Returns null if the previously written Bundle object was 246 * null. 247 */ readBundle()248 protected abstract @Nullable Bundle readBundle(); 249 250 /** 251 * Read a boolean value from the parcel at the current dataPosition(). 252 */ readBoolean()253 protected abstract boolean readBoolean(); 254 255 /** 256 * Prepares to read data from a specific field for the following read 257 * calls. 258 */ readField(int fieldId)259 protected abstract boolean readField(int fieldId); 260 261 /** 262 * Sets the output of write methods to be tagged as part of the specified 263 * fieldId. 264 */ setOutputField(int fieldId)265 protected abstract void setOutputField(int fieldId); 266 267 /** 268 * Configure the VersionedParcel for current serialization method. 269 */ setSerializationFlags(boolean allowSerialization, boolean ignoreParcelables)270 public void setSerializationFlags(boolean allowSerialization, boolean ignoreParcelables) { 271 // Don't care except in VersionedParcelStream 272 } 273 274 /** 275 * Write an object into the parcel at the current dataPosition(), 276 * growing dataCapacity() if needed. 277 */ writeStrongInterface(@ullable IInterface val, int fieldId)278 public void writeStrongInterface(@Nullable IInterface val, int fieldId) { 279 setOutputField(fieldId); 280 writeStrongInterface(val); 281 } 282 283 /** 284 * Flatten a Bundle into the parcel at the current dataPosition(), 285 * growing dataCapacity() if needed. 286 */ writeBundle(@ullable Bundle val, int fieldId)287 public void writeBundle(@Nullable Bundle val, int fieldId) { 288 setOutputField(fieldId); 289 writeBundle(val); 290 } 291 292 /** 293 * Write a boolean value into the parcel at the current dataPosition(), 294 * growing dataCapacity() if needed. 295 */ writeBoolean(boolean val, int fieldId)296 public void writeBoolean(boolean val, int fieldId) { 297 setOutputField(fieldId); 298 writeBoolean(val); 299 } 300 301 /** 302 * Write a byte array into the parcel. 303 * 304 * @param b Bytes to place into the parcel. 305 */ writeByteArray(byte @Nullable [] b, int fieldId)306 public void writeByteArray(byte @Nullable [] b, int fieldId) { 307 setOutputField(fieldId); 308 writeByteArray(b); 309 } 310 311 /** 312 * Write a byte array into the parcel. 313 * 314 * @param b Bytes to place into the parcel. 315 * @param offset Index of first byte to be written. 316 * @param len Number of bytes to write. 317 */ writeByteArray(byte @Nullable [] b, int offset, int len, int fieldId)318 public void writeByteArray(byte @Nullable [] b, int offset, int len, int fieldId) { 319 setOutputField(fieldId); 320 writeByteArray(b, offset, len); 321 } 322 323 /** 324 * Write a CharSequence into the parcel at the current dataPosition(), 325 * growing dataCapacity() if needed. 326 */ writeCharSequence(@ullable CharSequence val, int fieldId)327 public void writeCharSequence(@Nullable CharSequence val, int fieldId) { 328 setOutputField(fieldId); 329 writeCharSequence(val); 330 } 331 332 /** 333 * Write an integer value into the parcel at the current dataPosition(), 334 * growing dataCapacity() if needed. 335 */ writeInt(int val, int fieldId)336 public void writeInt(int val, int fieldId) { 337 setOutputField(fieldId); 338 writeInt(val); 339 } 340 341 /** 342 * Write a long integer value into the parcel at the current dataPosition(), 343 * growing dataCapacity() if needed. 344 */ writeLong(long val, int fieldId)345 public void writeLong(long val, int fieldId) { 346 setOutputField(fieldId); 347 writeLong(val); 348 } 349 350 /** 351 * Write a floating point value into the parcel at the current 352 * dataPosition(), growing dataCapacity() if needed. 353 */ writeFloat(float val, int fieldId)354 public void writeFloat(float val, int fieldId) { 355 setOutputField(fieldId); 356 writeFloat(val); 357 } 358 359 /** 360 * Write a double precision floating point value into the parcel at the 361 * current dataPosition(), growing dataCapacity() if needed. 362 */ writeDouble(double val, int fieldId)363 public void writeDouble(double val, int fieldId) { 364 setOutputField(fieldId); 365 writeDouble(val); 366 } 367 368 /** 369 * Write a string value into the parcel at the current dataPosition(), 370 * growing dataCapacity() if needed. 371 */ writeString(@ullable String val, int fieldId)372 public void writeString(@Nullable String val, int fieldId) { 373 setOutputField(fieldId); 374 writeString(val); 375 } 376 377 /** 378 * Write an object into the parcel at the current dataPosition(), 379 * growing dataCapacity() if needed. 380 */ writeStrongBinder(@ullable IBinder val, int fieldId)381 public void writeStrongBinder(@Nullable IBinder val, int fieldId) { 382 setOutputField(fieldId); 383 writeStrongBinder(val); 384 } 385 386 /** 387 * Flatten the name of the class of the Parcelable and its contents 388 * into the parcel. 389 * 390 * @param p The Parcelable object to be written. 391 * {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}. 392 */ writeParcelable(@ullable Parcelable p, int fieldId)393 public void writeParcelable(@Nullable Parcelable p, int fieldId) { 394 setOutputField(fieldId); 395 writeParcelable(p); 396 } 397 398 /** 399 * Read a boolean value from the parcel at the current dataPosition(). 400 */ readBoolean(boolean def, int fieldId)401 public boolean readBoolean(boolean def, int fieldId) { 402 if (!readField(fieldId)) { 403 return def; 404 } 405 return readBoolean(); 406 } 407 408 /** 409 * Read an integer value from the parcel at the current dataPosition(). 410 */ readInt(int def, int fieldId)411 public int readInt(int def, int fieldId) { 412 if (!readField(fieldId)) { 413 return def; 414 } 415 return readInt(); 416 } 417 418 /** 419 * Read a long integer value from the parcel at the current dataPosition(). 420 */ readLong(long def, int fieldId)421 public long readLong(long def, int fieldId) { 422 if (!readField(fieldId)) { 423 return def; 424 } 425 return readLong(); 426 } 427 428 /** 429 * Read a floating point value from the parcel at the current 430 * dataPosition(). 431 */ readFloat(float def, int fieldId)432 public float readFloat(float def, int fieldId) { 433 if (!readField(fieldId)) { 434 return def; 435 } 436 return readFloat(); 437 } 438 439 /** 440 * Read a double precision floating point value from the parcel at the 441 * current dataPosition(). 442 */ readDouble(double def, int fieldId)443 public double readDouble(double def, int fieldId) { 444 if (!readField(fieldId)) { 445 return def; 446 } 447 return readDouble(); 448 } 449 450 /** 451 * Read a string value from the parcel at the current dataPosition(). 452 */ readString(@ullable String def, int fieldId)453 public @Nullable String readString(@Nullable String def, int fieldId) { 454 if (!readField(fieldId)) { 455 return def; 456 } 457 return readString(); 458 } 459 460 /** 461 * Read an object from the parcel at the current dataPosition(). 462 */ readStrongBinder(@ullable IBinder def, int fieldId)463 public @Nullable IBinder readStrongBinder(@Nullable IBinder def, int fieldId) { 464 if (!readField(fieldId)) { 465 return def; 466 } 467 return readStrongBinder(); 468 } 469 470 /** 471 * Read a byte[] object from the parcel and copy it into the 472 * given byte array. 473 */ readByteArray(byte @Nullable [] def, int fieldId)474 public byte @Nullable [] readByteArray(byte @Nullable [] def, int fieldId) { 475 if (!readField(fieldId)) { 476 return def; 477 } 478 return readByteArray(); 479 } 480 481 /** 482 */ readParcelable(@ullable T def, int fieldId)483 public <T extends Parcelable> @Nullable T readParcelable(@Nullable T def, int fieldId) { 484 if (!readField(fieldId)) { 485 return def; 486 } 487 return readParcelable(); 488 } 489 490 /** 491 * Read and return a new Bundle object from the parcel at the current 492 * dataPosition(). Returns null if the previously written Bundle object was 493 * null. 494 */ readBundle(@ullable Bundle def, int fieldId)495 public @Nullable Bundle readBundle(@Nullable Bundle def, int fieldId) { 496 if (!readField(fieldId)) { 497 return def; 498 } 499 return readBundle(); 500 } 501 502 /** 503 * Write a byte value into the parcel at the current dataPosition(), 504 * growing dataCapacity() if needed. 505 */ writeByte(byte val, int fieldId)506 public void writeByte(byte val, int fieldId) { 507 setOutputField(fieldId); 508 writeInt(val); 509 } 510 511 /** 512 * Flatten a Size into the parcel at the current dataPosition(), 513 * growing dataCapacity() if needed. 514 */ 515 @RequiresApi(21) writeSize(@ullable Size val, int fieldId)516 public void writeSize(@Nullable Size val, int fieldId) { 517 setOutputField(fieldId); 518 Api21Impl.writeSize(this, val); 519 } 520 521 /** 522 * Flatten a SizeF into the parcel at the current dataPosition(), 523 * growing dataCapacity() if needed. 524 */ 525 @RequiresApi(21) writeSizeF(@ullable SizeF val, int fieldId)526 public void writeSizeF(@Nullable SizeF val, int fieldId) { 527 setOutputField(fieldId); 528 Api21Impl.writeSizeF(this, val); 529 } 530 531 /** 532 */ writeSparseBooleanArray(@ullable SparseBooleanArray val, int fieldId)533 public void writeSparseBooleanArray(@Nullable SparseBooleanArray val, int fieldId) { 534 setOutputField(fieldId); 535 if (val == null) { 536 writeInt(-1); 537 return; 538 } 539 int n = val.size(); 540 writeInt(n); 541 int i = 0; 542 while (i < n) { 543 writeInt(val.keyAt(i)); 544 writeBoolean(val.valueAt(i)); 545 i++; 546 } 547 } 548 549 /** 550 */ writeBooleanArray(boolean @Nullable [] val, int fieldId)551 public void writeBooleanArray(boolean @Nullable [] val, int fieldId) { 552 setOutputField(fieldId); 553 writeBooleanArray(val); 554 } 555 556 /** 557 */ writeBooleanArray(boolean @Nullable [] val)558 protected void writeBooleanArray(boolean @Nullable [] val) { 559 if (val != null) { 560 int n = val.length; 561 writeInt(n); 562 for (int i = 0; i < n; i++) { 563 writeInt(val[i] ? 1 : 0); 564 } 565 } else { 566 writeInt(-1); 567 } 568 } 569 570 /** 571 */ readBooleanArray(boolean @Nullable [] def, int fieldId)572 public boolean @Nullable [] readBooleanArray(boolean @Nullable [] def, int fieldId) { 573 if (!readField(fieldId)) { 574 return def; 575 } 576 return readBooleanArray(); 577 } 578 579 /** 580 */ readBooleanArray()581 protected boolean @Nullable [] readBooleanArray() { 582 int n = readInt(); 583 if (n < 0) { 584 return null; 585 } 586 boolean[] val = new boolean[n]; 587 for (int i = 0; i < n; i++) { 588 val[i] = readInt() != 0; 589 } 590 return val; 591 } 592 593 /** 594 */ writeCharArray(char @Nullable [] val, int fieldId)595 public void writeCharArray(char @Nullable [] val, int fieldId) { 596 setOutputField(fieldId); 597 if (val != null) { 598 int n = val.length; 599 writeInt(n); 600 for (int i = 0; i < n; i++) { 601 writeInt((int) val[i]); 602 } 603 } else { 604 writeInt(-1); 605 } 606 } 607 608 /** 609 */ readCharSequence(@ullable CharSequence def, int fieldId)610 public @Nullable CharSequence readCharSequence(@Nullable CharSequence def, int fieldId) { 611 if (!readField(fieldId)) { 612 return def; 613 } 614 return readCharSequence(); 615 } 616 617 /** 618 */ readCharArray(char @Nullable [] def, int fieldId)619 public char @Nullable [] readCharArray(char @Nullable [] def, int fieldId) { 620 if (!readField(fieldId)) { 621 return def; 622 } 623 int n = readInt(); 624 if (n < 0) { 625 return null; 626 } 627 char[] val = new char[n]; 628 for (int i = 0; i < n; i++) { 629 val[i] = (char) readInt(); 630 } 631 return val; 632 } 633 634 /** 635 */ writeIntArray(int @Nullable [] val, int fieldId)636 public void writeIntArray(int @Nullable [] val, int fieldId) { 637 setOutputField(fieldId); 638 writeIntArray(val); 639 } 640 641 /** 642 */ writeIntArray(int @Nullable [] val)643 protected void writeIntArray(int @Nullable [] val) { 644 if (val != null) { 645 int n = val.length; 646 writeInt(n); 647 for (int i = 0; i < n; i++) { 648 writeInt(val[i]); 649 } 650 } else { 651 writeInt(-1); 652 } 653 } 654 655 /** 656 */ readIntArray(int @Nullable [] def, int fieldId)657 public int @Nullable [] readIntArray(int @Nullable [] def, int fieldId) { 658 if (!readField(fieldId)) { 659 return def; 660 } 661 return readIntArray(); 662 } 663 664 /** 665 */ readIntArray()666 protected int @Nullable [] readIntArray() { 667 int n = readInt(); 668 if (n < 0) { 669 return null; 670 } 671 int[] val = new int[n]; 672 for (int i = 0; i < n; i++) { 673 val[i] = readInt(); 674 } 675 return val; 676 } 677 678 /** 679 */ writeLongArray(long @Nullable [] val, int fieldId)680 public void writeLongArray(long @Nullable [] val, int fieldId) { 681 setOutputField(fieldId); 682 writeLongArray(val); 683 } 684 685 /** 686 */ writeLongArray(long @Nullable [] val)687 protected void writeLongArray(long @Nullable [] val) { 688 if (val != null) { 689 int n = val.length; 690 writeInt(n); 691 for (int i = 0; i < n; i++) { 692 writeLong(val[i]); 693 } 694 } else { 695 writeInt(-1); 696 } 697 } 698 699 /** 700 */ readLongArray(long @Nullable [] def, int fieldId)701 public long @Nullable [] readLongArray(long @Nullable [] def, int fieldId) { 702 if (!readField(fieldId)) { 703 return def; 704 } 705 return readLongArray(); 706 } 707 708 /** 709 */ readLongArray()710 protected long @Nullable [] readLongArray() { 711 int n = readInt(); 712 if (n < 0) { 713 return null; 714 } 715 long[] val = new long[n]; 716 for (int i = 0; i < n; i++) { 717 val[i] = readLong(); 718 } 719 return val; 720 } 721 722 /** 723 */ writeFloatArray(float @Nullable [] val, int fieldId)724 public void writeFloatArray(float @Nullable [] val, int fieldId) { 725 setOutputField(fieldId); 726 writeFloatArray(val); 727 } 728 729 /** 730 */ writeFloatArray(float @Nullable [] val)731 protected void writeFloatArray(float @Nullable [] val) { 732 if (val != null) { 733 int n = val.length; 734 writeInt(n); 735 for (int i = 0; i < n; i++) { 736 writeFloat(val[i]); 737 } 738 } else { 739 writeInt(-1); 740 } 741 } 742 743 /** 744 */ readFloatArray(float @Nullable [] def, int fieldId)745 public float @Nullable [] readFloatArray(float @Nullable [] def, int fieldId) { 746 if (!readField(fieldId)) { 747 return def; 748 } 749 return readFloatArray(); 750 } 751 752 /** 753 */ readFloatArray()754 protected float @Nullable [] readFloatArray() { 755 int n = readInt(); 756 if (n < 0) { 757 return null; 758 } 759 float[] val = new float[n]; 760 for (int i = 0; i < n; i++) { 761 val[i] = readFloat(); 762 } 763 return val; 764 } 765 766 /** 767 */ writeDoubleArray(double @Nullable [] val, int fieldId)768 public void writeDoubleArray(double @Nullable [] val, int fieldId) { 769 setOutputField(fieldId); 770 writeDoubleArray(val); 771 } 772 773 /** 774 */ writeDoubleArray(double @Nullable [] val)775 protected void writeDoubleArray(double @Nullable [] val) { 776 if (val != null) { 777 int n = val.length; 778 writeInt(n); 779 for (int i = 0; i < n; i++) { 780 writeDouble(val[i]); 781 } 782 } else { 783 writeInt(-1); 784 } 785 } 786 787 /** 788 */ readDoubleArray(double @Nullable [] def, int fieldId)789 public double @Nullable [] readDoubleArray(double @Nullable [] def, int fieldId) { 790 if (!readField(fieldId)) { 791 return def; 792 } 793 return readDoubleArray(); 794 } 795 796 /** 797 */ readDoubleArray()798 protected double @Nullable [] readDoubleArray() { 799 int n = readInt(); 800 if (n < 0) { 801 return null; 802 } 803 double[] val = new double[n]; 804 for (int i = 0; i < n; i++) { 805 val[i] = readDouble(); 806 } 807 return val; 808 } 809 810 /** 811 * Flatten a Set containing a particular object type into the parcel, at 812 * the current dataPosition() and growing dataCapacity() if needed. The 813 * type of the objects in the list must be one that implements VersionedParcelable, 814 * Parcelable, String, or Serializable. 815 * 816 * @param val The list of objects to be written. 817 * @see #readSet 818 * @see VersionedParcelable 819 */ writeSet(@ullable Set<T> val, int fieldId)820 public <T> void writeSet(@Nullable Set<T> val, int fieldId) { 821 writeCollection(val, fieldId); 822 } 823 824 /** 825 * Flatten a List containing a particular object type into the parcel, at 826 * the current dataPosition() and growing dataCapacity() if needed. The 827 * type of the objects in the list must be one that implements VersionedParcelable, 828 * Parcelable, String, Float, Integer or Serializable. 829 * 830 * @param val The list of objects to be written. 831 * @see #readList 832 * @see VersionedParcelable 833 */ writeList(@ullable List<T> val, int fieldId)834 public <T> void writeList(@Nullable List<T> val, int fieldId) { 835 writeCollection(val, fieldId); 836 } 837 838 /** 839 * Flatten a Map containing a particular object type into the parcel, at 840 * the current dataPosition() and growing dataCapacity() if needed. The 841 * type of the objects in the list must be one that implements VersionedParcelable, 842 * Parcelable, String, Float, Integer or Serializable. 843 * 844 * @param val The list of objects to be written. 845 * @see #readMap 846 * @see VersionedParcelable 847 */ writeMap(@ullable Map<K, V> val, int fieldId)848 public <K, V> void writeMap(@Nullable Map<K, V> val, int fieldId) { 849 setOutputField(fieldId); 850 if (val == null) { 851 writeInt(-1); 852 return; 853 } 854 int size = val.size(); 855 writeInt(size); 856 if (size == 0) { 857 return; 858 } 859 List<K> keySet = new ArrayList<>(size); 860 List<V> valueSet = new ArrayList<>(size); 861 for (Map.Entry<K, V> entry : val.entrySet()) { 862 keySet.add(entry.getKey()); 863 valueSet.add(entry.getValue()); 864 } 865 writeCollection(keySet); 866 writeCollection(valueSet); 867 } 868 writeCollection(@ullable Collection<T> val, int fieldId)869 private <T> void writeCollection(@Nullable Collection<T> val, int fieldId) { 870 setOutputField(fieldId); 871 writeCollection(val); 872 } 873 writeCollection(@ullable Collection<T> val)874 private <T> void writeCollection(@Nullable Collection<T> val) { 875 if (val == null) { 876 writeInt(-1); 877 return; 878 } 879 880 int n = val.size(); 881 writeInt(n); 882 if (n > 0) { 883 int type = getType(val.iterator().next()); 884 writeInt(type); 885 switch (type) { 886 case TYPE_STRING: 887 for (T v : val) { 888 writeString((String) v); 889 } 890 break; 891 case TYPE_PARCELABLE: 892 for (T v : val) { 893 writeParcelable((Parcelable) v); 894 } 895 break; 896 case TYPE_VERSIONED_PARCELABLE: 897 for (T v : val) { 898 writeVersionedParcelable((VersionedParcelable) v); 899 } 900 break; 901 case TYPE_SERIALIZABLE: 902 for (T v : val) { 903 writeSerializable((Serializable) v); 904 } 905 break; 906 case TYPE_BINDER: 907 for (T v : val) { 908 writeStrongBinder((IBinder) v); 909 } 910 break; 911 case TYPE_INTEGER: 912 for (T v : val) { 913 writeInt((Integer) v); 914 } 915 break; 916 case TYPE_FLOAT: 917 for (T v : val) { 918 writeFloat((Float) v); 919 } 920 break; 921 } 922 } 923 } 924 925 /** 926 * Flatten an Array containing a particular object type into the parcel, at 927 * the current dataPosition() and growing dataCapacity() if needed. The 928 * type of the objects in the array must be one that implements VersionedParcelable, 929 * Parcelable, String, or Serializable. 930 * 931 * @param val The list of objects to be written. 932 * @see #readList 933 * @see VersionedParcelable 934 */ writeArray(T @ullable [] val, int fieldId)935 public <T> void writeArray(T @Nullable [] val, int fieldId) { 936 setOutputField(fieldId); 937 writeArray(val); 938 } 939 940 /** 941 */ writeArray(T @ullable [] val)942 protected <T> void writeArray(T @Nullable [] val) { 943 if (val == null) { 944 writeInt(-1); 945 return; 946 } 947 948 int n = val.length; 949 int i = 0; 950 writeInt(n); 951 if (n > 0) { 952 int type = getType(val[0]); 953 writeInt(type); 954 switch (type) { 955 case TYPE_STRING: 956 while (i < n) { 957 writeString((String) val[i]); 958 i++; 959 } 960 break; 961 case TYPE_PARCELABLE: 962 while (i < n) { 963 writeParcelable((Parcelable) val[i]); 964 i++; 965 } 966 break; 967 case TYPE_VERSIONED_PARCELABLE: 968 while (i < n) { 969 writeVersionedParcelable((VersionedParcelable) val[i]); 970 i++; 971 } 972 break; 973 case TYPE_SERIALIZABLE: 974 while (i < n) { 975 writeSerializable((Serializable) val[i]); 976 i++; 977 } 978 break; 979 case TYPE_BINDER: 980 while (i < n) { 981 writeStrongBinder((IBinder) val[i]); 982 i++; 983 } 984 break; 985 } 986 } 987 } 988 getType(@onNull T t)989 private <T> int getType(@NonNull T t) { 990 if (t instanceof String) { 991 return TYPE_STRING; 992 } else if (t instanceof Parcelable) { 993 return TYPE_PARCELABLE; 994 } else if (t instanceof VersionedParcelable) { 995 return TYPE_VERSIONED_PARCELABLE; 996 } else if (t instanceof Serializable) { 997 return TYPE_SERIALIZABLE; 998 } else if (t instanceof IBinder) { 999 return TYPE_BINDER; 1000 } else if (t instanceof Integer) { 1001 return TYPE_INTEGER; 1002 } else if (t instanceof Float) { 1003 return TYPE_FLOAT; 1004 } 1005 throw new IllegalArgumentException(t.getClass().getName() 1006 + " cannot be VersionedParcelled"); 1007 } 1008 1009 /** 1010 * Flatten the name of the class of the VersionedParcelable and its contents 1011 * into the parcel. 1012 * 1013 * @param p The VersionedParcelable object to be written. 1014 */ writeVersionedParcelable(@ullable VersionedParcelable p, int fieldId)1015 public void writeVersionedParcelable(@Nullable VersionedParcelable p, int fieldId) { 1016 setOutputField(fieldId); 1017 writeVersionedParcelable(p); 1018 } 1019 1020 /** 1021 */ writeVersionedParcelable(@ullable VersionedParcelable p)1022 protected void writeVersionedParcelable(@Nullable VersionedParcelable p) { 1023 if (p == null) { 1024 writeString(null); 1025 return; 1026 } 1027 writeVersionedParcelableCreator(p); 1028 1029 VersionedParcel subParcel = createSubParcel(); 1030 writeToParcel(p, subParcel); 1031 subParcel.closeField(); 1032 } 1033 writeVersionedParcelableCreator(@onNull VersionedParcelable p)1034 private void writeVersionedParcelableCreator(@NonNull VersionedParcelable p) { 1035 Class<?> name; 1036 try { 1037 name = findParcelClass(p.getClass()); 1038 } catch (ClassNotFoundException e) { 1039 throw new RuntimeException(p.getClass().getSimpleName() + " does not have a Parcelizer", 1040 e); 1041 } 1042 writeString(name.getName()); 1043 } 1044 1045 /** 1046 * Write a generic serializable object in to a VersionedParcel. It is strongly 1047 * recommended that this method be avoided, since the serialization 1048 * overhead is extremely large, and this approach will be much slower than 1049 * using the other approaches to writing data in to a VersionedParcel. 1050 */ writeSerializable(@ullable Serializable s, int fieldId)1051 public void writeSerializable(@Nullable Serializable s, int fieldId) { 1052 setOutputField(fieldId); 1053 writeSerializable(s); 1054 } 1055 writeSerializable(@ullable Serializable s)1056 private void writeSerializable(@Nullable Serializable s) { 1057 if (s == null) { 1058 writeString(null); 1059 return; 1060 } 1061 String name = s.getClass().getName(); 1062 writeString(name); 1063 1064 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 1065 try { 1066 ObjectOutputStream oos = new ObjectOutputStream(baos); 1067 oos.writeObject(s); 1068 oos.close(); 1069 1070 writeByteArray(baos.toByteArray()); 1071 } catch (IOException ioe) { 1072 throw new RuntimeException("VersionedParcelable encountered " 1073 + "IOException writing serializable object (name = " + name 1074 + ")", ioe); 1075 } 1076 } 1077 1078 /** 1079 * Special function for writing an exception result at the header of 1080 * a parcel, to be used when returning an exception from a transaction. 1081 * Note that this currently only supports a few exception types; any other 1082 * exception will be re-thrown by this function as a RuntimeException 1083 * (to be caught by the system's last-resort exception handling when 1084 * dispatching a transaction). 1085 * 1086 * <p>The supported exception types are: 1087 * <ul> 1088 * <li>{@link BadParcelableException} 1089 * <li>{@link IllegalArgumentException} 1090 * <li>{@link IllegalStateException} 1091 * <li>{@link NullPointerException} 1092 * <li>{@link SecurityException} 1093 * <li>{@link UnsupportedOperationException} 1094 * <li>{@link NetworkOnMainThreadException} 1095 * </ul> 1096 * 1097 * @param e The Exception to be written. 1098 * @see #writeNoException 1099 * @see #readException 1100 */ writeException(@ullable Exception e, int fieldId)1101 public void writeException(@Nullable Exception e, int fieldId) { 1102 setOutputField(fieldId); 1103 if (e == null) { 1104 writeNoException(); 1105 return; 1106 } 1107 int code = 0; 1108 if (e instanceof Parcelable 1109 && (e.getClass().getClassLoader() == Parcelable.class.getClassLoader())) { 1110 // We only send VersionedParcelable exceptions that are in the 1111 // BootClassLoader to ensure that the receiver can unpack them 1112 code = EX_PARCELABLE; 1113 } else if (e instanceof SecurityException) { 1114 code = EX_SECURITY; 1115 } else if (e instanceof BadParcelableException) { 1116 code = EX_BAD_PARCELABLE; 1117 } else if (e instanceof IllegalArgumentException) { 1118 code = EX_ILLEGAL_ARGUMENT; 1119 } else if (e instanceof NullPointerException) { 1120 code = EX_NULL_POINTER; 1121 } else if (e instanceof IllegalStateException) { 1122 code = EX_ILLEGAL_STATE; 1123 } else if (e instanceof NetworkOnMainThreadException) { 1124 code = EX_NETWORK_MAIN_THREAD; 1125 } else if (e instanceof UnsupportedOperationException) { 1126 code = EX_UNSUPPORTED_OPERATION; 1127 } 1128 writeInt(code); 1129 if (code == 0) { 1130 if (e instanceof RuntimeException) { 1131 throw (RuntimeException) e; 1132 } 1133 throw new RuntimeException(e); 1134 } 1135 writeString(e.getMessage()); 1136 switch (code) { 1137 case EX_PARCELABLE: 1138 // Write parceled exception prefixed by length 1139 writeParcelable((Parcelable) e); 1140 break; 1141 } 1142 } 1143 1144 /** 1145 * Special function for writing information at the front of the VersionedParcel 1146 * indicating that no exception occurred. 1147 * 1148 * @see #writeException 1149 * @see #readException 1150 */ writeNoException()1151 protected void writeNoException() { 1152 writeInt(0); 1153 } 1154 1155 /** 1156 * Special function for reading an exception result from the header of 1157 * a parcel, to be used after receiving the result of a transaction. This 1158 * will throw the exception for you if it had been written to the VersionedParcel, 1159 * otherwise return and let you read the normal result data from the VersionedParcel. 1160 * 1161 * @see #writeException 1162 * @see #writeNoException 1163 */ readException(@ullable Exception def, int fieldId)1164 public @Nullable Exception readException(@Nullable Exception def, int fieldId) { 1165 if (!readField(fieldId)) { 1166 return def; 1167 } 1168 int code = readExceptionCode(); 1169 if (code != 0) { 1170 String msg = readString(); 1171 return createException(code, msg); 1172 } 1173 return def; 1174 } 1175 1176 /** 1177 * Parses the header of a Binder call's response VersionedParcel and 1178 * returns the exception code. Deals with lite or fat headers. 1179 * In the common successful case, this header is generally zero. 1180 * In less common cases, it's a small negative number and will be 1181 * followed by an error string. 1182 * 1183 * This exists purely for android.database.DatabaseUtils and 1184 * insulating it from having to handle fat headers as returned by 1185 * e.g. StrictMode-induced RPC responses. 1186 */ readExceptionCode()1187 private int readExceptionCode() { 1188 int code = readInt(); 1189 return code; 1190 } 1191 1192 /** 1193 * Gets the root {@link Throwable#getCause() cause} of {@code t} 1194 */ getRootCause(@onNull Throwable t)1195 protected static @NonNull Throwable getRootCause(@NonNull Throwable t) { 1196 while (t.getCause() != null) t = t.getCause(); 1197 return t; 1198 } 1199 1200 /** 1201 * Creates an exception with the given message. 1202 * 1203 * @param code Used to determine which exception class to throw. 1204 * @param msg The exception message. 1205 */ createException(int code, String msg)1206 private @NonNull Exception createException(int code, String msg) { 1207 switch (code) { 1208 case EX_PARCELABLE: 1209 return (Exception) readParcelable(); 1210 case EX_SECURITY: 1211 return new SecurityException(msg); 1212 case EX_BAD_PARCELABLE: 1213 return new BadParcelableException(msg); 1214 case EX_ILLEGAL_ARGUMENT: 1215 return new IllegalArgumentException(msg); 1216 case EX_NULL_POINTER: 1217 return new NullPointerException(msg); 1218 case EX_ILLEGAL_STATE: 1219 return new IllegalStateException(msg); 1220 case EX_NETWORK_MAIN_THREAD: 1221 return new NetworkOnMainThreadException(); 1222 case EX_UNSUPPORTED_OPERATION: 1223 return new UnsupportedOperationException(msg); 1224 } 1225 return new RuntimeException("Unknown exception code: " + code 1226 + " msg " + msg); 1227 } 1228 1229 /** 1230 * Read a byte value from the parcel at the current dataPosition(). 1231 */ readByte(byte def, int fieldId)1232 public byte readByte(byte def, int fieldId) { 1233 if (!readField(fieldId)) { 1234 return def; 1235 } 1236 return (byte) (readInt() & 0xff); 1237 } 1238 1239 /** 1240 * Read a Size from the parcel at the current dataPosition(). 1241 */ 1242 @RequiresApi(21) readSize(@ullable Size def, int fieldId)1243 public @Nullable Size readSize(@Nullable Size def, int fieldId) { 1244 if (!readField(fieldId)) { 1245 return def; 1246 } 1247 return Api21Impl.readSize(this); 1248 } 1249 1250 /** 1251 * Read a SizeF from the parcel at the current dataPosition(). 1252 */ 1253 @RequiresApi(21) readSizeF(@ullable SizeF def, int fieldId)1254 public @Nullable SizeF readSizeF(@Nullable SizeF def, int fieldId) { 1255 if (!readField(fieldId)) { 1256 return def; 1257 } 1258 return Api21Impl.readSizeF(this); 1259 } 1260 1261 /** 1262 * Read and return a new SparseBooleanArray object from the parcel at the current 1263 * dataPosition(). Returns null if the previously written list object was 1264 * null. 1265 */ readSparseBooleanArray( @ullable SparseBooleanArray def, int fieldId )1266 public @Nullable SparseBooleanArray readSparseBooleanArray( 1267 @Nullable SparseBooleanArray def, 1268 int fieldId 1269 ) { 1270 if (!readField(fieldId)) { 1271 return def; 1272 } 1273 int n = readInt(); 1274 if (n < 0) { 1275 return null; 1276 } 1277 SparseBooleanArray sa = new SparseBooleanArray(n); 1278 int i = 0; 1279 while (i < n) { 1280 sa.put(readInt(), readBoolean()); 1281 i++; 1282 } 1283 return sa; 1284 } 1285 1286 /** 1287 * Read and return a new ArraySet containing a particular object type from 1288 * the parcel that was written with {@link #writeSet} at the 1289 * current dataPosition(). Returns null if the 1290 * previously written list object was null. The list <em>must</em> have 1291 * previously been written via {@link #writeSet} with the same object 1292 * type. 1293 * 1294 * @return A newly created ArraySet containing objects with the same data 1295 * as those that were previously written. 1296 * @see #writeSet 1297 */ readSet(@ullable Set<T> def, int fieldId)1298 public <T> @Nullable Set<T> readSet(@Nullable Set<T> def, int fieldId) { 1299 if (!readField(fieldId)) { 1300 return def; 1301 } 1302 return readCollection(new ArraySet<T>()); 1303 } 1304 1305 /** 1306 * Read and return a new ArrayList containing a particular object type from 1307 * the parcel that was written with {@link #writeList} at the 1308 * current dataPosition(). Returns null if the 1309 * previously written list object was null. The list <em>must</em> have 1310 * previously been written via {@link #writeList} with the same object 1311 * type. 1312 * 1313 * @return A newly created ArrayList containing objects with the same data 1314 * as those that were previously written. 1315 * @see #writeList 1316 */ readList(@ullable List<T> def, int fieldId)1317 public <T> @Nullable List<T> readList(@Nullable List<T> def, int fieldId) { 1318 if (!readField(fieldId)) { 1319 return def; 1320 } 1321 return readCollection(new ArrayList<T>()); 1322 } 1323 1324 @SuppressWarnings("unchecked") readCollection(@onNull S list)1325 private <T, S extends Collection<T>> @Nullable S readCollection(@NonNull S list) { 1326 int n = readInt(); 1327 if (n < 0) { 1328 return null; 1329 } 1330 if (n != 0) { 1331 int type = readInt(); 1332 if (n < 0) { 1333 return null; 1334 } 1335 switch (type) { 1336 case TYPE_STRING: 1337 while (n > 0) { 1338 list.add((T) readString()); 1339 n--; 1340 } 1341 break; 1342 case TYPE_PARCELABLE: 1343 while (n > 0) { 1344 list.add((T) readParcelable()); 1345 n--; 1346 } 1347 break; 1348 case TYPE_VERSIONED_PARCELABLE: 1349 while (n > 0) { 1350 list.add((T) readVersionedParcelable()); 1351 n--; 1352 } 1353 break; 1354 case TYPE_SERIALIZABLE: 1355 while (n > 0) { 1356 list.add((T) readSerializable()); 1357 n--; 1358 } 1359 break; 1360 case TYPE_BINDER: 1361 while (n > 0) { 1362 list.add((T) readStrongBinder()); 1363 n--; 1364 } 1365 break; 1366 } 1367 } 1368 return list; 1369 } 1370 1371 /** 1372 * Read and return a new ArrayMap containing a particular object type from 1373 * the parcel that was written with {@link #writeMap} at the 1374 * current dataPosition(). Returns null if the 1375 * previously written list object was null. The list <em>must</em> have 1376 * previously been written via {@link #writeMap} with the same object type. 1377 * 1378 * @return A newly created ArrayMap containing objects with the same data 1379 * as those that were previously written. 1380 * @see #writeMap 1381 */ readMap(@ullable Map<K, V> def, int fieldId)1382 public <K, V> @Nullable Map<K, V> readMap(@Nullable Map<K, V> def, int fieldId) { 1383 if (!readField(fieldId)) { 1384 return def; 1385 } 1386 int size = readInt(); 1387 if (size < 0) { 1388 return null; 1389 } 1390 Map<K, V> map = new ArrayMap<>(size); 1391 if (size == 0) { 1392 return map; 1393 } 1394 List<K> keyList = new ArrayList<>(size); 1395 List<V> valueList = new ArrayList<>(size); 1396 readCollection(keyList); 1397 readCollection(valueList); 1398 for (int i = 0; i < size; i++) { 1399 map.put(keyList.get(i), valueList.get(i)); 1400 } 1401 return map; 1402 } 1403 1404 /** 1405 * Read and return a new ArrayList containing a particular object type from 1406 * the parcel that was written with {@link #writeArray} at the 1407 * current dataPosition(). Returns null if the 1408 * previously written list object was null. The list <em>must</em> have 1409 * previously been written via {@link #writeArray} with the same object 1410 * type. 1411 * 1412 * @return A newly created ArrayList containing objects with the same data 1413 * as those that were previously written. 1414 * @see #writeArray 1415 */ readArray(T @ullable [] def, int fieldId)1416 public <T> T @Nullable [] readArray(T @Nullable [] def, int fieldId) { 1417 if (!readField(fieldId)) { 1418 return def; 1419 } 1420 return readArray(def); 1421 } 1422 1423 /** 1424 */ 1425 @SuppressWarnings("unchecked") readArray(T @ullable [] def)1426 protected <T> T @Nullable [] readArray(T @Nullable [] def) { 1427 int n = readInt(); 1428 if (n < 0) { 1429 return null; 1430 } 1431 ArrayList<T> list = new ArrayList<T>(n); 1432 if (n != 0) { 1433 int type = readInt(); 1434 if (n < 0) { 1435 return null; 1436 } 1437 switch (type) { 1438 case TYPE_STRING: 1439 while (n > 0) { 1440 list.add((T) readString()); 1441 n--; 1442 } 1443 break; 1444 case TYPE_PARCELABLE: 1445 while (n > 0) { 1446 list.add((T) readParcelable()); 1447 n--; 1448 } 1449 break; 1450 case TYPE_VERSIONED_PARCELABLE: 1451 while (n > 0) { 1452 list.add((T) readVersionedParcelable()); 1453 n--; 1454 } 1455 break; 1456 case TYPE_SERIALIZABLE: 1457 while (n > 0) { 1458 list.add((T) readSerializable()); 1459 n--; 1460 } 1461 break; 1462 case TYPE_BINDER: 1463 while (n > 0) { 1464 list.add((T) readStrongBinder()); 1465 n--; 1466 } 1467 break; 1468 } 1469 } 1470 return list.toArray(def); 1471 } 1472 1473 /** 1474 */ readVersionedParcelable( @ullable T def, int fieldId )1475 public <T extends VersionedParcelable> @Nullable T readVersionedParcelable( 1476 @Nullable T def, 1477 int fieldId 1478 ) { 1479 if (!readField(fieldId)) { 1480 return def; 1481 } 1482 return readVersionedParcelable(); 1483 } 1484 1485 /** 1486 * Read and return a new VersionedParcelable from the parcel. 1487 * 1488 * @return Returns the newly created VersionedParcelable, or null if a null 1489 * object has been written. 1490 * @throws BadParcelableException Throws BadVersionedParcelableException if there 1491 * was an error trying to instantiate the VersionedParcelable. 1492 */ 1493 @SuppressWarnings("TypeParameterUnusedInFormals") readVersionedParcelable()1494 protected <T extends VersionedParcelable> @Nullable T readVersionedParcelable() { 1495 String name = readString(); 1496 if (name == null) { 1497 return null; 1498 } 1499 return readFromParcel(name, createSubParcel()); 1500 } 1501 1502 /** 1503 * Read and return a new Serializable object from the parcel. 1504 * 1505 * @return the Serializable object, or null if the Serializable name 1506 * wasn't found in the parcel. 1507 */ readSerializable()1508 protected @Nullable Serializable readSerializable() { 1509 String name = readString(); 1510 if (name == null) { 1511 // For some reason we were unable to read the name of the Serializable (either there 1512 // is nothing left in the VersionedParcel to read, or the next value wasn't a String) 1513 // , so 1514 // return null, which indicates that the name wasn't found in the parcel. 1515 return null; 1516 } 1517 1518 byte[] serializedData = readByteArray(); 1519 ByteArrayInputStream bais = new ByteArrayInputStream(serializedData); 1520 try { 1521 ObjectInputStream ois = new ObjectInputStream(bais) { 1522 @Override 1523 protected Class<?> resolveClass(ObjectStreamClass osClass) 1524 throws IOException, ClassNotFoundException { 1525 Class<?> c = Class.forName(osClass.getName(), false, 1526 getClass().getClassLoader()); 1527 if (c != null) { 1528 return c; 1529 } 1530 return super.resolveClass(osClass); 1531 } 1532 }; 1533 return (Serializable) ois.readObject(); 1534 } catch (IOException ioe) { 1535 throw new RuntimeException("Unable to read Serializable object (name = " + name + ")", 1536 ioe); 1537 } catch (ClassNotFoundException cnfe) { 1538 throw new RuntimeException("Unable to read Serializable object (name = " + name + ")", 1539 cnfe); 1540 } 1541 } 1542 1543 /** 1544 */ 1545 @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) readFromParcel( @onNull String parcelCls, @NonNull VersionedParcel versionedParcel )1546 protected <T extends VersionedParcelable> @NonNull T readFromParcel( 1547 @NonNull String parcelCls, 1548 @NonNull VersionedParcel versionedParcel 1549 ) { 1550 try { 1551 Method m = getReadMethod(parcelCls); 1552 return (T) m.invoke(null, versionedParcel); 1553 } catch (IllegalAccessException e) { 1554 throw new RuntimeException(e); 1555 } catch (InvocationTargetException e) { 1556 Throwable cause = e.getCause(); 1557 if (cause instanceof RuntimeException) { 1558 throw (RuntimeException) cause; 1559 } 1560 if (cause instanceof Error) { 1561 throw (Error) cause; 1562 } 1563 throw new RuntimeException(e); 1564 } catch (NoSuchMethodException e) { 1565 throw new RuntimeException(e); 1566 } catch (ClassNotFoundException e) { 1567 throw new RuntimeException(e); 1568 } 1569 } 1570 1571 /** 1572 */ writeToParcel( @onNull T val, @NonNull VersionedParcel versionedParcel )1573 protected <T extends VersionedParcelable> void writeToParcel( 1574 @NonNull T val, 1575 @NonNull VersionedParcel versionedParcel 1576 ) { 1577 try { 1578 Method m = getWriteMethod(val.getClass()); 1579 m.invoke(null, val, versionedParcel); 1580 } catch (IllegalAccessException e) { 1581 throw new RuntimeException(e); 1582 } catch (InvocationTargetException e) { 1583 Throwable cause = e.getCause(); 1584 if (cause instanceof RuntimeException) { 1585 throw (RuntimeException) cause; 1586 } 1587 if (cause instanceof Error) { 1588 throw (Error) cause; 1589 } 1590 throw new RuntimeException(e); 1591 } catch (NoSuchMethodException e) { 1592 throw new RuntimeException(e); 1593 } catch (ClassNotFoundException e) { 1594 throw new RuntimeException(e); 1595 } 1596 } 1597 getReadMethod(@onNull String parcelCls)1598 private @NonNull Method getReadMethod(@NonNull String parcelCls) throws IllegalAccessException, 1599 NoSuchMethodException, ClassNotFoundException { 1600 Method m = mReadCache.get(parcelCls); 1601 if (m == null) { 1602 Class<?> cls = Class.forName(parcelCls, false, VersionedParcel.class.getClassLoader()); 1603 m = cls.getDeclaredMethod("read", VersionedParcel.class); 1604 mReadCache.put(parcelCls, m); 1605 } 1606 return m; 1607 } 1608 getWriteMethod(@onNull Class<?> baseCls)1609 private @NonNull Method getWriteMethod(@NonNull Class<?> baseCls) throws IllegalAccessException, 1610 NoSuchMethodException, ClassNotFoundException { 1611 Method m = mWriteCache.get(baseCls.getName()); 1612 if (m == null) { 1613 Class<?> cls = findParcelClass(baseCls); 1614 m = cls.getDeclaredMethod("write", baseCls, VersionedParcel.class); 1615 mWriteCache.put(baseCls.getName(), m); 1616 } 1617 return m; 1618 } 1619 findParcelClass(@onNull Class<?> cls)1620 private @NonNull Class<?> findParcelClass(@NonNull Class<?> cls) 1621 throws ClassNotFoundException { 1622 Class<?> ret = mParcelizerCache.get(cls.getName()); 1623 if (ret == null) { 1624 String pkg = cls.getPackage().getName(); 1625 String c = String.format("%s.%sParcelizer", pkg, cls.getSimpleName()); 1626 ret = Class.forName(c, false, cls.getClassLoader()); 1627 mParcelizerCache.put(cls.getName(), ret); 1628 } 1629 return ret; 1630 } 1631 1632 /** 1633 */ 1634 public static class ParcelException extends RuntimeException { ParcelException(@ullable Throwable source)1635 public ParcelException(@Nullable Throwable source) { 1636 super(source); 1637 } 1638 } 1639 1640 @RequiresApi(21) 1641 private static final class Api21Impl { writeSize(@onNull VersionedParcel self, @Nullable Size val)1642 static void writeSize(@NonNull VersionedParcel self, @Nullable Size val) { 1643 self.writeBoolean(val != null); 1644 if (val != null) { 1645 self.writeInt(val.getWidth()); 1646 self.writeInt(val.getHeight()); 1647 } 1648 } 1649 writeSizeF(@onNull VersionedParcel self, @Nullable SizeF val)1650 static void writeSizeF(@NonNull VersionedParcel self, @Nullable SizeF val) { 1651 self.writeBoolean(val != null); 1652 if (val != null) { 1653 self.writeFloat(val.getWidth()); 1654 self.writeFloat(val.getHeight()); 1655 } 1656 } 1657 readSize(@onNull VersionedParcel self)1658 static @Nullable Size readSize(@NonNull VersionedParcel self) { 1659 if (self.readBoolean()) { 1660 int width = self.readInt(); 1661 int height = self.readInt(); 1662 return new Size(width, height); 1663 } 1664 return null; 1665 } 1666 readSizeF(@onNull VersionedParcel self)1667 static @Nullable SizeF readSizeF(@NonNull VersionedParcel self) { 1668 if (self.readBoolean()) { 1669 float width = self.readFloat(); 1670 float height = self.readFloat(); 1671 return new SizeF(width, height); 1672 } 1673 return null; 1674 } 1675 } 1676 } 1677