• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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