CameraBinderDecorator.java revision 9bd5f1e6dff31e2299c065157ba3a43bc79a9d48
1/*
2 * Copyright (C) 2013 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
17package android.hardware.camera2.utils;
18
19import static android.hardware.camera2.CameraAccessException.CAMERA_DISABLED;
20import static android.hardware.camera2.CameraAccessException.CAMERA_DISCONNECTED;
21import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
22import static android.hardware.camera2.CameraAccessException.MAX_CAMERAS_IN_USE;
23import static android.hardware.camera2.CameraAccessException.CAMERA_DEPRECATED_HAL;
24
25import android.os.DeadObjectException;
26import android.os.RemoteException;
27
28import java.lang.reflect.Method;
29
30/**
31 * Translate camera service status_t return values into exceptions.
32 *
33 * @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance
34 * @hide
35 */
36public class CameraBinderDecorator {
37
38    public static final int NO_ERROR = 0;
39    public static final int PERMISSION_DENIED = -1;
40    public static final int ALREADY_EXISTS = -17;
41    public static final int BAD_VALUE = -22;
42    public static final int DEAD_OBJECT = -32;
43
44    /**
45     * TODO: add as error codes in Errors.h
46     * - POLICY_PROHIBITS
47     * - RESOURCE_BUSY
48     * - NO_SUCH_DEVICE
49     */
50    public static final int EACCES = -13;
51    public static final int EBUSY = -16;
52    public static final int ENODEV = -19;
53    public static final int EOPNOTSUPP = -95;
54    public static final int EUSERS = -87;
55
56    private static class CameraBinderDecoratorListener implements Decorator.DecoratorListener {
57
58        @Override
59        public void onBeforeInvocation(Method m, Object[] args) {
60        }
61
62        @Override
63        public void onAfterInvocation(Method m, Object[] args, Object result) {
64            // int return type => status_t => convert to exception
65            if (m.getReturnType() == Integer.TYPE) {
66                int returnValue = (Integer) result;
67
68                switch (returnValue) {
69                    case NO_ERROR:
70                        return;
71                    case PERMISSION_DENIED:
72                        throw new SecurityException("Lacking privileges to access camera service");
73                    case ALREADY_EXISTS:
74                        // This should be handled at the call site. Typically this isn't bad,
75                        // just means we tried to do an operation that already completed.
76                        return;
77                    case BAD_VALUE:
78                        throw new IllegalArgumentException("Bad argument passed to camera service");
79                    case DEAD_OBJECT:
80                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
81                                CAMERA_DISCONNECTED));
82                    case EACCES:
83                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
84                                CAMERA_DISABLED));
85                    case EBUSY:
86                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
87                                CAMERA_IN_USE));
88                    case EUSERS:
89                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
90                                MAX_CAMERAS_IN_USE));
91                    case ENODEV:
92                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
93                                CAMERA_DISCONNECTED));
94                    case EOPNOTSUPP:
95                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
96                                CAMERA_DEPRECATED_HAL));
97                }
98
99                /**
100                 * Trap the rest of the negative return values. If we have known
101                 * error codes i.e. ALREADY_EXISTS that aren't really runtime
102                 * errors, then add them to the top switch statement
103                 */
104                if (returnValue < 0) {
105                    throw new UnsupportedOperationException(String.format("Unknown error %d",
106                            returnValue));
107                }
108            }
109        }
110
111        @Override
112        public boolean onCatchException(Method m, Object[] args, Throwable t) {
113
114            if (t instanceof DeadObjectException) {
115                UncheckedThrow.throwAnyException(new CameraRuntimeException(
116                        CAMERA_DISCONNECTED,
117                        "Process hosting the camera service has died unexpectedly",
118                        t));
119            } else if (t instanceof RemoteException) {
120                throw new UnsupportedOperationException("An unknown RemoteException was thrown" +
121                        " which should never happen.", t);
122            }
123
124            return false;
125        }
126
127        @Override
128        public void onFinally(Method m, Object[] args) {
129        }
130
131    }
132
133    /**
134     * <p>
135     * Wraps the type T with a proxy that will check 'status_t' return codes
136     * from the native side of the camera service, and throw Java exceptions
137     * automatically based on the code.
138     * </p>
139     * <p>
140     * In addition it also rewrites binder's RemoteException into either a
141     * CameraAccessException or an UnsupportedOperationException.
142     * </p>
143     * <p>
144     * As a result of calling any method on the proxy, RemoteException is
145     * guaranteed never to be thrown.
146     * </p>
147     *
148     * @param obj object that will serve as the target for all method calls
149     * @param <T> the type of the element you want to wrap. This must be an interface.
150     * @return a proxy that will intercept all invocations to obj
151     */
152    public static <T> T newInstance(T obj) {
153        return Decorator.<T> newInstance(obj, new CameraBinderDecoratorListener());
154    }
155}
156