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