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