Home | History | Annotate | Download | only in os
      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      */
     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      */
    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      */
    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      */
    123     BaseBundle(Parcel parcelledData) {
    124         readFromParcelInner(parcelledData);
    125     }
    126 
    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      */
    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      */
    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      */
    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      */
    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      */
    213     void setClassLoader(ClassLoader loader) {
    214         mClassLoader = loader;
    215     }
    216 
    217     /**
    218      * Return the ClassLoader currently associated with this Bundle.
    219      */
    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      */
    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      */
    290     public boolean isParcelled() {
    291         return mParcelledData != null;
    292     }
    293 
    294     /**
    295      * @hide
    296      */
    297     public boolean isEmptyParcel() {
    298         return mParcelledData == NoImagePreloadHolder.EMPTY_PARCEL;
    299     }
    300 
    301     /** @hide */
    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      */
    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      */
    320     public boolean isEmpty() {
    321         unparcel();
    322         return mMap.isEmpty();
    323     }
    324 
    325     /**
    326      * Removes all elements from the mapping of this Bundle.
    327      */
    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      */
    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
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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
    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 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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
    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      */
   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
   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      */
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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      */
   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      */
   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 
   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