Home | History | Annotate | Download | only in utils
      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
     59         public void onBeforeInvocation(Method m, Object[] args) {
     60         }
     61 
     62         @Override
     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
    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
    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      */
    152     public static <T> T newInstance(T obj) {
    153         return Decorator.<T> newInstance(obj, new CameraBinderDecoratorListener());
    154     }
    155 }
    156