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