• 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.Q;
11 import static android.os.Build.VERSION_CODES.R;
12 import static android.os.Build.VERSION_CODES.S;
13 import static android.os.Build.VERSION_CODES.TIRAMISU;
14 import static org.robolectric.RuntimeEnvironment.castNativePtr;
15 
16 import android.os.BadParcelableException;
17 import android.os.IBinder;
18 import android.os.Parcel;
19 import android.os.ParcelFileDescriptor;
20 import android.os.Parcelable;
21 import android.os.Parcelable.Creator;
22 import android.util.Log;
23 import android.util.Pair;
24 import java.io.ByteArrayInputStream;
25 import java.io.ByteArrayOutputStream;
26 import java.io.FileDescriptor;
27 import java.io.IOException;
28 import java.io.ObjectInputStream;
29 import java.io.ObjectOutputStream;
30 import java.io.RandomAccessFile;
31 import java.io.Serializable;
32 import java.lang.reflect.Field;
33 import java.lang.reflect.Modifier;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Locale;
39 import java.util.Objects;
40 import org.robolectric.annotation.HiddenApi;
41 import org.robolectric.annotation.Implementation;
42 import org.robolectric.annotation.Implements;
43 import org.robolectric.annotation.RealObject;
44 import org.robolectric.annotation.Resetter;
45 import org.robolectric.res.android.NativeObjRegistry;
46 import org.robolectric.util.ReflectionHelpers;
47 import org.robolectric.util.ReflectionHelpers.ClassParameter;
48 
49 /**
50  * Robolectric's {@link Parcel} pretends to be backed by a byte buffer, closely matching {@link
51  * Parcel}'s position, size, and capacity behavior. However, its internal pure-Java representation
52  * is strongly typed, to detect non-portable code and common testing mistakes. It may throw {@link
53  * IllegalArgumentException} or {@link IllegalStateException} for error-prone behavior normal {@link
54  * Parcel} tolerates.
55  */
56 @Implements(value = Parcel.class, looseSignatures = true)
57 public class ShadowParcel {
58   protected static final String TAG = "Parcel";
59 
60   @RealObject private Parcel realObject;
61 
62   private static final NativeObjRegistry<ByteBuffer> NATIVE_BYTE_BUFFER_REGISTRY =
63       new NativeObjRegistry<>(ByteBuffer.class);
64 
65   private static final HashMap<ClassLoader, HashMap<String, Pair<Creator<?>, Class<?>>>>
66       pairedCreators = new HashMap<>();
67 
68   @Implementation(maxSdk = JELLY_BEAN_MR1)
69   @SuppressWarnings("TypeParameterUnusedInFormals")
readParcelable(ClassLoader loader)70   protected <T extends Parcelable> T readParcelable(ClassLoader loader) {
71     // prior to JB MR2, readParcelableCreator() is inlined here.
72     Parcelable.Creator<?> creator = readParcelableCreator(loader);
73     if (creator == null) {
74       return null;
75     }
76 
77     if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
78       Parcelable.ClassLoaderCreator<?> classLoaderCreator =
79           (Parcelable.ClassLoaderCreator<?>) creator;
80       return (T) classLoaderCreator.createFromParcel(realObject, loader);
81     }
82     return (T) creator.createFromParcel(realObject);
83   }
84 
85   @HiddenApi
86   @Implementation(minSdk = JELLY_BEAN_MR2)
readParcelableCreator(ClassLoader loader)87   public Parcelable.Creator<?> readParcelableCreator(ClassLoader loader) {
88     // note: calling `readString` will also consume the string, and increment the data-pointer.
89     // which is exactly what we need, since we do not call the real `readParcelableCreator`.
90     final String name = realObject.readString();
91     if (name == null) {
92       return null;
93     }
94 
95     Parcelable.Creator<?> creator;
96     try {
97       // If loader == null, explicitly emulate Class.forName(String) "caller
98       // classloader" behavior.
99       ClassLoader parcelableClassLoader = (loader == null ? getClass().getClassLoader() : loader);
100       // Avoid initializing the Parcelable class until we know it implements
101       // Parcelable and has the necessary CREATOR field.
102       Class<?> parcelableClass = Class.forName(name, false /* initialize */, parcelableClassLoader);
103       if (!Parcelable.class.isAssignableFrom(parcelableClass)) {
104         throw new BadParcelableException(
105             "Parcelable protocol requires that the " + "class implements Parcelable");
106       }
107       Field f = parcelableClass.getField("CREATOR");
108 
109       // this is a fix for JDK8<->Android VM incompatibility:
110       // Apparently, JDK will not allow access to a public field if its
111       // class is not visible (private or package-private) from the call-site.
112       f.setAccessible(true);
113 
114       if ((f.getModifiers() & Modifier.STATIC) == 0) {
115         throw new BadParcelableException(
116             "Parcelable protocol requires " + "the CREATOR object to be static on class " + name);
117       }
118       Class<?> creatorType = f.getType();
119       if (!Parcelable.Creator.class.isAssignableFrom(creatorType)) {
120         // Fail before calling Field.get(), not after, to avoid initializing
121         // parcelableClass unnecessarily.
122         throw new BadParcelableException(
123             "Parcelable protocol requires a "
124                 + "Parcelable.Creator object called "
125                 + "CREATOR on class "
126                 + name);
127       }
128       creator = (Parcelable.Creator<?>) f.get(null);
129     } catch (IllegalAccessException e) {
130       Log.e(TAG, "Illegal access when unmarshalling: " + name, e);
131       throw new BadParcelableException("IllegalAccessException when unmarshalling: " + name);
132     } catch (ClassNotFoundException e) {
133       Log.e(TAG, "Class not found when unmarshalling: " + name, e);
134       throw new BadParcelableException("ClassNotFoundException when unmarshalling: " + name);
135     } catch (NoSuchFieldException e) {
136       throw new BadParcelableException(
137           "Parcelable protocol requires a "
138               + "Parcelable.Creator object called "
139               + "CREATOR on class "
140               + name);
141     }
142     if (creator == null) {
143       throw new BadParcelableException(
144           "Parcelable protocol requires a "
145               + "non-null Parcelable.Creator object called "
146               + "CREATOR on class "
147               + name);
148     }
149     return creator;
150   }
151 
152   /**
153    * The goal of this shadow method is to workaround a JVM/ART incompatibility.
154    *
155    * <p>In ART, a public field is visible regardless whether or not the enclosing class is public.
156    * On the JVM, this is not the case. For compatibility, we need to use {@link
157    * Field#setAccessible(boolean)} to simulate the same behavior.
158    */
159   @SuppressWarnings("unchecked")
160   @Implementation(minSdk = TIRAMISU)
readParcelableCreatorInternal( ClassLoader loader, Class<T> clazz)161   protected <T> Parcelable.Creator<T> readParcelableCreatorInternal(
162       ClassLoader loader, Class<T> clazz) {
163     String name = realObject.readString();
164     if (name == null) {
165       return null;
166     }
167 
168     Pair<Creator<?>, Class<?>> creatorAndParcelableClass;
169     synchronized (pairedCreators) {
170       HashMap<String, Pair<Creator<?>, Class<?>>> map = pairedCreators.get(loader);
171       if (map == null) {
172         pairedCreators.put(loader, new HashMap<>());
173         creatorAndParcelableClass = null;
174       } else {
175         creatorAndParcelableClass = map.get(name);
176       }
177     }
178 
179     if (creatorAndParcelableClass != null) {
180       Parcelable.Creator<?> creator = creatorAndParcelableClass.first;
181       Class<?> parcelableClass = creatorAndParcelableClass.second;
182       if (clazz != null) {
183         if (!clazz.isAssignableFrom(parcelableClass)) {
184           throw newBadTypeParcelableException(
185               "Parcelable creator "
186                   + name
187                   + " is not "
188                   + "a subclass of required class "
189                   + clazz.getName()
190                   + " provided in the parameter");
191         }
192       }
193 
194       return (Parcelable.Creator<T>) creator;
195     }
196 
197     Parcelable.Creator<?> creator;
198     Class<?> parcelableClass;
199     try {
200       // If loader == null, explicitly emulate Class.forName(String) "caller
201       // classloader" behavior.
202       ClassLoader parcelableClassLoader = (loader == null ? getClass().getClassLoader() : loader);
203       // Avoid initializing the Parcelable class until we know it implements
204       // Parcelable and has the necessary CREATOR field.
205       parcelableClass = Class.forName(name, /* initialize= */ false, parcelableClassLoader);
206       if (!Parcelable.class.isAssignableFrom(parcelableClass)) {
207         throw new BadParcelableException(
208             "Parcelable protocol requires subclassing " + "from Parcelable on class " + name);
209       }
210       if (clazz != null) {
211         if (!clazz.isAssignableFrom(parcelableClass)) {
212           throw newBadTypeParcelableException(
213               "Parcelable creator "
214                   + name
215                   + " is not "
216                   + "a subclass of required class "
217                   + clazz.getName()
218                   + " provided in the parameter");
219         }
220       }
221 
222       Field f = parcelableClass.getField("CREATOR");
223 
224       // this is a fix for JDK8<->Android VM incompatibility:
225       // Apparently, JDK will not allow access to a public field if its
226       // class is not visible (private or package-private) from the call-site.
227       f.setAccessible(true);
228 
229       if ((f.getModifiers() & Modifier.STATIC) == 0) {
230         throw new BadParcelableException(
231             "Parcelable protocol requires " + "the CREATOR object to be static on class " + name);
232       }
233       Class<?> creatorType = f.getType();
234       if (!Parcelable.Creator.class.isAssignableFrom(creatorType)) {
235         // Fail before calling Field.get(), not after, to avoid initializing
236         // parcelableClass unnecessarily.
237         throw new BadParcelableException(
238             "Parcelable protocol requires a "
239                 + "Parcelable.Creator object called "
240                 + "CREATOR on class "
241                 + name);
242       }
243       creator = (Parcelable.Creator<?>) f.get(null);
244     } catch (IllegalAccessException e) {
245       Log.e(TAG, "Illegal access when unmarshalling: " + name, e);
246       throw new BadParcelableException("IllegalAccessException when unmarshalling: " + name, e);
247     } catch (ClassNotFoundException e) {
248       Log.e(TAG, "Class not found when unmarshalling: " + name, e);
249       throw new BadParcelableException("ClassNotFoundException when unmarshalling: " + name, e);
250     } catch (NoSuchFieldException e) {
251       throw new BadParcelableException(
252           "Parcelable protocol requires a "
253               + "Parcelable.Creator object called "
254               + "CREATOR on class "
255               + name,
256           e);
257     }
258     if (creator == null) {
259       throw new BadParcelableException(
260           "Parcelable protocol requires a "
261               + "non-null Parcelable.Creator object called "
262               + "CREATOR on class "
263               + name);
264     }
265 
266     synchronized (pairedCreators) {
267       pairedCreators.get(loader).put(name, Pair.create(creator, parcelableClass));
268     }
269 
270     return (Parcelable.Creator<T>) creator;
271   }
272 
newBadTypeParcelableException(String message)273   private BadParcelableException newBadTypeParcelableException(String message) {
274     try {
275       return (BadParcelableException)
276           ReflectionHelpers.callConstructor(
277               Class.forName("android.os.BadTypeParcelableException"),
278               ClassParameter.from(String.class, message));
279     } catch (ClassNotFoundException e) {
280       throw new LinkageError(e.getMessage(), e);
281     }
282   }
283 
284   @Implementation
writeByteArray(byte[] b, int offset, int len)285   protected void writeByteArray(byte[] b, int offset, int len) {
286     if (b == null) {
287       realObject.writeInt(-1);
288       return;
289     }
290     Number nativePtr = ReflectionHelpers.getField(realObject, "mNativePtr");
291     nativeWriteByteArray(nativePtr.longValue(), b, offset, len);
292   }
293 
294   @HiddenApi
295   @Implementation(maxSdk = KITKAT_WATCH)
nativeDataSize(int nativePtr)296   public static int nativeDataSize(int nativePtr) {
297     return nativeDataSize((long) nativePtr);
298   }
299 
300   @Implementation(minSdk = LOLLIPOP)
nativeDataSize(long nativePtr)301   protected static int nativeDataSize(long nativePtr) {
302     return NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).dataSize();
303   }
304 
305   @HiddenApi
306   @Implementation(maxSdk = KITKAT_WATCH)
nativeDataAvail(int nativePtr)307   public static int nativeDataAvail(int nativePtr) {
308     return nativeDataAvail((long) nativePtr);
309   }
310 
311   @Implementation(minSdk = LOLLIPOP)
nativeDataAvail(long nativePtr)312   protected static int nativeDataAvail(long nativePtr) {
313     return NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).dataAvailable();
314   }
315 
316   @HiddenApi
317   @Implementation(maxSdk = KITKAT_WATCH)
nativeDataPosition(int nativePtr)318   public static int nativeDataPosition(int nativePtr) {
319     return nativeDataPosition((long) nativePtr);
320   }
321 
322   @Implementation(minSdk = LOLLIPOP)
nativeDataPosition(long nativePtr)323   protected static int nativeDataPosition(long nativePtr) {
324     return NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).dataPosition();
325   }
326 
327   @HiddenApi
328   @Implementation(maxSdk = KITKAT_WATCH)
nativeDataCapacity(int nativePtr)329   public static int nativeDataCapacity(int nativePtr) {
330     return nativeDataCapacity((long) nativePtr);
331   }
332 
333   @Implementation(minSdk = LOLLIPOP)
nativeDataCapacity(long nativePtr)334   protected static int nativeDataCapacity(long nativePtr) {
335     return NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).dataCapacity();
336   }
337 
338   @HiddenApi
339   @Implementation(maxSdk = KITKAT_WATCH)
nativeSetDataSize(int nativePtr, int size)340   public static void nativeSetDataSize(int nativePtr, int size) {
341     nativeSetDataSize((long) nativePtr, size);
342   }
343 
344   @Implementation(minSdk = LOLLIPOP)
345   @SuppressWarnings("robolectric.ShadowReturnTypeMismatch")
nativeSetDataSize(long nativePtr, int size)346   protected static void nativeSetDataSize(long nativePtr, int size) {
347     NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).setDataSize(size);
348   }
349 
350   @HiddenApi
351   @Implementation(maxSdk = KITKAT_WATCH)
nativeSetDataPosition(int nativePtr, int pos)352   public static void nativeSetDataPosition(int nativePtr, int pos) {
353     nativeSetDataPosition((long) nativePtr, pos);
354   }
355 
356   @Implementation(minSdk = LOLLIPOP)
nativeSetDataPosition(long nativePtr, int pos)357   protected static void nativeSetDataPosition(long nativePtr, int pos) {
358     NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).setDataPosition(pos);
359   }
360 
361   @HiddenApi
362   @Implementation(maxSdk = KITKAT_WATCH)
nativeSetDataCapacity(int nativePtr, int size)363   public static void nativeSetDataCapacity(int nativePtr, int size) {
364     nativeSetDataCapacity((long) nativePtr, size);
365   }
366 
367   @Implementation(minSdk = LOLLIPOP)
nativeSetDataCapacity(long nativePtr, int size)368   protected static void nativeSetDataCapacity(long nativePtr, int size) {
369     NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).setDataCapacityAtLeast(size);
370   }
371 
372   @HiddenApi
373   @Implementation(maxSdk = KITKAT_WATCH)
nativeWriteByteArray(int nativePtr, byte[] b, int offset, int len)374   public static void nativeWriteByteArray(int nativePtr, byte[] b, int offset, int len) {
375     nativeWriteByteArray((long) nativePtr, b, offset, len);
376   }
377 
378   @Implementation(minSdk = LOLLIPOP)
nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len)379   protected static void nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len) {
380     NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).writeByteArray(b, offset, len);
381   }
382 
383   // duplicate the writeBlob implementation from latest android, to avoid referencing the
384   // non-existent-in-JDK java.util.Arrays.checkOffsetAndCount method.
385   @Implementation(minSdk = M)
writeBlob(byte[] b, int offset, int len)386   protected void writeBlob(byte[] b, int offset, int len) {
387     if (b == null) {
388       realObject.writeInt(-1);
389       return;
390     }
391     throwsIfOutOfBounds(b.length, offset, len);
392     long nativePtr = ReflectionHelpers.getField(realObject, "mNativePtr");
393     nativeWriteBlob(nativePtr, b, offset, len);
394   }
395 
throwsIfOutOfBounds(int len, int offset, int count)396   private static void throwsIfOutOfBounds(int len, int offset, int count) {
397     if (len < 0) {
398       throw new ArrayIndexOutOfBoundsException("Negative length: " + len);
399     }
400 
401     if ((offset | count) < 0 || offset > len - count) {
402       throw new ArrayIndexOutOfBoundsException();
403     }
404   }
405 
406   // nativeWriteBlob was introduced in lollipop, thus no need for a int nativePtr variant
407   @Implementation(minSdk = LOLLIPOP)
nativeWriteBlob(long nativePtr, byte[] b, int offset, int len)408   protected static void nativeWriteBlob(long nativePtr, byte[] b, int offset, int len) {
409     nativeWriteByteArray(nativePtr, b, offset, len);
410   }
411 
412   @HiddenApi
413   @Implementation(maxSdk = KITKAT_WATCH)
nativeWriteInt(int nativePtr, int val)414   public static void nativeWriteInt(int nativePtr, int val) {
415     nativeWriteInt((long) nativePtr, val);
416   }
417 
418   @Implementation(minSdk = LOLLIPOP, maxSdk = R)
nativeWriteInt(long nativePtr, int val)419   protected static void nativeWriteInt(long nativePtr, int val) {
420     NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).writeInt(val);
421   }
422 
423   @HiddenApi
424   @Implementation(maxSdk = KITKAT_WATCH)
nativeWriteLong(int nativePtr, long val)425   public static void nativeWriteLong(int nativePtr, long val) {
426     nativeWriteLong((long) nativePtr, val);
427   }
428 
429   @Implementation(minSdk = LOLLIPOP, maxSdk = R)
nativeWriteLong(long nativePtr, long val)430   protected static void nativeWriteLong(long nativePtr, long val) {
431     NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).writeLong(val);
432   }
433 
434   @HiddenApi
435   @Implementation(maxSdk = KITKAT_WATCH)
nativeWriteFloat(int nativePtr, float val)436   public static void nativeWriteFloat(int nativePtr, float val) {
437     nativeWriteFloat((long) nativePtr, val);
438   }
439 
440   @Implementation(minSdk = LOLLIPOP, maxSdk = R)
nativeWriteFloat(long nativePtr, float val)441   protected static void nativeWriteFloat(long nativePtr, float val) {
442     NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).writeFloat(val);
443   }
444 
445   @HiddenApi
446   @Implementation(maxSdk = KITKAT_WATCH)
nativeWriteDouble(int nativePtr, double val)447   public static void nativeWriteDouble(int nativePtr, double val) {
448     nativeWriteDouble((long) nativePtr, val);
449   }
450 
451   @Implementation(minSdk = LOLLIPOP, maxSdk = R)
nativeWriteDouble(long nativePtr, double val)452   protected static void nativeWriteDouble(long nativePtr, double val) {
453     NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).writeDouble(val);
454   }
455 
456   @HiddenApi
457   @Implementation(maxSdk = KITKAT_WATCH)
nativeWriteString(int nativePtr, String val)458   public static void nativeWriteString(int nativePtr, String val) {
459     nativeWriteString((long) nativePtr, val);
460   }
461 
462   @Implementation(minSdk = LOLLIPOP, maxSdk = Q)
nativeWriteString(long nativePtr, String val)463   protected static void nativeWriteString(long nativePtr, String val) {
464     NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).writeString(val);
465   }
466 
467   @HiddenApi
468   @Implementation(maxSdk = KITKAT_WATCH)
nativeWriteStrongBinder(int nativePtr, IBinder val)469   protected static void nativeWriteStrongBinder(int nativePtr, IBinder val) {
470     nativeWriteStrongBinder((long) nativePtr, val);
471   }
472 
473   @Implementation(minSdk = LOLLIPOP)
nativeWriteStrongBinder(long nativePtr, IBinder val)474   protected static void nativeWriteStrongBinder(long nativePtr, IBinder val) {
475     NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).writeStrongBinder(val);
476   }
477 
478   @HiddenApi
479   @Implementation(maxSdk = KITKAT_WATCH)
nativeCreateByteArray(int nativePtr)480   public static byte[] nativeCreateByteArray(int nativePtr) {
481     return nativeCreateByteArray((long) nativePtr);
482   }
483 
484   @Implementation(minSdk = LOLLIPOP)
nativeCreateByteArray(long nativePtr)485   protected static byte[] nativeCreateByteArray(long nativePtr) {
486     return NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).createByteArray();
487   }
488 
489   // nativeReadBlob was introduced in lollipop, thus no need for a int nativePtr variant
490   @Implementation(minSdk = LOLLIPOP)
nativeReadBlob(long nativePtr)491   protected static byte[] nativeReadBlob(long nativePtr) {
492     return nativeCreateByteArray(nativePtr);
493   }
494 
495   @Implementation(minSdk = O_MR1)
nativeReadByteArray(long nativePtr, byte[] dest, int destLen)496   protected static boolean nativeReadByteArray(long nativePtr, byte[] dest, int destLen) {
497     return NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).readByteArray(dest, destLen);
498   }
499 
500   @HiddenApi
501   @Implementation(maxSdk = KITKAT_WATCH)
nativeReadInt(int nativePtr)502   public static int nativeReadInt(int nativePtr) {
503     return nativeReadInt((long) nativePtr);
504   }
505 
506   @Implementation(minSdk = LOLLIPOP)
nativeReadInt(long nativePtr)507   protected static int nativeReadInt(long nativePtr) {
508     return NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).readInt();
509   }
510 
511   @HiddenApi
512   @Implementation(maxSdk = KITKAT_WATCH)
nativeReadLong(int nativePtr)513   public static long nativeReadLong(int nativePtr) {
514     return nativeReadLong((long) nativePtr);
515   }
516 
517   @Implementation(minSdk = LOLLIPOP)
nativeReadLong(long nativePtr)518   protected static long nativeReadLong(long nativePtr) {
519     return NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).readLong();
520   }
521 
522   @HiddenApi
523   @Implementation(maxSdk = KITKAT_WATCH)
nativeReadFloat(int nativePtr)524   public static float nativeReadFloat(int nativePtr) {
525     return nativeReadFloat((long) nativePtr);
526   }
527 
528   @Implementation(minSdk = LOLLIPOP)
nativeReadFloat(long nativePtr)529   protected static float nativeReadFloat(long nativePtr) {
530     return NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).readFloat();
531   }
532 
533   @HiddenApi
534   @Implementation(maxSdk = KITKAT_WATCH)
nativeReadDouble(int nativePtr)535   public static double nativeReadDouble(int nativePtr) {
536     return nativeReadDouble((long) nativePtr);
537   }
538 
539   @Implementation(minSdk = LOLLIPOP)
nativeReadDouble(long nativePtr)540   protected static double nativeReadDouble(long nativePtr) {
541     return NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).readDouble();
542   }
543 
544   @HiddenApi
545   @Implementation(maxSdk = KITKAT_WATCH)
nativeReadString(int nativePtr)546   public static String nativeReadString(int nativePtr) {
547     return nativeReadString((long) nativePtr);
548   }
549 
550   @Implementation(minSdk = LOLLIPOP, maxSdk = Q)
nativeReadString(long nativePtr)551   protected static String nativeReadString(long nativePtr) {
552     return NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).readString();
553   }
554 
555   @HiddenApi
556   @Implementation(maxSdk = KITKAT_WATCH)
nativeReadStrongBinder(int nativePtr)557   protected static IBinder nativeReadStrongBinder(int nativePtr) {
558     return nativeReadStrongBinder((long) nativePtr);
559   }
560 
561   @Implementation(minSdk = LOLLIPOP)
nativeReadStrongBinder(long nativePtr)562   protected static IBinder nativeReadStrongBinder(long nativePtr) {
563     return NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).readStrongBinder();
564   }
565 
566   @Implementation
567   @HiddenApi
nativeCreate()568   public static Number nativeCreate() {
569     return castNativePtr(NATIVE_BYTE_BUFFER_REGISTRY.register(new ByteBuffer()));
570   }
571 
572   @HiddenApi
573   @Implementation(maxSdk = KITKAT_WATCH)
nativeFreeBuffer(int nativePtr)574   public static void nativeFreeBuffer(int nativePtr) {
575     nativeFreeBuffer((long) nativePtr);
576   }
577 
578   @Implementation(minSdk = LOLLIPOP)
579   @SuppressWarnings("robolectric.ShadowReturnTypeMismatch")
nativeFreeBuffer(long nativePtr)580   protected static void nativeFreeBuffer(long nativePtr) {
581     NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).clear();
582   }
583 
584   @HiddenApi
585   @Implementation(maxSdk = KITKAT_WATCH)
nativeDestroy(int nativePtr)586   public static void nativeDestroy(int nativePtr) {
587     nativeDestroy((long) nativePtr);
588   }
589 
590   @Implementation(minSdk = LOLLIPOP)
nativeDestroy(long nativePtr)591   protected static void nativeDestroy(long nativePtr) {
592     NATIVE_BYTE_BUFFER_REGISTRY.unregister(nativePtr);
593   }
594 
595   @HiddenApi
596   @Implementation(maxSdk = KITKAT_WATCH)
nativeMarshall(int nativePtr)597   public static byte[] nativeMarshall(int nativePtr) {
598     return nativeMarshall((long) nativePtr);
599   }
600 
601   @Implementation(minSdk = LOLLIPOP)
nativeMarshall(long nativePtr)602   protected static byte[] nativeMarshall(long nativePtr) {
603     return NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).toByteArray();
604   }
605 
606   @HiddenApi
607   @Implementation(maxSdk = KITKAT_WATCH)
nativeUnmarshall(int nativePtr, byte[] data, int offset, int length)608   public static void nativeUnmarshall(int nativePtr, byte[] data, int offset, int length) {
609     nativeUnmarshall((long) nativePtr, data, offset, length);
610   }
611 
612   @Implementation(minSdk = LOLLIPOP)
613   @SuppressWarnings("robolectric.ShadowReturnTypeMismatch")
nativeUnmarshall(long nativePtr, byte[] data, int offset, int length)614   protected static void nativeUnmarshall(long nativePtr, byte[] data, int offset, int length) {
615     NATIVE_BYTE_BUFFER_REGISTRY.update(nativePtr, ByteBuffer.fromByteArray(data, offset, length));
616   }
617 
618   @HiddenApi
619   @Implementation(maxSdk = KITKAT_WATCH)
nativeAppendFrom( int thisNativePtr, int otherNativePtr, int offset, int length)620   public static void nativeAppendFrom(
621       int thisNativePtr, int otherNativePtr, int offset, int length) {
622     nativeAppendFrom((long) thisNativePtr, otherNativePtr, offset, length);
623   }
624 
625   @Implementation(minSdk = LOLLIPOP)
626   @SuppressWarnings("robolectric.ShadowReturnTypeMismatch")
nativeAppendFrom( long thisNativePtr, long otherNativePtr, int offset, int length)627   protected static void nativeAppendFrom(
628       long thisNativePtr, long otherNativePtr, int offset, int length) {
629     ByteBuffer thisByteBuffer = NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(thisNativePtr);
630     ByteBuffer otherByteBuffer = NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(otherNativePtr);
631     thisByteBuffer.appendFrom(otherByteBuffer, offset, length);
632   }
633 
634   @HiddenApi
635   @Implementation(maxSdk = KITKAT_WATCH)
nativeWriteInterfaceToken(int nativePtr, String interfaceName)636   public static void nativeWriteInterfaceToken(int nativePtr, String interfaceName) {
637     nativeWriteInterfaceToken((long) nativePtr, interfaceName);
638   }
639 
640   @Implementation(minSdk = LOLLIPOP)
nativeWriteInterfaceToken(long nativePtr, String interfaceName)641   protected static void nativeWriteInterfaceToken(long nativePtr, String interfaceName) {
642     // Write StrictMode.ThreadPolicy bits (assume 0 for test).
643     nativeWriteInt(nativePtr, 0);
644     nativeWriteString(nativePtr, interfaceName);
645   }
646 
647   @HiddenApi
648   @Implementation(maxSdk = KITKAT_WATCH)
nativeEnforceInterface(int nativePtr, String interfaceName)649   public static void nativeEnforceInterface(int nativePtr, String interfaceName) {
650     nativeEnforceInterface((long) nativePtr, interfaceName);
651   }
652 
653   @Implementation(minSdk = LOLLIPOP)
nativeEnforceInterface(long nativePtr, String interfaceName)654   protected static void nativeEnforceInterface(long nativePtr, String interfaceName) {
655     // Consume StrictMode.ThreadPolicy bits (don't bother setting in test).
656     nativeReadInt(nativePtr);
657     String actualInterfaceName = nativeReadString(nativePtr);
658     if (!Objects.equals(interfaceName, actualInterfaceName)) {
659       throw new SecurityException("Binder invocation to an incorrect interface");
660     }
661   }
662 
663   /**
664    * Robolectric-specific error thrown when tests exercise error-prone behavior in Parcel.
665    *
666    * <p>Standard Android parcels rarely throw exceptions, but will happily behave in unintended
667    * ways. Parcels are not strongly typed, so will happily re-interpret corrupt contents in ways
668    * that cause hard-to-diagnose failures, or will cause tests to pass when they should not.
669    * ShadowParcel attempts to detect these conditions.
670    *
671    * <p>This exception is package-private because production or test code should never catch or rely
672    * on this, and may be changed to be an Error (rather than Exception) in the future.
673    */
674   static class UnreliableBehaviorError extends AssertionError {
UnreliableBehaviorError(String message)675     UnreliableBehaviorError(String message) {
676       super(message);
677     }
678 
UnreliableBehaviorError(String message, Throwable cause)679     UnreliableBehaviorError(String message, Throwable cause) {
680       super(message, cause);
681     }
682 
UnreliableBehaviorError( Class<?> clazz, int position, ByteBuffer.FakeEncodedItem item, String extraMessage)683     UnreliableBehaviorError(
684         Class<?> clazz, int position, ByteBuffer.FakeEncodedItem item, String extraMessage) {
685       super(
686           String.format(
687               Locale.US,
688               "Looking for %s at position %d, found %s [%s] taking %d bytes, %s",
689               clazz.getSimpleName(),
690               position,
691               item.value == null ? "null" : item.value.getClass().getSimpleName(),
692               item.value,
693               item.sizeBytes,
694               extraMessage));
695     }
696   }
697 
698   /**
699    * ByteBuffer pretends to be the underlying Parcel implementation.
700    *
701    * <p>It faithfully simulates Parcel's handling of position, size, and capacity, but is strongly
702    * typed internally. It was debated whether this should instead faithfully represent Android's
703    * Parcel bug-for-bug as a true byte array, along with all of its error-tolerant behavior and
704    * ability essentially to {@code reinterpret_cast} data. However, the fail-fast behavior here has
705    * found several test bugs and avoids reliance on architecture-specific details like Endian-ness.
706    *
707    * <p>Quirky behavior this explicitly emulates:
708    *
709    * <ul>
710    *   <li>Continuing to read past the end returns zeros/nulls.
711    *   <li>{@link setDataCapacity} never decreases buffer size.
712    *   <li>It is possible to partially or completely overwrite byte ranges in the buffer.
713    *   <li>Zero bytes can be exchanged between primitive data types and empty array/string.
714    * </ul>
715    *
716    * <p>Quirky behavior this forbids:
717    *
718    * <ul>
719    *   <li>Reading past the end after writing without calling setDataPosition(0), since there's no
720    *       legitimate reason to do this, and is a very common test bug.
721    *   <li>Writing one type and reading another; for example, writing a Long and reading two
722    *       Integers, or writing a byte array and reading a String. This, effectively like {@code
723    *       reinterpret_cast}, may not be portable across architectures.
724    *   <li>Similarly, reading from objects that have been truncated or partially overwritten, or
725    *       reading from the middle of them.
726    *   <li>Using appendFrom to overwrite data, which in Parcel will overwrite the data <i>and</i>
727    *       expand data size by the same amount, introducing empty gaps.
728    *   <li>Reading from or marshalling buffers with uninitialized gaps (e.g. where data position was
729    *       expanded but nothing was written)
730    * </ul>
731    *
732    * <p>Possibly-unwanted divergent behavior:
733    *
734    * <ul>
735    *   <li>Reading an object will often return the same instance that was written.
736    *   <li>The marshalled form does not at all resemble Parcel's. This is to maintain compatibility
737    *       with existing clients that rely on the Java-serialization-based format.
738    *   <li>Uses substantially more memory, since each "byte" takes at minimum 4 bytes for a pointer,
739    *       and even more for the overhead of allocating a record for each write. But note there is
740    *       only at most one allocation for every 4 byte positions.
741    * </ul>
742    */
743   private static class ByteBuffer {
744     /** Number of bytes in Parcel used by an int, length, or anything smaller. */
745     private static final int INT_SIZE_BYTES = 4;
746     /** Number of bytes in Parcel used by a long or double. */
747     private static final int LONG_OR_DOUBLE_SIZE_BYTES = 8;
748     /** Immutable empty byte array. */
749     private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
750 
751     /** Representation for an item that has been serialized in a parcel. */
752     private static class FakeEncodedItem implements Serializable {
753       /** Number of consecutive bytes consumed by this object. */
754       final int sizeBytes;
755       /** The original typed value stored. */
756       final Object value;
757       /**
758        * Whether this item's byte-encoding is all zero.
759        *
760        * <p>This is the one exception to strong typing in ShadowParcel. Since zero can be portably
761        * handled by many primitive types as zeros, and strings and arrays as empty. Note that when
762        * zeroes are successfully read, the size of this entry may be ignored and the position may
763        * progress to the middle of this, which remains safe as long as types that handle zeros are
764        * used.
765        */
766       final boolean isEncodedAsAllZeroBytes;
767 
FakeEncodedItem(int sizeBytes, Object value)768       FakeEncodedItem(int sizeBytes, Object value) {
769         this.sizeBytes = sizeBytes;
770         this.value = value;
771         this.isEncodedAsAllZeroBytes = isEncodedAsAllZeroBytes(value);
772       }
773     }
774 
775     /**
776      * A type-safe simulation of the Parcel's data buffer.
777      *
778      * <p>Each index represents a byte of the parcel. Instead of storing raw bytes, this contains
779      * records containing both the original data (in its original Java type) as well as the length.
780      * Consecutive indices will point to the same FakeEncodedItem instance; for example, an item
781      * with sizeBytes of 24 will, in normal cases, have references from 24 consecutive indices.
782      *
783      * <p>There are two main fail-fast features in this type-safe buffer. First, objects may only be
784      * read from the parcel as the same type they were stored with, enforced by casting. Second,
785      * this fails fast when reading incomplete or partially overwritten items.
786      *
787      * <p>Even though writing a custom resizable array is a code smell vs ArrayList, arrays' fixed
788      * capacity closely models Parcel's dataCapacity (which we emulate anyway), and bulk array
789      * utilities are robust compared to ArrayList's bulk operations.
790      */
791     private FakeEncodedItem[] data;
792     /** The read/write pointer. */
793     private int dataPosition;
794     /** The length of the buffer; the capacity is data.length. */
795     private int dataSize;
796     /**
797      * Whether the next read should fail if it's past the end of the array.
798      *
799      * <p>This is set true when modifying the end of the buffer, and cleared if a data position was
800      * explicitly set.
801      */
802     private boolean failNextReadIfPastEnd;
803 
ByteBuffer()804     ByteBuffer() {
805       clear();
806     }
807 
808     /** Removes all elements from the byte buffer */
clear()809     public void clear() {
810       data = new FakeEncodedItem[0];
811       dataPosition = 0;
812       dataSize = 0;
813       failNextReadIfPastEnd = false;
814     }
815 
816     /** Reads a byte array from the byte buffer based on the current data position */
createByteArray()817     public byte[] createByteArray() {
818       // It would be simpler just to store the byte array without a separate length.  However, the
819       // "non-native" code in Parcel short-circuits null to -1, so this must consistently write a
820       // separate length field in all cases.
821       int length = readInt();
822       if (length == -1) {
823         return null;
824       }
825       if (length == 0) {
826         return EMPTY_BYTE_ARRAY;
827       }
828       Object current = peek();
829       if (current instanceof Byte) {
830         // Legacy-encoded byte arrays (created by some tests) encode individual bytes, and do not
831         // align to the integer.
832         return readLegacyByteArray(length);
833       } else if (readZeroes(alignToInt(length))) {
834         return new byte[length];
835       }
836       byte[] result = readValue(EMPTY_BYTE_ARRAY, byte[].class, /* allowNull= */ false);
837       if (result.length != length) {
838         // Looks like the length doesn't correspond to the array.
839         throw new UnreliableBehaviorError(
840             String.format(
841                 Locale.US,
842                 "Byte array's length prefix is %d but real length is %d",
843                 length,
844                 result.length));
845       }
846       return result;
847     }
848 
849     /** Reads a byte array encoded the way ShadowParcel previously encoded byte arrays. */
readLegacyByteArray(int length)850     private byte[] readLegacyByteArray(int length) {
851       // Some tests rely on ShadowParcel's previous byte-by-byte encoding.
852       byte[] result = new byte[length];
853       for (int i = 0; i < length; i++) {
854         result[i] = readPrimitive(1, (byte) 0, Byte.class);
855       }
856       return result;
857     }
858 
859     /** Reads a byte array from the byte buffer based on the current data position */
readByteArray(byte[] dest, int destLen)860     public boolean readByteArray(byte[] dest, int destLen) {
861       byte[] result = createByteArray();
862       if (result == null || destLen != result.length) {
863         // Since older versions of Android (pre O MR1) don't call this method at all, let's be more
864         // consistent with them and let android.os.Parcel throw RuntimeException, instead of
865         // throwing a more helpful exception.
866         return false;
867       }
868       System.arraycopy(result, 0, dest, 0, destLen);
869       return true;
870     }
871 
872     /**
873      * Writes a byte array starting at offset for length bytes to the byte buffer at the current
874      * data position
875      */
writeByteArray(byte[] b, int offset, int length)876     public void writeByteArray(byte[] b, int offset, int length) {
877       writeInt(length);
878       // Native parcel writes a byte array as length plus the individual bytes.  But we can't write
879       // bytes individually because each byte would take up 4 bytes due to Parcel's alignment
880       // behavior.  Instead we write the length, and if non-empty, we write the array.
881       if (length != 0) {
882         writeValue(length, Arrays.copyOfRange(b, offset, offset + length));
883       }
884     }
885 
886     /** Writes an int to the byte buffer at the current data position */
writeInt(int i)887     public void writeInt(int i) {
888       writeValue(INT_SIZE_BYTES, i);
889     }
890 
891     /** Reads a int from the byte buffer based on the current data position */
readInt()892     public int readInt() {
893       return readPrimitive(INT_SIZE_BYTES, 0, Integer.class);
894     }
895 
896     /** Writes a long to the byte buffer at the current data position */
writeLong(long l)897     public void writeLong(long l) {
898       writeValue(LONG_OR_DOUBLE_SIZE_BYTES, l);
899     }
900 
901     /** Reads a long from the byte buffer based on the current data position */
readLong()902     public long readLong() {
903       return readPrimitive(LONG_OR_DOUBLE_SIZE_BYTES, 0L, Long.class);
904     }
905 
906     /** Writes a float to the byte buffer at the current data position */
writeFloat(float f)907     public void writeFloat(float f) {
908       writeValue(INT_SIZE_BYTES, f);
909     }
910 
911     /** Reads a float from the byte buffer based on the current data position */
readFloat()912     public float readFloat() {
913       return readPrimitive(INT_SIZE_BYTES, 0f, Float.class);
914     }
915 
916     /** Writes a double to the byte buffer at the current data position */
writeDouble(double d)917     public void writeDouble(double d) {
918       writeValue(LONG_OR_DOUBLE_SIZE_BYTES, d);
919     }
920 
921     /** Reads a double from the byte buffer based on the current data position */
readDouble()922     public double readDouble() {
923       return readPrimitive(LONG_OR_DOUBLE_SIZE_BYTES, 0d, Double.class);
924     }
925 
926     /** Writes a String to the byte buffer at the current data position */
writeString(String s)927     public void writeString(String s) {
928       int nullTerminatedChars = (s != null) ? (s.length() + 1) : 0;
929       // Android encodes strings as length plus a null-terminated array of 2-byte characters.
930       // writeValue will pad to nearest 4 bytes.  Null is encoded as just -1.
931       int sizeBytes = INT_SIZE_BYTES + (nullTerminatedChars * 2);
932       writeValue(sizeBytes, s);
933     }
934 
935     /** Reads a String from the byte buffer based on the current data position */
readString()936     public String readString() {
937       if (readZeroes(INT_SIZE_BYTES * 2)) {
938         // Empty string is 4 bytes for length of 0, and 4 bytes for null terminator and padding.
939         return "";
940       }
941       return readValue(null, String.class, /* allowNull= */ true);
942     }
943 
944     /** Writes an IBinder to the byte buffer at the current data position */
writeStrongBinder(IBinder b)945     public void writeStrongBinder(IBinder b) {
946       // Size of struct flat_binder_object in android/binder.h used to encode binders in the real
947       // parceling code.
948       int length = 5 * INT_SIZE_BYTES;
949       writeValue(length, b);
950     }
951 
952     /** Reads an IBinder from the byte buffer based on the current data position */
readStrongBinder()953     public IBinder readStrongBinder() {
954       return readValue(null, IBinder.class, /* allowNull= */ true);
955     }
956 
957     /**
958      * Appends the contents of the other byte buffer to this byte buffer starting at offset and
959      * ending at length.
960      *
961      * @param other ByteBuffer to append to this one
962      * @param offset number of bytes from beginning of byte buffer to start copy from
963      * @param length number of bytes to copy
964      */
appendFrom(ByteBuffer other, int offset, int length)965     public void appendFrom(ByteBuffer other, int offset, int length) {
966       int oldSize = dataSize;
967       if (dataPosition != dataSize) {
968         // Parcel.cpp will always expand the buffer by length even if it is overwriting existing
969         // data, yielding extra uninitialized data at the end, in contrast to write methods that
970         // won't increase the data length if they are overwriting in place.  This is surprising
971         // behavior that production code should avoid.
972         throw new UnreliableBehaviorError(
973             "Real Android parcels behave unreliably if appendFrom is "
974                 + "called from any position other than the end");
975       }
976       setDataSize(oldSize + length);
977       // Just blindly copy whatever happens to be in the buffer.  Reads will validate whether any
978       // of the objects were only incompletely copied.
979       System.arraycopy(other.data, offset, data, dataPosition, length);
980       dataPosition += length;
981       failNextReadIfPastEnd = true;
982     }
983 
984     /** Returns whether a data type is encoded as all zeroes. */
isEncodedAsAllZeroBytes(Object value)985     private static boolean isEncodedAsAllZeroBytes(Object value) {
986       if (value == null) {
987         return false; // Nulls are usually encoded as -1.
988       }
989       if (value instanceof Number) {
990         Number number = (Number) value;
991         return number.longValue() == 0 && number.doubleValue() == 0;
992       }
993       if (value instanceof byte[]) {
994         byte[] array = (byte[]) value;
995         return isAllZeroes(array, 0, array.length);
996       }
997       // NOTE: While empty string is all zeros, trying to read an empty string as zeroes is
998       // probably unintended; the reverse is supported just so all-zero buffers don't fail.
999       return false;
1000     }
1001 
1002     /** Identifies all zeroes, which can be safely reinterpreted to other types. */
isAllZeroes(byte[] array, int offset, int length)1003     private static boolean isAllZeroes(byte[] array, int offset, int length) {
1004       for (int i = offset; i < length; i++) {
1005         if (array[i] != 0) {
1006           return false;
1007         }
1008       }
1009       return true;
1010     }
1011 
1012     /**
1013      * Creates a Byte buffer from a raw byte array.
1014      *
1015      * @param array byte array to read from
1016      * @param offset starting position in bytes to start reading array at
1017      * @param length number of bytes to read from array
1018      */
1019     @SuppressWarnings("BanSerializableRead")
fromByteArray(byte[] array, int offset, int length)1020     public static ByteBuffer fromByteArray(byte[] array, int offset, int length) {
1021       ByteBuffer byteBuffer = new ByteBuffer();
1022 
1023       if (isAllZeroes(array, offset, length)) {
1024         // Special case: for all zeroes, it's definitely not an ObjectInputStream, because it has a
1025         // non-zero mandatory magic.  Zeroes have a portable, unambiguous interpretation.
1026         byteBuffer.setDataSize(length);
1027         byteBuffer.writeItem(new FakeEncodedItem(length, new byte[length]));
1028         return byteBuffer;
1029       }
1030 
1031       try {
1032         ByteArrayInputStream bis = new ByteArrayInputStream(array, offset, length);
1033         ObjectInputStream ois = new ObjectInputStream(bis);
1034         int numElements = ois.readInt();
1035         for (int i = 0; i < numElements; i++) {
1036           int sizeOf = ois.readInt();
1037           Object value = ois.readObject();
1038           // NOTE: Bypassing writeValue so that this will support ShadowParcels that were
1039           // marshalled before ShadowParcel simulated alignment.
1040           byteBuffer.writeItem(new FakeEncodedItem(sizeOf, value));
1041         }
1042         // Android leaves the data position at the end in this case.
1043         return byteBuffer;
1044       } catch (Exception e) {
1045         throw new UnreliableBehaviorError("ShadowParcel unable to unmarshall its custom format", e);
1046       }
1047     }
1048 
1049     /**
1050      * Converts a ByteBuffer to a raw byte array. This method should be symmetrical with
1051      * fromByteArray.
1052      */
toByteArray()1053     public byte[] toByteArray() {
1054       int oldDataPosition = dataPosition;
1055       try {
1056         ByteArrayOutputStream bos = new ByteArrayOutputStream();
1057         ObjectOutputStream oos = new ObjectOutputStream(bos);
1058         // NOTE: Serializing the data array would be simpler, and serialization would actually
1059         // preserve reference equality between entries.  However, the length-encoded format here
1060         // preserves the previous format, which some tests appear to rely on.
1061         List<FakeEncodedItem> entries = new ArrayList<>();
1062         // NOTE: Use readNextItem to scan so the contents can be proactively validated.
1063         dataPosition = 0;
1064         while (dataPosition < dataSize) {
1065           entries.add(readNextItem(Object.class));
1066         }
1067         oos.writeInt(entries.size());
1068         for (FakeEncodedItem item : entries) {
1069           oos.writeInt(item.sizeBytes);
1070           oos.writeObject(item.value);
1071         }
1072         oos.flush();
1073         return bos.toByteArray();
1074       } catch (IOException e) {
1075         throw new UnreliableBehaviorError("ErrorProne unable to serialize its custom format", e);
1076       } finally {
1077         dataPosition = oldDataPosition;
1078       }
1079     }
1080 
1081     /** Number of unused bytes in this byte buffer. */
dataAvailable()1082     public int dataAvailable() {
1083       return dataSize() - dataPosition();
1084     }
1085 
1086     /** Total buffer size in bytes of byte buffer included unused space. */
dataCapacity()1087     public int dataCapacity() {
1088       return data.length;
1089     }
1090 
1091     /** Current data position of byte buffer in bytes. Reads / writes are from this position. */
dataPosition()1092     public int dataPosition() {
1093       return dataPosition;
1094     }
1095 
1096     /** Current amount of bytes currently written for ByteBuffer. */
dataSize()1097     public int dataSize() {
1098       return dataSize;
1099     }
1100 
1101     /**
1102      * Sets the current data position.
1103      *
1104      * @param pos Desired position in bytes
1105      */
setDataPosition(int pos)1106     public void setDataPosition(int pos) {
1107       if (pos > dataSize) {
1108         // NOTE: Real parcel ignores this until a write occurs.
1109         throw new UnreliableBehaviorError(pos + " greater than dataSize " + dataSize);
1110       }
1111       dataPosition = pos;
1112       failNextReadIfPastEnd = false;
1113     }
1114 
setDataSize(int size)1115     public void setDataSize(int size) {
1116       if (size < dataSize) {
1117         // Clear all the inaccessible bytes when shrinking, to allow garbage collection, and so
1118         // they remain cleared if expanded again.  Note this might truncate something mid-object,
1119         // which would be handled at read time.
1120         Arrays.fill(data, size, dataSize, null);
1121       }
1122       setDataCapacityAtLeast(size);
1123       dataSize = size;
1124       if (dataPosition >= dataSize) {
1125         dataPosition = dataSize;
1126       }
1127     }
1128 
setDataCapacityAtLeast(int newCapacity)1129     public void setDataCapacityAtLeast(int newCapacity) {
1130       // NOTE: Oddly, Parcel only every increases data capacity, and never decreases it, so this
1131       // really should have never been named setDataCapacity.
1132       if (newCapacity > data.length) {
1133         FakeEncodedItem[] newData = new FakeEncodedItem[newCapacity];
1134         dataSize = Math.min(dataSize, newCapacity);
1135         dataPosition = Math.min(dataPosition, dataSize);
1136         System.arraycopy(data, 0, newData, 0, dataSize);
1137         data = newData;
1138       }
1139     }
1140 
1141     /** Rounds to next 4-byte bounder similar to native Parcel. */
alignToInt(int unpaddedSizeBytes)1142     private int alignToInt(int unpaddedSizeBytes) {
1143       return ((unpaddedSizeBytes + 3) / 4) * 4;
1144     }
1145 
1146     /**
1147      * Ensures that the next sizeBytes are all the initial value we read.
1148      *
1149      * <p>This detects:
1150      *
1151      * <ul>
1152      *   <li>Reading an item, but not starting at its start position
1153      *   <li>Reading items that were truncated by setSize
1154      *   <li>Reading items that were partially overwritten by another
1155      * </ul>
1156      */
checkConsistentReadAndIncrementPosition(Class<?> clazz, FakeEncodedItem item)1157     private void checkConsistentReadAndIncrementPosition(Class<?> clazz, FakeEncodedItem item) {
1158       int endPosition = dataPosition + item.sizeBytes;
1159       for (int i = dataPosition; i < endPosition; i++) {
1160         FakeEncodedItem foundItemItem = i < dataSize ? data[i] : null;
1161         if (foundItemItem != item) {
1162           throw new UnreliableBehaviorError(
1163               clazz,
1164               dataPosition,
1165               item,
1166               String.format(
1167                   Locale.US,
1168                   "but [%s] interrupts it at position %d",
1169                   foundItemItem == null
1170                       ? "uninitialized data or the end of the buffer"
1171                       : foundItemItem.value,
1172                   i));
1173         }
1174       }
1175       dataPosition = Math.min(dataSize, dataPosition + item.sizeBytes);
1176     }
1177 
1178     /** Returns the item at the current position, or null if uninitialized or null. */
1179     private Object peek() {
1180       return dataPosition < dataSize && data[dataPosition] != null
1181           ? data[dataPosition].value
1182           : null;
1183     }
1184 
1185     /**
1186      * Reads a complete item in the byte buffer.
1187      *
1188      * @param clazz this is the type that is being read, but not checked in this method
1189      * @return null if the default value should be returned, otherwise the item holding the data
1190      */
1191     private <T> FakeEncodedItem readNextItem(Class<T> clazz) {
1192       FakeEncodedItem item = data[dataPosition];
1193       if (item == null) {
1194         // While Parcel will treat these as zeros, in tests, this is almost always an error.
1195         throw new UnreliableBehaviorError("Reading uninitialized data at position " + dataPosition);
1196       }
1197       checkConsistentReadAndIncrementPosition(clazz, item);
1198       return item;
1199     }
1200 
1201     /**
1202      * Reads the next value in the byte buffer of a specified type.
1203      *
1204      * @param pastEndValue value to return when reading past the end of the buffer
1205      * @param clazz this is the type that is being read, but not checked in this method
1206      * @param allowNull whether null values are permitted
1207      */
1208     private <T> T readValue(T pastEndValue, Class<T> clazz, boolean allowNull) {
1209       if (dataPosition >= dataSize) {
1210         // Normally, reading past the end is permitted, and returns the default values.  However,
1211         // writing to a parcel then reading without setting the position back to 0 is an incredibly
1212         // common error to make in tests, and should never really happen in production code, so
1213         // this shadow will fail in this condition.
1214         if (failNextReadIfPastEnd) {
1215           throw new UnreliableBehaviorError(
1216               "Did you forget to setDataPosition(0) before reading the parcel?");
1217         }
1218         return pastEndValue;
1219       }
1220       int startPosition = dataPosition;
1221       FakeEncodedItem item = readNextItem(clazz);
1222       if (item == null) {
1223         return pastEndValue;
1224       } else if (item.value == null && allowNull) {
1225         return null;
1226       } else if (clazz.isInstance(item.value)) {
1227         return clazz.cast(item.value);
1228       } else {
1229         // Numerous existing tests rely on ShadowParcel throwing RuntimeException and catching
1230         // them.  Many of these tests are trying to test what happens when an invalid Parcel is
1231         // provided.  However, Android has no concept of an "invalid parcel" because Parcel will
1232         // happily return garbage if you ask for it.  The only runtime exceptions are thrown on
1233         // array length mismatches, or higher-level APIs like Parcelable (which has its own safety
1234         // checks).  Tests trying to test error-handling behavior should instead craft a Parcel
1235         // that specifically triggers a BadParcelableException.
1236         throw new RuntimeException(
1237             new UnreliableBehaviorError(
1238                 clazz, startPosition, item, "and it is non-portable to reinterpret it"));
1239       }
1240     }
1241 
1242     /**
1243      * Determines if there is a sequence of castable zeroes, and consumes them.
1244      *
1245      * <p>This is the only exception for strong typing, because zero bytes are portable and
1246      * unambiguous. There are a few situations where well-written code can rely on this, so it is
1247      * worthwhile making a special exception for. This tolerates partially-overwritten and truncated
1248      * values if all bytes are zero.
1249      */
1250     private boolean readZeroes(int bytes) {
1251       int endPosition = dataPosition + bytes;
1252       if (endPosition > dataSize) {
1253         return false;
1254       }
1255       for (int i = dataPosition; i < endPosition; i++) {
1256         if (data[i] == null || !data[i].isEncodedAsAllZeroBytes) {
1257           return false;
1258         }
1259       }
1260       // Note in this case we short-circuit other verification -- even if we are reading weirdly
1261       // clobbered zeroes, they're still zeroes.  Future reads might fail, though.
1262       dataPosition = endPosition;
1263       return true;
1264     }
1265 
1266     /**
1267      * Reads a primitive, which may reinterpret zeros of other types.
1268      *
1269      * @param defaultSizeBytes if reinterpreting zeros, the number of bytes to consume
1270      * @param defaultValue the default value for zeros or reading past the end
1271      * @param clazz this is the type that is being read, but not checked in this method
1272      */
readPrimitive(int defaultSizeBytes, T defaultValue, Class<T> clazz)1273     private <T> T readPrimitive(int defaultSizeBytes, T defaultValue, Class<T> clazz) {
1274       // Check for zeroes first, since partially-overwritten values are not an error for zeroes.
1275       if (readZeroes(defaultSizeBytes)) {
1276         return defaultValue;
1277       }
1278       return readValue(defaultValue, clazz, /* allowNull= */ false);
1279     }
1280 
1281     /** Writes an encoded item directly, bypassing alignment, and possibly repeating an item. */
writeItem(FakeEncodedItem item)1282     private void writeItem(FakeEncodedItem item) {
1283       int endPosition = dataPosition + item.sizeBytes;
1284       if (endPosition > data.length) {
1285         // Parcel grows by 3/2 of the new size.
1286         setDataCapacityAtLeast(endPosition * 3 / 2);
1287       }
1288       if (endPosition > dataSize) {
1289         failNextReadIfPastEnd = true;
1290         dataSize = endPosition;
1291       }
1292       Arrays.fill(data, dataPosition, endPosition, item);
1293       dataPosition = endPosition;
1294     }
1295 
1296     /**
1297      * Writes a value to the next range of bytes.
1298      *
1299      * <p>Writes are aligned to 4-byte regions.
1300      */
writeValue(int unpaddedSizeBytes, Object o)1301     private void writeValue(int unpaddedSizeBytes, Object o) {
1302       // Create the item with its final, aligned byte size.
1303       writeItem(new FakeEncodedItem(alignToInt(unpaddedSizeBytes), o));
1304     }
1305   }
1306 
1307   @Implementation(maxSdk = P)
openFileDescriptor(String file, int mode)1308   protected static FileDescriptor openFileDescriptor(String file, int mode) throws IOException {
1309     RandomAccessFile randomAccessFile =
1310         new RandomAccessFile(file, mode == ParcelFileDescriptor.MODE_READ_ONLY ? "r" : "rw");
1311     return randomAccessFile.getFD();
1312   }
1313 
1314   @Implementation(minSdk = M, maxSdk = R)
nativeWriteFileDescriptor(long nativePtr, FileDescriptor val)1315   protected static long nativeWriteFileDescriptor(long nativePtr, FileDescriptor val) {
1316     // The Java version of FileDescriptor stored the fd in a field called "fd", and the Android
1317     // version changed the field name to "descriptor". But it looks like Robolectric uses the
1318     // Java version of FileDescriptor instead of the Android version.
1319     int fd = ReflectionHelpers.getField(val, "fd");
1320     NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).writeInt(fd);
1321     return (long) nativeDataPosition(nativePtr);
1322   }
1323 
1324   @Implementation(minSdk = M)
nativeReadFileDescriptor(long nativePtr)1325   protected static FileDescriptor nativeReadFileDescriptor(long nativePtr) {
1326     int fd = NATIVE_BYTE_BUFFER_REGISTRY.getNativeObject(nativePtr).readInt();
1327     return ReflectionHelpers.callConstructor(
1328         FileDescriptor.class, ClassParameter.from(int.class, fd));
1329   }
1330 
1331   @Implementation(minSdk = R)
nativeWriteString8(long nativePtr, String val)1332   protected static void nativeWriteString8(long nativePtr, String val) {
1333     nativeWriteString(nativePtr, val);
1334   }
1335 
1336   @Implementation(minSdk = R)
nativeWriteString16(long nativePtr, String val)1337   protected static void nativeWriteString16(long nativePtr, String val) {
1338     nativeWriteString(nativePtr, val);
1339   }
1340 
1341   @Implementation(minSdk = R)
nativeReadString8(long nativePtr)1342   protected static String nativeReadString8(long nativePtr) {
1343     return nativeReadString(nativePtr);
1344   }
1345 
1346   @Implementation(minSdk = R)
nativeReadString16(long nativePtr)1347   protected static String nativeReadString16(long nativePtr) {
1348     return nativeReadString(nativePtr);
1349   }
1350 
1351   // need to use looseSignatures for the S methods because method signatures differ only by return
1352   // type
1353   @Implementation(minSdk = S)
nativeWriteInt(Object nativePtr, Object val)1354   protected static int nativeWriteInt(Object nativePtr, Object val) {
1355     nativeWriteInt((long) nativePtr, (int) val);
1356     return 0; /* OK */
1357   }
1358 
1359   @Implementation(minSdk = S)
nativeWriteLong(Object nativePtr, Object val)1360   protected static int nativeWriteLong(Object nativePtr, Object val) {
1361     nativeWriteLong((long) nativePtr, (long) val);
1362     return 0; /* OK */
1363   }
1364 
1365   @Implementation(minSdk = S)
nativeWriteFloat(Object nativePtr, Object val)1366   protected static int nativeWriteFloat(Object nativePtr, Object val) {
1367     nativeWriteFloat((long) nativePtr, (float) val);
1368     return 0; /* OK */
1369   }
1370 
1371   @Implementation(minSdk = S)
nativeWriteDouble(Object nativePtr, Object val)1372   protected static int nativeWriteDouble(Object nativePtr, Object val) {
1373     nativeWriteDouble((long) nativePtr, (double) val);
1374     return 0; /* OK */
1375   }
1376 
1377   @Implementation(minSdk = S)
nativeWriteFileDescriptor(Object nativePtr, Object val)1378   protected static void nativeWriteFileDescriptor(Object nativePtr, Object val) {
1379     nativeWriteFileDescriptor((long) nativePtr, (FileDescriptor) val);
1380   }
1381 
1382   @Resetter
reset()1383   public static void reset() {
1384     pairedCreators.clear();
1385   }
1386 }
1387