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