Merge "Improve exception handling in SoundTrigger"
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index 456ebf2..1932f46 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -34,6 +34,7 @@
 import android.media.AudioFormat;
 import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
+import android.media.soundtrigger_middleware.Status;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -41,6 +42,7 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 
 import java.lang.annotation.Retention;
@@ -1676,6 +1678,45 @@
     }
 
     /**
+     * Translate an exception thrown from interaction with the underlying service to an error code.
+     * Throws a runtime exception for unexpected conditions.
+     * @param e The caught exception.
+     * @return The error code.
+     *
+     * @hide
+     */
+    static int handleException(Exception e) {
+        Log.w(TAG, "Exception caught", e);
+        if (e instanceof RemoteException) {
+            return STATUS_DEAD_OBJECT;
+        }
+        if (e instanceof ServiceSpecificException) {
+            switch (((ServiceSpecificException) e).errorCode) {
+                case Status.OPERATION_NOT_SUPPORTED:
+                    return STATUS_INVALID_OPERATION;
+                case Status.TEMPORARY_PERMISSION_DENIED:
+                    return STATUS_PERMISSION_DENIED;
+                case Status.DEAD_OBJECT:
+                    return STATUS_DEAD_OBJECT;
+            }
+            return STATUS_ERROR;
+        }
+        if (e instanceof SecurityException) {
+            return STATUS_PERMISSION_DENIED;
+        }
+        if (e instanceof IllegalStateException) {
+            return STATUS_INVALID_OPERATION;
+        }
+        if (e instanceof IllegalArgumentException || e instanceof NullPointerException) {
+            return STATUS_BAD_VALUE;
+        }
+        // This is not one of the conditions represented by our error code, escalate to a
+        // RuntimeException.
+        Log.e(TAG, "Escalating unexpected exception: ", e);
+        throw new RuntimeException(e);
+    }
+
+    /**
      * Returns a list of descriptors for all hardware modules loaded.
      * @param modules A ModuleProperties array where the list will be returned.
      * @return - {@link #STATUS_OK} in case of success
@@ -1697,9 +1738,8 @@
                 modules.add(ConversionUtil.aidl2apiModuleDescriptor(desc));
             }
             return STATUS_OK;
-        } catch (RemoteException e) {
-            Log.e(TAG, "Exception caught", e);
-            return STATUS_DEAD_OBJECT;
+        } catch (Exception e) {
+            return handleException(e);
         }
     }
 
diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
index 03d29a3..9bd3992 100644
--- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
+++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
@@ -78,7 +78,7 @@
                 mService = null;
             }
         } catch (Exception e) {
-            handleException(e);
+            SoundTrigger.handleException(e);
         }
     }
 
@@ -115,7 +115,7 @@
             }
             return SoundTrigger.STATUS_BAD_VALUE;
         } catch (Exception e) {
-            return handleException(e);
+            return SoundTrigger.handleException(e);
         }
     }
 
@@ -137,7 +137,7 @@
             mService.unloadModel(soundModelHandle);
             return SoundTrigger.STATUS_OK;
         } catch (Exception e) {
-            return handleException(e);
+            return SoundTrigger.handleException(e);
         }
     }
 
@@ -166,7 +166,7 @@
                     ConversionUtil.api2aidlRecognitionConfig(config));
             return SoundTrigger.STATUS_OK;
         } catch (Exception e) {
-            return handleException(e);
+            return SoundTrigger.handleException(e);
         }
     }
 
@@ -189,7 +189,7 @@
             mService.stopRecognition(soundModelHandle);
             return SoundTrigger.STATUS_OK;
         } catch (Exception e) {
-            return handleException(e);
+            return SoundTrigger.handleException(e);
         }
     }
 
@@ -214,7 +214,7 @@
             mService.forceRecognitionEvent(soundModelHandle);
             return SoundTrigger.STATUS_OK;
         } catch (Exception e) {
-            return handleException(e);
+            return SoundTrigger.handleException(e);
         }
     }
 
@@ -242,7 +242,7 @@
                     ConversionUtil.api2aidlModelParameter(modelParam), value);
             return SoundTrigger.STATUS_OK;
         } catch (Exception e) {
-            return handleException(e);
+            return SoundTrigger.handleException(e);
         }
     }
 
@@ -296,23 +296,6 @@
         }
     }
 
-    private int handleException(Exception e) {
-        Log.e(TAG, "", e);
-        if (e instanceof NullPointerException) {
-            return SoundTrigger.STATUS_NO_INIT;
-        }
-        if (e instanceof RemoteException) {
-            return SoundTrigger.STATUS_DEAD_OBJECT;
-        }
-        if (e instanceof IllegalArgumentException) {
-            return SoundTrigger.STATUS_BAD_VALUE;
-        }
-        if (e instanceof IllegalStateException) {
-            return SoundTrigger.STATUS_INVALID_OPERATION;
-        }
-        return SoundTrigger.STATUS_ERROR;
-    }
-
     private class EventHandlerDelegate extends ISoundTriggerCallback.Stub implements
             IBinder.DeathRecipient {
         private final Handler mHandler;