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.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 * @hide this should probably be the implementation of isEmpty(). To do that we 369 * need to ensure we always use the special empty parcel form when the bundle is 370 * empty. (This may already be the case, but to be safe we'll do this later when 371 * we aren't trying to stabilize.) 372 */ maybeIsEmpty()373 public boolean maybeIsEmpty() { 374 if (isParcelled()) { 375 return isEmptyParcel(); 376 } else { 377 return isEmpty(); 378 } 379 } 380 381 /** 382 * Does a loose equality check between two given {@link BaseBundle} objects. 383 * Returns {@code true} if both are {@code null}, or if both are equal as per 384 * {@link #kindofEquals(BaseBundle)} 385 * 386 * @param a A {@link BaseBundle} object 387 * @param b Another {@link BaseBundle} to compare with a 388 * @return {@code true} if both are the same, {@code false} otherwise 389 * 390 * @see #kindofEquals(BaseBundle) 391 * 392 * @hide 393 */ kindofEquals(BaseBundle a, BaseBundle b)394 public static boolean kindofEquals(BaseBundle a, BaseBundle b) { 395 return (a == b) || (a != null && a.kindofEquals(b)); 396 } 397 398 /** 399 * @hide This kind-of does an equality comparison. Kind-of. 400 */ kindofEquals(BaseBundle other)401 public boolean kindofEquals(BaseBundle other) { 402 if (other == null) { 403 return false; 404 } 405 if (isParcelled() != other.isParcelled()) { 406 // Big kind-of here! 407 return false; 408 } else if (isParcelled()) { 409 return mParcelledData.compareData(other.mParcelledData) == 0; 410 } else { 411 return mMap.equals(other.mMap); 412 } 413 } 414 415 /** 416 * Removes all elements from the mapping of this Bundle. 417 */ clear()418 public void clear() { 419 unparcel(); 420 mMap.clear(); 421 } 422 copyInternal(BaseBundle from, boolean deep)423 void copyInternal(BaseBundle from, boolean deep) { 424 synchronized (from) { 425 if (from.mParcelledData != null) { 426 if (from.isEmptyParcel()) { 427 mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL; 428 mParcelledByNative = false; 429 } else { 430 mParcelledData = Parcel.obtain(); 431 mParcelledData.appendFrom(from.mParcelledData, 0, 432 from.mParcelledData.dataSize()); 433 mParcelledData.setDataPosition(0); 434 mParcelledByNative = from.mParcelledByNative; 435 } 436 } else { 437 mParcelledData = null; 438 mParcelledByNative = false; 439 } 440 441 if (from.mMap != null) { 442 if (!deep) { 443 mMap = new ArrayMap<>(from.mMap); 444 } else { 445 final ArrayMap<String, Object> fromMap = from.mMap; 446 final int N = fromMap.size(); 447 mMap = new ArrayMap<>(N); 448 for (int i = 0; i < N; i++) { 449 mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i))); 450 } 451 } 452 } else { 453 mMap = null; 454 } 455 456 mClassLoader = from.mClassLoader; 457 } 458 } 459 deepCopyValue(Object value)460 Object deepCopyValue(Object value) { 461 if (value == null) { 462 return null; 463 } 464 if (value instanceof Bundle) { 465 return ((Bundle)value).deepCopy(); 466 } else if (value instanceof PersistableBundle) { 467 return ((PersistableBundle)value).deepCopy(); 468 } else if (value instanceof ArrayList) { 469 return deepcopyArrayList((ArrayList) value); 470 } else if (value.getClass().isArray()) { 471 if (value instanceof int[]) { 472 return ((int[])value).clone(); 473 } else if (value instanceof long[]) { 474 return ((long[])value).clone(); 475 } else if (value instanceof float[]) { 476 return ((float[])value).clone(); 477 } else if (value instanceof double[]) { 478 return ((double[])value).clone(); 479 } else if (value instanceof Object[]) { 480 return ((Object[])value).clone(); 481 } else if (value instanceof byte[]) { 482 return ((byte[])value).clone(); 483 } else if (value instanceof short[]) { 484 return ((short[])value).clone(); 485 } else if (value instanceof char[]) { 486 return ((char[]) value).clone(); 487 } 488 } 489 return value; 490 } 491 deepcopyArrayList(ArrayList from)492 ArrayList deepcopyArrayList(ArrayList from) { 493 final int N = from.size(); 494 ArrayList out = new ArrayList(N); 495 for (int i=0; i<N; i++) { 496 out.add(deepCopyValue(from.get(i))); 497 } 498 return out; 499 } 500 501 /** 502 * Returns true if the given key is contained in the mapping 503 * of this Bundle. 504 * 505 * @param key a String key 506 * @return true if the key is part of the mapping, false otherwise 507 */ containsKey(String key)508 public boolean containsKey(String key) { 509 unparcel(); 510 return mMap.containsKey(key); 511 } 512 513 /** 514 * Returns the entry with the given key as an object. 515 * 516 * @param key a String key 517 * @return an Object, or null 518 */ 519 @Nullable get(String key)520 public Object get(String key) { 521 unparcel(); 522 return mMap.get(key); 523 } 524 525 /** 526 * Removes any entry with the given key from the mapping of this Bundle. 527 * 528 * @param key a String key 529 */ remove(String key)530 public void remove(String key) { 531 unparcel(); 532 mMap.remove(key); 533 } 534 535 /** 536 * Inserts all mappings from the given PersistableBundle into this BaseBundle. 537 * 538 * @param bundle a PersistableBundle 539 */ putAll(PersistableBundle bundle)540 public void putAll(PersistableBundle bundle) { 541 unparcel(); 542 bundle.unparcel(); 543 mMap.putAll(bundle.mMap); 544 } 545 546 /** 547 * Inserts all mappings from the given Map into this BaseBundle. 548 * 549 * @param map a Map 550 */ putAll(ArrayMap map)551 void putAll(ArrayMap map) { 552 unparcel(); 553 mMap.putAll(map); 554 } 555 556 /** 557 * Returns a Set containing the Strings used as keys in this Bundle. 558 * 559 * @return a Set of String keys 560 */ keySet()561 public Set<String> keySet() { 562 unparcel(); 563 return mMap.keySet(); 564 } 565 566 /** 567 * Inserts a Boolean value into the mapping of this Bundle, replacing 568 * any existing value for the given key. Either key or value may be null. 569 * 570 * @param key a String, or null 571 * @param value a boolean 572 */ putBoolean(@ullable String key, boolean value)573 public void putBoolean(@Nullable String key, boolean value) { 574 unparcel(); 575 mMap.put(key, value); 576 } 577 578 /** 579 * Inserts a byte value into the mapping of this Bundle, replacing 580 * any existing value for the given key. 581 * 582 * @param key a String, or null 583 * @param value a byte 584 */ putByte(@ullable String key, byte value)585 void putByte(@Nullable String key, byte value) { 586 unparcel(); 587 mMap.put(key, value); 588 } 589 590 /** 591 * Inserts a char value into the mapping of this Bundle, replacing 592 * any existing value for the given key. 593 * 594 * @param key a String, or null 595 * @param value a char 596 */ putChar(@ullable String key, char value)597 void putChar(@Nullable String key, char value) { 598 unparcel(); 599 mMap.put(key, value); 600 } 601 602 /** 603 * Inserts a short value into the mapping of this Bundle, replacing 604 * any existing value for the given key. 605 * 606 * @param key a String, or null 607 * @param value a short 608 */ putShort(@ullable String key, short value)609 void putShort(@Nullable String key, short value) { 610 unparcel(); 611 mMap.put(key, value); 612 } 613 614 /** 615 * Inserts an int 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 an int 620 */ putInt(@ullable String key, int value)621 public void putInt(@Nullable String key, int value) { 622 unparcel(); 623 mMap.put(key, value); 624 } 625 626 /** 627 * Inserts a long 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 long 632 */ putLong(@ullable String key, long value)633 public void putLong(@Nullable String key, long value) { 634 unparcel(); 635 mMap.put(key, value); 636 } 637 638 /** 639 * Inserts a float 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 float 644 */ putFloat(@ullable String key, float value)645 void putFloat(@Nullable String key, float value) { 646 unparcel(); 647 mMap.put(key, value); 648 } 649 650 /** 651 * Inserts a double 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 a double 656 */ putDouble(@ullable String key, double value)657 public void putDouble(@Nullable String key, double value) { 658 unparcel(); 659 mMap.put(key, value); 660 } 661 662 /** 663 * Inserts a String value into the mapping of this Bundle, replacing 664 * any existing value for the given key. Either key or value may be null. 665 * 666 * @param key a String, or null 667 * @param value a String, or null 668 */ putString(@ullable String key, @Nullable String value)669 public void putString(@Nullable String key, @Nullable String value) { 670 unparcel(); 671 mMap.put(key, value); 672 } 673 674 /** 675 * Inserts a CharSequence value into the mapping of this Bundle, replacing 676 * any existing value for the given key. Either key or value may be null. 677 * 678 * @param key a String, or null 679 * @param value a CharSequence, or null 680 */ putCharSequence(@ullable String key, @Nullable CharSequence value)681 void putCharSequence(@Nullable String key, @Nullable CharSequence value) { 682 unparcel(); 683 mMap.put(key, value); 684 } 685 686 /** 687 * Inserts an ArrayList<Integer> value into the mapping of this Bundle, replacing 688 * any existing value for the given key. Either key or value may be null. 689 * 690 * @param key a String, or null 691 * @param value an ArrayList<Integer> object, or null 692 */ putIntegerArrayList(@ullable String key, @Nullable ArrayList<Integer> value)693 void putIntegerArrayList(@Nullable String key, @Nullable ArrayList<Integer> value) { 694 unparcel(); 695 mMap.put(key, value); 696 } 697 698 /** 699 * Inserts an ArrayList<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 an ArrayList<String> object, or null 704 */ putStringArrayList(@ullable String key, @Nullable ArrayList<String> value)705 void putStringArrayList(@Nullable String key, @Nullable ArrayList<String> value) { 706 unparcel(); 707 mMap.put(key, value); 708 } 709 710 /** 711 * Inserts an ArrayList<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 an ArrayList<CharSequence> object, or null 716 */ putCharSequenceArrayList(@ullable String key, @Nullable ArrayList<CharSequence> value)717 void putCharSequenceArrayList(@Nullable String key, @Nullable ArrayList<CharSequence> value) { 718 unparcel(); 719 mMap.put(key, value); 720 } 721 722 /** 723 * Inserts a Serializable 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 a Serializable object, or null 728 */ putSerializable(@ullable String key, @Nullable Serializable value)729 void putSerializable(@Nullable String key, @Nullable Serializable value) { 730 unparcel(); 731 mMap.put(key, value); 732 } 733 734 /** 735 * Inserts a boolean array 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 a boolean array object, or null 740 */ putBooleanArray(@ullable String key, @Nullable boolean[] value)741 public void putBooleanArray(@Nullable String key, @Nullable boolean[] value) { 742 unparcel(); 743 mMap.put(key, value); 744 } 745 746 /** 747 * Inserts a byte array 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 a byte array object, or null 752 */ putByteArray(@ullable String key, @Nullable byte[] value)753 void putByteArray(@Nullable String key, @Nullable byte[] value) { 754 unparcel(); 755 mMap.put(key, value); 756 } 757 758 /** 759 * Inserts a short array 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 short array object, or null 764 */ putShortArray(@ullable String key, @Nullable short[] value)765 void putShortArray(@Nullable String key, @Nullable short[] value) { 766 unparcel(); 767 mMap.put(key, value); 768 } 769 770 /** 771 * Inserts a char 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 char array object, or null 776 */ putCharArray(@ullable String key, @Nullable char[] value)777 void putCharArray(@Nullable String key, @Nullable char[] value) { 778 unparcel(); 779 mMap.put(key, value); 780 } 781 782 /** 783 * Inserts an int 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 an int array object, or null 788 */ putIntArray(@ullable String key, @Nullable int[] value)789 public void putIntArray(@Nullable String key, @Nullable int[] value) { 790 unparcel(); 791 mMap.put(key, value); 792 } 793 794 /** 795 * Inserts a long 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 long array object, or null 800 */ putLongArray(@ullable String key, @Nullable long[] value)801 public void putLongArray(@Nullable String key, @Nullable long[] value) { 802 unparcel(); 803 mMap.put(key, value); 804 } 805 806 /** 807 * Inserts a float 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 float array object, or null 812 */ putFloatArray(@ullable String key, @Nullable float[] value)813 void putFloatArray(@Nullable String key, @Nullable float[] value) { 814 unparcel(); 815 mMap.put(key, value); 816 } 817 818 /** 819 * Inserts a double 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 a double array object, or null 824 */ putDoubleArray(@ullable String key, @Nullable double[] value)825 public void putDoubleArray(@Nullable String key, @Nullable double[] value) { 826 unparcel(); 827 mMap.put(key, value); 828 } 829 830 /** 831 * Inserts a String 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 String array object, or null 836 */ putStringArray(@ullable String key, @Nullable String[] value)837 public void putStringArray(@Nullable String key, @Nullable String[] value) { 838 unparcel(); 839 mMap.put(key, value); 840 } 841 842 /** 843 * Inserts a CharSequence 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 CharSequence array object, or null 848 */ putCharSequenceArray(@ullable String key, @Nullable CharSequence[] value)849 void putCharSequenceArray(@Nullable String key, @Nullable CharSequence[] value) { 850 unparcel(); 851 mMap.put(key, value); 852 } 853 854 /** 855 * Returns the value associated with the given key, or false if 856 * no mapping of the desired type exists for the given key. 857 * 858 * @param key a String 859 * @return a boolean value 860 */ getBoolean(String key)861 public boolean getBoolean(String key) { 862 unparcel(); 863 if (DEBUG) Log.d(TAG, "Getting boolean in " 864 + Integer.toHexString(System.identityHashCode(this))); 865 return getBoolean(key, false); 866 } 867 868 // 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)869 void typeWarning(String key, Object value, String className, 870 Object defaultValue, ClassCastException e) { 871 StringBuilder sb = new StringBuilder(); 872 sb.append("Key "); 873 sb.append(key); 874 sb.append(" expected "); 875 sb.append(className); 876 sb.append(" but value was a "); 877 sb.append(value.getClass().getName()); 878 sb.append(". The default value "); 879 sb.append(defaultValue); 880 sb.append(" was returned."); 881 Log.w(TAG, sb.toString()); 882 Log.w(TAG, "Attempt to cast generated internal exception:", e); 883 } 884 typeWarning(String key, Object value, String className, ClassCastException e)885 void typeWarning(String key, Object value, String className, 886 ClassCastException e) { 887 typeWarning(key, value, className, "<null>", e); 888 } 889 890 /** 891 * Returns the value associated with the given key, or defaultValue if 892 * no mapping of the desired type exists for the given key. 893 * 894 * @param key a String 895 * @param defaultValue Value to return if key does not exist 896 * @return a boolean value 897 */ getBoolean(String key, boolean defaultValue)898 public boolean getBoolean(String key, boolean defaultValue) { 899 unparcel(); 900 Object o = mMap.get(key); 901 if (o == null) { 902 return defaultValue; 903 } 904 try { 905 return (Boolean) o; 906 } catch (ClassCastException e) { 907 typeWarning(key, o, "Boolean", defaultValue, e); 908 return defaultValue; 909 } 910 } 911 912 /** 913 * Returns the value associated with the given key, or (byte) 0 if 914 * no mapping of the desired type exists for the given key. 915 * 916 * @param key a String 917 * @return a byte value 918 */ getByte(String key)919 byte getByte(String key) { 920 unparcel(); 921 return getByte(key, (byte) 0); 922 } 923 924 /** 925 * Returns the value associated with the given key, or defaultValue if 926 * no mapping of the desired type exists for the given key. 927 * 928 * @param key a String 929 * @param defaultValue Value to return if key does not exist 930 * @return a byte value 931 */ getByte(String key, byte defaultValue)932 Byte getByte(String key, byte defaultValue) { 933 unparcel(); 934 Object o = mMap.get(key); 935 if (o == null) { 936 return defaultValue; 937 } 938 try { 939 return (Byte) o; 940 } catch (ClassCastException e) { 941 typeWarning(key, o, "Byte", defaultValue, e); 942 return defaultValue; 943 } 944 } 945 946 /** 947 * Returns the value associated with the given key, or (char) 0 if 948 * no mapping of the desired type exists for the given key. 949 * 950 * @param key a String 951 * @return a char value 952 */ getChar(String key)953 char getChar(String key) { 954 unparcel(); 955 return getChar(key, (char) 0); 956 } 957 958 /** 959 * Returns the value associated with the given key, or defaultValue if 960 * no mapping of the desired type exists for the given key. 961 * 962 * @param key a String 963 * @param defaultValue Value to return if key does not exist 964 * @return a char value 965 */ getChar(String key, char defaultValue)966 char getChar(String key, char defaultValue) { 967 unparcel(); 968 Object o = mMap.get(key); 969 if (o == null) { 970 return defaultValue; 971 } 972 try { 973 return (Character) o; 974 } catch (ClassCastException e) { 975 typeWarning(key, o, "Character", defaultValue, e); 976 return defaultValue; 977 } 978 } 979 980 /** 981 * Returns the value associated with the given key, or (short) 0 if 982 * no mapping of the desired type exists for the given key. 983 * 984 * @param key a String 985 * @return a short value 986 */ getShort(String key)987 short getShort(String key) { 988 unparcel(); 989 return getShort(key, (short) 0); 990 } 991 992 /** 993 * Returns the value associated with the given key, or defaultValue if 994 * no mapping of the desired type exists for the given key. 995 * 996 * @param key a String 997 * @param defaultValue Value to return if key does not exist 998 * @return a short value 999 */ getShort(String key, short defaultValue)1000 short getShort(String key, short defaultValue) { 1001 unparcel(); 1002 Object o = mMap.get(key); 1003 if (o == null) { 1004 return defaultValue; 1005 } 1006 try { 1007 return (Short) o; 1008 } catch (ClassCastException e) { 1009 typeWarning(key, o, "Short", defaultValue, e); 1010 return defaultValue; 1011 } 1012 } 1013 1014 /** 1015 * Returns the value associated with the given key, or 0 if 1016 * no mapping of the desired type exists for the given key. 1017 * 1018 * @param key a String 1019 * @return an int value 1020 */ getInt(String key)1021 public int getInt(String key) { 1022 unparcel(); 1023 return getInt(key, 0); 1024 } 1025 1026 /** 1027 * Returns the value associated with the given key, or defaultValue if 1028 * no mapping of the desired type exists for the given key. 1029 * 1030 * @param key a String 1031 * @param defaultValue Value to return if key does not exist 1032 * @return an int value 1033 */ getInt(String key, int defaultValue)1034 public int getInt(String key, int defaultValue) { 1035 unparcel(); 1036 Object o = mMap.get(key); 1037 if (o == null) { 1038 return defaultValue; 1039 } 1040 try { 1041 return (Integer) o; 1042 } catch (ClassCastException e) { 1043 typeWarning(key, o, "Integer", defaultValue, e); 1044 return defaultValue; 1045 } 1046 } 1047 1048 /** 1049 * Returns the value associated with the given key, or 0L if 1050 * no mapping of the desired type exists for the given key. 1051 * 1052 * @param key a String 1053 * @return a long value 1054 */ getLong(String key)1055 public long getLong(String key) { 1056 unparcel(); 1057 return getLong(key, 0L); 1058 } 1059 1060 /** 1061 * Returns the value associated with the given key, or defaultValue if 1062 * no mapping of the desired type exists for the given key. 1063 * 1064 * @param key a String 1065 * @param defaultValue Value to return if key does not exist 1066 * @return a long value 1067 */ getLong(String key, long defaultValue)1068 public long getLong(String key, long defaultValue) { 1069 unparcel(); 1070 Object o = mMap.get(key); 1071 if (o == null) { 1072 return defaultValue; 1073 } 1074 try { 1075 return (Long) o; 1076 } catch (ClassCastException e) { 1077 typeWarning(key, o, "Long", defaultValue, e); 1078 return defaultValue; 1079 } 1080 } 1081 1082 /** 1083 * Returns the value associated with the given key, or 0.0f if 1084 * no mapping of the desired type exists for the given key. 1085 * 1086 * @param key a String 1087 * @return a float value 1088 */ getFloat(String key)1089 float getFloat(String key) { 1090 unparcel(); 1091 return getFloat(key, 0.0f); 1092 } 1093 1094 /** 1095 * Returns the value associated with the given key, or defaultValue if 1096 * no mapping of the desired type exists for the given key. 1097 * 1098 * @param key a String 1099 * @param defaultValue Value to return if key does not exist 1100 * @return a float value 1101 */ getFloat(String key, float defaultValue)1102 float getFloat(String key, float defaultValue) { 1103 unparcel(); 1104 Object o = mMap.get(key); 1105 if (o == null) { 1106 return defaultValue; 1107 } 1108 try { 1109 return (Float) o; 1110 } catch (ClassCastException e) { 1111 typeWarning(key, o, "Float", defaultValue, e); 1112 return defaultValue; 1113 } 1114 } 1115 1116 /** 1117 * Returns the value associated with the given key, or 0.0 if 1118 * no mapping of the desired type exists for the given key. 1119 * 1120 * @param key a String 1121 * @return a double value 1122 */ getDouble(String key)1123 public double getDouble(String key) { 1124 unparcel(); 1125 return getDouble(key, 0.0); 1126 } 1127 1128 /** 1129 * Returns the value associated with the given key, or defaultValue if 1130 * no mapping of the desired type exists for the given key. 1131 * 1132 * @param key a String 1133 * @param defaultValue Value to return if key does not exist 1134 * @return a double value 1135 */ getDouble(String key, double defaultValue)1136 public double getDouble(String key, double defaultValue) { 1137 unparcel(); 1138 Object o = mMap.get(key); 1139 if (o == null) { 1140 return defaultValue; 1141 } 1142 try { 1143 return (Double) o; 1144 } catch (ClassCastException e) { 1145 typeWarning(key, o, "Double", defaultValue, e); 1146 return defaultValue; 1147 } 1148 } 1149 1150 /** 1151 * Returns the value associated with the given key, or null if 1152 * no mapping of the desired type exists for the given key or a null 1153 * value is explicitly associated with the key. 1154 * 1155 * @param key a String, or null 1156 * @return a String value, or null 1157 */ 1158 @Nullable getString(@ullable String key)1159 public String getString(@Nullable String key) { 1160 unparcel(); 1161 final Object o = mMap.get(key); 1162 try { 1163 return (String) o; 1164 } catch (ClassCastException e) { 1165 typeWarning(key, o, "String", e); 1166 return null; 1167 } 1168 } 1169 1170 /** 1171 * Returns the value associated with the given key, or defaultValue if 1172 * no mapping of the desired type exists for the given key or if a null 1173 * value is explicitly associated with the given key. 1174 * 1175 * @param key a String, or null 1176 * @param defaultValue Value to return if key does not exist or if a null 1177 * value is associated with the given key. 1178 * @return the String value associated with the given key, or defaultValue 1179 * if no valid String object is currently mapped to that key. 1180 */ getString(@ullable String key, String defaultValue)1181 public String getString(@Nullable String key, String defaultValue) { 1182 final String s = getString(key); 1183 return (s == null) ? defaultValue : s; 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 CharSequence value, or null 1193 */ 1194 @Nullable getCharSequence(@ullable String key)1195 CharSequence getCharSequence(@Nullable String key) { 1196 unparcel(); 1197 final Object o = mMap.get(key); 1198 try { 1199 return (CharSequence) o; 1200 } catch (ClassCastException e) { 1201 typeWarning(key, o, "CharSequence", 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 CharSequence value associated with the given key, or defaultValue 1215 * if no valid CharSequence object is currently mapped to that key. 1216 */ getCharSequence(@ullable String key, CharSequence defaultValue)1217 CharSequence getCharSequence(@Nullable String key, CharSequence defaultValue) { 1218 final CharSequence cs = getCharSequence(key); 1219 return (cs == null) ? defaultValue : cs; 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 Serializable value, or null 1229 */ 1230 @Nullable getSerializable(@ullable String key)1231 Serializable getSerializable(@Nullable String key) { 1232 unparcel(); 1233 Object o = mMap.get(key); 1234 if (o == null) { 1235 return null; 1236 } 1237 try { 1238 return (Serializable) o; 1239 } catch (ClassCastException e) { 1240 typeWarning(key, o, "Serializable", e); 1241 return null; 1242 } 1243 } 1244 1245 /** 1246 * Returns the value associated with the given key, or null if 1247 * no mapping of the desired type exists for the given key or a null 1248 * value is explicitly associated with the key. 1249 * 1250 * @param key a String, or null 1251 * @return an ArrayList<String> value, or null 1252 */ 1253 @Nullable getIntegerArrayList(@ullable String key)1254 ArrayList<Integer> getIntegerArrayList(@Nullable String key) { 1255 unparcel(); 1256 Object o = mMap.get(key); 1257 if (o == null) { 1258 return null; 1259 } 1260 try { 1261 return (ArrayList<Integer>) o; 1262 } catch (ClassCastException e) { 1263 typeWarning(key, o, "ArrayList<Integer>", e); 1264 return null; 1265 } 1266 } 1267 1268 /** 1269 * Returns the value associated with the given key, or null if 1270 * no mapping of the desired type exists for the given key or a null 1271 * value is explicitly associated with the key. 1272 * 1273 * @param key a String, or null 1274 * @return an ArrayList<String> value, or null 1275 */ 1276 @Nullable getStringArrayList(@ullable String key)1277 ArrayList<String> getStringArrayList(@Nullable String key) { 1278 unparcel(); 1279 Object o = mMap.get(key); 1280 if (o == null) { 1281 return null; 1282 } 1283 try { 1284 return (ArrayList<String>) o; 1285 } catch (ClassCastException e) { 1286 typeWarning(key, o, "ArrayList<String>", e); 1287 return null; 1288 } 1289 } 1290 1291 /** 1292 * Returns the value associated with the given key, or null if 1293 * no mapping of the desired type exists for the given key or a null 1294 * value is explicitly associated with the key. 1295 * 1296 * @param key a String, or null 1297 * @return an ArrayList<CharSequence> value, or null 1298 */ 1299 @Nullable getCharSequenceArrayList(@ullable String key)1300 ArrayList<CharSequence> getCharSequenceArrayList(@Nullable String key) { 1301 unparcel(); 1302 Object o = mMap.get(key); 1303 if (o == null) { 1304 return null; 1305 } 1306 try { 1307 return (ArrayList<CharSequence>) o; 1308 } catch (ClassCastException e) { 1309 typeWarning(key, o, "ArrayList<CharSequence>", e); 1310 return null; 1311 } 1312 } 1313 1314 /** 1315 * Returns the value associated with the given key, or null if 1316 * no mapping of the desired type exists for the given key or a null 1317 * value is explicitly associated with the key. 1318 * 1319 * @param key a String, or null 1320 * @return a boolean[] value, or null 1321 */ 1322 @Nullable getBooleanArray(@ullable String key)1323 public boolean[] getBooleanArray(@Nullable String key) { 1324 unparcel(); 1325 Object o = mMap.get(key); 1326 if (o == null) { 1327 return null; 1328 } 1329 try { 1330 return (boolean[]) o; 1331 } catch (ClassCastException e) { 1332 typeWarning(key, o, "byte[]", e); 1333 return null; 1334 } 1335 } 1336 1337 /** 1338 * Returns the value associated with the given key, or null if 1339 * no mapping of the desired type exists for the given key or a null 1340 * value is explicitly associated with the key. 1341 * 1342 * @param key a String, or null 1343 * @return a byte[] value, or null 1344 */ 1345 @Nullable getByteArray(@ullable String key)1346 byte[] getByteArray(@Nullable String key) { 1347 unparcel(); 1348 Object o = mMap.get(key); 1349 if (o == null) { 1350 return null; 1351 } 1352 try { 1353 return (byte[]) o; 1354 } catch (ClassCastException e) { 1355 typeWarning(key, o, "byte[]", e); 1356 return null; 1357 } 1358 } 1359 1360 /** 1361 * Returns the value associated with the given key, or null if 1362 * no mapping of the desired type exists for the given key or a null 1363 * value is explicitly associated with the key. 1364 * 1365 * @param key a String, or null 1366 * @return a short[] value, or null 1367 */ 1368 @Nullable getShortArray(@ullable String key)1369 short[] getShortArray(@Nullable String key) { 1370 unparcel(); 1371 Object o = mMap.get(key); 1372 if (o == null) { 1373 return null; 1374 } 1375 try { 1376 return (short[]) o; 1377 } catch (ClassCastException e) { 1378 typeWarning(key, o, "short[]", e); 1379 return null; 1380 } 1381 } 1382 1383 /** 1384 * Returns the value associated with the given key, or null if 1385 * no mapping of the desired type exists for the given key or a null 1386 * value is explicitly associated with the key. 1387 * 1388 * @param key a String, or null 1389 * @return a char[] value, or null 1390 */ 1391 @Nullable getCharArray(@ullable String key)1392 char[] getCharArray(@Nullable String key) { 1393 unparcel(); 1394 Object o = mMap.get(key); 1395 if (o == null) { 1396 return null; 1397 } 1398 try { 1399 return (char[]) o; 1400 } catch (ClassCastException e) { 1401 typeWarning(key, o, "char[]", e); 1402 return null; 1403 } 1404 } 1405 1406 /** 1407 * Returns the value associated with the given key, or null if 1408 * no mapping of the desired type exists for the given key or a null 1409 * value is explicitly associated with the key. 1410 * 1411 * @param key a String, or null 1412 * @return an int[] value, or null 1413 */ 1414 @Nullable getIntArray(@ullable String key)1415 public int[] getIntArray(@Nullable String key) { 1416 unparcel(); 1417 Object o = mMap.get(key); 1418 if (o == null) { 1419 return null; 1420 } 1421 try { 1422 return (int[]) o; 1423 } catch (ClassCastException e) { 1424 typeWarning(key, o, "int[]", e); 1425 return null; 1426 } 1427 } 1428 1429 /** 1430 * Returns the value associated with the given key, or null if 1431 * no mapping of the desired type exists for the given key or a null 1432 * value is explicitly associated with the key. 1433 * 1434 * @param key a String, or null 1435 * @return a long[] value, or null 1436 */ 1437 @Nullable getLongArray(@ullable String key)1438 public long[] getLongArray(@Nullable String key) { 1439 unparcel(); 1440 Object o = mMap.get(key); 1441 if (o == null) { 1442 return null; 1443 } 1444 try { 1445 return (long[]) o; 1446 } catch (ClassCastException e) { 1447 typeWarning(key, o, "long[]", e); 1448 return null; 1449 } 1450 } 1451 1452 /** 1453 * Returns the value associated with the given key, or null if 1454 * no mapping of the desired type exists for the given key or a null 1455 * value is explicitly associated with the key. 1456 * 1457 * @param key a String, or null 1458 * @return a float[] value, or null 1459 */ 1460 @Nullable getFloatArray(@ullable String key)1461 float[] getFloatArray(@Nullable String key) { 1462 unparcel(); 1463 Object o = mMap.get(key); 1464 if (o == null) { 1465 return null; 1466 } 1467 try { 1468 return (float[]) o; 1469 } catch (ClassCastException e) { 1470 typeWarning(key, o, "float[]", e); 1471 return null; 1472 } 1473 } 1474 1475 /** 1476 * Returns the value associated with the given key, or null if 1477 * no mapping of the desired type exists for the given key or a null 1478 * value is explicitly associated with the key. 1479 * 1480 * @param key a String, or null 1481 * @return a double[] value, or null 1482 */ 1483 @Nullable getDoubleArray(@ullable String key)1484 public double[] getDoubleArray(@Nullable String key) { 1485 unparcel(); 1486 Object o = mMap.get(key); 1487 if (o == null) { 1488 return null; 1489 } 1490 try { 1491 return (double[]) o; 1492 } catch (ClassCastException e) { 1493 typeWarning(key, o, "double[]", e); 1494 return null; 1495 } 1496 } 1497 1498 /** 1499 * Returns the value associated with the given key, or null if 1500 * no mapping of the desired type exists for the given key or a null 1501 * value is explicitly associated with the key. 1502 * 1503 * @param key a String, or null 1504 * @return a String[] value, or null 1505 */ 1506 @Nullable getStringArray(@ullable String key)1507 public String[] getStringArray(@Nullable String key) { 1508 unparcel(); 1509 Object o = mMap.get(key); 1510 if (o == null) { 1511 return null; 1512 } 1513 try { 1514 return (String[]) o; 1515 } catch (ClassCastException e) { 1516 typeWarning(key, o, "String[]", e); 1517 return null; 1518 } 1519 } 1520 1521 /** 1522 * Returns the value associated with the given key, or null if 1523 * no mapping of the desired type exists for the given key or a null 1524 * value is explicitly associated with the key. 1525 * 1526 * @param key a String, or null 1527 * @return a CharSequence[] value, or null 1528 */ 1529 @Nullable getCharSequenceArray(@ullable String key)1530 CharSequence[] getCharSequenceArray(@Nullable String key) { 1531 unparcel(); 1532 Object o = mMap.get(key); 1533 if (o == null) { 1534 return null; 1535 } 1536 try { 1537 return (CharSequence[]) o; 1538 } catch (ClassCastException e) { 1539 typeWarning(key, o, "CharSequence[]", e); 1540 return null; 1541 } 1542 } 1543 1544 /** 1545 * Writes the Bundle contents to a Parcel, typically in order for 1546 * it to be passed through an IBinder connection. 1547 * @param parcel The parcel to copy this bundle to. 1548 */ writeToParcelInner(Parcel parcel, int flags)1549 void writeToParcelInner(Parcel parcel, int flags) { 1550 // If the parcel has a read-write helper, we can't just copy the blob, so unparcel it first. 1551 if (parcel.hasReadWriteHelper()) { 1552 unparcel(); 1553 } 1554 // Keep implementation in sync with writeToParcel() in 1555 // frameworks/native/libs/binder/PersistableBundle.cpp. 1556 final ArrayMap<String, Object> map; 1557 synchronized (this) { 1558 // unparcel() can race with this method and cause the parcel to recycle 1559 // at the wrong time. So synchronize access the mParcelledData's content. 1560 if (mParcelledData != null) { 1561 if (mParcelledData == NoImagePreloadHolder.EMPTY_PARCEL) { 1562 parcel.writeInt(0); 1563 } else { 1564 int length = mParcelledData.dataSize(); 1565 parcel.writeInt(length); 1566 parcel.writeInt(mParcelledByNative ? BUNDLE_MAGIC_NATIVE : BUNDLE_MAGIC); 1567 parcel.appendFrom(mParcelledData, 0, length); 1568 } 1569 return; 1570 } 1571 map = mMap; 1572 } 1573 1574 // Special case for empty bundles. 1575 if (map == null || map.size() <= 0) { 1576 parcel.writeInt(0); 1577 return; 1578 } 1579 int lengthPos = parcel.dataPosition(); 1580 parcel.writeInt(-1); // dummy, will hold length 1581 parcel.writeInt(BUNDLE_MAGIC); 1582 1583 int startPos = parcel.dataPosition(); 1584 parcel.writeArrayMapInternal(map); 1585 int endPos = parcel.dataPosition(); 1586 1587 // Backpatch length 1588 parcel.setDataPosition(lengthPos); 1589 int length = endPos - startPos; 1590 parcel.writeInt(length); 1591 parcel.setDataPosition(endPos); 1592 } 1593 1594 /** 1595 * Reads the Parcel contents into this Bundle, typically in order for 1596 * it to be passed through an IBinder connection. 1597 * @param parcel The parcel to overwrite this bundle from. 1598 */ readFromParcelInner(Parcel parcel)1599 void readFromParcelInner(Parcel parcel) { 1600 // Keep implementation in sync with readFromParcel() in 1601 // frameworks/native/libs/binder/PersistableBundle.cpp. 1602 int length = parcel.readInt(); 1603 readFromParcelInner(parcel, length); 1604 } 1605 readFromParcelInner(Parcel parcel, int length)1606 private void readFromParcelInner(Parcel parcel, int length) { 1607 if (length < 0) { 1608 throw new RuntimeException("Bad length in parcel: " + length); 1609 } else if (length == 0) { 1610 // Empty Bundle or end of data. 1611 mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL; 1612 mParcelledByNative = false; 1613 return; 1614 } else if (length % 4 != 0) { 1615 throw new IllegalStateException("Bundle length is not aligned by 4: " + length); 1616 } 1617 1618 final int magic = parcel.readInt(); 1619 final boolean isJavaBundle = magic == BUNDLE_MAGIC; 1620 final boolean isNativeBundle = magic == BUNDLE_MAGIC_NATIVE; 1621 if (!isJavaBundle && !isNativeBundle) { 1622 throw new IllegalStateException("Bad magic number for Bundle: 0x" 1623 + Integer.toHexString(magic)); 1624 } 1625 1626 if (parcel.hasReadWriteHelper()) { 1627 // If the parcel has a read-write helper, then we can't lazily-unparcel it, so just 1628 // unparcel right away. 1629 synchronized (this) { 1630 initializeFromParcelLocked(parcel, /*recycleParcel=*/ false, isNativeBundle); 1631 } 1632 return; 1633 } 1634 1635 // Advance within this Parcel 1636 int offset = parcel.dataPosition(); 1637 parcel.setDataPosition(MathUtils.addOrThrow(offset, length)); 1638 1639 Parcel p = Parcel.obtain(); 1640 p.setDataPosition(0); 1641 p.appendFrom(parcel, offset, length); 1642 p.adoptClassCookies(parcel); 1643 if (DEBUG) Log.d(TAG, "Retrieving " + Integer.toHexString(System.identityHashCode(this)) 1644 + ": " + length + " bundle bytes starting at " + offset); 1645 p.setDataPosition(0); 1646 1647 mParcelledData = p; 1648 mParcelledByNative = isNativeBundle; 1649 } 1650 1651 /** {@hide} */ dumpStats(IndentingPrintWriter pw, String key, Object value)1652 public static void dumpStats(IndentingPrintWriter pw, String key, Object value) { 1653 final Parcel tmp = Parcel.obtain(); 1654 tmp.writeValue(value); 1655 final int size = tmp.dataPosition(); 1656 tmp.recycle(); 1657 1658 // We only really care about logging large values 1659 if (size > 1024) { 1660 pw.println(key + " [size=" + size + "]"); 1661 if (value instanceof BaseBundle) { 1662 dumpStats(pw, (BaseBundle) value); 1663 } else if (value instanceof SparseArray) { 1664 dumpStats(pw, (SparseArray) value); 1665 } 1666 } 1667 } 1668 1669 /** {@hide} */ dumpStats(IndentingPrintWriter pw, SparseArray array)1670 public static void dumpStats(IndentingPrintWriter pw, SparseArray array) { 1671 pw.increaseIndent(); 1672 if (array == null) { 1673 pw.println("[null]"); 1674 return; 1675 } 1676 for (int i = 0; i < array.size(); i++) { 1677 dumpStats(pw, "0x" + Integer.toHexString(array.keyAt(i)), array.valueAt(i)); 1678 } 1679 pw.decreaseIndent(); 1680 } 1681 1682 /** {@hide} */ dumpStats(IndentingPrintWriter pw, BaseBundle bundle)1683 public static void dumpStats(IndentingPrintWriter pw, BaseBundle bundle) { 1684 pw.increaseIndent(); 1685 if (bundle == null) { 1686 pw.println("[null]"); 1687 return; 1688 } 1689 final ArrayMap<String, Object> map = bundle.getMap(); 1690 for (int i = 0; i < map.size(); i++) { 1691 dumpStats(pw, map.keyAt(i), map.valueAt(i)); 1692 } 1693 pw.decreaseIndent(); 1694 } 1695 } 1696