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