13c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin/*
23c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * Copyright (C) 2014 The Android Open Source Project
33c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin *
43c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * Licensed under the Apache License, Version 2.0 (the "License");
53c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * you may not use this file except in compliance with the License.
63c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * You may obtain a copy of the License at
73c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin *
83c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin *      http://www.apache.org/licenses/LICENSE-2.0
93c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin *
103c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * Unless required by applicable law or agreed to in writing, software
113c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * distributed under the License is distributed on an "AS IS" BASIS,
123c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * See the License for the specific language governing permissions and
143c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * limitations under the License.
153c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin */
163c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinpackage android.hardware.camera2.marshal.impl;
173c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
183c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.hardware.camera2.marshal.Marshaler;
193c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.hardware.camera2.marshal.MarshalQueryable;
203c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.hardware.camera2.utils.TypeReference;
213c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.os.Parcel;
223c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.os.Parcelable;
233c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.util.Log;
243c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
253c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport java.lang.reflect.Field;
263c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport java.nio.ByteBuffer;
273c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
283c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin/**
293c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * Marshal any {@code T extends Parcelable} to/from any native type
303c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin *
313c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * <p>Use with extreme caution! File descriptors and binders will not be marshaled across.</p>
323c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin */
333c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinpublic class MarshalQueryableParcelable<T extends Parcelable>
343c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        implements MarshalQueryable<T> {
353c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
363c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    private static final String TAG = "MarshalParcelable";
37a78791f22af6c6985d186494737468bb19b69540Eino-Ville Talvala    private static final boolean DEBUG = false;
383c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
393c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    private static final String FIELD_CREATOR = "CREATOR";
403c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
413c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    private class MarshalerParcelable extends Marshaler<T> {
423c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
433c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        private final Class<T> mClass;
443c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        private final Parcelable.Creator<T> mCreator;
453c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
463c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        @SuppressWarnings("unchecked")
473c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        protected MarshalerParcelable(TypeReference<T> typeReference,
483c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                int nativeType) {
493c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            super(MarshalQueryableParcelable.this, typeReference, nativeType);
503c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
513c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            mClass = (Class<T>)typeReference.getRawType();
523c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            Field creatorField;
533c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            try {
543c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                creatorField = mClass.getDeclaredField(FIELD_CREATOR);
553c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            } catch (NoSuchFieldException e) {
563c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                // Impossible. All Parcelable implementations must have a 'CREATOR' static field
573c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                throw new AssertionError(e);
583c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            }
593c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
603c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            try {
613c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                mCreator = (Parcelable.Creator<T>)creatorField.get(null);
623c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            } catch (IllegalAccessException e) {
633c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                // Impossible: All 'CREATOR' static fields must be public
643c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                throw new AssertionError(e);
653c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            } catch (IllegalArgumentException e) {
663c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                // Impossible: This is a static field, so null must be ok
673c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                throw new AssertionError(e);
683c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            }
693c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        }
703c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
713c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        @Override
723c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        public void marshal(T value, ByteBuffer buffer) {
73a78791f22af6c6985d186494737468bb19b69540Eino-Ville Talvala            if (DEBUG) {
743c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                Log.v(TAG, "marshal " + value);
753c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            }
763c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
773c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            Parcel parcel = Parcel.obtain();
783c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            byte[] parcelContents;
793c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
803c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            try {
813c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                value.writeToParcel(parcel, /*flags*/0);
823c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
833c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                if (parcel.hasFileDescriptors()) {
843c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                    throw new UnsupportedOperationException(
853c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                            "Parcelable " + value + " must not have file descriptors");
863c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                }
873c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
883c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                parcelContents = parcel.marshall();
893c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            }
903c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            finally {
913c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                parcel.recycle();
923c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            }
933c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
943c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            if (parcelContents.length == 0) {
953c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                throw new AssertionError("No data marshaled for " + value);
963c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            }
973c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
983c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            buffer.put(parcelContents);
993c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        }
1003c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1013c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        @Override
1023c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        public T unmarshal(ByteBuffer buffer) {
103a78791f22af6c6985d186494737468bb19b69540Eino-Ville Talvala            if (DEBUG) {
1043c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                Log.v(TAG, "unmarshal, buffer remaining " + buffer.remaining());
1053c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            }
1063c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1073c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            /*
1083c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin             * Quadratically slow when marshaling an array of parcelables.
1093c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin             *
1103c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin             * Read out the entire byte buffer as an array, then copy it into the parcel.
1113c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin             *
1123c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin             * Once we unparcel the entire object, advance the byte buffer by only how many
1133c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin             * bytes the parcel actually used up.
1143c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin             *
1153c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin             * Future: If we ever do need to use parcelable arrays, we can do this a little smarter
1163c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin             * by reading out a chunk like 4,8,16,24 each time, but not sure how to detect
1173c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin             * parcels being too short in this case.
1183c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin             *
1193c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin             * Future: Alternatively use Parcel#obtain(long) directly into the native
1203c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin             * pointer of a ByteBuffer, which would not copy if the ByteBuffer was direct.
1213c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin             */
1223c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            buffer.mark();
1233c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1243c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            Parcel parcel = Parcel.obtain();
1253c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            try {
1263c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                int maxLength = buffer.remaining();
1273c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1283c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                byte[] remaining = new byte[maxLength];
1293c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                buffer.get(remaining);
1303c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1313c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                parcel.unmarshall(remaining, /*offset*/0, maxLength);
1323c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                parcel.setDataPosition(/*pos*/0);
1333c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1343c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                T value = mCreator.createFromParcel(parcel);
1353c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                int actualLength = parcel.dataPosition();
1363c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1373c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                if (actualLength == 0) {
1383c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                    throw new AssertionError("No data marshaled for " + value);
1393c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                }
1403c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1413c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                // set the position past the bytes the parcelable actually used
1423c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                buffer.reset();
1433c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                buffer.position(buffer.position() + actualLength);
1443c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
145a78791f22af6c6985d186494737468bb19b69540Eino-Ville Talvala                if (DEBUG) {
1463c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                    Log.v(TAG, "unmarshal, parcel length was " + actualLength);
1473c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                    Log.v(TAG, "unmarshal, value is " + value);
1483c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                }
1493c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1503c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                return mClass.cast(value);
1513c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            } finally {
1523c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                parcel.recycle();
1533c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            }
1543c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        }
1553c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1563c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        @Override
1573c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        public int getNativeSize() {
1583c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            return NATIVE_SIZE_DYNAMIC;
1593c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        }
1603c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1613c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        @Override
1623c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        public int calculateMarshalSize(T value) {
1633c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            Parcel parcel = Parcel.obtain();
1643c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            try {
1653c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                value.writeToParcel(parcel, /*flags*/0);
1663c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                int length = parcel.marshall().length;
1673c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
168a78791f22af6c6985d186494737468bb19b69540Eino-Ville Talvala                if (DEBUG) {
1693c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                    Log.v(TAG, "calculateMarshalSize, length when parceling "
1703c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                            + value + " is " + length);
1713c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                }
1723c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1733c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                return length;
1743c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            } finally {
1753c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                parcel.recycle();
1763c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            }
1773c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        }
1783c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    }
1793c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1803c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    @Override
1813c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
1823c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        return new MarshalerParcelable(managedType, nativeType);
1833c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    }
1843c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1853c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    @Override
1863c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
1873c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        return Parcelable.class.isAssignableFrom(managedType.getRawType());
1883c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    }
1893c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1903c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin}
191