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 
17 package android.hardware.camera2.utils;
18 
19 import static android.hardware.camera2.CameraAccessException.CAMERA_DISABLED;
20 import static android.hardware.camera2.CameraAccessException.CAMERA_DISCONNECTED;
21 import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
22 import static android.hardware.camera2.CameraAccessException.CAMERA_ERROR;
23 import static android.hardware.camera2.CameraAccessException.MAX_CAMERAS_IN_USE;
24 import static android.hardware.camera2.CameraAccessException.CAMERA_DEPRECATED_HAL;
25 
26 import android.os.DeadObjectException;
27 import android.os.RemoteException;
28 
29 import java.lang.reflect.Method;
30 
31 /**
32  * Translate camera device status_t return values into exceptions.
33  *
34  * @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance
35  * @hide
36  */
37 public class CameraBinderDecorator {
38 
39     public static final int NO_ERROR = 0;
40     public static final int PERMISSION_DENIED = -1;
41     public static final int ALREADY_EXISTS = -17;
42     public static final int BAD_VALUE = -22;
43     public static final int DEAD_OBJECT = -32;
44     public static final int INVALID_OPERATION = -38;
45     public static final int TIMED_OUT = -110;
46 
47     /**
48      * TODO: add as error codes in Errors.h
49      * - POLICY_PROHIBITS
50      * - RESOURCE_BUSY
51      * - NO_SUCH_DEVICE
52      * - NOT_SUPPORTED
53      * - TOO_MANY_USERS
54      */
55     public static final int EACCES = -13;
56     public static final int EBUSY = -16;
57     public static final int ENODEV = -19;
58     public static final int EOPNOTSUPP = -95;
59     public static final int EUSERS = -87;
60 
61 
62     static class CameraBinderDecoratorListener implements Decorator.DecoratorListener {
63 
64         @Override
onBeforeInvocation(Method m, Object[] args)65         public void onBeforeInvocation(Method m, Object[] args) {
66         }
67 
68         @Override
onAfterInvocation(Method m, Object[] args, Object result)69         public void onAfterInvocation(Method m, Object[] args, Object result) {
70             // int return type => status_t => convert to exception
71             if (m.getReturnType() == Integer.TYPE) {
72                 int returnValue = (Integer) result;
73                 throwOnError(returnValue);
74             }
75         }
76 
77         @Override
onCatchException(Method m, Object[] args, Throwable t)78         public boolean onCatchException(Method m, Object[] args, Throwable t) {
79 
80             if (t instanceof DeadObjectException) {
81                 throw new CameraRuntimeException(CAMERA_DISCONNECTED,
82                         "Process hosting the camera service has died unexpectedly",
83                         t);
84             } else if (t instanceof RemoteException) {
85                 throw new UnsupportedOperationException("An unknown RemoteException was thrown" +
86                         " which should never happen.", t);
87             }
88 
89             return false;
90         }
91 
92         @Override
onFinally(Method m, Object[] args)93         public void onFinally(Method m, Object[] args) {
94         }
95 
96     }
97 
98     /**
99      * Throw error codes returned by the camera service as exceptions.
100      *
101      * @param errorFlag error to throw as an exception.
102      */
throwOnError(int errorFlag)103     public static void throwOnError(int errorFlag) {
104         switch (errorFlag) {
105             case NO_ERROR:
106                 return;
107             case PERMISSION_DENIED:
108                 throw new SecurityException("Lacking privileges to access camera service");
109             case ALREADY_EXISTS:
110                 // This should be handled at the call site. Typically this isn't bad,
111                 // just means we tried to do an operation that already completed.
112                 return;
113             case BAD_VALUE:
114                 throw new IllegalArgumentException("Bad argument passed to camera service");
115             case DEAD_OBJECT:
116                 throw new CameraRuntimeException(CAMERA_DISCONNECTED);
117             case TIMED_OUT:
118                 throw new CameraRuntimeException(CAMERA_ERROR,
119                         "Operation timed out in camera service");
120             case EACCES:
121                 throw new CameraRuntimeException(CAMERA_DISABLED);
122             case EBUSY:
123                 throw new CameraRuntimeException(CAMERA_IN_USE);
124             case EUSERS:
125                 throw new CameraRuntimeException(MAX_CAMERAS_IN_USE);
126             case ENODEV:
127                 throw new CameraRuntimeException(CAMERA_DISCONNECTED);
128             case EOPNOTSUPP:
129                 throw new CameraRuntimeException(CAMERA_DEPRECATED_HAL);
130             case INVALID_OPERATION:
131                 throw new CameraRuntimeException(CAMERA_ERROR,
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 CameraRuntimeException(CAMERA_ERROR,
142                     String.format("Unknown camera device error %d", 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      */
newInstance(T obj)165     public static <T> T newInstance(T obj) {
166         return Decorator.<T> newInstance(obj, new CameraBinderDecoratorListener());
167     }
168 }
169