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