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