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