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") MarshalerParcelable(TypeReference<T> typeReference, int nativeType)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 marshal(T value, ByteBuffer buffer)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 79 try { 80 value.writeToParcel(parcel, /*flags*/0); 81 82 if (parcel.hasFileDescriptors()) { 83 throw new UnsupportedOperationException( 84 "Parcelable " + value + " must not have file descriptors"); 85 } 86 87 final int position = buffer.position(); 88 parcel.marshall(buffer); 89 if (buffer.position() == position) { 90 throw new AssertionError("No data marshaled for " + value); 91 } 92 } 93 finally { 94 parcel.recycle(); 95 } 96 } 97 98 @Override unmarshal(ByteBuffer buffer)99 public T unmarshal(ByteBuffer buffer) { 100 if (DEBUG) { 101 Log.v(TAG, "unmarshal, buffer remaining " + buffer.remaining()); 102 } 103 104 /* 105 * Quadratically slow when marshaling an array of parcelables. 106 * 107 * Read out the entire byte buffer as an array, then copy it into the parcel. 108 * 109 * Once we unparcel the entire object, advance the byte buffer by only how many 110 * bytes the parcel actually used up. 111 * 112 * Future: If we ever do need to use parcelable arrays, we can do this a little smarter 113 * by reading out a chunk like 4,8,16,24 each time, but not sure how to detect 114 * parcels being too short in this case. 115 * 116 * Future: Alternatively use Parcel#obtain(long) directly into the native 117 * pointer of a ByteBuffer, which would not copy if the ByteBuffer was direct. 118 */ 119 buffer.mark(); 120 121 Parcel parcel = Parcel.obtain(); 122 try { 123 int maxLength = buffer.remaining(); 124 125 byte[] remaining = new byte[maxLength]; 126 buffer.get(remaining); 127 128 parcel.unmarshall(remaining, /*offset*/0, maxLength); 129 parcel.setDataPosition(/*pos*/0); 130 131 T value = mCreator.createFromParcel(parcel); 132 int actualLength = parcel.dataPosition(); 133 134 if (actualLength == 0) { 135 throw new AssertionError("No data marshaled for " + value); 136 } 137 138 // set the position past the bytes the parcelable actually used 139 buffer.reset(); 140 buffer.position(buffer.position() + actualLength); 141 142 if (DEBUG) { 143 Log.v(TAG, "unmarshal, parcel length was " + actualLength); 144 Log.v(TAG, "unmarshal, value is " + value); 145 } 146 147 return mClass.cast(value); 148 } finally { 149 parcel.recycle(); 150 } 151 } 152 153 @Override getNativeSize()154 public int getNativeSize() { 155 return NATIVE_SIZE_DYNAMIC; 156 } 157 158 @Override calculateMarshalSize(T value)159 public int calculateMarshalSize(T value) { 160 Parcel parcel = Parcel.obtain(); 161 try { 162 value.writeToParcel(parcel, /*flags*/0); 163 int length = parcel.marshall().length; 164 165 if (DEBUG) { 166 Log.v(TAG, "calculateMarshalSize, length when parceling " 167 + value + " is " + length); 168 } 169 170 return length; 171 } finally { 172 parcel.recycle(); 173 } 174 } 175 } 176 177 @Override createMarshaler(TypeReference<T> managedType, int nativeType)178 public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) { 179 return new MarshalerParcelable(managedType, nativeType); 180 } 181 182 @Override isTypeMappingSupported(TypeReference<T> managedType, int nativeType)183 public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) { 184 return Parcelable.class.isAssignableFrom(managedType.getRawType()); 185 } 186 187 } 188