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