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