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