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