1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; 4 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; 5 import static android.os.Build.VERSION_CODES.KITKAT_WATCH; 6 import static android.os.Build.VERSION_CODES.LOLLIPOP; 7 import static android.os.Build.VERSION_CODES.M; 8 import static android.os.Build.VERSION_CODES.O_MR1; 9 import static android.os.Build.VERSION_CODES.P; 10 import static org.robolectric.RuntimeEnvironment.castNativePtr; 11 12 import android.os.BadParcelableException; 13 import android.os.IBinder; 14 import android.os.Parcel; 15 import android.os.ParcelFileDescriptor; 16 import android.os.Parcelable; 17 import android.text.TextUtils; 18 import android.util.Log; 19 import android.util.Pair; 20 import java.io.ByteArrayInputStream; 21 import java.io.ByteArrayOutputStream; 22 import java.io.FileDescriptor; 23 import java.io.IOException; 24 import java.io.ObjectInputStream; 25 import java.io.ObjectOutputStream; 26 import java.io.RandomAccessFile; 27 import java.lang.reflect.Field; 28 import java.lang.reflect.Modifier; 29 import java.util.ArrayList; 30 import java.util.LinkedHashMap; 31 import java.util.List; 32 import java.util.Map; 33 import java.util.Objects; 34 import org.robolectric.annotation.HiddenApi; 35 import org.robolectric.annotation.Implementation; 36 import org.robolectric.annotation.Implements; 37 import org.robolectric.annotation.RealObject; 38 import org.robolectric.util.ReflectionHelpers; 39 40 @Implements(Parcel.class) 41 @SuppressWarnings("unchecked") 42 public class ShadowParcel { 43 private static final String TAG = "Parcel"; 44 45 @RealObject private Parcel realObject; 46 private static final Map<Long, ByteBuffer> NATIVE_PTR_TO_PARCEL = new LinkedHashMap<>(); 47 private static long nextNativePtr = 1; // this needs to start above 0, which is a magic number to Parcel 48 49 @Implementation(maxSdk = JELLY_BEAN_MR1) 50 @SuppressWarnings("TypeParameterUnusedInFormals") readParcelable(ClassLoader loader)51 protected <T extends Parcelable> T readParcelable(ClassLoader loader) { 52 // prior to JB MR2, readParcelableCreator() is inlined here. 53 Parcelable.Creator<?> creator = readParcelableCreator(loader); 54 if (creator == null) { 55 return null; 56 } 57 58 if (creator instanceof Parcelable.ClassLoaderCreator<?>) { 59 Parcelable.ClassLoaderCreator<?> classLoaderCreator = 60 (Parcelable.ClassLoaderCreator<?>) creator; 61 return (T) classLoaderCreator.createFromParcel(realObject, loader); 62 } 63 return (T) creator.createFromParcel(realObject); 64 } 65 66 @HiddenApi 67 @Implementation(minSdk = JELLY_BEAN_MR2) readParcelableCreator(ClassLoader loader)68 public Parcelable.Creator<?> readParcelableCreator(ClassLoader loader) { 69 //note: calling `readString` will also consume the string, and increment the data-pointer. 70 //which is exactly what we need, since we do not call the real `readParcelableCreator`. 71 final String name = realObject.readString(); 72 if (name == null) { 73 return null; 74 } 75 76 Parcelable.Creator<?> creator; 77 try { 78 // If loader == null, explicitly emulate Class.forName(String) "caller 79 // classloader" behavior. 80 ClassLoader parcelableClassLoader = 81 (loader == null ? getClass().getClassLoader() : loader); 82 // Avoid initializing the Parcelable class until we know it implements 83 // Parcelable and has the necessary CREATOR field. http://b/1171613. 84 Class<?> parcelableClass = Class.forName(name, false /* initialize */, 85 parcelableClassLoader); 86 if (!Parcelable.class.isAssignableFrom(parcelableClass)) { 87 throw new BadParcelableException("Parcelable protocol requires that the " 88 + "class implements Parcelable"); 89 } 90 Field f = parcelableClass.getField("CREATOR"); 91 92 // this is a fix for JDK8<->Android VM incompatibility: 93 // Apparently, JDK will not allow access to a public field if its 94 // class is not visible (private or package-private) from the call-site. 95 f.setAccessible(true); 96 97 if ((f.getModifiers() & Modifier.STATIC) == 0) { 98 throw new BadParcelableException("Parcelable protocol requires " 99 + "the CREATOR object to be static on class " + name); 100 } 101 Class<?> creatorType = f.getType(); 102 if (!Parcelable.Creator.class.isAssignableFrom(creatorType)) { 103 // Fail before calling Field.get(), not after, to avoid initializing 104 // parcelableClass unnecessarily. 105 throw new BadParcelableException("Parcelable protocol requires a " 106 + "Parcelable.Creator object called " 107 + "CREATOR on class " + name); 108 } 109 creator = (Parcelable.Creator<?>) f.get(null); 110 } catch (IllegalAccessException e) { 111 Log.e(TAG, "Illegal access when unmarshalling: " + name, e); 112 throw new BadParcelableException( 113 "IllegalAccessException when unmarshalling: " + name); 114 } catch (ClassNotFoundException e) { 115 Log.e(TAG, "Class not found when unmarshalling: " + name, e); 116 throw new BadParcelableException( 117 "ClassNotFoundException when unmarshalling: " + name); 118 } catch (NoSuchFieldException e) { 119 throw new BadParcelableException("Parcelable protocol requires a " 120 + "Parcelable.Creator object called " 121 + "CREATOR on class " + name); 122 } 123 if (creator == null) { 124 throw new BadParcelableException("Parcelable protocol requires a " 125 + "non-null Parcelable.Creator object called " 126 + "CREATOR on class " + name); 127 } 128 return creator; 129 } 130 131 @Implementation writeByteArray(byte[] b, int offset, int len)132 protected void writeByteArray(byte[] b, int offset, int len) { 133 if (b == null) { 134 realObject.writeInt(-1); 135 return; 136 } 137 Number nativePtr = ReflectionHelpers.getField(realObject, "mNativePtr"); 138 nativeWriteByteArray(nativePtr.longValue(), b, offset, len); 139 } 140 141 @HiddenApi 142 @Implementation(maxSdk = KITKAT_WATCH) nativeDataSize(int nativePtr)143 public static int nativeDataSize(int nativePtr) { 144 return nativeDataSize((long) nativePtr); 145 } 146 147 @Implementation(minSdk = LOLLIPOP) nativeDataSize(long nativePtr)148 protected static int nativeDataSize(long nativePtr) { 149 return NATIVE_PTR_TO_PARCEL.get(nativePtr).dataSize(); 150 } 151 152 @HiddenApi 153 @Implementation(maxSdk = KITKAT_WATCH) nativeDataAvail(int nativePtr)154 public static int nativeDataAvail(int nativePtr) { 155 return nativeDataAvail((long) nativePtr); 156 } 157 158 @Implementation(minSdk = LOLLIPOP) nativeDataAvail(long nativePtr)159 protected static int nativeDataAvail(long nativePtr) { 160 return NATIVE_PTR_TO_PARCEL.get(nativePtr).dataAvailable(); 161 } 162 163 @HiddenApi 164 @Implementation(maxSdk = KITKAT_WATCH) nativeDataPosition(int nativePtr)165 public static int nativeDataPosition(int nativePtr) { 166 return nativeDataPosition((long) nativePtr); 167 } 168 169 @Implementation(minSdk = LOLLIPOP) nativeDataPosition(long nativePtr)170 protected static int nativeDataPosition(long nativePtr) { 171 return NATIVE_PTR_TO_PARCEL.get(nativePtr).dataPosition(); 172 } 173 174 @HiddenApi 175 @Implementation(maxSdk = KITKAT_WATCH) nativeDataCapacity(int nativePtr)176 public static int nativeDataCapacity(int nativePtr) { 177 return nativeDataCapacity((long) nativePtr); 178 } 179 180 @Implementation(minSdk = LOLLIPOP) nativeDataCapacity(long nativePtr)181 protected static int nativeDataCapacity(long nativePtr) { 182 return NATIVE_PTR_TO_PARCEL.get(nativePtr).dataCapacity(); 183 } 184 185 @HiddenApi 186 @Implementation(maxSdk = KITKAT_WATCH) nativeSetDataSize(int nativePtr, int size)187 public static void nativeSetDataSize(int nativePtr, int size) { 188 nativeSetDataSize((long) nativePtr, size); 189 } 190 191 @Implementation(minSdk = LOLLIPOP) 192 @SuppressWarnings("robolectric.ShadowReturnTypeMismatch") nativeSetDataSize(long nativePtr, int size)193 protected static void nativeSetDataSize(long nativePtr, int size) { 194 NATIVE_PTR_TO_PARCEL.get(nativePtr).setDataSize(size); 195 } 196 197 @HiddenApi 198 @Implementation(maxSdk = KITKAT_WATCH) nativeSetDataPosition(int nativePtr, int pos)199 public static void nativeSetDataPosition(int nativePtr, int pos) { 200 nativeSetDataPosition((long) nativePtr, pos); 201 } 202 203 @Implementation(minSdk = LOLLIPOP) nativeSetDataPosition(long nativePtr, int pos)204 protected static void nativeSetDataPosition(long nativePtr, int pos) { 205 NATIVE_PTR_TO_PARCEL.get(nativePtr).setDataPosition(pos); 206 } 207 208 @HiddenApi 209 @Implementation(maxSdk = KITKAT_WATCH) nativeSetDataCapacity(int nativePtr, int size)210 public static void nativeSetDataCapacity(int nativePtr, int size) { 211 nativeSetDataCapacity((long) nativePtr, size); 212 } 213 214 @Implementation(minSdk = LOLLIPOP) nativeSetDataCapacity(long nativePtr, int size)215 protected static void nativeSetDataCapacity(long nativePtr, int size) { 216 NATIVE_PTR_TO_PARCEL.get(nativePtr).setDataCapacity(size); 217 } 218 219 @HiddenApi 220 @Implementation(maxSdk = KITKAT_WATCH) nativeWriteByteArray(int nativePtr, byte[] b, int offset, int len)221 public static void nativeWriteByteArray(int nativePtr, byte[] b, int offset, int len) { 222 nativeWriteByteArray((long) nativePtr, b, offset, len); 223 } 224 225 @Implementation(minSdk = LOLLIPOP) nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len)226 protected static void nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len) { 227 NATIVE_PTR_TO_PARCEL.get(nativePtr).writeByteArray(b, offset, len); 228 } 229 230 // duplicate the writeBlob implementation from latest android, to avoid referencing the 231 // non-existent-in-JDK java.util.Arrays.checkOffsetAndCount method. 232 @Implementation(minSdk = M) writeBlob(byte[] b, int offset, int len)233 protected void writeBlob(byte[] b, int offset, int len) { 234 if (b == null) { 235 realObject.writeInt(-1); 236 return; 237 } 238 throwsIfOutOfBounds(b.length, offset, len); 239 long nativePtr = ReflectionHelpers.getField(realObject, "mNativePtr"); 240 nativeWriteBlob(nativePtr, b, offset, len); 241 } 242 throwsIfOutOfBounds(int len, int offset, int count)243 private static void throwsIfOutOfBounds(int len, int offset, int count) { 244 if (len < 0) { 245 throw new ArrayIndexOutOfBoundsException("Negative length: " + len); 246 } 247 248 if ((offset | count) < 0 || offset > len - count) { 249 throw new ArrayIndexOutOfBoundsException(); 250 } 251 } 252 253 // nativeWriteBlob was introduced in lollipop, thus no need for a int nativePtr variant 254 @Implementation(minSdk = LOLLIPOP) nativeWriteBlob(long nativePtr, byte[] b, int offset, int len)255 protected static void nativeWriteBlob(long nativePtr, byte[] b, int offset, int len) { 256 nativeWriteByteArray(nativePtr, b, offset, len); 257 } 258 259 @HiddenApi 260 @Implementation(maxSdk = KITKAT_WATCH) nativeWriteInt(int nativePtr, int val)261 public static void nativeWriteInt(int nativePtr, int val) { 262 nativeWriteInt((long) nativePtr, val); 263 } 264 265 @Implementation(minSdk = LOLLIPOP) nativeWriteInt(long nativePtr, int val)266 protected static void nativeWriteInt(long nativePtr, int val) { 267 NATIVE_PTR_TO_PARCEL.get(nativePtr).writeInt(val); 268 } 269 270 @HiddenApi 271 @Implementation(maxSdk = KITKAT_WATCH) nativeWriteLong(int nativePtr, long val)272 public static void nativeWriteLong(int nativePtr, long val) { 273 nativeWriteLong((long) nativePtr, val); 274 } 275 276 @Implementation(minSdk = LOLLIPOP) nativeWriteLong(long nativePtr, long val)277 protected static void nativeWriteLong(long nativePtr, long val) { 278 NATIVE_PTR_TO_PARCEL.get(nativePtr).writeLong(val); 279 } 280 281 @HiddenApi 282 @Implementation(maxSdk = KITKAT_WATCH) nativeWriteFloat(int nativePtr, float val)283 public static void nativeWriteFloat(int nativePtr, float val) { 284 nativeWriteFloat((long) nativePtr, val); 285 } 286 287 @Implementation(minSdk = LOLLIPOP) nativeWriteFloat(long nativePtr, float val)288 protected static void nativeWriteFloat(long nativePtr, float val) { 289 NATIVE_PTR_TO_PARCEL.get(nativePtr).writeFloat(val); 290 } 291 292 @HiddenApi 293 @Implementation(maxSdk = KITKAT_WATCH) nativeWriteDouble(int nativePtr, double val)294 public static void nativeWriteDouble(int nativePtr, double val) { 295 nativeWriteDouble((long) nativePtr, val); 296 } 297 298 @Implementation(minSdk = LOLLIPOP) nativeWriteDouble(long nativePtr, double val)299 protected static void nativeWriteDouble(long nativePtr, double val) { 300 NATIVE_PTR_TO_PARCEL.get(nativePtr).writeDouble(val); 301 } 302 303 @HiddenApi 304 @Implementation(maxSdk = KITKAT_WATCH) nativeWriteString(int nativePtr, String val)305 public static void nativeWriteString(int nativePtr, String val) { 306 nativeWriteString((long) nativePtr, val); 307 } 308 309 @Implementation(minSdk = LOLLIPOP) nativeWriteString(long nativePtr, String val)310 protected static void nativeWriteString(long nativePtr, String val) { 311 NATIVE_PTR_TO_PARCEL.get(nativePtr).writeString(val); 312 } 313 314 @HiddenApi 315 @Implementation(maxSdk = KITKAT_WATCH) nativeWriteStrongBinder(int nativePtr, IBinder val)316 protected static void nativeWriteStrongBinder(int nativePtr, IBinder val) { 317 nativeWriteStrongBinder((long) nativePtr, val); 318 } 319 320 @Implementation(minSdk = LOLLIPOP) nativeWriteStrongBinder(long nativePtr, IBinder val)321 protected static void nativeWriteStrongBinder(long nativePtr, IBinder val) { 322 NATIVE_PTR_TO_PARCEL.get(nativePtr).writeStrongBinder(val); 323 } 324 325 @HiddenApi 326 @Implementation(maxSdk = KITKAT_WATCH) nativeCreateByteArray(int nativePtr)327 public static byte[] nativeCreateByteArray(int nativePtr) { 328 return nativeCreateByteArray((long) nativePtr); 329 } 330 331 @Implementation(minSdk = LOLLIPOP) nativeCreateByteArray(long nativePtr)332 protected static byte[] nativeCreateByteArray(long nativePtr) { 333 return NATIVE_PTR_TO_PARCEL.get(nativePtr).readByteArray(); 334 } 335 336 // nativeReadBlob was introduced in lollipop, thus no need for a int nativePtr variant 337 @Implementation(minSdk = LOLLIPOP) nativeReadBlob(long nativePtr)338 protected static byte[] nativeReadBlob(long nativePtr) { 339 return nativeCreateByteArray(nativePtr); 340 } 341 342 @Implementation(minSdk = O_MR1) nativeReadByteArray(long nativePtr, byte[] dest, int destLen)343 protected static boolean nativeReadByteArray(long nativePtr, byte[] dest, int destLen) { 344 return NATIVE_PTR_TO_PARCEL.get(nativePtr).readByteArray(dest, destLen); 345 } 346 347 @HiddenApi 348 @Implementation(maxSdk = KITKAT_WATCH) nativeReadInt(int nativePtr)349 public static int nativeReadInt(int nativePtr) { 350 return nativeReadInt((long) nativePtr); 351 } 352 353 @Implementation(minSdk = LOLLIPOP) nativeReadInt(long nativePtr)354 protected static int nativeReadInt(long nativePtr) { 355 return NATIVE_PTR_TO_PARCEL.get(nativePtr).readInt(); 356 } 357 358 @HiddenApi 359 @Implementation(maxSdk = KITKAT_WATCH) nativeReadLong(int nativePtr)360 public static long nativeReadLong(int nativePtr) { 361 return nativeReadLong((long) nativePtr); 362 } 363 364 @Implementation(minSdk = LOLLIPOP) nativeReadLong(long nativePtr)365 protected static long nativeReadLong(long nativePtr) { 366 return NATIVE_PTR_TO_PARCEL.get(nativePtr).readLong(); 367 } 368 369 @HiddenApi 370 @Implementation(maxSdk = KITKAT_WATCH) nativeReadFloat(int nativePtr)371 public static float nativeReadFloat(int nativePtr) { 372 return nativeReadFloat((long) nativePtr); 373 } 374 375 @Implementation(minSdk = LOLLIPOP) nativeReadFloat(long nativePtr)376 protected static float nativeReadFloat(long nativePtr) { 377 return NATIVE_PTR_TO_PARCEL.get(nativePtr).readFloat(); 378 } 379 380 @HiddenApi 381 @Implementation(maxSdk = KITKAT_WATCH) nativeReadDouble(int nativePtr)382 public static double nativeReadDouble(int nativePtr) { 383 return nativeReadDouble((long) nativePtr); 384 } 385 386 @Implementation(minSdk = LOLLIPOP) nativeReadDouble(long nativePtr)387 protected static double nativeReadDouble(long nativePtr) { 388 return NATIVE_PTR_TO_PARCEL.get(nativePtr).readDouble(); 389 } 390 391 @HiddenApi 392 @Implementation(maxSdk = KITKAT_WATCH) nativeReadString(int nativePtr)393 public static String nativeReadString(int nativePtr) { 394 return nativeReadString((long) nativePtr); 395 } 396 397 @Implementation(minSdk = LOLLIPOP) nativeReadString(long nativePtr)398 protected static String nativeReadString(long nativePtr) { 399 return NATIVE_PTR_TO_PARCEL.get(nativePtr).readString(); 400 } 401 402 @HiddenApi 403 @Implementation(maxSdk = KITKAT_WATCH) nativeReadStrongBinder(int nativePtr)404 protected static IBinder nativeReadStrongBinder(int nativePtr) { 405 return nativeReadStrongBinder((long) nativePtr); 406 } 407 408 @Implementation(minSdk = LOLLIPOP) nativeReadStrongBinder(long nativePtr)409 protected static IBinder nativeReadStrongBinder(long nativePtr) { 410 return NATIVE_PTR_TO_PARCEL.get(nativePtr).readStrongBinder(); 411 } 412 413 @Implementation @HiddenApi nativeCreate()414 synchronized public static Number nativeCreate() { 415 long nativePtr = nextNativePtr++; 416 NATIVE_PTR_TO_PARCEL.put(nativePtr, new ByteBuffer()); 417 return castNativePtr(nativePtr); 418 } 419 420 @HiddenApi 421 @Implementation(maxSdk = KITKAT_WATCH) nativeFreeBuffer(int nativePtr)422 public static void nativeFreeBuffer(int nativePtr) { 423 nativeFreeBuffer((long) nativePtr); 424 } 425 426 @Implementation(minSdk = LOLLIPOP) 427 @SuppressWarnings("robolectric.ShadowReturnTypeMismatch") nativeFreeBuffer(long nativePtr)428 protected static void nativeFreeBuffer(long nativePtr) { 429 NATIVE_PTR_TO_PARCEL.get(nativePtr).clear(); 430 } 431 432 @HiddenApi 433 @Implementation(maxSdk = KITKAT_WATCH) nativeDestroy(int nativePtr)434 public static void nativeDestroy(int nativePtr) { 435 nativeDestroy((long) nativePtr); 436 } 437 438 @Implementation(minSdk = LOLLIPOP) nativeDestroy(long nativePtr)439 protected static void nativeDestroy(long nativePtr) { 440 NATIVE_PTR_TO_PARCEL.remove(nativePtr); 441 } 442 443 @HiddenApi 444 @Implementation(maxSdk = KITKAT_WATCH) nativeMarshall(int nativePtr)445 public static byte[] nativeMarshall(int nativePtr) { 446 return nativeMarshall((long) nativePtr); 447 } 448 449 @Implementation(minSdk = LOLLIPOP) nativeMarshall(long nativePtr)450 protected static byte[] nativeMarshall(long nativePtr) { 451 return NATIVE_PTR_TO_PARCEL.get(nativePtr).toByteArray(); 452 } 453 454 @HiddenApi 455 @Implementation(maxSdk = KITKAT_WATCH) nativeUnmarshall(int nativePtr, byte[] data, int offset, int length)456 public static void nativeUnmarshall(int nativePtr, byte[] data, int offset, int length) { 457 nativeUnmarshall((long) nativePtr, data, offset, length); 458 } 459 460 @Implementation(minSdk = LOLLIPOP) 461 @SuppressWarnings("robolectric.ShadowReturnTypeMismatch") nativeUnmarshall(long nativePtr, byte[] data, int offset, int length)462 protected static void nativeUnmarshall(long nativePtr, byte[] data, int offset, int length) { 463 NATIVE_PTR_TO_PARCEL.put(nativePtr, ByteBuffer.fromByteArray(data, offset, length)); 464 } 465 466 @HiddenApi 467 @Implementation(maxSdk = KITKAT_WATCH) nativeAppendFrom(int thisNativePtr, int otherNativePtr, int offset, int length)468 public static void nativeAppendFrom(int thisNativePtr, int otherNativePtr, int offset, int length) { 469 nativeAppendFrom((long) thisNativePtr, otherNativePtr, offset, length); 470 } 471 472 @Implementation(minSdk = LOLLIPOP) 473 @SuppressWarnings("robolectric.ShadowReturnTypeMismatch") nativeAppendFrom( long thisNativePtr, long otherNativePtr, int offset, int length)474 protected static void nativeAppendFrom( 475 long thisNativePtr, long otherNativePtr, int offset, int length) { 476 ByteBuffer thisByteBuffer = NATIVE_PTR_TO_PARCEL.get(thisNativePtr); 477 ByteBuffer otherByteBuffer = NATIVE_PTR_TO_PARCEL.get(otherNativePtr); 478 thisByteBuffer.appendFrom(otherByteBuffer, offset, length); 479 } 480 481 @HiddenApi 482 @Implementation(maxSdk = KITKAT_WATCH) nativeWriteInterfaceToken(int nativePtr, String interfaceName)483 public static void nativeWriteInterfaceToken(int nativePtr, String interfaceName) { 484 nativeWriteInterfaceToken((long) nativePtr, interfaceName); 485 } 486 487 @Implementation(minSdk = LOLLIPOP) nativeWriteInterfaceToken(long nativePtr, String interfaceName)488 protected static void nativeWriteInterfaceToken(long nativePtr, String interfaceName) { 489 // Write StrictMode.ThreadPolicy bits (assume 0 for test). 490 nativeWriteInt(nativePtr, 0); 491 nativeWriteString(nativePtr, interfaceName); 492 } 493 494 @HiddenApi 495 @Implementation(maxSdk = KITKAT_WATCH) nativeEnforceInterface(int nativePtr, String interfaceName)496 public static void nativeEnforceInterface(int nativePtr, String interfaceName) { 497 nativeEnforceInterface((long) nativePtr, interfaceName); 498 } 499 500 @Implementation(minSdk = LOLLIPOP) nativeEnforceInterface(long nativePtr, String interfaceName)501 protected static void nativeEnforceInterface(long nativePtr, String interfaceName) { 502 // Consume StrictMode.ThreadPolicy bits (don't bother setting in test). 503 nativeReadInt(nativePtr); 504 String actualInterfaceName = nativeReadString(nativePtr); 505 if (!Objects.equals(interfaceName, actualInterfaceName)) { 506 throw new SecurityException("Binder invocation to an incorrect interface"); 507 } 508 } 509 510 private static class ByteBuffer { 511 512 // List of elements where a pair is a piece of data and the sizeof that data 513 private List<Pair<Integer, ?>> buffer = new ArrayList<>(); 514 private int index; 515 516 /** 517 * Removes all elements from the byte buffer 518 */ clear()519 public void clear() { 520 index = 0; 521 buffer.clear(); 522 } 523 524 /** 525 * Reads a byte array from the byte buffer based on the current data position 526 */ readByteArray()527 public byte[] readByteArray() { 528 int length = readInt(); 529 if (length == -1) { 530 return null; 531 } 532 byte[] array = new byte[length]; 533 for (int i = 0; i < length; i++) { 534 array[i] = readByte(); 535 } 536 return array; 537 } 538 539 /** 540 * Reads a byte array from the byte buffer based on the current data position 541 */ readByteArray(byte[] dest, int destLen)542 public boolean readByteArray(byte[] dest, int destLen) { 543 int length = readInt(); 544 if (length >= 0 && length <= dataAvailable() && length == destLen) { 545 for (int i = 0; i < length; i++) { 546 dest[i] = readByte(); 547 } 548 return true; 549 } 550 return false; 551 } 552 553 /** 554 * Writes a byte to the byte buffer at the current data position 555 */ writeByte(byte b)556 public void writeByte(byte b) { 557 writeValue(Byte.SIZE / 8, b); 558 } 559 560 /** 561 * Writes a byte array starting at offset for length bytes to the byte buffer at the current 562 * data position 563 */ writeByteArray(byte[] b, int offset, int length)564 public void writeByteArray(byte[] b, int offset, int length) { 565 writeInt(b.length); 566 for (int i = offset; i < offset + length && i < b.length; i++) { 567 writeByte(b[i]); 568 } 569 } 570 571 /** 572 * Reads a byte from the byte buffer based on the current data position 573 */ readByte()574 public byte readByte() { 575 return readValue((byte) 0); 576 } 577 578 /** 579 * Writes an int to the byte buffer at the current data position 580 */ writeInt(int i)581 public void writeInt(int i) { 582 writeValue(Integer.SIZE / 8, i); 583 } 584 585 /** 586 * Reads a int from the byte buffer based on the current data position 587 */ readInt()588 public int readInt() { 589 return readValue(0); 590 } 591 592 /** 593 * Writes a long to the byte buffer at the current data position 594 */ writeLong(long l)595 public void writeLong(long l) { 596 writeValue(Long.SIZE / 8, l); 597 } 598 599 /** 600 * Reads a long from the byte buffer based on the current data position 601 */ readLong()602 public long readLong() { 603 return readValue(0L); 604 } 605 606 /** 607 * Writes a float to the byte buffer at the current data position 608 */ writeFloat(float f)609 public void writeFloat(float f) { 610 writeValue(Float.SIZE / 8, f); 611 } 612 613 /** 614 * Reads a float from the byte buffer based on the current data position 615 */ readFloat()616 public float readFloat() { 617 return readValue(0f); 618 } 619 620 /** 621 * Writes a double to the byte buffer at the current data position 622 */ writeDouble(double d)623 public void writeDouble(double d) { 624 writeValue(Double.SIZE / 8, d); 625 } 626 627 /** 628 * Reads a double from the byte buffer based on the current data position 629 */ readDouble()630 public double readDouble() { 631 return readValue(0d); 632 } 633 634 /** 635 * Writes a String to the byte buffer at the current data position 636 */ writeString(String s)637 public void writeString(String s) { 638 int length = TextUtils.isEmpty(s) ? Integer.SIZE / 8 : s.length(); 639 writeValue(length, s); 640 } 641 642 /** 643 * Reads a String from the byte buffer based on the current data position 644 */ readString()645 public String readString() { 646 return readValue(null); 647 } 648 649 /** 650 * Writes an IBinder to the byte buffer at the current data position 651 */ writeStrongBinder(IBinder b)652 public void writeStrongBinder(IBinder b) { 653 // Size of struct flat_binder_object in android/binder.h used to encode binders in the real 654 // parceling code. 655 int length = 5 * Integer.SIZE / 8; 656 writeValue(length, b); 657 } 658 659 /** 660 * Reads an IBinder from the byte buffer based on the current data position 661 */ readStrongBinder()662 public IBinder readStrongBinder() { 663 return readValue(null); 664 } 665 666 /** 667 * Appends the contents of the other byte buffer to this byte buffer 668 * starting at offset and ending at length. 669 * 670 * @param other ByteBuffer to append to this one 671 * @param offset number of bytes from beginning of byte buffer to start copy from 672 * @param length number of bytes to copy 673 */ appendFrom(ByteBuffer other, int offset, int length)674 public void appendFrom(ByteBuffer other, int offset, int length) { 675 int otherIndex = other.toIndex(offset); 676 int otherEndIndex = other.toIndex(offset + length); 677 for (int i = otherIndex; i < otherEndIndex && i < other.buffer.size(); i++) { 678 int elementSize = other.buffer.get(i).first; 679 Object elementValue = other.buffer.get(i).second; 680 writeValue(elementSize, elementValue); 681 } 682 } 683 684 /** 685 * Creates a Byte buffer from a raw byte array. 686 * 687 * @param array byte array to read from 688 * @param offset starting position in bytes to start reading array at 689 * @param length number of bytes to read from array 690 */ fromByteArray(byte[] array, int offset, int length)691 public static ByteBuffer fromByteArray(byte[] array, int offset, int length) { 692 ByteBuffer byteBuffer = new ByteBuffer(); 693 694 try { 695 ByteArrayInputStream bis = new ByteArrayInputStream(array, offset, 696 length); 697 ObjectInputStream ois = new ObjectInputStream(bis); 698 int numElements = ois.readInt(); 699 for (int i = 0; i < numElements; i++) { 700 int sizeOf = ois.readInt(); 701 Object value = ois.readObject(); 702 byteBuffer.buffer.add(Pair.create(sizeOf, value)); 703 } 704 return byteBuffer; 705 } catch (Exception e) { 706 throw new RuntimeException(e); 707 } 708 } 709 710 /** 711 * Converts a ByteBuffer to a raw byte array. This method should be 712 * symmetrical with fromByteArray. 713 */ toByteArray()714 public byte[] toByteArray() { 715 try { 716 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 717 ObjectOutputStream oos = new ObjectOutputStream(bos); 718 int length = buffer.size(); 719 oos.writeInt(length); 720 for (Pair<Integer, ?> element : buffer) { 721 oos.writeInt(element.first); 722 oos.writeObject(element.second); 723 } 724 return bos.toByteArray(); 725 } catch (IOException e) { 726 throw new RuntimeException(e); 727 } 728 } 729 730 /** 731 * Number of unused bytes in this byte buffer. 732 */ dataAvailable()733 public int dataAvailable() { 734 return dataSize() - dataPosition(); 735 } 736 737 /** 738 * Total buffer size in bytes of byte buffer included unused space. 739 */ dataCapacity()740 public int dataCapacity() { 741 return dataSize(); 742 } 743 744 /** 745 * Current data position of byte buffer in bytes. Reads / writes are from this position. 746 */ dataPosition()747 public int dataPosition() { 748 return toDataPosition(index); 749 } 750 751 /** 752 * Current amount of bytes currently written for ByteBuffer. 753 */ dataSize()754 public int dataSize() { 755 int totalSize = totalSize(); 756 int dataPosition = dataPosition(); 757 return totalSize > dataPosition ? totalSize : dataPosition; 758 } 759 760 /** 761 * Sets the current data position. 762 * 763 * @param pos 764 * Desired position in bytes 765 */ setDataPosition(int pos)766 public void setDataPosition(int pos) { 767 index = toIndex(pos); 768 } 769 setDataSize(int size)770 public void setDataSize(int size) { 771 // TODO 772 } 773 setDataCapacity(int size)774 public void setDataCapacity(int size) { 775 // TODO 776 } 777 totalSize()778 private int totalSize() { 779 int size = 0; 780 for (Pair<Integer, ?> element : buffer) { 781 size += element.first; 782 } 783 return size; 784 } 785 readValue(T defaultValue)786 private <T> T readValue(T defaultValue) { 787 return (index < buffer.size()) ? (T) buffer.get(index++).second : defaultValue; 788 } 789 writeValue(int i, Object o)790 private void writeValue(int i, Object o) { 791 // Align the data size to 4-byte boundaries like Parcel does. 792 final int pad = (4 - (i & 3)) & 3; 793 if (pad != 0) { 794 i += pad; 795 } 796 797 Pair<Integer, ?> value = Pair.create(i, o); 798 if (index < buffer.size()) { 799 buffer.set(index, value); 800 } else { 801 buffer.add(value); 802 } 803 index++; 804 } 805 toDataPosition(int index)806 private int toDataPosition(int index) { 807 int pos = 0; 808 for (int i = 0; i < index; i++) { 809 pos += buffer.get(i).first; 810 } 811 return pos; 812 } 813 toIndex(int dataPosition)814 private int toIndex(int dataPosition) { 815 int calculatedPos = 0; 816 int i = 0; 817 for (; i < buffer.size() && calculatedPos < dataPosition; i++) { 818 calculatedPos += buffer.get(i).first; 819 } 820 return i; 821 } 822 } 823 824 @Implementation(maxSdk = P) openFileDescriptor(String file, int mode)825 protected static FileDescriptor openFileDescriptor(String file, int mode) throws IOException { 826 RandomAccessFile randomAccessFile = 827 new RandomAccessFile(file, mode == ParcelFileDescriptor.MODE_READ_ONLY ? "r" : "rw"); 828 return randomAccessFile.getFD(); 829 } 830 } 831