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