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 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 /** 574 * Inserts a Boolean value into the mapping of this Bundle, replacing 575 * any existing value for the given key. Either key or value may be null. 576 * 577 * @param key a String, or null 578 * @param value a boolean 579 */ putBoolean(@ullable String key, boolean value)580 public void putBoolean(@Nullable String key, boolean value) { 581 unparcel(); 582 mMap.put(key, value); 583 } 584 585 /** 586 * Inserts a byte value into the mapping of this Bundle, replacing 587 * any existing value for the given key. 588 * 589 * @param key a String, or null 590 * @param value a byte 591 */ putByte(@ullable String key, byte value)592 void putByte(@Nullable String key, byte value) { 593 unparcel(); 594 mMap.put(key, value); 595 } 596 597 /** 598 * Inserts a char value into the mapping of this Bundle, replacing 599 * any existing value for the given key. 600 * 601 * @param key a String, or null 602 * @param value a char 603 */ putChar(@ullable String key, char value)604 void putChar(@Nullable String key, char value) { 605 unparcel(); 606 mMap.put(key, value); 607 } 608 609 /** 610 * Inserts a short value into the mapping of this Bundle, replacing 611 * any existing value for the given key. 612 * 613 * @param key a String, or null 614 * @param value a short 615 */ putShort(@ullable String key, short value)616 void putShort(@Nullable String key, short value) { 617 unparcel(); 618 mMap.put(key, value); 619 } 620 621 /** 622 * Inserts an int value into the mapping of this Bundle, replacing 623 * any existing value for the given key. 624 * 625 * @param key a String, or null 626 * @param value an int 627 */ putInt(@ullable String key, int value)628 public void putInt(@Nullable String key, int value) { 629 unparcel(); 630 mMap.put(key, value); 631 } 632 633 /** 634 * Inserts a long value into the mapping of this Bundle, replacing 635 * any existing value for the given key. 636 * 637 * @param key a String, or null 638 * @param value a long 639 */ putLong(@ullable String key, long value)640 public void putLong(@Nullable String key, long value) { 641 unparcel(); 642 mMap.put(key, value); 643 } 644 645 /** 646 * Inserts a float value into the mapping of this Bundle, replacing 647 * any existing value for the given key. 648 * 649 * @param key a String, or null 650 * @param value a float 651 */ putFloat(@ullable String key, float value)652 void putFloat(@Nullable String key, float value) { 653 unparcel(); 654 mMap.put(key, value); 655 } 656 657 /** 658 * Inserts a double value into the mapping of this Bundle, replacing 659 * any existing value for the given key. 660 * 661 * @param key a String, or null 662 * @param value a double 663 */ putDouble(@ullable String key, double value)664 public void putDouble(@Nullable String key, double value) { 665 unparcel(); 666 mMap.put(key, value); 667 } 668 669 /** 670 * Inserts a String value into the mapping of this Bundle, replacing 671 * any existing value for the given key. Either key or value may be null. 672 * 673 * @param key a String, or null 674 * @param value a String, or null 675 */ putString(@ullable String key, @Nullable String value)676 public void putString(@Nullable String key, @Nullable String value) { 677 unparcel(); 678 mMap.put(key, value); 679 } 680 681 /** 682 * Inserts a CharSequence value into the mapping of this Bundle, replacing 683 * any existing value for the given key. Either key or value may be null. 684 * 685 * @param key a String, or null 686 * @param value a CharSequence, or null 687 */ putCharSequence(@ullable String key, @Nullable CharSequence value)688 void putCharSequence(@Nullable String key, @Nullable CharSequence value) { 689 unparcel(); 690 mMap.put(key, value); 691 } 692 693 /** 694 * Inserts an ArrayList<Integer> value into the mapping of this Bundle, replacing 695 * any existing value for the given key. Either key or value may be null. 696 * 697 * @param key a String, or null 698 * @param value an ArrayList<Integer> object, or null 699 */ putIntegerArrayList(@ullable String key, @Nullable ArrayList<Integer> value)700 void putIntegerArrayList(@Nullable String key, @Nullable ArrayList<Integer> value) { 701 unparcel(); 702 mMap.put(key, value); 703 } 704 705 /** 706 * Inserts an ArrayList<String> value into the mapping of this Bundle, replacing 707 * any existing value for the given key. Either key or value may be null. 708 * 709 * @param key a String, or null 710 * @param value an ArrayList<String> object, or null 711 */ putStringArrayList(@ullable String key, @Nullable ArrayList<String> value)712 void putStringArrayList(@Nullable String key, @Nullable ArrayList<String> value) { 713 unparcel(); 714 mMap.put(key, value); 715 } 716 717 /** 718 * Inserts an ArrayList<CharSequence> value into the mapping of this Bundle, replacing 719 * any existing value for the given key. Either key or value may be null. 720 * 721 * @param key a String, or null 722 * @param value an ArrayList<CharSequence> object, or null 723 */ putCharSequenceArrayList(@ullable String key, @Nullable ArrayList<CharSequence> value)724 void putCharSequenceArrayList(@Nullable String key, @Nullable ArrayList<CharSequence> value) { 725 unparcel(); 726 mMap.put(key, value); 727 } 728 729 /** 730 * Inserts a Serializable value into the mapping of this Bundle, replacing 731 * any existing value for the given key. Either key or value may be null. 732 * 733 * @param key a String, or null 734 * @param value a Serializable object, or null 735 */ putSerializable(@ullable String key, @Nullable Serializable value)736 void putSerializable(@Nullable String key, @Nullable Serializable value) { 737 unparcel(); 738 mMap.put(key, value); 739 } 740 741 /** 742 * Inserts a boolean array value into the mapping of this Bundle, replacing 743 * any existing value for the given key. Either key or value may be null. 744 * 745 * @param key a String, or null 746 * @param value a boolean array object, or null 747 */ putBooleanArray(@ullable String key, @Nullable boolean[] value)748 public void putBooleanArray(@Nullable String key, @Nullable boolean[] value) { 749 unparcel(); 750 mMap.put(key, value); 751 } 752 753 /** 754 * Inserts a byte array value into the mapping of this Bundle, replacing 755 * any existing value for the given key. Either key or value may be null. 756 * 757 * @param key a String, or null 758 * @param value a byte array object, or null 759 */ putByteArray(@ullable String key, @Nullable byte[] value)760 void putByteArray(@Nullable String key, @Nullable byte[] value) { 761 unparcel(); 762 mMap.put(key, value); 763 } 764 765 /** 766 * Inserts a short array value into the mapping of this Bundle, replacing 767 * any existing value for the given key. Either key or value may be null. 768 * 769 * @param key a String, or null 770 * @param value a short array object, or null 771 */ putShortArray(@ullable String key, @Nullable short[] value)772 void putShortArray(@Nullable String key, @Nullable short[] value) { 773 unparcel(); 774 mMap.put(key, value); 775 } 776 777 /** 778 * Inserts a char array value into the mapping of this Bundle, replacing 779 * any existing value for the given key. Either key or value may be null. 780 * 781 * @param key a String, or null 782 * @param value a char array object, or null 783 */ putCharArray(@ullable String key, @Nullable char[] value)784 void putCharArray(@Nullable String key, @Nullable char[] value) { 785 unparcel(); 786 mMap.put(key, value); 787 } 788 789 /** 790 * Inserts an int array value into the mapping of this Bundle, replacing 791 * any existing value for the given key. Either key or value may be null. 792 * 793 * @param key a String, or null 794 * @param value an int array object, or null 795 */ putIntArray(@ullable String key, @Nullable int[] value)796 public void putIntArray(@Nullable String key, @Nullable int[] value) { 797 unparcel(); 798 mMap.put(key, value); 799 } 800 801 /** 802 * Inserts a long array value into the mapping of this Bundle, replacing 803 * any existing value for the given key. Either key or value may be null. 804 * 805 * @param key a String, or null 806 * @param value a long array object, or null 807 */ putLongArray(@ullable String key, @Nullable long[] value)808 public void putLongArray(@Nullable String key, @Nullable long[] value) { 809 unparcel(); 810 mMap.put(key, value); 811 } 812 813 /** 814 * Inserts a float array value into the mapping of this Bundle, replacing 815 * any existing value for the given key. Either key or value may be null. 816 * 817 * @param key a String, or null 818 * @param value a float array object, or null 819 */ putFloatArray(@ullable String key, @Nullable float[] value)820 void putFloatArray(@Nullable String key, @Nullable float[] value) { 821 unparcel(); 822 mMap.put(key, value); 823 } 824 825 /** 826 * Inserts a double array value into the mapping of this Bundle, replacing 827 * any existing value for the given key. Either key or value may be null. 828 * 829 * @param key a String, or null 830 * @param value a double array object, or null 831 */ putDoubleArray(@ullable String key, @Nullable double[] value)832 public void putDoubleArray(@Nullable String key, @Nullable double[] value) { 833 unparcel(); 834 mMap.put(key, value); 835 } 836 837 /** 838 * Inserts a String array value into the mapping of this Bundle, replacing 839 * any existing value for the given key. Either key or value may be null. 840 * 841 * @param key a String, or null 842 * @param value a String array object, or null 843 */ putStringArray(@ullable String key, @Nullable String[] value)844 public void putStringArray(@Nullable String key, @Nullable String[] value) { 845 unparcel(); 846 mMap.put(key, value); 847 } 848 849 /** 850 * Inserts a CharSequence array value into the mapping of this Bundle, replacing 851 * any existing value for the given key. Either key or value may be null. 852 * 853 * @param key a String, or null 854 * @param value a CharSequence array object, or null 855 */ putCharSequenceArray(@ullable String key, @Nullable CharSequence[] value)856 void putCharSequenceArray(@Nullable String key, @Nullable CharSequence[] value) { 857 unparcel(); 858 mMap.put(key, value); 859 } 860 861 /** 862 * Returns the value associated with the given key, or false if 863 * no mapping of the desired type exists for the given key. 864 * 865 * @param key a String 866 * @return a boolean value 867 */ getBoolean(String key)868 public boolean getBoolean(String key) { 869 unparcel(); 870 if (DEBUG) Log.d(TAG, "Getting boolean in " 871 + Integer.toHexString(System.identityHashCode(this))); 872 return getBoolean(key, false); 873 } 874 875 // 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)876 void typeWarning(String key, Object value, String className, 877 Object defaultValue, ClassCastException e) { 878 StringBuilder sb = new StringBuilder(); 879 sb.append("Key "); 880 sb.append(key); 881 sb.append(" expected "); 882 sb.append(className); 883 sb.append(" but value was a "); 884 sb.append(value.getClass().getName()); 885 sb.append(". The default value "); 886 sb.append(defaultValue); 887 sb.append(" was returned."); 888 Log.w(TAG, sb.toString()); 889 Log.w(TAG, "Attempt to cast generated internal exception:", e); 890 } 891 typeWarning(String key, Object value, String className, ClassCastException e)892 void typeWarning(String key, Object value, String className, 893 ClassCastException e) { 894 typeWarning(key, value, className, "<null>", e); 895 } 896 897 /** 898 * Returns the value associated with the given key, or defaultValue if 899 * no mapping of the desired type exists for the given key. 900 * 901 * @param key a String 902 * @param defaultValue Value to return if key does not exist 903 * @return a boolean value 904 */ getBoolean(String key, boolean defaultValue)905 public boolean getBoolean(String key, boolean defaultValue) { 906 unparcel(); 907 Object o = mMap.get(key); 908 if (o == null) { 909 return defaultValue; 910 } 911 try { 912 return (Boolean) o; 913 } catch (ClassCastException e) { 914 typeWarning(key, o, "Boolean", defaultValue, e); 915 return defaultValue; 916 } 917 } 918 919 /** 920 * Returns the value associated with the given key, or (byte) 0 if 921 * no mapping of the desired type exists for the given key. 922 * 923 * @param key a String 924 * @return a byte value 925 */ getByte(String key)926 byte getByte(String key) { 927 unparcel(); 928 return getByte(key, (byte) 0); 929 } 930 931 /** 932 * Returns the value associated with the given key, or defaultValue if 933 * no mapping of the desired type exists for the given key. 934 * 935 * @param key a String 936 * @param defaultValue Value to return if key does not exist 937 * @return a byte value 938 */ getByte(String key, byte defaultValue)939 Byte getByte(String key, byte defaultValue) { 940 unparcel(); 941 Object o = mMap.get(key); 942 if (o == null) { 943 return defaultValue; 944 } 945 try { 946 return (Byte) o; 947 } catch (ClassCastException e) { 948 typeWarning(key, o, "Byte", defaultValue, e); 949 return defaultValue; 950 } 951 } 952 953 /** 954 * Returns the value associated with the given key, or (char) 0 if 955 * no mapping of the desired type exists for the given key. 956 * 957 * @param key a String 958 * @return a char value 959 */ getChar(String key)960 char getChar(String key) { 961 unparcel(); 962 return getChar(key, (char) 0); 963 } 964 965 /** 966 * Returns the value associated with the given key, or defaultValue if 967 * no mapping of the desired type exists for the given key. 968 * 969 * @param key a String 970 * @param defaultValue Value to return if key does not exist 971 * @return a char value 972 */ getChar(String key, char defaultValue)973 char getChar(String key, char defaultValue) { 974 unparcel(); 975 Object o = mMap.get(key); 976 if (o == null) { 977 return defaultValue; 978 } 979 try { 980 return (Character) o; 981 } catch (ClassCastException e) { 982 typeWarning(key, o, "Character", defaultValue, e); 983 return defaultValue; 984 } 985 } 986 987 /** 988 * Returns the value associated with the given key, or (short) 0 if 989 * no mapping of the desired type exists for the given key. 990 * 991 * @param key a String 992 * @return a short value 993 */ getShort(String key)994 short getShort(String key) { 995 unparcel(); 996 return getShort(key, (short) 0); 997 } 998 999 /** 1000 * Returns the value associated with the given key, or defaultValue if 1001 * no mapping of the desired type exists for the given key. 1002 * 1003 * @param key a String 1004 * @param defaultValue Value to return if key does not exist 1005 * @return a short value 1006 */ getShort(String key, short defaultValue)1007 short getShort(String key, short defaultValue) { 1008 unparcel(); 1009 Object o = mMap.get(key); 1010 if (o == null) { 1011 return defaultValue; 1012 } 1013 try { 1014 return (Short) o; 1015 } catch (ClassCastException e) { 1016 typeWarning(key, o, "Short", defaultValue, e); 1017 return defaultValue; 1018 } 1019 } 1020 1021 /** 1022 * Returns the value associated with the given key, or 0 if 1023 * no mapping of the desired type exists for the given key. 1024 * 1025 * @param key a String 1026 * @return an int value 1027 */ getInt(String key)1028 public int getInt(String key) { 1029 unparcel(); 1030 return getInt(key, 0); 1031 } 1032 1033 /** 1034 * Returns the value associated with the given key, or defaultValue if 1035 * no mapping of the desired type exists for the given key. 1036 * 1037 * @param key a String 1038 * @param defaultValue Value to return if key does not exist 1039 * @return an int value 1040 */ getInt(String key, int defaultValue)1041 public int getInt(String key, int defaultValue) { 1042 unparcel(); 1043 Object o = mMap.get(key); 1044 if (o == null) { 1045 return defaultValue; 1046 } 1047 try { 1048 return (Integer) o; 1049 } catch (ClassCastException e) { 1050 typeWarning(key, o, "Integer", defaultValue, e); 1051 return defaultValue; 1052 } 1053 } 1054 1055 /** 1056 * Returns the value associated with the given key, or 0L if 1057 * no mapping of the desired type exists for the given key. 1058 * 1059 * @param key a String 1060 * @return a long value 1061 */ getLong(String key)1062 public long getLong(String key) { 1063 unparcel(); 1064 return getLong(key, 0L); 1065 } 1066 1067 /** 1068 * Returns the value associated with the given key, or defaultValue if 1069 * no mapping of the desired type exists for the given key. 1070 * 1071 * @param key a String 1072 * @param defaultValue Value to return if key does not exist 1073 * @return a long value 1074 */ getLong(String key, long defaultValue)1075 public long getLong(String key, long defaultValue) { 1076 unparcel(); 1077 Object o = mMap.get(key); 1078 if (o == null) { 1079 return defaultValue; 1080 } 1081 try { 1082 return (Long) o; 1083 } catch (ClassCastException e) { 1084 typeWarning(key, o, "Long", defaultValue, e); 1085 return defaultValue; 1086 } 1087 } 1088 1089 /** 1090 * Returns the value associated with the given key, or 0.0f if 1091 * no mapping of the desired type exists for the given key. 1092 * 1093 * @param key a String 1094 * @return a float value 1095 */ getFloat(String key)1096 float getFloat(String key) { 1097 unparcel(); 1098 return getFloat(key, 0.0f); 1099 } 1100 1101 /** 1102 * Returns the value associated with the given key, or defaultValue if 1103 * no mapping of the desired type exists for the given key. 1104 * 1105 * @param key a String 1106 * @param defaultValue Value to return if key does not exist 1107 * @return a float value 1108 */ getFloat(String key, float defaultValue)1109 float getFloat(String key, float defaultValue) { 1110 unparcel(); 1111 Object o = mMap.get(key); 1112 if (o == null) { 1113 return defaultValue; 1114 } 1115 try { 1116 return (Float) o; 1117 } catch (ClassCastException e) { 1118 typeWarning(key, o, "Float", defaultValue, e); 1119 return defaultValue; 1120 } 1121 } 1122 1123 /** 1124 * Returns the value associated with the given key, or 0.0 if 1125 * no mapping of the desired type exists for the given key. 1126 * 1127 * @param key a String 1128 * @return a double value 1129 */ getDouble(String key)1130 public double getDouble(String key) { 1131 unparcel(); 1132 return getDouble(key, 0.0); 1133 } 1134 1135 /** 1136 * Returns the value associated with the given key, or defaultValue if 1137 * no mapping of the desired type exists for the given key. 1138 * 1139 * @param key a String 1140 * @param defaultValue Value to return if key does not exist 1141 * @return a double value 1142 */ getDouble(String key, double defaultValue)1143 public double getDouble(String key, double defaultValue) { 1144 unparcel(); 1145 Object o = mMap.get(key); 1146 if (o == null) { 1147 return defaultValue; 1148 } 1149 try { 1150 return (Double) o; 1151 } catch (ClassCastException e) { 1152 typeWarning(key, o, "Double", defaultValue, e); 1153 return defaultValue; 1154 } 1155 } 1156 1157 /** 1158 * Returns the value associated with the given key, or null if 1159 * no mapping of the desired type exists for the given key or a null 1160 * value is explicitly associated with the key. 1161 * 1162 * @param key a String, or null 1163 * @return a String value, or null 1164 */ 1165 @Nullable getString(@ullable String key)1166 public String getString(@Nullable String key) { 1167 unparcel(); 1168 final Object o = mMap.get(key); 1169 try { 1170 return (String) o; 1171 } catch (ClassCastException e) { 1172 typeWarning(key, o, "String", e); 1173 return null; 1174 } 1175 } 1176 1177 /** 1178 * Returns the value associated with the given key, or defaultValue if 1179 * no mapping of the desired type exists for the given key or if a null 1180 * value is explicitly associated with the given key. 1181 * 1182 * @param key a String, or null 1183 * @param defaultValue Value to return if key does not exist or if a null 1184 * value is associated with the given key. 1185 * @return the String value associated with the given key, or defaultValue 1186 * if no valid String object is currently mapped to that key. 1187 */ getString(@ullable String key, String defaultValue)1188 public String getString(@Nullable String key, String defaultValue) { 1189 final String s = getString(key); 1190 return (s == null) ? defaultValue : s; 1191 } 1192 1193 /** 1194 * Returns the value associated with the given key, or null if 1195 * no mapping of the desired type exists for the given key or a null 1196 * value is explicitly associated with the key. 1197 * 1198 * @param key a String, or null 1199 * @return a CharSequence value, or null 1200 */ 1201 @Nullable getCharSequence(@ullable String key)1202 CharSequence getCharSequence(@Nullable String key) { 1203 unparcel(); 1204 final Object o = mMap.get(key); 1205 try { 1206 return (CharSequence) o; 1207 } catch (ClassCastException e) { 1208 typeWarning(key, o, "CharSequence", e); 1209 return null; 1210 } 1211 } 1212 1213 /** 1214 * Returns the value associated with the given key, or defaultValue if 1215 * no mapping of the desired type exists for the given key or if a null 1216 * value is explicitly associated with the given key. 1217 * 1218 * @param key a String, or null 1219 * @param defaultValue Value to return if key does not exist or if a null 1220 * value is associated with the given key. 1221 * @return the CharSequence value associated with the given key, or defaultValue 1222 * if no valid CharSequence object is currently mapped to that key. 1223 */ getCharSequence(@ullable String key, CharSequence defaultValue)1224 CharSequence getCharSequence(@Nullable String key, CharSequence defaultValue) { 1225 final CharSequence cs = getCharSequence(key); 1226 return (cs == null) ? defaultValue : cs; 1227 } 1228 1229 /** 1230 * Returns the value associated with the given key, or null if 1231 * no mapping of the desired type exists for the given key or a null 1232 * value is explicitly associated with the key. 1233 * 1234 * @param key a String, or null 1235 * @return a Serializable value, or null 1236 */ 1237 @Nullable getSerializable(@ullable String key)1238 Serializable getSerializable(@Nullable String key) { 1239 unparcel(); 1240 Object o = mMap.get(key); 1241 if (o == null) { 1242 return null; 1243 } 1244 try { 1245 return (Serializable) o; 1246 } catch (ClassCastException e) { 1247 typeWarning(key, o, "Serializable", e); 1248 return null; 1249 } 1250 } 1251 1252 /** 1253 * Returns the value associated with the given key, or null if 1254 * no mapping of the desired type exists for the given key or a null 1255 * value is explicitly associated with the key. 1256 * 1257 * @param key a String, or null 1258 * @return an ArrayList<String> value, or null 1259 */ 1260 @Nullable getIntegerArrayList(@ullable String key)1261 ArrayList<Integer> getIntegerArrayList(@Nullable String key) { 1262 unparcel(); 1263 Object o = mMap.get(key); 1264 if (o == null) { 1265 return null; 1266 } 1267 try { 1268 return (ArrayList<Integer>) o; 1269 } catch (ClassCastException e) { 1270 typeWarning(key, o, "ArrayList<Integer>", e); 1271 return null; 1272 } 1273 } 1274 1275 /** 1276 * Returns the value associated with the given key, or null if 1277 * no mapping of the desired type exists for the given key or a null 1278 * value is explicitly associated with the key. 1279 * 1280 * @param key a String, or null 1281 * @return an ArrayList<String> value, or null 1282 */ 1283 @Nullable getStringArrayList(@ullable String key)1284 ArrayList<String> getStringArrayList(@Nullable String key) { 1285 unparcel(); 1286 Object o = mMap.get(key); 1287 if (o == null) { 1288 return null; 1289 } 1290 try { 1291 return (ArrayList<String>) o; 1292 } catch (ClassCastException e) { 1293 typeWarning(key, o, "ArrayList<String>", e); 1294 return null; 1295 } 1296 } 1297 1298 /** 1299 * Returns the value associated with the given key, or null if 1300 * no mapping of the desired type exists for the given key or a null 1301 * value is explicitly associated with the key. 1302 * 1303 * @param key a String, or null 1304 * @return an ArrayList<CharSequence> value, or null 1305 */ 1306 @Nullable getCharSequenceArrayList(@ullable String key)1307 ArrayList<CharSequence> getCharSequenceArrayList(@Nullable String key) { 1308 unparcel(); 1309 Object o = mMap.get(key); 1310 if (o == null) { 1311 return null; 1312 } 1313 try { 1314 return (ArrayList<CharSequence>) o; 1315 } catch (ClassCastException e) { 1316 typeWarning(key, o, "ArrayList<CharSequence>", e); 1317 return null; 1318 } 1319 } 1320 1321 /** 1322 * Returns the value associated with the given key, or null if 1323 * no mapping of the desired type exists for the given key or a null 1324 * value is explicitly associated with the key. 1325 * 1326 * @param key a String, or null 1327 * @return a boolean[] value, or null 1328 */ 1329 @Nullable getBooleanArray(@ullable String key)1330 public boolean[] getBooleanArray(@Nullable String key) { 1331 unparcel(); 1332 Object o = mMap.get(key); 1333 if (o == null) { 1334 return null; 1335 } 1336 try { 1337 return (boolean[]) o; 1338 } catch (ClassCastException e) { 1339 typeWarning(key, o, "byte[]", e); 1340 return null; 1341 } 1342 } 1343 1344 /** 1345 * Returns the value associated with the given key, or null if 1346 * no mapping of the desired type exists for the given key or a null 1347 * value is explicitly associated with the key. 1348 * 1349 * @param key a String, or null 1350 * @return a byte[] value, or null 1351 */ 1352 @Nullable getByteArray(@ullable String key)1353 byte[] getByteArray(@Nullable String key) { 1354 unparcel(); 1355 Object o = mMap.get(key); 1356 if (o == null) { 1357 return null; 1358 } 1359 try { 1360 return (byte[]) o; 1361 } catch (ClassCastException e) { 1362 typeWarning(key, o, "byte[]", e); 1363 return null; 1364 } 1365 } 1366 1367 /** 1368 * Returns the value associated with the given key, or null if 1369 * no mapping of the desired type exists for the given key or a null 1370 * value is explicitly associated with the key. 1371 * 1372 * @param key a String, or null 1373 * @return a short[] value, or null 1374 */ 1375 @Nullable getShortArray(@ullable String key)1376 short[] getShortArray(@Nullable String key) { 1377 unparcel(); 1378 Object o = mMap.get(key); 1379 if (o == null) { 1380 return null; 1381 } 1382 try { 1383 return (short[]) o; 1384 } catch (ClassCastException e) { 1385 typeWarning(key, o, "short[]", e); 1386 return null; 1387 } 1388 } 1389 1390 /** 1391 * Returns the value associated with the given key, or null if 1392 * no mapping of the desired type exists for the given key or a null 1393 * value is explicitly associated with the key. 1394 * 1395 * @param key a String, or null 1396 * @return a char[] value, or null 1397 */ 1398 @Nullable getCharArray(@ullable String key)1399 char[] getCharArray(@Nullable String key) { 1400 unparcel(); 1401 Object o = mMap.get(key); 1402 if (o == null) { 1403 return null; 1404 } 1405 try { 1406 return (char[]) o; 1407 } catch (ClassCastException e) { 1408 typeWarning(key, o, "char[]", e); 1409 return null; 1410 } 1411 } 1412 1413 /** 1414 * Returns the value associated with the given key, or null if 1415 * no mapping of the desired type exists for the given key or a null 1416 * value is explicitly associated with the key. 1417 * 1418 * @param key a String, or null 1419 * @return an int[] value, or null 1420 */ 1421 @Nullable getIntArray(@ullable String key)1422 public int[] getIntArray(@Nullable String key) { 1423 unparcel(); 1424 Object o = mMap.get(key); 1425 if (o == null) { 1426 return null; 1427 } 1428 try { 1429 return (int[]) o; 1430 } catch (ClassCastException e) { 1431 typeWarning(key, o, "int[]", e); 1432 return null; 1433 } 1434 } 1435 1436 /** 1437 * Returns the value associated with the given key, or null if 1438 * no mapping of the desired type exists for the given key or a null 1439 * value is explicitly associated with the key. 1440 * 1441 * @param key a String, or null 1442 * @return a long[] value, or null 1443 */ 1444 @Nullable getLongArray(@ullable String key)1445 public long[] getLongArray(@Nullable String key) { 1446 unparcel(); 1447 Object o = mMap.get(key); 1448 if (o == null) { 1449 return null; 1450 } 1451 try { 1452 return (long[]) o; 1453 } catch (ClassCastException e) { 1454 typeWarning(key, o, "long[]", e); 1455 return null; 1456 } 1457 } 1458 1459 /** 1460 * Returns the value associated with the given key, or null if 1461 * no mapping of the desired type exists for the given key or a null 1462 * value is explicitly associated with the key. 1463 * 1464 * @param key a String, or null 1465 * @return a float[] value, or null 1466 */ 1467 @Nullable getFloatArray(@ullable String key)1468 float[] getFloatArray(@Nullable String key) { 1469 unparcel(); 1470 Object o = mMap.get(key); 1471 if (o == null) { 1472 return null; 1473 } 1474 try { 1475 return (float[]) o; 1476 } catch (ClassCastException e) { 1477 typeWarning(key, o, "float[]", e); 1478 return null; 1479 } 1480 } 1481 1482 /** 1483 * Returns the value associated with the given key, or null if 1484 * no mapping of the desired type exists for the given key or a null 1485 * value is explicitly associated with the key. 1486 * 1487 * @param key a String, or null 1488 * @return a double[] value, or null 1489 */ 1490 @Nullable getDoubleArray(@ullable String key)1491 public double[] getDoubleArray(@Nullable String key) { 1492 unparcel(); 1493 Object o = mMap.get(key); 1494 if (o == null) { 1495 return null; 1496 } 1497 try { 1498 return (double[]) o; 1499 } catch (ClassCastException e) { 1500 typeWarning(key, o, "double[]", e); 1501 return null; 1502 } 1503 } 1504 1505 /** 1506 * Returns the value associated with the given key, or null if 1507 * no mapping of the desired type exists for the given key or a null 1508 * value is explicitly associated with the key. 1509 * 1510 * @param key a String, or null 1511 * @return a String[] value, or null 1512 */ 1513 @Nullable getStringArray(@ullable String key)1514 public String[] getStringArray(@Nullable String key) { 1515 unparcel(); 1516 Object o = mMap.get(key); 1517 if (o == null) { 1518 return null; 1519 } 1520 try { 1521 return (String[]) o; 1522 } catch (ClassCastException e) { 1523 typeWarning(key, o, "String[]", e); 1524 return null; 1525 } 1526 } 1527 1528 /** 1529 * Returns the value associated with the given key, or null if 1530 * no mapping of the desired type exists for the given key or a null 1531 * value is explicitly associated with the key. 1532 * 1533 * @param key a String, or null 1534 * @return a CharSequence[] value, or null 1535 */ 1536 @Nullable getCharSequenceArray(@ullable String key)1537 CharSequence[] getCharSequenceArray(@Nullable String key) { 1538 unparcel(); 1539 Object o = mMap.get(key); 1540 if (o == null) { 1541 return null; 1542 } 1543 try { 1544 return (CharSequence[]) o; 1545 } catch (ClassCastException e) { 1546 typeWarning(key, o, "CharSequence[]", e); 1547 return null; 1548 } 1549 } 1550 1551 /** 1552 * Writes the Bundle contents to a Parcel, typically in order for 1553 * it to be passed through an IBinder connection. 1554 * @param parcel The parcel to copy this bundle to. 1555 */ writeToParcelInner(Parcel parcel, int flags)1556 void writeToParcelInner(Parcel parcel, int flags) { 1557 // If the parcel has a read-write helper, we can't just copy the blob, so unparcel it first. 1558 if (parcel.hasReadWriteHelper()) { 1559 unparcel(); 1560 } 1561 // Keep implementation in sync with writeToParcel() in 1562 // frameworks/native/libs/binder/PersistableBundle.cpp. 1563 final ArrayMap<String, Object> map; 1564 synchronized (this) { 1565 // unparcel() can race with this method and cause the parcel to recycle 1566 // at the wrong time. So synchronize access the mParcelledData's content. 1567 if (mParcelledData != null) { 1568 if (mParcelledData == NoImagePreloadHolder.EMPTY_PARCEL) { 1569 parcel.writeInt(0); 1570 } else { 1571 int length = mParcelledData.dataSize(); 1572 parcel.writeInt(length); 1573 parcel.writeInt(mParcelledByNative ? BUNDLE_MAGIC_NATIVE : BUNDLE_MAGIC); 1574 parcel.appendFrom(mParcelledData, 0, length); 1575 } 1576 return; 1577 } 1578 map = mMap; 1579 } 1580 1581 // Special case for empty bundles. 1582 if (map == null || map.size() <= 0) { 1583 parcel.writeInt(0); 1584 return; 1585 } 1586 int lengthPos = parcel.dataPosition(); 1587 parcel.writeInt(-1); // dummy, will hold length 1588 parcel.writeInt(BUNDLE_MAGIC); 1589 1590 int startPos = parcel.dataPosition(); 1591 parcel.writeArrayMapInternal(map); 1592 int endPos = parcel.dataPosition(); 1593 1594 // Backpatch length 1595 parcel.setDataPosition(lengthPos); 1596 int length = endPos - startPos; 1597 parcel.writeInt(length); 1598 parcel.setDataPosition(endPos); 1599 } 1600 1601 /** 1602 * Reads the Parcel contents into this Bundle, typically in order for 1603 * it to be passed through an IBinder connection. 1604 * @param parcel The parcel to overwrite this bundle from. 1605 */ readFromParcelInner(Parcel parcel)1606 void readFromParcelInner(Parcel parcel) { 1607 // Keep implementation in sync with readFromParcel() in 1608 // frameworks/native/libs/binder/PersistableBundle.cpp. 1609 int length = parcel.readInt(); 1610 readFromParcelInner(parcel, length); 1611 } 1612 readFromParcelInner(Parcel parcel, int length)1613 private void readFromParcelInner(Parcel parcel, int length) { 1614 if (length < 0) { 1615 throw new RuntimeException("Bad length in parcel: " + length); 1616 } else if (length == 0) { 1617 // Empty Bundle or end of data. 1618 mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL; 1619 mParcelledByNative = false; 1620 return; 1621 } else if (length % 4 != 0) { 1622 throw new IllegalStateException("Bundle length is not aligned by 4: " + length); 1623 } 1624 1625 final int magic = parcel.readInt(); 1626 final boolean isJavaBundle = magic == BUNDLE_MAGIC; 1627 final boolean isNativeBundle = magic == BUNDLE_MAGIC_NATIVE; 1628 if (!isJavaBundle && !isNativeBundle) { 1629 throw new IllegalStateException("Bad magic number for Bundle: 0x" 1630 + Integer.toHexString(magic)); 1631 } 1632 1633 if (parcel.hasReadWriteHelper()) { 1634 // If the parcel has a read-write helper, then we can't lazily-unparcel it, so just 1635 // unparcel right away. 1636 synchronized (this) { 1637 initializeFromParcelLocked(parcel, /*recycleParcel=*/ false, isNativeBundle); 1638 } 1639 return; 1640 } 1641 1642 // Advance within this Parcel 1643 int offset = parcel.dataPosition(); 1644 parcel.setDataPosition(MathUtils.addOrThrow(offset, length)); 1645 1646 Parcel p = Parcel.obtain(); 1647 p.setDataPosition(0); 1648 p.appendFrom(parcel, offset, length); 1649 p.adoptClassCookies(parcel); 1650 if (DEBUG) Log.d(TAG, "Retrieving " + Integer.toHexString(System.identityHashCode(this)) 1651 + ": " + length + " bundle bytes starting at " + offset); 1652 p.setDataPosition(0); 1653 1654 mParcelledData = p; 1655 mParcelledByNative = isNativeBundle; 1656 } 1657 1658 /** {@hide} */ dumpStats(IndentingPrintWriter pw, String key, Object value)1659 public static void dumpStats(IndentingPrintWriter pw, String key, Object value) { 1660 final Parcel tmp = Parcel.obtain(); 1661 tmp.writeValue(value); 1662 final int size = tmp.dataPosition(); 1663 tmp.recycle(); 1664 1665 // We only really care about logging large values 1666 if (size > 1024) { 1667 pw.println(key + " [size=" + size + "]"); 1668 if (value instanceof BaseBundle) { 1669 dumpStats(pw, (BaseBundle) value); 1670 } else if (value instanceof SparseArray) { 1671 dumpStats(pw, (SparseArray) value); 1672 } 1673 } 1674 } 1675 1676 /** {@hide} */ dumpStats(IndentingPrintWriter pw, SparseArray array)1677 public static void dumpStats(IndentingPrintWriter pw, SparseArray array) { 1678 pw.increaseIndent(); 1679 if (array == null) { 1680 pw.println("[null]"); 1681 return; 1682 } 1683 for (int i = 0; i < array.size(); i++) { 1684 dumpStats(pw, "0x" + Integer.toHexString(array.keyAt(i)), array.valueAt(i)); 1685 } 1686 pw.decreaseIndent(); 1687 } 1688 1689 /** {@hide} */ dumpStats(IndentingPrintWriter pw, BaseBundle bundle)1690 public static void dumpStats(IndentingPrintWriter pw, BaseBundle bundle) { 1691 pw.increaseIndent(); 1692 if (bundle == null) { 1693 pw.println("[null]"); 1694 return; 1695 } 1696 final ArrayMap<String, Object> map = bundle.getMap(); 1697 for (int i = 0; i < map.size(); i++) { 1698 dumpStats(pw, map.keyAt(i), map.valueAt(i)); 1699 } 1700 pw.decreaseIndent(); 1701 } 1702 } 1703