1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app.appsearch.safeparcel;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.app.PendingIntent;
22 import android.os.Bundle;
23 import android.os.IBinder;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 import android.util.SparseArray;
27 import android.util.SparseBooleanArray;
28 import android.util.SparseIntArray;
29 import android.util.SparseLongArray;
30 
31 import java.math.BigDecimal;
32 import java.math.BigInteger;
33 import java.util.ArrayList;
34 import java.util.List;
35 
36 /**
37  * Functions to read in a safe parcel.
38  *
39  * @hide
40  */
41 // Include the SafeParcel source code directly in AppSearch until it gets officially open-sourced.
42 public class SafeParcelReader {
43     /** class to parse the exception. */
44     public static class ParseException extends RuntimeException {
ParseException(@onNull String message, @NonNull Parcel p)45         public ParseException(@NonNull String message, @NonNull Parcel p) {
46             super(message + " Parcel: pos=" + p.dataPosition() + " size=" + p.dataSize());
47         }
48     }
49 
SafeParcelReader()50     private SafeParcelReader() {}
51 
52     /** Reads the header. */
readHeader(@onNull Parcel p)53     public static int readHeader(@NonNull Parcel p) {
54         return p.readInt();
55     }
56 
57     /** Gets the id for the field. */
getFieldId(int header)58     public static int getFieldId(int header) {
59         return header & 0x0000ffff;
60     }
61 
62     /** Reads the size. */
readSize(@onNull Parcel p, int header)63     public static int readSize(@NonNull Parcel p, int header) {
64         if ((header & 0xffff0000) != 0xffff0000) {
65             return (header >> 16) & 0x0000ffff;
66         } else {
67             return p.readInt();
68         }
69     }
70 
71     /** Skips the unknown field. */
skipUnknownField(@onNull Parcel p, int header)72     public static void skipUnknownField(@NonNull Parcel p, int header) {
73         int size = readSize(p, header);
74         p.setDataPosition(p.dataPosition() + size);
75     }
76 
readAndEnforceSize(@onNull Parcel p, int header, int required)77     private static void readAndEnforceSize(@NonNull Parcel p, int header, int required) {
78         final int size = readSize(p, header);
79         if (size != required) {
80             throw new ParseException(
81                     "Expected size "
82                             + required
83                             + " got "
84                             + size
85                             + " (0x"
86                             + Integer.toHexString(size)
87                             + ")",
88                     p);
89         }
90     }
91 
enforceSize(@onNull Parcel p, int header, int size, int required)92     private static void enforceSize(@NonNull Parcel p, int header, int size, int required) {
93         if (size != required) {
94             throw new ParseException(
95                     "Expected size "
96                             + required
97                             + " got "
98                             + size
99                             + " (0x"
100                             + Integer.toHexString(size)
101                             + ")",
102                     p);
103         }
104     }
105 
106     /** Returns the end position of the object in the parcel. */
validateObjectHeader(@onNull Parcel p)107     public static int validateObjectHeader(@NonNull Parcel p) {
108         final int header = readHeader(p);
109         final int size = readSize(p, header);
110         final int start = p.dataPosition();
111         if (getFieldId(header) != SafeParcelWriter.OBJECT_HEADER) {
112             throw new ParseException(
113                     "Expected object header. Got 0x" + Integer.toHexString(header), p);
114         }
115         final int end = start + size;
116         if (end < start || end > p.dataSize()) {
117             throw new ParseException("Size read is invalid start=" + start + " end=" + end, p);
118         }
119         return end;
120     }
121 
122     /** Reads a boolean. */
readBoolean(@onNull Parcel p, int header)123     public static boolean readBoolean(@NonNull Parcel p, int header) {
124         readAndEnforceSize(p, header, 4);
125         return p.readInt() != 0;
126     }
127 
128     /** Reads a {@link Boolean} object. */
129     @Nullable
readBooleanObject(@onNull Parcel p, int header)130     public static Boolean readBooleanObject(@NonNull Parcel p, int header) {
131         final int size = readSize(p, header);
132         if (size == 0) {
133             return null;
134         } else {
135             enforceSize(p, header, size, 4);
136             return p.readInt() != 0;
137         }
138     }
139 
140     /** Reads a byte. */
readByte(@onNull Parcel p, int header)141     public static byte readByte(@NonNull Parcel p, int header) {
142         readAndEnforceSize(p, header, 4);
143         return (byte) p.readInt();
144     }
145 
146     /** Reads a char. */
readChar(@onNull Parcel p, int header)147     public static char readChar(@NonNull Parcel p, int header) {
148         readAndEnforceSize(p, header, 4);
149         return (char) p.readInt();
150     }
151 
152     /** Reads a short. */
readShort(@onNull Parcel p, int header)153     public static short readShort(@NonNull Parcel p, int header) {
154         readAndEnforceSize(p, header, 4);
155         return (short) p.readInt();
156     }
157 
158     /** Reads an int. */
readInt(@onNull Parcel p, int header)159     public static int readInt(@NonNull Parcel p, int header) {
160         readAndEnforceSize(p, header, 4);
161         return p.readInt();
162     }
163 
164     /** Reads an {@link Integer} object. */
165     @Nullable
readIntegerObject(@onNull Parcel p, int header)166     public static Integer readIntegerObject(@NonNull Parcel p, int header) {
167         final int size = readSize(p, header);
168         if (size == 0) {
169             return null;
170         } else {
171             enforceSize(p, header, size, 4);
172             return p.readInt();
173         }
174     }
175 
176     /** Reads a long. */
readLong(@onNull Parcel p, int header)177     public static long readLong(@NonNull Parcel p, int header) {
178         readAndEnforceSize(p, header, 8);
179         return p.readLong();
180     }
181 
182     /** Reads a {@link Long} object. */
183     @Nullable
readLongObject(@onNull Parcel p, int header)184     public static Long readLongObject(@NonNull Parcel p, int header) {
185         final int size = readSize(p, header);
186         if (size == 0) {
187             return null;
188         } else {
189             enforceSize(p, header, size, 8);
190             return p.readLong();
191         }
192     }
193 
194     /** Creates a {@link BigInteger}. */
195     @Nullable
createBigInteger(@onNull Parcel p, int header)196     public static BigInteger createBigInteger(@NonNull Parcel p, int header) {
197         final int size = readSize(p, header);
198         final int pos = p.dataPosition();
199         if (size == 0) {
200             return null;
201         }
202         final byte[] val = p.createByteArray();
203         p.setDataPosition(pos + size);
204         return new BigInteger(val);
205     }
206 
207     /** Reads a float. */
readFloat(@onNull Parcel p, int header)208     public static float readFloat(@NonNull Parcel p, int header) {
209         readAndEnforceSize(p, header, 4);
210         return p.readFloat();
211     }
212 
213     /** Reads a {@link Float}. */
214     @Nullable
readFloatObject(@onNull Parcel p, int header)215     public static Float readFloatObject(@NonNull Parcel p, int header) {
216         final int size = readSize(p, header);
217         if (size == 0) {
218             return null;
219         } else {
220             enforceSize(p, header, size, 4);
221             return p.readFloat();
222         }
223     }
224 
225     /** Reads a double. */
readDouble(@onNull Parcel p, int header)226     public static double readDouble(@NonNull Parcel p, int header) {
227         readAndEnforceSize(p, header, 8);
228         return p.readDouble();
229     }
230 
231     /** Reads a {@link Double}. */
232     @Nullable
readDoubleObject(@onNull Parcel p, int header)233     public static Double readDoubleObject(@NonNull Parcel p, int header) {
234         final int size = readSize(p, header);
235         if (size == 0) {
236             return null;
237         } else {
238             enforceSize(p, header, size, 8);
239             return p.readDouble();
240         }
241     }
242 
243     /** Creates a {@link BigDecimal}. */
244     @Nullable
createBigDecimal(@onNull Parcel p, int header)245     public static BigDecimal createBigDecimal(@NonNull Parcel p, int header) {
246         final int size = readSize(p, header);
247         final int pos = p.dataPosition();
248         if (size == 0) {
249             return null;
250         }
251         final byte[] unscaledValue = p.createByteArray();
252         final int scale = p.readInt();
253         p.setDataPosition(pos + size);
254         return new BigDecimal(new BigInteger(unscaledValue), scale);
255     }
256 
257     /** Creates a {@link String}. */
258     @Nullable
createString(@onNull Parcel p, int header)259     public static String createString(@NonNull Parcel p, int header) {
260         final int size = readSize(p, header);
261         final int pos = p.dataPosition();
262         if (size == 0) {
263             return null;
264         }
265         final String result = p.readString();
266         p.setDataPosition(pos + size);
267         return result;
268     }
269 
270     /** Reads an {@link IBinder}. */
271     @Nullable
readIBinder(@onNull Parcel p, int header)272     public static IBinder readIBinder(@NonNull Parcel p, int header) {
273         final int size = readSize(p, header);
274         final int pos = p.dataPosition();
275         if (size == 0) {
276             return null;
277         }
278         final IBinder result = p.readStrongBinder();
279         p.setDataPosition(pos + size);
280         return result;
281     }
282 
283     /** Reads a {@link PendingIntent}. */
284     @Nullable
readPendingIntent(@onNull Parcel p, int header)285     public static PendingIntent readPendingIntent(@NonNull Parcel p, int header) {
286         final int size = readSize(p, header);
287         final int pos = p.dataPosition();
288         if (size == 0) {
289             return null;
290         }
291         final PendingIntent result = PendingIntent.readPendingIntentOrNullFromParcel(p);
292         p.setDataPosition(pos + size);
293         return result;
294     }
295 
296     /** Creates a {@link Parcelable}. */
297     @Nullable
createParcelable( @onNull Parcel p, int header, @NonNull Parcelable.Creator<T> creator)298     public static <T extends Parcelable> T createParcelable(
299             @NonNull Parcel p, int header, @NonNull Parcelable.Creator<T> creator) {
300         final int size = readSize(p, header);
301         final int pos = p.dataPosition();
302         if (size == 0) {
303             return null;
304         }
305         final T result = creator.createFromParcel(p);
306         p.setDataPosition(pos + size);
307         return result;
308     }
309 
310     /** Creates a {@link Bundle}. */
311     @Nullable
createBundle(@onNull Parcel p, int header)312     public static Bundle createBundle(@NonNull Parcel p, int header) {
313         final int size = readSize(p, header);
314         final int pos = p.dataPosition();
315         if (size == 0) {
316             return null;
317         }
318         final Bundle result = p.readBundle();
319         p.setDataPosition(pos + size);
320         return result;
321     }
322 
323     /** Creates a byte array. */
324     @Nullable
createByteArray(@onNull Parcel p, int header)325     public static byte[] createByteArray(@NonNull Parcel p, int header) {
326         final int size = readSize(p, header);
327         final int pos = p.dataPosition();
328         if (size == 0) {
329             return null;
330         }
331         final byte[] result = p.createByteArray();
332         p.setDataPosition(pos + size);
333         return result;
334     }
335 
336     /** Creates a byte array array. */
337     @Nullable
createByteArrayArray(@onNull Parcel p, int header)338     public static byte[][] createByteArrayArray(@NonNull Parcel p, int header) {
339         final int size = readSize(p, header);
340         final int pos = p.dataPosition();
341         if (size == 0) {
342             return null;
343         }
344         final int length = p.readInt();
345         final byte[][] result = new byte[length][];
346         for (int i = 0; i < length; i++) {
347             result[i] = p.createByteArray();
348         }
349         p.setDataPosition(pos + size);
350         return result;
351     }
352 
353     /** Creates a boolean array array. */
354     @Nullable
createBooleanArray(@onNull Parcel p, int header)355     public static boolean[] createBooleanArray(@NonNull Parcel p, int header) {
356         final int size = readSize(p, header);
357         final int pos = p.dataPosition();
358         if (size == 0) {
359             return null;
360         }
361         final boolean[] result = p.createBooleanArray();
362         p.setDataPosition(pos + size);
363         return result;
364     }
365 
366     /** Creates a char array. */
367     @Nullable
createCharArray(@onNull Parcel p, int header)368     public static char[] createCharArray(@NonNull Parcel p, int header) {
369         final int size = readSize(p, header);
370         final int pos = p.dataPosition();
371         if (size == 0) {
372             return null;
373         }
374         final char[] result = p.createCharArray();
375         p.setDataPosition(pos + size);
376         return result;
377     }
378 
379     /** Creates an int array. */
380     @Nullable
createIntArray(@onNull Parcel p, int header)381     public static int[] createIntArray(@NonNull Parcel p, int header) {
382         final int size = readSize(p, header);
383         final int pos = p.dataPosition();
384         if (size == 0) {
385             return null;
386         }
387         final int[] result = p.createIntArray();
388         p.setDataPosition(pos + size);
389         return result;
390     }
391 
392     /** Creates a long array. */
393     @Nullable
createLongArray(@onNull Parcel p, int header)394     public static long[] createLongArray(@NonNull Parcel p, int header) {
395         final int size = readSize(p, header);
396         final int pos = p.dataPosition();
397         if (size == 0) {
398             return null;
399         }
400         final long[] result = p.createLongArray();
401         p.setDataPosition(pos + size);
402         return result;
403     }
404 
405     /** Creates a {@link BigInteger} array. */
406     @Nullable
createBigIntegerArray(@onNull Parcel p, int header)407     public static BigInteger[] createBigIntegerArray(@NonNull Parcel p, int header) {
408         final int size = readSize(p, header);
409         final int pos = p.dataPosition();
410         if (size == 0) {
411             return null;
412         }
413         final int length = p.readInt();
414         final BigInteger[] result = new BigInteger[length];
415         for (int i = 0; i < length; i++) {
416             result[i] = new BigInteger(p.createByteArray());
417         }
418         p.setDataPosition(pos + size);
419         return result;
420     }
421 
422     /** Creates a float array. */
423     @Nullable
createFloatArray(@onNull Parcel p, int header)424     public static float[] createFloatArray(@NonNull Parcel p, int header) {
425         final int size = readSize(p, header);
426         final int pos = p.dataPosition();
427         if (size == 0) {
428             return null;
429         }
430         final float[] result = p.createFloatArray();
431         p.setDataPosition(pos + size);
432         return result;
433     }
434 
435     /** Creates a double array. */
436     @Nullable
createDoubleArray(@onNull Parcel p, int header)437     public static double[] createDoubleArray(@NonNull Parcel p, int header) {
438         final int size = readSize(p, header);
439         final int pos = p.dataPosition();
440         if (size == 0) {
441             return null;
442         }
443         final double[] result = p.createDoubleArray();
444         p.setDataPosition(pos + size);
445         return result;
446     }
447 
448     /** Creates a {@link BigDecimal} array. */
449     @Nullable
createBigDecimalArray(@onNull Parcel p, int header)450     public static BigDecimal[] createBigDecimalArray(@NonNull Parcel p, int header) {
451         final int size = readSize(p, header);
452         final int pos = p.dataPosition();
453         if (size == 0) {
454             return null;
455         }
456         final int length = p.readInt();
457         final BigDecimal[] result = new BigDecimal[length];
458         for (int i = 0; i < length; i++) {
459             byte[] unscaledValue = p.createByteArray();
460             int scale = p.readInt();
461             result[i] = new BigDecimal(new BigInteger(unscaledValue), scale);
462         }
463         p.setDataPosition(pos + size);
464         return result;
465     }
466 
467     /** Creates a {@link String} array. */
468     @Nullable
createStringArray(@onNull Parcel p, int header)469     public static String[] createStringArray(@NonNull Parcel p, int header) {
470         final int size = readSize(p, header);
471         final int pos = p.dataPosition();
472         if (size == 0) {
473             return null;
474         }
475         final String[] result = p.createStringArray();
476         p.setDataPosition(pos + size);
477         return result;
478     }
479 
480     /** Creates a {@link IBinder} array. */
481     @Nullable
createIBinderArray(@onNull Parcel p, int header)482     public static IBinder[] createIBinderArray(@NonNull Parcel p, int header) {
483         final int size = readSize(p, header);
484         final int pos = p.dataPosition();
485         if (size == 0) {
486             return null;
487         }
488         final IBinder[] result = p.createBinderArray();
489         p.setDataPosition(pos + size);
490         return result;
491     }
492 
493     /** Creates a {@link Boolean} list. */
494     @Nullable
createBooleanList(@onNull Parcel p, int header)495     public static ArrayList<Boolean> createBooleanList(@NonNull Parcel p, int header) {
496         final int size = readSize(p, header);
497         final int pos = p.dataPosition();
498         if (size == 0) {
499             return null;
500         }
501         final ArrayList<Boolean> result = new ArrayList<Boolean>();
502         final int count = p.readInt();
503         for (int i = 0; i < count; i++) {
504             result.add(p.readInt() != 0 ? true : false);
505         }
506         p.setDataPosition(pos + size);
507         return result;
508     }
509 
510     /** Creates a {@link Integer} list. */
511     @Nullable
createIntegerList(@onNull Parcel p, int header)512     public static ArrayList<Integer> createIntegerList(@NonNull Parcel p, int header) {
513         final int size = readSize(p, header);
514         final int pos = p.dataPosition();
515         if (size == 0) {
516             return null;
517         }
518         final ArrayList<Integer> result = new ArrayList<Integer>();
519         final int count = p.readInt();
520         for (int i = 0; i < count; i++) {
521             result.add(p.readInt());
522         }
523         p.setDataPosition(pos + size);
524         return result;
525     }
526 
527     /** Creates a {@link SparseBooleanArray}. */
528     @Nullable
createSparseBooleanArray(@onNull Parcel p, int header)529     public static SparseBooleanArray createSparseBooleanArray(@NonNull Parcel p, int header) {
530         final int size = readSize(p, header);
531         final int pos = p.dataPosition();
532         if (size == 0) {
533             return null;
534         }
535         SparseBooleanArray result = p.readSparseBooleanArray();
536         p.setDataPosition(pos + size);
537         return result;
538     }
539 
540     /** Creates a {@link SparseIntArray}. */
541     @Nullable
createSparseIntArray(@onNull Parcel p, int header)542     public static SparseIntArray createSparseIntArray(@NonNull Parcel p, int header) {
543         final int size = readSize(p, header);
544         final int pos = p.dataPosition();
545         if (size == 0) {
546             return null;
547         }
548         final SparseIntArray result = new SparseIntArray();
549         final int count = p.readInt();
550         for (int i = 0; i < count; i++) {
551             int key = p.readInt();
552             int value = p.readInt();
553             result.append(key, value);
554         }
555         p.setDataPosition(pos + size);
556         return result;
557     }
558 
559     /** Creates a {@link Float} {@link SparseArray}. */
560     @Nullable
createFloatSparseArray(@onNull Parcel p, int header)561     public static SparseArray<Float> createFloatSparseArray(@NonNull Parcel p, int header) {
562         final int size = readSize(p, header);
563         final int pos = p.dataPosition();
564         if (size == 0) {
565             return null;
566         }
567         final SparseArray<Float> result = new SparseArray<Float>();
568         final int count = p.readInt();
569         for (int i = 0; i < count; i++) {
570             int key = p.readInt();
571             float value = p.readFloat();
572             result.append(key, value);
573         }
574         p.setDataPosition(pos + size);
575         return result;
576     }
577 
578     /** Creates a {@link Double} {@link SparseArray}. */
579     @Nullable
createDoubleSparseArray(@onNull Parcel p, int header)580     public static SparseArray<Double> createDoubleSparseArray(@NonNull Parcel p, int header) {
581         final int size = readSize(p, header);
582         final int pos = p.dataPosition();
583         if (size == 0) {
584             return null;
585         }
586         final SparseArray<Double> result = new SparseArray<Double>();
587         final int count = p.readInt();
588         for (int i = 0; i < count; i++) {
589             int key = p.readInt();
590             double value = p.readDouble();
591             result.append(key, value);
592         }
593         p.setDataPosition(pos + size);
594         return result;
595     }
596 
597     /** Creates a {@link SparseLongArray}. */
598     @Nullable
createSparseLongArray(@onNull Parcel p, int header)599     public static SparseLongArray createSparseLongArray(@NonNull Parcel p, int header) {
600         final int size = readSize(p, header);
601         final int pos = p.dataPosition();
602         if (size == 0) {
603             return null;
604         }
605         final SparseLongArray result = new SparseLongArray();
606         final int count = p.readInt();
607         for (int i = 0; i < count; i++) {
608             int key = p.readInt();
609             long value = p.readLong();
610             result.append(key, value);
611         }
612         p.setDataPosition(pos + size);
613         return result;
614     }
615 
616     /** Creates a {@link String} {@link SparseArray}. */
617     @Nullable
createStringSparseArray(@onNull Parcel p, int header)618     public static SparseArray<String> createStringSparseArray(@NonNull Parcel p, int header) {
619         final int size = readSize(p, header);
620         final int pos = p.dataPosition();
621         if (size == 0) {
622             return null;
623         }
624         final SparseArray<String> result = new SparseArray<String>();
625         final int count = p.readInt();
626         for (int i = 0; i < count; i++) {
627             int key = p.readInt();
628             String value = p.readString();
629             result.append(key, value);
630         }
631         p.setDataPosition(pos + size);
632         return result;
633     }
634 
635     /** Creates a {@link Parcel} {@link SparseArray}. */
636     @Nullable
createParcelSparseArray(@onNull Parcel p, int header)637     public static SparseArray<Parcel> createParcelSparseArray(@NonNull Parcel p, int header) {
638         final int size = readSize(p, header);
639         final int pos = p.dataPosition();
640         if (size == 0) {
641             return null;
642         }
643         final int count = p.readInt();
644         final SparseArray<Parcel> result = new SparseArray<Parcel>();
645         for (int i = 0; i < count; i++) {
646             int key = p.readInt();
647             // read in the flag of whether this element is null
648             int parcelSize = p.readInt();
649             if (parcelSize != 0) {
650                 // non-null
651                 int currentDataPosition = p.dataPosition();
652                 Parcel item = Parcel.obtain();
653                 item.appendFrom(p, currentDataPosition, parcelSize);
654                 result.append(key, item);
655 
656                 // move p's data position
657                 p.setDataPosition(currentDataPosition + parcelSize);
658             } else {
659                 // is null
660                 result.append(key, null);
661             }
662         }
663         p.setDataPosition(pos + size);
664         return result;
665     }
666 
667     /** Creates typed {@link SparseArray}. */
668     @Nullable
createTypedSparseArray( @onNull Parcel p, int header, @NonNull Parcelable.Creator<T> c)669     public static <T> SparseArray<T> createTypedSparseArray(
670             @NonNull Parcel p, int header, @NonNull Parcelable.Creator<T> c) {
671         final int size = readSize(p, header);
672         final int pos = p.dataPosition();
673         if (size == 0) {
674             return null;
675         }
676         final int count = p.readInt();
677         final SparseArray<T> result = new SparseArray<>();
678         for (int i = 0; i < count; i++) {
679             int key = p.readInt();
680             T value;
681             if (p.readInt() != 0) {
682                 value = c.createFromParcel(p);
683             } else {
684                 value = null;
685             }
686             result.append(key, value);
687         }
688         p.setDataPosition(pos + size);
689         return result;
690     }
691 
692     /** Creates {@link IBinder} {@link SparseArray}. */
693     @Nullable
createIBinderSparseArray(@onNull Parcel p, int header)694     public static SparseArray<IBinder> createIBinderSparseArray(@NonNull Parcel p, int header) {
695         final int size = readSize(p, header);
696         final int pos = p.dataPosition();
697         if (size == 0) {
698             return null;
699         }
700         final int count = p.readInt();
701         final SparseArray<IBinder> result = new SparseArray<>(count);
702         for (int i = 0; i < count; i++) {
703             int key = p.readInt();
704             IBinder value = p.readStrongBinder();
705             result.append(key, value);
706         }
707         p.setDataPosition(pos + size);
708         return result;
709     }
710 
711     /** Creates byte array {@link SparseArray}. */
712     @Nullable
createByteArraySparseArray(@onNull Parcel p, int header)713     public static SparseArray<byte[]> createByteArraySparseArray(@NonNull Parcel p, int header) {
714         final int size = readSize(p, header);
715 
716         final int pos = p.dataPosition();
717         if (size == 0) {
718             return null;
719         }
720         final int count = p.readInt();
721         final SparseArray<byte[]> result = new SparseArray<byte[]>(count);
722         for (int i = 0; i < count; i++) {
723             int key = p.readInt();
724             byte[] value = p.createByteArray();
725             result.append(key, value);
726         }
727         p.setDataPosition(pos + size);
728         return result;
729     }
730 
731     /** Creates {@link Long} {@link ArrayList}. */
732     @Nullable
createLongList(@onNull Parcel p, int header)733     public static ArrayList<Long> createLongList(@NonNull Parcel p, int header) {
734         final int size = readSize(p, header);
735         final int pos = p.dataPosition();
736         if (size == 0) {
737             return null;
738         }
739         final ArrayList<Long> result = new ArrayList<Long>();
740         final int count = p.readInt();
741         for (int i = 0; i < count; i++) {
742             result.add(p.readLong());
743         }
744         p.setDataPosition(pos + size);
745         return result;
746     }
747 
748     /** Creates {@link Float} {@link ArrayList}. */
749     @Nullable
createFloatList(@onNull Parcel p, int header)750     public static ArrayList<Float> createFloatList(@NonNull Parcel p, int header) {
751         final int size = readSize(p, header);
752         final int pos = p.dataPosition();
753         if (size == 0) {
754             return null;
755         }
756         final ArrayList<Float> result = new ArrayList<Float>();
757         final int count = p.readInt();
758         for (int i = 0; i < count; i++) {
759             result.add(p.readFloat());
760         }
761         p.setDataPosition(pos + size);
762         return result;
763     }
764 
765     /** Creates {@link Double} {@link ArrayList}. */
766     @Nullable
createDoubleList(@onNull Parcel p, int header)767     public static ArrayList<Double> createDoubleList(@NonNull Parcel p, int header) {
768         final int size = readSize(p, header);
769         final int pos = p.dataPosition();
770         if (size == 0) {
771             return null;
772         }
773         final ArrayList<Double> result = new ArrayList<Double>();
774         final int count = p.readInt();
775         for (int i = 0; i < count; i++) {
776             result.add(p.readDouble());
777         }
778         p.setDataPosition(pos + size);
779         return result;
780     }
781 
782     /** Creates {@link String} {@link ArrayList}. */
783     @Nullable
createStringList(@onNull Parcel p, int header)784     public static ArrayList<String> createStringList(@NonNull Parcel p, int header) {
785         final int size = readSize(p, header);
786         final int pos = p.dataPosition();
787         if (size == 0) {
788             return null;
789         }
790         final ArrayList<String> result = p.createStringArrayList();
791         p.setDataPosition(pos + size);
792         return result;
793     }
794 
795     /** Creates {@link IBinder} {@link ArrayList}. */
796     @Nullable
createIBinderList(@onNull Parcel p, int header)797     public static ArrayList<IBinder> createIBinderList(@NonNull Parcel p, int header) {
798         final int size = readSize(p, header);
799         final int pos = p.dataPosition();
800         if (size == 0) {
801             return null;
802         }
803         final ArrayList<IBinder> result = p.createBinderArrayList();
804         p.setDataPosition(pos + size);
805         return result;
806     }
807 
808     /** Creates typed array. */
809     @Nullable
createTypedArray( @onNull Parcel p, int header, @NonNull Parcelable.Creator<T> c)810     public static <T> T[] createTypedArray(
811             @NonNull Parcel p, int header, @NonNull Parcelable.Creator<T> c) {
812         final int size = readSize(p, header);
813         final int pos = p.dataPosition();
814         if (size == 0) {
815             return null;
816         }
817         final T[] result = p.createTypedArray(c);
818         p.setDataPosition(pos + size);
819         return result;
820     }
821 
822     /** Creates typed {@link ArrayList}. */
823     @Nullable
createTypedList( @onNull Parcel p, int header, @NonNull Parcelable.Creator<T> c)824     public static <T> ArrayList<T> createTypedList(
825             @NonNull Parcel p, int header, @NonNull Parcelable.Creator<T> c) {
826         final int size = readSize(p, header);
827         final int pos = p.dataPosition();
828         if (size == 0) {
829             return null;
830         }
831         final ArrayList<T> result = p.createTypedArrayList(c);
832         p.setDataPosition(pos + size);
833         return result;
834     }
835 
836     /** Creates {@link Parcel}. */
837     @Nullable
createParcel(@onNull Parcel p, int header)838     public static Parcel createParcel(@NonNull Parcel p, int header) {
839         final int size = readSize(p, header);
840         final int pos = p.dataPosition();
841         if (size == 0) {
842             return null;
843         }
844         final Parcel result = Parcel.obtain();
845         result.appendFrom(p, pos, size);
846         p.setDataPosition(pos + size);
847         return result;
848     }
849 
850     /** Creates {@link Parcel} array. */
851     @Nullable
createParcelArray(@onNull Parcel p, int header)852     public static Parcel[] createParcelArray(@NonNull Parcel p, int header) {
853         final int size = readSize(p, header);
854         final int pos = p.dataPosition();
855         if (size == 0) {
856             return null;
857         }
858         final int length = p.readInt();
859         final Parcel[] result = new Parcel[length];
860         for (int i = 0; i < length; i++) {
861             int parcelSize = p.readInt();
862             if (parcelSize != 0) {
863                 int currentDataPosition = p.dataPosition();
864                 Parcel item = Parcel.obtain();
865                 item.appendFrom(p, currentDataPosition, parcelSize);
866                 result[i] = item;
867 
868                 // move p's data position
869                 p.setDataPosition(currentDataPosition + parcelSize);
870             } else {
871                 result[i] = null;
872             }
873         }
874         p.setDataPosition(pos + size);
875         return result;
876     }
877 
878     /** Creates {@link Parcel} {@link ArrayList}. */
879     @Nullable
createParcelList(@onNull Parcel p, int header)880     public static ArrayList<Parcel> createParcelList(@NonNull Parcel p, int header) {
881         final int size = readSize(p, header);
882         final int pos = p.dataPosition();
883         if (size == 0) {
884             return null;
885         }
886         final int length = p.readInt();
887         final ArrayList<Parcel> result = new ArrayList<Parcel>();
888         for (int i = 0; i < length; i++) {
889             // read in the flag of whether this element is null
890             int parcelSize = p.readInt();
891             if (parcelSize != 0) {
892                 // non-null
893                 int currentDataPosition = p.dataPosition();
894                 Parcel item = Parcel.obtain();
895                 item.appendFrom(p, currentDataPosition, parcelSize);
896                 result.add(item);
897 
898                 // move p's data position
899                 p.setDataPosition(currentDataPosition + parcelSize);
900             } else {
901                 // is null
902                 result.add(null);
903             }
904         }
905         p.setDataPosition(pos + size);
906         return result;
907     }
908 
909     /** Reads the list. */
readList( @onNull Parcel p, int header, @SuppressWarnings("rawtypes") @NonNull List list, @Nullable ClassLoader loader)910     public static void readList(
911             @NonNull Parcel p,
912             int header,
913             @SuppressWarnings("rawtypes") @NonNull List list,
914             @Nullable ClassLoader loader) {
915         final int size = readSize(p, header);
916         final int pos = p.dataPosition();
917         if (size == 0) {
918             return;
919         }
920         p.readList(list, loader);
921         p.setDataPosition(pos + size);
922     }
923 
924     /** Ensures at end. */
ensureAtEnd(@onNull Parcel parcel, int end)925     public static void ensureAtEnd(@NonNull Parcel parcel, int end) {
926         if (parcel.dataPosition() != end) {
927             throw new ParseException("Overread allowed size end=" + end, parcel);
928         }
929     }
930 }
931