• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.os;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.UnsupportedAppUsage;
22 import android.util.ArrayMap;
23 import android.util.Log;
24 import android.util.MathUtils;
25 import android.util.Slog;
26 import android.util.SparseArray;
27 
28 import com.android.internal.annotations.VisibleForTesting;
29 import com.android.internal.util.IndentingPrintWriter;
30 
31 import java.io.Serializable;
32 import java.util.ArrayList;
33 import java.util.Set;
34 
35 /**
36  * A mapping from String keys to values of various types. In most cases, you
37  * should work directly with either the {@link Bundle} or
38  * {@link PersistableBundle} subclass.
39  */
40 public class BaseBundle {
41     private static final String TAG = "Bundle";
42     static final boolean DEBUG = false;
43 
44     // Keep them in sync with frameworks/native/libs/binder/PersistableBundle.cpp.
45     private static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
46     private static final int BUNDLE_MAGIC_NATIVE = 0x4C444E44; // 'B' 'N' 'D' 'N'
47 
48     /**
49      * Flag indicating that this Bundle is okay to "defuse." That is, it's okay
50      * for system processes to ignore any {@link BadParcelableException}
51      * encountered when unparceling it, leaving an empty bundle in its place.
52      * <p>
53      * This should <em>only</em> be set when the Bundle reaches its final
54      * destination, otherwise a system process may clobber contents that were
55      * destined for an app that could have unparceled them.
56      */
57     static final int FLAG_DEFUSABLE = 1 << 0;
58 
59     private static final boolean LOG_DEFUSABLE = false;
60 
61     private static volatile boolean sShouldDefuse = false;
62 
63     /**
64      * Set global variable indicating that any Bundles parsed in this process
65      * should be "defused." That is, any {@link BadParcelableException}
66      * encountered will be suppressed and logged, leaving an empty Bundle
67      * instead of crashing.
68      *
69      * @hide
70      */
setShouldDefuse(boolean shouldDefuse)71     public static void setShouldDefuse(boolean shouldDefuse) {
72         sShouldDefuse = shouldDefuse;
73     }
74 
75     // A parcel cannot be obtained during compile-time initialization. Put the
76     // empty parcel into an inner class that can be initialized separately. This
77     // allows to initialize BaseBundle, and classes depending on it.
78     /** {@hide} */
79     static final class NoImagePreloadHolder {
80         public static final Parcel EMPTY_PARCEL = Parcel.obtain();
81     }
82 
83     // Invariant - exactly one of mMap / mParcelledData will be null
84     // (except inside a call to unparcel)
85 
86     @UnsupportedAppUsage
87     ArrayMap<String, Object> mMap = null;
88 
89     /*
90      * If mParcelledData is non-null, then mMap will be null and the
91      * data are stored as a Parcel containing a Bundle.  When the data
92      * are unparcelled, mParcelledData willbe set to null.
93      */
94     @UnsupportedAppUsage
95     Parcel mParcelledData = null;
96 
97     /**
98      * Whether {@link #mParcelledData} was generated by native coed or not.
99      */
100     private boolean mParcelledByNative;
101 
102     /**
103      * The ClassLoader used when unparcelling data from mParcelledData.
104      */
105     private ClassLoader mClassLoader;
106 
107     /** {@hide} */
108     @VisibleForTesting
109     public int mFlags;
110 
111     /**
112      * Constructs a new, empty Bundle that uses a specific ClassLoader for
113      * instantiating Parcelable and Serializable objects.
114      *
115      * @param loader An explicit ClassLoader to use when instantiating objects
116      * inside of the Bundle.
117      * @param capacity Initial size of the ArrayMap.
118      */
BaseBundle(@ullable ClassLoader loader, int capacity)119     BaseBundle(@Nullable ClassLoader loader, int capacity) {
120         mMap = capacity > 0 ?
121                 new ArrayMap<String, Object>(capacity) : new ArrayMap<String, Object>();
122         mClassLoader = loader == null ? getClass().getClassLoader() : loader;
123     }
124 
125     /**
126      * Constructs a new, empty Bundle.
127      */
BaseBundle()128     BaseBundle() {
129         this((ClassLoader) null, 0);
130     }
131 
132     /**
133      * Constructs a Bundle whose data is stored as a Parcel.  The data
134      * will be unparcelled on first contact, using the assigned ClassLoader.
135      *
136      * @param parcelledData a Parcel containing a Bundle
137      */
BaseBundle(Parcel parcelledData)138     BaseBundle(Parcel parcelledData) {
139         readFromParcelInner(parcelledData);
140     }
141 
BaseBundle(Parcel parcelledData, int length)142     BaseBundle(Parcel parcelledData, int length) {
143         readFromParcelInner(parcelledData, length);
144     }
145 
146     /**
147      * Constructs a new, empty Bundle that uses a specific ClassLoader for
148      * instantiating Parcelable and Serializable objects.
149      *
150      * @param loader An explicit ClassLoader to use when instantiating objects
151      * inside of the Bundle.
152      */
BaseBundle(ClassLoader loader)153     BaseBundle(ClassLoader loader) {
154         this(loader, 0);
155     }
156 
157     /**
158      * Constructs a new, empty Bundle sized to hold the given number of
159      * elements. The Bundle will grow as needed.
160      *
161      * @param capacity the initial capacity of the Bundle
162      */
BaseBundle(int capacity)163     BaseBundle(int capacity) {
164         this((ClassLoader) null, capacity);
165     }
166 
167     /**
168      * Constructs a Bundle containing a copy of the mappings from the given
169      * Bundle.
170      *
171      * @param b a Bundle to be copied.
172      */
BaseBundle(BaseBundle b)173     BaseBundle(BaseBundle b) {
174         copyInternal(b, false);
175     }
176 
177     /**
178      * Special constructor that does not initialize the bundle.
179      */
BaseBundle(boolean doInit)180     BaseBundle(boolean doInit) {
181     }
182 
183     /**
184      * TODO: optimize this later (getting just the value part of a Bundle
185      * with a single pair) once Bundle.forPair() above is implemented
186      * with a special single-value Map implementation/serialization.
187      *
188      * Note: value in single-pair Bundle may be null.
189      *
190      * @hide
191      */
getPairValue()192     public String getPairValue() {
193         unparcel();
194         int size = mMap.size();
195         if (size > 1) {
196             Log.w(TAG, "getPairValue() used on Bundle with multiple pairs.");
197         }
198         if (size == 0) {
199             return null;
200         }
201         Object o = mMap.valueAt(0);
202         try {
203             return (String) o;
204         } catch (ClassCastException e) {
205             typeWarning("getPairValue()", o, "String", e);
206             return null;
207         }
208     }
209 
210     /**
211      * Changes the ClassLoader this Bundle uses when instantiating objects.
212      *
213      * @param loader An explicit ClassLoader to use when instantiating objects
214      * inside of the Bundle.
215      */
setClassLoader(ClassLoader loader)216     void setClassLoader(ClassLoader loader) {
217         mClassLoader = loader;
218     }
219 
220     /**
221      * Return the ClassLoader currently associated with this Bundle.
222      */
getClassLoader()223     ClassLoader getClassLoader() {
224         return mClassLoader;
225     }
226 
227     /**
228      * If the underlying data are stored as a Parcel, unparcel them
229      * using the currently assigned class loader.
230      */
231     @UnsupportedAppUsage
unparcel()232     /* package */ void unparcel() {
233         synchronized (this) {
234             final Parcel source = mParcelledData;
235             if (source != null) {
236                 initializeFromParcelLocked(source, /*recycleParcel=*/ true, mParcelledByNative);
237             } else {
238                 if (DEBUG) {
239                     Log.d(TAG, "unparcel "
240                             + Integer.toHexString(System.identityHashCode(this))
241                             + ": no parcelled data");
242                 }
243             }
244         }
245     }
246 
initializeFromParcelLocked(@onNull Parcel parcelledData, boolean recycleParcel, boolean parcelledByNative)247     private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean recycleParcel,
248             boolean parcelledByNative) {
249         if (LOG_DEFUSABLE && sShouldDefuse && (mFlags & FLAG_DEFUSABLE) == 0) {
250             Slog.wtf(TAG, "Attempting to unparcel a Bundle while in transit; this may "
251                     + "clobber all data inside!", new Throwable());
252         }
253 
254         if (isEmptyParcel(parcelledData)) {
255             if (DEBUG) {
256                 Log.d(TAG, "unparcel "
257                         + Integer.toHexString(System.identityHashCode(this)) + ": empty");
258             }
259             if (mMap == null) {
260                 mMap = new ArrayMap<>(1);
261             } else {
262                 mMap.erase();
263             }
264             mParcelledData = null;
265             mParcelledByNative = false;
266             return;
267         }
268 
269         final int count = parcelledData.readInt();
270         if (DEBUG) {
271             Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
272                     + ": reading " + count + " maps");
273         }
274         if (count < 0) {
275             return;
276         }
277         ArrayMap<String, Object> map = mMap;
278         if (map == null) {
279             map = new ArrayMap<>(count);
280         } else {
281             map.erase();
282             map.ensureCapacity(count);
283         }
284         try {
285             if (parcelledByNative) {
286                 // If it was parcelled by native code, then the array map keys aren't sorted
287                 // by their hash codes, so use the safe (slow) one.
288                 parcelledData.readArrayMapSafelyInternal(map, count, mClassLoader);
289             } else {
290                 // If parcelled by Java, we know the contents are sorted properly,
291                 // so we can use ArrayMap.append().
292                 parcelledData.readArrayMapInternal(map, count, mClassLoader);
293             }
294         } catch (BadParcelableException e) {
295             if (sShouldDefuse) {
296                 Log.w(TAG, "Failed to parse Bundle, but defusing quietly", e);
297                 map.erase();
298             } else {
299                 throw e;
300             }
301         } finally {
302             mMap = map;
303             if (recycleParcel) {
304                 recycleParcel(parcelledData);
305             }
306             mParcelledData = null;
307             mParcelledByNative = false;
308         }
309         if (DEBUG) {
310             Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
311                     + " final map: " + mMap);
312         }
313     }
314 
315     /**
316      * @hide
317      */
318     @UnsupportedAppUsage
isParcelled()319     public boolean isParcelled() {
320         return mParcelledData != null;
321     }
322 
323     /**
324      * @hide
325      */
isEmptyParcel()326     public boolean isEmptyParcel() {
327         return isEmptyParcel(mParcelledData);
328     }
329 
330     /**
331      * @hide
332      */
isEmptyParcel(Parcel p)333     private static boolean isEmptyParcel(Parcel p) {
334         return p == NoImagePreloadHolder.EMPTY_PARCEL;
335     }
336 
recycleParcel(Parcel p)337     private static void recycleParcel(Parcel p) {
338         if (p != null && !isEmptyParcel(p)) {
339             p.recycle();
340         }
341     }
342 
343     /** @hide */
getMap()344     ArrayMap<String, Object> getMap() {
345         unparcel();
346         return mMap;
347     }
348 
349     /**
350      * Returns the number of mappings contained in this Bundle.
351      *
352      * @return the number of mappings as an int.
353      */
size()354     public int size() {
355         unparcel();
356         return mMap.size();
357     }
358 
359     /**
360      * Returns true if the mapping of this Bundle is empty, false otherwise.
361      */
isEmpty()362     public boolean isEmpty() {
363         unparcel();
364         return mMap.isEmpty();
365     }
366 
367     /**
368      * @hide this should probably be the implementation of isEmpty().  To do that we
369      * need to ensure we always use the special empty parcel form when the bundle is
370      * empty.  (This may already be the case, but to be safe we'll do this later when
371      * we aren't trying to stabilize.)
372      */
maybeIsEmpty()373     public boolean maybeIsEmpty() {
374         if (isParcelled()) {
375             return isEmptyParcel();
376         } else {
377             return isEmpty();
378         }
379     }
380 
381     /**
382      * Does a loose equality check between two given {@link BaseBundle} objects.
383      * Returns {@code true} if both are {@code null}, or if both are equal as per
384      * {@link #kindofEquals(BaseBundle)}
385      *
386      * @param a A {@link BaseBundle} object
387      * @param b Another {@link BaseBundle} to compare with a
388      * @return {@code true} if both are the same, {@code false} otherwise
389      *
390      * @see #kindofEquals(BaseBundle)
391      *
392      * @hide
393      */
kindofEquals(BaseBundle a, BaseBundle b)394     public static boolean kindofEquals(BaseBundle a, BaseBundle b) {
395         return (a == b) || (a != null && a.kindofEquals(b));
396     }
397 
398     /**
399      * @hide This kind-of does an equality comparison.  Kind-of.
400      */
kindofEquals(BaseBundle other)401     public boolean kindofEquals(BaseBundle other) {
402         if (other == null) {
403             return false;
404         }
405         if (isParcelled() != other.isParcelled()) {
406             // Big kind-of here!
407             return false;
408         } else if (isParcelled()) {
409             return mParcelledData.compareData(other.mParcelledData) == 0;
410         } else {
411             return mMap.equals(other.mMap);
412         }
413     }
414 
415     /**
416      * Removes all elements from the mapping of this Bundle.
417      */
clear()418     public void clear() {
419         unparcel();
420         mMap.clear();
421     }
422 
copyInternal(BaseBundle from, boolean deep)423     void copyInternal(BaseBundle from, boolean deep) {
424         synchronized (from) {
425             if (from.mParcelledData != null) {
426                 if (from.isEmptyParcel()) {
427                     mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
428                     mParcelledByNative = false;
429                 } else {
430                     mParcelledData = Parcel.obtain();
431                     mParcelledData.appendFrom(from.mParcelledData, 0,
432                             from.mParcelledData.dataSize());
433                     mParcelledData.setDataPosition(0);
434                     mParcelledByNative = from.mParcelledByNative;
435                 }
436             } else {
437                 mParcelledData = null;
438                 mParcelledByNative = false;
439             }
440 
441             if (from.mMap != null) {
442                 if (!deep) {
443                     mMap = new ArrayMap<>(from.mMap);
444                 } else {
445                     final ArrayMap<String, Object> fromMap = from.mMap;
446                     final int N = fromMap.size();
447                     mMap = new ArrayMap<>(N);
448                     for (int i = 0; i < N; i++) {
449                         mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i)));
450                     }
451                 }
452             } else {
453                 mMap = null;
454             }
455 
456             mClassLoader = from.mClassLoader;
457         }
458     }
459 
deepCopyValue(Object value)460     Object deepCopyValue(Object value) {
461         if (value == null) {
462             return null;
463         }
464         if (value instanceof Bundle) {
465             return ((Bundle)value).deepCopy();
466         } else if (value instanceof PersistableBundle) {
467             return ((PersistableBundle)value).deepCopy();
468         } else if (value instanceof ArrayList) {
469             return deepcopyArrayList((ArrayList) value);
470         } else if (value.getClass().isArray()) {
471             if (value instanceof int[]) {
472                 return ((int[])value).clone();
473             } else if (value instanceof long[]) {
474                 return ((long[])value).clone();
475             } else if (value instanceof float[]) {
476                 return ((float[])value).clone();
477             } else if (value instanceof double[]) {
478                 return ((double[])value).clone();
479             } else if (value instanceof Object[]) {
480                 return ((Object[])value).clone();
481             } else if (value instanceof byte[]) {
482                 return ((byte[])value).clone();
483             } else if (value instanceof short[]) {
484                 return ((short[])value).clone();
485             } else if (value instanceof char[]) {
486                 return ((char[]) value).clone();
487             }
488         }
489         return value;
490     }
491 
deepcopyArrayList(ArrayList from)492     ArrayList deepcopyArrayList(ArrayList from) {
493         final int N = from.size();
494         ArrayList out = new ArrayList(N);
495         for (int i=0; i<N; i++) {
496             out.add(deepCopyValue(from.get(i)));
497         }
498         return out;
499     }
500 
501     /**
502      * Returns true if the given key is contained in the mapping
503      * of this Bundle.
504      *
505      * @param key a String key
506      * @return true if the key is part of the mapping, false otherwise
507      */
containsKey(String key)508     public boolean containsKey(String key) {
509         unparcel();
510         return mMap.containsKey(key);
511     }
512 
513     /**
514      * Returns the entry with the given key as an object.
515      *
516      * @param key a String key
517      * @return an Object, or null
518      */
519     @Nullable
get(String key)520     public Object get(String key) {
521         unparcel();
522         return mMap.get(key);
523     }
524 
525     /**
526      * Removes any entry with the given key from the mapping of this Bundle.
527      *
528      * @param key a String key
529      */
remove(String key)530     public void remove(String key) {
531         unparcel();
532         mMap.remove(key);
533     }
534 
535     /**
536      * Inserts all mappings from the given PersistableBundle into this BaseBundle.
537      *
538      * @param bundle a PersistableBundle
539      */
putAll(PersistableBundle bundle)540     public void putAll(PersistableBundle bundle) {
541         unparcel();
542         bundle.unparcel();
543         mMap.putAll(bundle.mMap);
544     }
545 
546     /**
547      * Inserts all mappings from the given Map into this BaseBundle.
548      *
549      * @param map a Map
550      */
putAll(ArrayMap map)551     void putAll(ArrayMap map) {
552         unparcel();
553         mMap.putAll(map);
554     }
555 
556     /**
557      * Returns a Set containing the Strings used as keys in this Bundle.
558      *
559      * @return a Set of String keys
560      */
keySet()561     public Set<String> keySet() {
562         unparcel();
563         return mMap.keySet();
564     }
565 
566     /**
567      * Inserts a Boolean value into the mapping of this Bundle, replacing
568      * any existing value for the given key.  Either key or value may be null.
569      *
570      * @param key a String, or null
571      * @param value a boolean
572      */
putBoolean(@ullable String key, boolean value)573     public void putBoolean(@Nullable String key, boolean value) {
574         unparcel();
575         mMap.put(key, value);
576     }
577 
578     /**
579      * Inserts a byte value into the mapping of this Bundle, replacing
580      * any existing value for the given key.
581      *
582      * @param key a String, or null
583      * @param value a byte
584      */
putByte(@ullable String key, byte value)585     void putByte(@Nullable String key, byte value) {
586         unparcel();
587         mMap.put(key, value);
588     }
589 
590     /**
591      * Inserts a char value into the mapping of this Bundle, replacing
592      * any existing value for the given key.
593      *
594      * @param key a String, or null
595      * @param value a char
596      */
putChar(@ullable String key, char value)597     void putChar(@Nullable String key, char value) {
598         unparcel();
599         mMap.put(key, value);
600     }
601 
602     /**
603      * Inserts a short value into the mapping of this Bundle, replacing
604      * any existing value for the given key.
605      *
606      * @param key a String, or null
607      * @param value a short
608      */
putShort(@ullable String key, short value)609     void putShort(@Nullable String key, short value) {
610         unparcel();
611         mMap.put(key, value);
612     }
613 
614     /**
615      * Inserts an int value into the mapping of this Bundle, replacing
616      * any existing value for the given key.
617      *
618      * @param key a String, or null
619      * @param value an int
620      */
putInt(@ullable String key, int value)621     public void putInt(@Nullable String key, int value) {
622         unparcel();
623         mMap.put(key, value);
624     }
625 
626     /**
627      * Inserts a long value into the mapping of this Bundle, replacing
628      * any existing value for the given key.
629      *
630      * @param key a String, or null
631      * @param value a long
632      */
putLong(@ullable String key, long value)633     public void putLong(@Nullable String key, long value) {
634         unparcel();
635         mMap.put(key, value);
636     }
637 
638     /**
639      * Inserts a float value into the mapping of this Bundle, replacing
640      * any existing value for the given key.
641      *
642      * @param key a String, or null
643      * @param value a float
644      */
putFloat(@ullable String key, float value)645     void putFloat(@Nullable String key, float value) {
646         unparcel();
647         mMap.put(key, value);
648     }
649 
650     /**
651      * Inserts a double value into the mapping of this Bundle, replacing
652      * any existing value for the given key.
653      *
654      * @param key a String, or null
655      * @param value a double
656      */
putDouble(@ullable String key, double value)657     public void putDouble(@Nullable String key, double value) {
658         unparcel();
659         mMap.put(key, value);
660     }
661 
662     /**
663      * Inserts a String value into the mapping of this Bundle, replacing
664      * any existing value for the given key.  Either key or value may be null.
665      *
666      * @param key a String, or null
667      * @param value a String, or null
668      */
putString(@ullable String key, @Nullable String value)669     public void putString(@Nullable String key, @Nullable String value) {
670         unparcel();
671         mMap.put(key, value);
672     }
673 
674     /**
675      * Inserts a CharSequence value into the mapping of this Bundle, replacing
676      * any existing value for the given key.  Either key or value may be null.
677      *
678      * @param key a String, or null
679      * @param value a CharSequence, or null
680      */
putCharSequence(@ullable String key, @Nullable CharSequence value)681     void putCharSequence(@Nullable String key, @Nullable CharSequence value) {
682         unparcel();
683         mMap.put(key, value);
684     }
685 
686     /**
687      * Inserts an ArrayList<Integer> value into the mapping of this Bundle, replacing
688      * any existing value for the given key.  Either key or value may be null.
689      *
690      * @param key a String, or null
691      * @param value an ArrayList<Integer> object, or null
692      */
putIntegerArrayList(@ullable String key, @Nullable ArrayList<Integer> value)693     void putIntegerArrayList(@Nullable String key, @Nullable ArrayList<Integer> value) {
694         unparcel();
695         mMap.put(key, value);
696     }
697 
698     /**
699      * Inserts an ArrayList<String> value into the mapping of this Bundle, replacing
700      * any existing value for the given key.  Either key or value may be null.
701      *
702      * @param key a String, or null
703      * @param value an ArrayList<String> object, or null
704      */
putStringArrayList(@ullable String key, @Nullable ArrayList<String> value)705     void putStringArrayList(@Nullable String key, @Nullable ArrayList<String> value) {
706         unparcel();
707         mMap.put(key, value);
708     }
709 
710     /**
711      * Inserts an ArrayList<CharSequence> value into the mapping of this Bundle, replacing
712      * any existing value for the given key.  Either key or value may be null.
713      *
714      * @param key a String, or null
715      * @param value an ArrayList<CharSequence> object, or null
716      */
putCharSequenceArrayList(@ullable String key, @Nullable ArrayList<CharSequence> value)717     void putCharSequenceArrayList(@Nullable String key, @Nullable ArrayList<CharSequence> value) {
718         unparcel();
719         mMap.put(key, value);
720     }
721 
722     /**
723      * Inserts a Serializable value into the mapping of this Bundle, replacing
724      * any existing value for the given key.  Either key or value may be null.
725      *
726      * @param key a String, or null
727      * @param value a Serializable object, or null
728      */
putSerializable(@ullable String key, @Nullable Serializable value)729     void putSerializable(@Nullable String key, @Nullable Serializable value) {
730         unparcel();
731         mMap.put(key, value);
732     }
733 
734     /**
735      * Inserts a boolean array value into the mapping of this Bundle, replacing
736      * any existing value for the given key.  Either key or value may be null.
737      *
738      * @param key a String, or null
739      * @param value a boolean array object, or null
740      */
putBooleanArray(@ullable String key, @Nullable boolean[] value)741     public void putBooleanArray(@Nullable String key, @Nullable boolean[] value) {
742         unparcel();
743         mMap.put(key, value);
744     }
745 
746     /**
747      * Inserts a byte array value into the mapping of this Bundle, replacing
748      * any existing value for the given key.  Either key or value may be null.
749      *
750      * @param key a String, or null
751      * @param value a byte array object, or null
752      */
putByteArray(@ullable String key, @Nullable byte[] value)753     void putByteArray(@Nullable String key, @Nullable byte[] value) {
754         unparcel();
755         mMap.put(key, value);
756     }
757 
758     /**
759      * Inserts a short array value into the mapping of this Bundle, replacing
760      * any existing value for the given key.  Either key or value may be null.
761      *
762      * @param key a String, or null
763      * @param value a short array object, or null
764      */
putShortArray(@ullable String key, @Nullable short[] value)765     void putShortArray(@Nullable String key, @Nullable short[] value) {
766         unparcel();
767         mMap.put(key, value);
768     }
769 
770     /**
771      * Inserts a char array value into the mapping of this Bundle, replacing
772      * any existing value for the given key.  Either key or value may be null.
773      *
774      * @param key a String, or null
775      * @param value a char array object, or null
776      */
putCharArray(@ullable String key, @Nullable char[] value)777     void putCharArray(@Nullable String key, @Nullable char[] value) {
778         unparcel();
779         mMap.put(key, value);
780     }
781 
782     /**
783      * Inserts an int array value into the mapping of this Bundle, replacing
784      * any existing value for the given key.  Either key or value may be null.
785      *
786      * @param key a String, or null
787      * @param value an int array object, or null
788      */
putIntArray(@ullable String key, @Nullable int[] value)789     public void putIntArray(@Nullable String key, @Nullable int[] value) {
790         unparcel();
791         mMap.put(key, value);
792     }
793 
794     /**
795      * Inserts a long array value into the mapping of this Bundle, replacing
796      * any existing value for the given key.  Either key or value may be null.
797      *
798      * @param key a String, or null
799      * @param value a long array object, or null
800      */
putLongArray(@ullable String key, @Nullable long[] value)801     public void putLongArray(@Nullable String key, @Nullable long[] value) {
802         unparcel();
803         mMap.put(key, value);
804     }
805 
806     /**
807      * Inserts a float array value into the mapping of this Bundle, replacing
808      * any existing value for the given key.  Either key or value may be null.
809      *
810      * @param key a String, or null
811      * @param value a float array object, or null
812      */
putFloatArray(@ullable String key, @Nullable float[] value)813     void putFloatArray(@Nullable String key, @Nullable float[] value) {
814         unparcel();
815         mMap.put(key, value);
816     }
817 
818     /**
819      * Inserts a double array value into the mapping of this Bundle, replacing
820      * any existing value for the given key.  Either key or value may be null.
821      *
822      * @param key a String, or null
823      * @param value a double array object, or null
824      */
putDoubleArray(@ullable String key, @Nullable double[] value)825     public void putDoubleArray(@Nullable String key, @Nullable double[] value) {
826         unparcel();
827         mMap.put(key, value);
828     }
829 
830     /**
831      * Inserts a String array value into the mapping of this Bundle, replacing
832      * any existing value for the given key.  Either key or value may be null.
833      *
834      * @param key a String, or null
835      * @param value a String array object, or null
836      */
putStringArray(@ullable String key, @Nullable String[] value)837     public void putStringArray(@Nullable String key, @Nullable String[] value) {
838         unparcel();
839         mMap.put(key, value);
840     }
841 
842     /**
843      * Inserts a CharSequence array value into the mapping of this Bundle, replacing
844      * any existing value for the given key.  Either key or value may be null.
845      *
846      * @param key a String, or null
847      * @param value a CharSequence array object, or null
848      */
putCharSequenceArray(@ullable String key, @Nullable CharSequence[] value)849     void putCharSequenceArray(@Nullable String key, @Nullable CharSequence[] value) {
850         unparcel();
851         mMap.put(key, value);
852     }
853 
854     /**
855      * Returns the value associated with the given key, or false if
856      * no mapping of the desired type exists for the given key.
857      *
858      * @param key a String
859      * @return a boolean value
860      */
getBoolean(String key)861     public boolean getBoolean(String key) {
862         unparcel();
863         if (DEBUG) Log.d(TAG, "Getting boolean in "
864                 + Integer.toHexString(System.identityHashCode(this)));
865         return getBoolean(key, false);
866     }
867 
868     // Log a message if the value was non-null but not of the expected type
typeWarning(String key, Object value, String className, Object defaultValue, ClassCastException e)869     void typeWarning(String key, Object value, String className,
870             Object defaultValue, ClassCastException e) {
871         StringBuilder sb = new StringBuilder();
872         sb.append("Key ");
873         sb.append(key);
874         sb.append(" expected ");
875         sb.append(className);
876         sb.append(" but value was a ");
877         sb.append(value.getClass().getName());
878         sb.append(".  The default value ");
879         sb.append(defaultValue);
880         sb.append(" was returned.");
881         Log.w(TAG, sb.toString());
882         Log.w(TAG, "Attempt to cast generated internal exception:", e);
883     }
884 
typeWarning(String key, Object value, String className, ClassCastException e)885     void typeWarning(String key, Object value, String className,
886             ClassCastException e) {
887         typeWarning(key, value, className, "<null>", e);
888     }
889 
890     /**
891      * Returns the value associated with the given key, or defaultValue if
892      * no mapping of the desired type exists for the given key.
893      *
894      * @param key a String
895      * @param defaultValue Value to return if key does not exist
896      * @return a boolean value
897      */
getBoolean(String key, boolean defaultValue)898     public boolean getBoolean(String key, boolean defaultValue) {
899         unparcel();
900         Object o = mMap.get(key);
901         if (o == null) {
902             return defaultValue;
903         }
904         try {
905             return (Boolean) o;
906         } catch (ClassCastException e) {
907             typeWarning(key, o, "Boolean", defaultValue, e);
908             return defaultValue;
909         }
910     }
911 
912     /**
913      * Returns the value associated with the given key, or (byte) 0 if
914      * no mapping of the desired type exists for the given key.
915      *
916      * @param key a String
917      * @return a byte value
918      */
getByte(String key)919     byte getByte(String key) {
920         unparcel();
921         return getByte(key, (byte) 0);
922     }
923 
924     /**
925      * Returns the value associated with the given key, or defaultValue if
926      * no mapping of the desired type exists for the given key.
927      *
928      * @param key a String
929      * @param defaultValue Value to return if key does not exist
930      * @return a byte value
931      */
getByte(String key, byte defaultValue)932     Byte getByte(String key, byte defaultValue) {
933         unparcel();
934         Object o = mMap.get(key);
935         if (o == null) {
936             return defaultValue;
937         }
938         try {
939             return (Byte) o;
940         } catch (ClassCastException e) {
941             typeWarning(key, o, "Byte", defaultValue, e);
942             return defaultValue;
943         }
944     }
945 
946     /**
947      * Returns the value associated with the given key, or (char) 0 if
948      * no mapping of the desired type exists for the given key.
949      *
950      * @param key a String
951      * @return a char value
952      */
getChar(String key)953     char getChar(String key) {
954         unparcel();
955         return getChar(key, (char) 0);
956     }
957 
958     /**
959      * Returns the value associated with the given key, or defaultValue if
960      * no mapping of the desired type exists for the given key.
961      *
962      * @param key a String
963      * @param defaultValue Value to return if key does not exist
964      * @return a char value
965      */
getChar(String key, char defaultValue)966     char getChar(String key, char defaultValue) {
967         unparcel();
968         Object o = mMap.get(key);
969         if (o == null) {
970             return defaultValue;
971         }
972         try {
973             return (Character) o;
974         } catch (ClassCastException e) {
975             typeWarning(key, o, "Character", defaultValue, e);
976             return defaultValue;
977         }
978     }
979 
980     /**
981      * Returns the value associated with the given key, or (short) 0 if
982      * no mapping of the desired type exists for the given key.
983      *
984      * @param key a String
985      * @return a short value
986      */
getShort(String key)987     short getShort(String key) {
988         unparcel();
989         return getShort(key, (short) 0);
990     }
991 
992     /**
993      * Returns the value associated with the given key, or defaultValue if
994      * no mapping of the desired type exists for the given key.
995      *
996      * @param key a String
997      * @param defaultValue Value to return if key does not exist
998      * @return a short value
999      */
getShort(String key, short defaultValue)1000     short getShort(String key, short defaultValue) {
1001         unparcel();
1002         Object o = mMap.get(key);
1003         if (o == null) {
1004             return defaultValue;
1005         }
1006         try {
1007             return (Short) o;
1008         } catch (ClassCastException e) {
1009             typeWarning(key, o, "Short", defaultValue, e);
1010             return defaultValue;
1011         }
1012     }
1013 
1014     /**
1015      * Returns the value associated with the given key, or 0 if
1016      * no mapping of the desired type exists for the given key.
1017      *
1018      * @param key a String
1019      * @return an int value
1020      */
getInt(String key)1021     public int getInt(String key) {
1022         unparcel();
1023         return getInt(key, 0);
1024     }
1025 
1026     /**
1027      * Returns the value associated with the given key, or defaultValue if
1028      * no mapping of the desired type exists for the given key.
1029      *
1030      * @param key a String
1031      * @param defaultValue Value to return if key does not exist
1032      * @return an int value
1033      */
getInt(String key, int defaultValue)1034    public int getInt(String key, int defaultValue) {
1035         unparcel();
1036         Object o = mMap.get(key);
1037         if (o == null) {
1038             return defaultValue;
1039         }
1040         try {
1041             return (Integer) o;
1042         } catch (ClassCastException e) {
1043             typeWarning(key, o, "Integer", defaultValue, e);
1044             return defaultValue;
1045         }
1046     }
1047 
1048     /**
1049      * Returns the value associated with the given key, or 0L if
1050      * no mapping of the desired type exists for the given key.
1051      *
1052      * @param key a String
1053      * @return a long value
1054      */
getLong(String key)1055     public long getLong(String key) {
1056         unparcel();
1057         return getLong(key, 0L);
1058     }
1059 
1060     /**
1061      * Returns the value associated with the given key, or defaultValue if
1062      * no mapping of the desired type exists for the given key.
1063      *
1064      * @param key a String
1065      * @param defaultValue Value to return if key does not exist
1066      * @return a long value
1067      */
getLong(String key, long defaultValue)1068     public long getLong(String key, long defaultValue) {
1069         unparcel();
1070         Object o = mMap.get(key);
1071         if (o == null) {
1072             return defaultValue;
1073         }
1074         try {
1075             return (Long) o;
1076         } catch (ClassCastException e) {
1077             typeWarning(key, o, "Long", defaultValue, e);
1078             return defaultValue;
1079         }
1080     }
1081 
1082     /**
1083      * Returns the value associated with the given key, or 0.0f if
1084      * no mapping of the desired type exists for the given key.
1085      *
1086      * @param key a String
1087      * @return a float value
1088      */
getFloat(String key)1089     float getFloat(String key) {
1090         unparcel();
1091         return getFloat(key, 0.0f);
1092     }
1093 
1094     /**
1095      * Returns the value associated with the given key, or defaultValue if
1096      * no mapping of the desired type exists for the given key.
1097      *
1098      * @param key a String
1099      * @param defaultValue Value to return if key does not exist
1100      * @return a float value
1101      */
getFloat(String key, float defaultValue)1102     float getFloat(String key, float defaultValue) {
1103         unparcel();
1104         Object o = mMap.get(key);
1105         if (o == null) {
1106             return defaultValue;
1107         }
1108         try {
1109             return (Float) o;
1110         } catch (ClassCastException e) {
1111             typeWarning(key, o, "Float", defaultValue, e);
1112             return defaultValue;
1113         }
1114     }
1115 
1116     /**
1117      * Returns the value associated with the given key, or 0.0 if
1118      * no mapping of the desired type exists for the given key.
1119      *
1120      * @param key a String
1121      * @return a double value
1122      */
getDouble(String key)1123     public double getDouble(String key) {
1124         unparcel();
1125         return getDouble(key, 0.0);
1126     }
1127 
1128     /**
1129      * Returns the value associated with the given key, or defaultValue if
1130      * no mapping of the desired type exists for the given key.
1131      *
1132      * @param key a String
1133      * @param defaultValue Value to return if key does not exist
1134      * @return a double value
1135      */
getDouble(String key, double defaultValue)1136     public double getDouble(String key, double defaultValue) {
1137         unparcel();
1138         Object o = mMap.get(key);
1139         if (o == null) {
1140             return defaultValue;
1141         }
1142         try {
1143             return (Double) o;
1144         } catch (ClassCastException e) {
1145             typeWarning(key, o, "Double", defaultValue, e);
1146             return defaultValue;
1147         }
1148     }
1149 
1150     /**
1151      * Returns the value associated with the given key, or null if
1152      * no mapping of the desired type exists for the given key or a null
1153      * value is explicitly associated with the key.
1154      *
1155      * @param key a String, or null
1156      * @return a String value, or null
1157      */
1158     @Nullable
getString(@ullable String key)1159     public String getString(@Nullable String key) {
1160         unparcel();
1161         final Object o = mMap.get(key);
1162         try {
1163             return (String) o;
1164         } catch (ClassCastException e) {
1165             typeWarning(key, o, "String", e);
1166             return null;
1167         }
1168     }
1169 
1170     /**
1171      * Returns the value associated with the given key, or defaultValue if
1172      * no mapping of the desired type exists for the given key or if a null
1173      * value is explicitly associated with the given key.
1174      *
1175      * @param key a String, or null
1176      * @param defaultValue Value to return if key does not exist or if a null
1177      *     value is associated with the given key.
1178      * @return the String value associated with the given key, or defaultValue
1179      *     if no valid String object is currently mapped to that key.
1180      */
getString(@ullable String key, String defaultValue)1181     public String getString(@Nullable String key, String defaultValue) {
1182         final String s = getString(key);
1183         return (s == null) ? defaultValue : s;
1184     }
1185 
1186     /**
1187      * Returns the value associated with the given key, or null if
1188      * no mapping of the desired type exists for the given key or a null
1189      * value is explicitly associated with the key.
1190      *
1191      * @param key a String, or null
1192      * @return a CharSequence value, or null
1193      */
1194     @Nullable
getCharSequence(@ullable String key)1195     CharSequence getCharSequence(@Nullable String key) {
1196         unparcel();
1197         final Object o = mMap.get(key);
1198         try {
1199             return (CharSequence) o;
1200         } catch (ClassCastException e) {
1201             typeWarning(key, o, "CharSequence", e);
1202             return null;
1203         }
1204     }
1205 
1206     /**
1207      * Returns the value associated with the given key, or defaultValue if
1208      * no mapping of the desired type exists for the given key or if a null
1209      * value is explicitly associated with the given key.
1210      *
1211      * @param key a String, or null
1212      * @param defaultValue Value to return if key does not exist or if a null
1213      *     value is associated with the given key.
1214      * @return the CharSequence value associated with the given key, or defaultValue
1215      *     if no valid CharSequence object is currently mapped to that key.
1216      */
getCharSequence(@ullable String key, CharSequence defaultValue)1217     CharSequence getCharSequence(@Nullable String key, CharSequence defaultValue) {
1218         final CharSequence cs = getCharSequence(key);
1219         return (cs == null) ? defaultValue : cs;
1220     }
1221 
1222     /**
1223      * Returns the value associated with the given key, or null if
1224      * no mapping of the desired type exists for the given key or a null
1225      * value is explicitly associated with the key.
1226      *
1227      * @param key a String, or null
1228      * @return a Serializable value, or null
1229      */
1230     @Nullable
getSerializable(@ullable String key)1231     Serializable getSerializable(@Nullable String key) {
1232         unparcel();
1233         Object o = mMap.get(key);
1234         if (o == null) {
1235             return null;
1236         }
1237         try {
1238             return (Serializable) o;
1239         } catch (ClassCastException e) {
1240             typeWarning(key, o, "Serializable", e);
1241             return null;
1242         }
1243     }
1244 
1245     /**
1246      * Returns the value associated with the given key, or null if
1247      * no mapping of the desired type exists for the given key or a null
1248      * value is explicitly associated with the key.
1249      *
1250      * @param key a String, or null
1251      * @return an ArrayList<String> value, or null
1252      */
1253     @Nullable
getIntegerArrayList(@ullable String key)1254     ArrayList<Integer> getIntegerArrayList(@Nullable String key) {
1255         unparcel();
1256         Object o = mMap.get(key);
1257         if (o == null) {
1258             return null;
1259         }
1260         try {
1261             return (ArrayList<Integer>) o;
1262         } catch (ClassCastException e) {
1263             typeWarning(key, o, "ArrayList<Integer>", e);
1264             return null;
1265         }
1266     }
1267 
1268     /**
1269      * Returns the value associated with the given key, or null if
1270      * no mapping of the desired type exists for the given key or a null
1271      * value is explicitly associated with the key.
1272      *
1273      * @param key a String, or null
1274      * @return an ArrayList<String> value, or null
1275      */
1276     @Nullable
getStringArrayList(@ullable String key)1277     ArrayList<String> getStringArrayList(@Nullable String key) {
1278         unparcel();
1279         Object o = mMap.get(key);
1280         if (o == null) {
1281             return null;
1282         }
1283         try {
1284             return (ArrayList<String>) o;
1285         } catch (ClassCastException e) {
1286             typeWarning(key, o, "ArrayList<String>", e);
1287             return null;
1288         }
1289     }
1290 
1291     /**
1292      * Returns the value associated with the given key, or null if
1293      * no mapping of the desired type exists for the given key or a null
1294      * value is explicitly associated with the key.
1295      *
1296      * @param key a String, or null
1297      * @return an ArrayList<CharSequence> value, or null
1298      */
1299     @Nullable
getCharSequenceArrayList(@ullable String key)1300     ArrayList<CharSequence> getCharSequenceArrayList(@Nullable String key) {
1301         unparcel();
1302         Object o = mMap.get(key);
1303         if (o == null) {
1304             return null;
1305         }
1306         try {
1307             return (ArrayList<CharSequence>) o;
1308         } catch (ClassCastException e) {
1309             typeWarning(key, o, "ArrayList<CharSequence>", e);
1310             return null;
1311         }
1312     }
1313 
1314     /**
1315      * Returns the value associated with the given key, or null if
1316      * no mapping of the desired type exists for the given key or a null
1317      * value is explicitly associated with the key.
1318      *
1319      * @param key a String, or null
1320      * @return a boolean[] value, or null
1321      */
1322     @Nullable
getBooleanArray(@ullable String key)1323     public boolean[] getBooleanArray(@Nullable String key) {
1324         unparcel();
1325         Object o = mMap.get(key);
1326         if (o == null) {
1327             return null;
1328         }
1329         try {
1330             return (boolean[]) o;
1331         } catch (ClassCastException e) {
1332             typeWarning(key, o, "byte[]", e);
1333             return null;
1334         }
1335     }
1336 
1337     /**
1338      * Returns the value associated with the given key, or null if
1339      * no mapping of the desired type exists for the given key or a null
1340      * value is explicitly associated with the key.
1341      *
1342      * @param key a String, or null
1343      * @return a byte[] value, or null
1344      */
1345     @Nullable
getByteArray(@ullable String key)1346     byte[] getByteArray(@Nullable String key) {
1347         unparcel();
1348         Object o = mMap.get(key);
1349         if (o == null) {
1350             return null;
1351         }
1352         try {
1353             return (byte[]) o;
1354         } catch (ClassCastException e) {
1355             typeWarning(key, o, "byte[]", e);
1356             return null;
1357         }
1358     }
1359 
1360     /**
1361      * Returns the value associated with the given key, or null if
1362      * no mapping of the desired type exists for the given key or a null
1363      * value is explicitly associated with the key.
1364      *
1365      * @param key a String, or null
1366      * @return a short[] value, or null
1367      */
1368     @Nullable
getShortArray(@ullable String key)1369     short[] getShortArray(@Nullable String key) {
1370         unparcel();
1371         Object o = mMap.get(key);
1372         if (o == null) {
1373             return null;
1374         }
1375         try {
1376             return (short[]) o;
1377         } catch (ClassCastException e) {
1378             typeWarning(key, o, "short[]", e);
1379             return null;
1380         }
1381     }
1382 
1383     /**
1384      * Returns the value associated with the given key, or null if
1385      * no mapping of the desired type exists for the given key or a null
1386      * value is explicitly associated with the key.
1387      *
1388      * @param key a String, or null
1389      * @return a char[] value, or null
1390      */
1391     @Nullable
getCharArray(@ullable String key)1392     char[] getCharArray(@Nullable String key) {
1393         unparcel();
1394         Object o = mMap.get(key);
1395         if (o == null) {
1396             return null;
1397         }
1398         try {
1399             return (char[]) o;
1400         } catch (ClassCastException e) {
1401             typeWarning(key, o, "char[]", e);
1402             return null;
1403         }
1404     }
1405 
1406     /**
1407      * Returns the value associated with the given key, or null if
1408      * no mapping of the desired type exists for the given key or a null
1409      * value is explicitly associated with the key.
1410      *
1411      * @param key a String, or null
1412      * @return an int[] value, or null
1413      */
1414     @Nullable
getIntArray(@ullable String key)1415     public int[] getIntArray(@Nullable String key) {
1416         unparcel();
1417         Object o = mMap.get(key);
1418         if (o == null) {
1419             return null;
1420         }
1421         try {
1422             return (int[]) o;
1423         } catch (ClassCastException e) {
1424             typeWarning(key, o, "int[]", e);
1425             return null;
1426         }
1427     }
1428 
1429     /**
1430      * Returns the value associated with the given key, or null if
1431      * no mapping of the desired type exists for the given key or a null
1432      * value is explicitly associated with the key.
1433      *
1434      * @param key a String, or null
1435      * @return a long[] value, or null
1436      */
1437     @Nullable
getLongArray(@ullable String key)1438     public long[] getLongArray(@Nullable String key) {
1439         unparcel();
1440         Object o = mMap.get(key);
1441         if (o == null) {
1442             return null;
1443         }
1444         try {
1445             return (long[]) o;
1446         } catch (ClassCastException e) {
1447             typeWarning(key, o, "long[]", e);
1448             return null;
1449         }
1450     }
1451 
1452     /**
1453      * Returns the value associated with the given key, or null if
1454      * no mapping of the desired type exists for the given key or a null
1455      * value is explicitly associated with the key.
1456      *
1457      * @param key a String, or null
1458      * @return a float[] value, or null
1459      */
1460     @Nullable
getFloatArray(@ullable String key)1461     float[] getFloatArray(@Nullable String key) {
1462         unparcel();
1463         Object o = mMap.get(key);
1464         if (o == null) {
1465             return null;
1466         }
1467         try {
1468             return (float[]) o;
1469         } catch (ClassCastException e) {
1470             typeWarning(key, o, "float[]", e);
1471             return null;
1472         }
1473     }
1474 
1475     /**
1476      * Returns the value associated with the given key, or null if
1477      * no mapping of the desired type exists for the given key or a null
1478      * value is explicitly associated with the key.
1479      *
1480      * @param key a String, or null
1481      * @return a double[] value, or null
1482      */
1483     @Nullable
getDoubleArray(@ullable String key)1484     public double[] getDoubleArray(@Nullable String key) {
1485         unparcel();
1486         Object o = mMap.get(key);
1487         if (o == null) {
1488             return null;
1489         }
1490         try {
1491             return (double[]) o;
1492         } catch (ClassCastException e) {
1493             typeWarning(key, o, "double[]", e);
1494             return null;
1495         }
1496     }
1497 
1498     /**
1499      * Returns the value associated with the given key, or null if
1500      * no mapping of the desired type exists for the given key or a null
1501      * value is explicitly associated with the key.
1502      *
1503      * @param key a String, or null
1504      * @return a String[] value, or null
1505      */
1506     @Nullable
getStringArray(@ullable String key)1507     public String[] getStringArray(@Nullable String key) {
1508         unparcel();
1509         Object o = mMap.get(key);
1510         if (o == null) {
1511             return null;
1512         }
1513         try {
1514             return (String[]) o;
1515         } catch (ClassCastException e) {
1516             typeWarning(key, o, "String[]", e);
1517             return null;
1518         }
1519     }
1520 
1521     /**
1522      * Returns the value associated with the given key, or null if
1523      * no mapping of the desired type exists for the given key or a null
1524      * value is explicitly associated with the key.
1525      *
1526      * @param key a String, or null
1527      * @return a CharSequence[] value, or null
1528      */
1529     @Nullable
getCharSequenceArray(@ullable String key)1530     CharSequence[] getCharSequenceArray(@Nullable String key) {
1531         unparcel();
1532         Object o = mMap.get(key);
1533         if (o == null) {
1534             return null;
1535         }
1536         try {
1537             return (CharSequence[]) o;
1538         } catch (ClassCastException e) {
1539             typeWarning(key, o, "CharSequence[]", e);
1540             return null;
1541         }
1542     }
1543 
1544     /**
1545      * Writes the Bundle contents to a Parcel, typically in order for
1546      * it to be passed through an IBinder connection.
1547      * @param parcel The parcel to copy this bundle to.
1548      */
writeToParcelInner(Parcel parcel, int flags)1549     void writeToParcelInner(Parcel parcel, int flags) {
1550         // If the parcel has a read-write helper, we can't just copy the blob, so unparcel it first.
1551         if (parcel.hasReadWriteHelper()) {
1552             unparcel();
1553         }
1554         // Keep implementation in sync with writeToParcel() in
1555         // frameworks/native/libs/binder/PersistableBundle.cpp.
1556         final ArrayMap<String, Object> map;
1557         synchronized (this) {
1558             // unparcel() can race with this method and cause the parcel to recycle
1559             // at the wrong time. So synchronize access the mParcelledData's content.
1560             if (mParcelledData != null) {
1561                 if (mParcelledData == NoImagePreloadHolder.EMPTY_PARCEL) {
1562                     parcel.writeInt(0);
1563                 } else {
1564                     int length = mParcelledData.dataSize();
1565                     parcel.writeInt(length);
1566                     parcel.writeInt(mParcelledByNative ? BUNDLE_MAGIC_NATIVE : BUNDLE_MAGIC);
1567                     parcel.appendFrom(mParcelledData, 0, length);
1568                 }
1569                 return;
1570             }
1571             map = mMap;
1572         }
1573 
1574         // Special case for empty bundles.
1575         if (map == null || map.size() <= 0) {
1576             parcel.writeInt(0);
1577             return;
1578         }
1579         int lengthPos = parcel.dataPosition();
1580         parcel.writeInt(-1); // dummy, will hold length
1581         parcel.writeInt(BUNDLE_MAGIC);
1582 
1583         int startPos = parcel.dataPosition();
1584         parcel.writeArrayMapInternal(map);
1585         int endPos = parcel.dataPosition();
1586 
1587         // Backpatch length
1588         parcel.setDataPosition(lengthPos);
1589         int length = endPos - startPos;
1590         parcel.writeInt(length);
1591         parcel.setDataPosition(endPos);
1592     }
1593 
1594     /**
1595      * Reads the Parcel contents into this Bundle, typically in order for
1596      * it to be passed through an IBinder connection.
1597      * @param parcel The parcel to overwrite this bundle from.
1598      */
readFromParcelInner(Parcel parcel)1599     void readFromParcelInner(Parcel parcel) {
1600         // Keep implementation in sync with readFromParcel() in
1601         // frameworks/native/libs/binder/PersistableBundle.cpp.
1602         int length = parcel.readInt();
1603         readFromParcelInner(parcel, length);
1604     }
1605 
readFromParcelInner(Parcel parcel, int length)1606     private void readFromParcelInner(Parcel parcel, int length) {
1607         if (length < 0) {
1608             throw new RuntimeException("Bad length in parcel: " + length);
1609         } else if (length == 0) {
1610             // Empty Bundle or end of data.
1611             mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
1612             mParcelledByNative = false;
1613             return;
1614         } else if (length % 4 != 0) {
1615             throw new IllegalStateException("Bundle length is not aligned by 4: " + length);
1616         }
1617 
1618         final int magic = parcel.readInt();
1619         final boolean isJavaBundle = magic == BUNDLE_MAGIC;
1620         final boolean isNativeBundle = magic == BUNDLE_MAGIC_NATIVE;
1621         if (!isJavaBundle && !isNativeBundle) {
1622             throw new IllegalStateException("Bad magic number for Bundle: 0x"
1623                     + Integer.toHexString(magic));
1624         }
1625 
1626         if (parcel.hasReadWriteHelper()) {
1627             // If the parcel has a read-write helper, then we can't lazily-unparcel it, so just
1628             // unparcel right away.
1629             synchronized (this) {
1630                 initializeFromParcelLocked(parcel, /*recycleParcel=*/ false, isNativeBundle);
1631             }
1632             return;
1633         }
1634 
1635         // Advance within this Parcel
1636         int offset = parcel.dataPosition();
1637         parcel.setDataPosition(MathUtils.addOrThrow(offset, length));
1638 
1639         Parcel p = Parcel.obtain();
1640         p.setDataPosition(0);
1641         p.appendFrom(parcel, offset, length);
1642         p.adoptClassCookies(parcel);
1643         if (DEBUG) Log.d(TAG, "Retrieving "  + Integer.toHexString(System.identityHashCode(this))
1644                 + ": " + length + " bundle bytes starting at " + offset);
1645         p.setDataPosition(0);
1646 
1647         mParcelledData = p;
1648         mParcelledByNative = isNativeBundle;
1649     }
1650 
1651     /** {@hide} */
dumpStats(IndentingPrintWriter pw, String key, Object value)1652     public static void dumpStats(IndentingPrintWriter pw, String key, Object value) {
1653         final Parcel tmp = Parcel.obtain();
1654         tmp.writeValue(value);
1655         final int size = tmp.dataPosition();
1656         tmp.recycle();
1657 
1658         // We only really care about logging large values
1659         if (size > 1024) {
1660             pw.println(key + " [size=" + size + "]");
1661             if (value instanceof BaseBundle) {
1662                 dumpStats(pw, (BaseBundle) value);
1663             } else if (value instanceof SparseArray) {
1664                 dumpStats(pw, (SparseArray) value);
1665             }
1666         }
1667     }
1668 
1669     /** {@hide} */
dumpStats(IndentingPrintWriter pw, SparseArray array)1670     public static void dumpStats(IndentingPrintWriter pw, SparseArray array) {
1671         pw.increaseIndent();
1672         if (array == null) {
1673             pw.println("[null]");
1674             return;
1675         }
1676         for (int i = 0; i < array.size(); i++) {
1677             dumpStats(pw, "0x" + Integer.toHexString(array.keyAt(i)), array.valueAt(i));
1678         }
1679         pw.decreaseIndent();
1680     }
1681 
1682     /** {@hide} */
dumpStats(IndentingPrintWriter pw, BaseBundle bundle)1683     public static void dumpStats(IndentingPrintWriter pw, BaseBundle bundle) {
1684         pw.increaseIndent();
1685         if (bundle == null) {
1686             pw.println("[null]");
1687             return;
1688         }
1689         final ArrayMap<String, Object> map = bundle.getMap();
1690         for (int i = 0; i < map.size(); i++) {
1691             dumpStats(pw, map.keyAt(i), map.valueAt(i));
1692         }
1693         pw.decreaseIndent();
1694     }
1695 }
1696