• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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