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 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 unmarshal(ByteBuffer buffer)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 getNativeSize()157 public int getNativeSize() { 158 return NATIVE_SIZE_DYNAMIC; 159 } 160 161 @Override calculateMarshalSize(T value)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 createMarshaler(TypeReference<T> managedType, int nativeType)181 public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) { 182 return new MarshalerParcelable(managedType, nativeType); 183 } 184 185 @Override isTypeMappingSupported(TypeReference<T> managedType, int nativeType)186 public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) { 187 return Parcelable.class.isAssignableFrom(managedType.getRawType()); 188 } 189 190 } 191