Home | History | Annotate | Download | only in impl
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package android.hardware.camera2.marshal.impl;
     17 
     18 import android.hardware.camera2.marshal.Marshaler;
     19 import android.hardware.camera2.marshal.MarshalQueryable;
     20 import android.hardware.camera2.utils.TypeReference;
     21 import android.os.Parcel;
     22 import android.os.Parcelable;
     23 import android.util.Log;
     24 
     25 import java.lang.reflect.Field;
     26 import java.nio.ByteBuffer;
     27 
     28 /**
     29  * Marshal any {@code T extends Parcelable} to/from any native type
     30  *
     31  * <p>Use with extreme caution! File descriptors and binders will not be marshaled across.</p>
     32  */
     33 public class MarshalQueryableParcelable<T extends Parcelable>
     34         implements MarshalQueryable<T> {
     35 
     36     private static final String TAG = "MarshalParcelable";
     37     private static final boolean DEBUG = false;
     38 
     39     private static final String FIELD_CREATOR = "CREATOR";
     40 
     41     private class MarshalerParcelable extends Marshaler<T> {
     42 
     43         private final Class<T> mClass;
     44         private final Parcelable.Creator<T> mCreator;
     45 
     46         @SuppressWarnings("unchecked")
     47         protected MarshalerParcelable(TypeReference<T> typeReference,
     48                 int nativeType) {
     49             super(MarshalQueryableParcelable.this, typeReference, nativeType);
     50 
     51             mClass = (Class<T>)typeReference.getRawType();
     52             Field creatorField;
     53             try {
     54                 creatorField = mClass.getDeclaredField(FIELD_CREATOR);
     55             } catch (NoSuchFieldException e) {
     56                 // Impossible. All Parcelable implementations must have a 'CREATOR' static field
     57                 throw new AssertionError(e);
     58             }
     59 
     60             try {
     61                 mCreator = (Parcelable.Creator<T>)creatorField.get(null);
     62             } catch (IllegalAccessException e) {
     63                 // Impossible: All 'CREATOR' static fields must be public
     64                 throw new AssertionError(e);
     65             } catch (IllegalArgumentException e) {
     66                 // Impossible: This is a static field, so null must be ok
     67                 throw new AssertionError(e);
     68             }
     69         }
     70 
     71         @Override
     72         public void marshal(T value, ByteBuffer buffer) {
     73             if (DEBUG) {
     74                 Log.v(TAG, "marshal " + value);
     75             }
     76 
     77             Parcel parcel = Parcel.obtain();
     78             byte[] parcelContents;
     79 
     80             try {
     81                 value.writeToParcel(parcel, /*flags*/0);
     82 
     83                 if (parcel.hasFileDescriptors()) {
     84                     throw new UnsupportedOperationException(
     85                             "Parcelable " + value + " must not have file descriptors");
     86                 }
     87 
     88                 parcelContents = parcel.marshall();
     89             }
     90             finally {
     91                 parcel.recycle();
     92             }
     93 
     94             if (parcelContents.length == 0) {
     95                 throw new AssertionError("No data marshaled for " + value);
     96             }
     97 
     98             buffer.put(parcelContents);
     99         }
    100 
    101         @Override
    102         public T unmarshal(ByteBuffer buffer) {
    103             if (DEBUG) {
    104                 Log.v(TAG, "unmarshal, buffer remaining " + buffer.remaining());
    105             }
    106 
    107             /*
    108              * Quadratically slow when marshaling an array of parcelables.
    109              *
    110              * Read out the entire byte buffer as an array, then copy it into the parcel.
    111              *
    112              * Once we unparcel the entire object, advance the byte buffer by only how many
    113              * bytes the parcel actually used up.
    114              *
    115              * Future: If we ever do need to use parcelable arrays, we can do this a little smarter
    116              * by reading out a chunk like 4,8,16,24 each time, but not sure how to detect
    117              * parcels being too short in this case.
    118              *
    119              * Future: Alternatively use Parcel#obtain(long) directly into the native
    120              * pointer of a ByteBuffer, which would not copy if the ByteBuffer was direct.
    121              */
    122             buffer.mark();
    123 
    124             Parcel parcel = Parcel.obtain();
    125             try {
    126                 int maxLength = buffer.remaining();
    127 
    128                 byte[] remaining = new byte[maxLength];
    129                 buffer.get(remaining);
    130 
    131                 parcel.unmarshall(remaining, /*offset*/0, maxLength);
    132                 parcel.setDataPosition(/*pos*/0);
    133 
    134                 T value = mCreator.createFromParcel(parcel);
    135                 int actualLength = parcel.dataPosition();
    136 
    137                 if (actualLength == 0) {
    138                     throw new AssertionError("No data marshaled for " + value);
    139                 }
    140 
    141                 // set the position past the bytes the parcelable actually used
    142                 buffer.reset();
    143                 buffer.position(buffer.position() + actualLength);
    144 
    145                 if (DEBUG) {
    146                     Log.v(TAG, "unmarshal, parcel length was " + actualLength);
    147                     Log.v(TAG, "unmarshal, value is " + value);
    148                 }
    149 
    150                 return mClass.cast(value);
    151             } finally {
    152                 parcel.recycle();
    153             }
    154         }
    155 
    156         @Override
    157         public int getNativeSize() {
    158             return NATIVE_SIZE_DYNAMIC;
    159         }
    160 
    161         @Override
    162         public int calculateMarshalSize(T value) {
    163             Parcel parcel = Parcel.obtain();
    164             try {
    165                 value.writeToParcel(parcel, /*flags*/0);
    166                 int length = parcel.marshall().length;
    167 
    168                 if (DEBUG) {
    169                     Log.v(TAG, "calculateMarshalSize, length when parceling "
    170                             + value + " is " + length);
    171                 }
    172 
    173                 return length;
    174             } finally {
    175                 parcel.recycle();
    176             }
    177         }
    178     }
    179 
    180     @Override
    181     public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
    182         return new MarshalerParcelable(managedType, nativeType);
    183     }
    184 
    185     @Override
    186     public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
    187         return Parcelable.class.isAssignableFrom(managedType.getRawType());
    188     }
    189 
    190 }
    191