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