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