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