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