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