diff options
| author | 2015-02-04 17:26:17 -0800 | |
|---|---|---|
| committer | 2015-02-04 17:26:17 -0800 | |
| commit | e3c0434d9741c78ef0405de3e9f4d16b6a8ef360 (patch) | |
| tree | 5f46788ec2b1716339f0ab165294515b9452df5f | |
| parent | d7310bd1499c0b48594a8fbbcbe0c7e80c1e5832 (diff) | |
camera2: Make legacy error handling more robust.
- Relax internal timeout for JPEG captures in LEGACY mode.
- Make RequestThreadManager.quit() idempotent to avoid queuing
  messages on a dead thread's handler.
- Catch RuntimeExceptions from other Camera1 API methods to
  allow proper cleanup + release of Camera1 API client.
Bug: 19255187
Change-Id: I6cb08bb6b832b0d0df6ee6e8983c35de2df4a408
| -rw-r--r-- | core/java/android/hardware/camera2/legacy/RequestThreadManager.java | 60 | 
1 files changed, 46 insertions, 14 deletions
| diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java index 6535a4e77ac1..f1f2f0c466c4 100644 --- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java +++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java @@ -44,6 +44,7 @@ import java.util.Collections;  import java.util.Iterator;  import java.util.List;  import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean;  import static com.android.internal.util.Preconditions.*; @@ -68,7 +69,7 @@ public class RequestThreadManager {      // For slightly more spammy messages that will get repeated every frame      private static final boolean VERBOSE =              Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.VERBOSE); -    private final Camera mCamera; +    private Camera mCamera;      private final CameraCharacteristics mCharacteristics;      private final CameraDeviceState mDeviceState; @@ -83,8 +84,8 @@ public class RequestThreadManager {      private static final int MAX_IN_FLIGHT_REQUESTS = 2;      private static final int PREVIEW_FRAME_TIMEOUT = 1000; // ms -    private static final int JPEG_FRAME_TIMEOUT = 3000; // ms (same as CTS for API2) -    private static final int REQUEST_COMPLETE_TIMEOUT = 3000; // ms (same as JPEG timeout) +    private static final int JPEG_FRAME_TIMEOUT = 4000; // ms (same as CTS for API2) +    private static final int REQUEST_COMPLETE_TIMEOUT = JPEG_FRAME_TIMEOUT; // ms (same as JPEG timeout)      private static final float ASPECT_RATIO_TOLERANCE = 0.01f;      private boolean mPreviewRunning = false; @@ -108,6 +109,8 @@ public class RequestThreadManager {      private final FpsCounter mPrevCounter = new FpsCounter("Incoming Preview");      private final FpsCounter mRequestCounter = new FpsCounter("Incoming Requests"); +    private final AtomicBoolean mQuit = new AtomicBoolean(false); +      // Stuff JPEGs into HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers to get around SW write      // limitations for (b/17379185).      private static final boolean USE_BLOB_FORMAT_OVERRIDE = true; @@ -325,7 +328,15 @@ public class RequestThreadManager {              Log.d(TAG, "configureOutputs with " + outputsStr);          } -        stopPreview(); +        try { +            stopPreview(); +        }  catch (RuntimeException e) { +            Log.e(TAG, "Received device exception in configure call: ", e); +            mDeviceState.setError( +                    CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE); +            return; +        } +          /*           * Try to release the previous preview's surface texture earlier if we end up           * using a different one; this also reduces the likelihood of getting into a deadlock @@ -335,6 +346,11 @@ public class RequestThreadManager {              mCamera.setPreviewTexture(/*surfaceTexture*/null);          } catch (IOException e) {              Log.w(TAG, "Failed to clear prior SurfaceTexture, may cause GL deadlock: ", e); +        } catch (RuntimeException e) { +            Log.e(TAG, "Received device exception in configure call: ", e); +            mDeviceState.setError( +                    CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE); +            return;          }          if (mGLThreadManager != null) { @@ -470,7 +486,14 @@ public class RequestThreadManager {              mPreviewTexture.setOnFrameAvailableListener(mPreviewCallback);          } -        mCamera.setParameters(mParams); +        try { +            mCamera.setParameters(mParams); +        } catch (RuntimeException e) { +                Log.e(TAG, "Received device exception while configuring: ", e); +                mDeviceState.setError( +                        CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE); + +        }      }      private void resetJpegSurfaceFormats(Collection<Surface> surfaces) { @@ -793,7 +816,7 @@ public class RequestThreadManager {                              }                          } catch (IOException e) { -                            Log.e(TAG, "Received device exception: ", e); +                            Log.e(TAG, "Received device exception during capture call: ", e);                              mDeviceState.setError(                                      CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);                              break; @@ -802,6 +825,11 @@ public class RequestThreadManager {                              mDeviceState.setError(                                      CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);                              break; +                        } catch (RuntimeException e) { +                            Log.e(TAG, "Received device exception during capture call: ", e); +                            mDeviceState.setError( +                                    CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE); +                            break;                          }                          if (paramsChanged) { @@ -878,9 +906,11 @@ public class RequestThreadManager {                      }                      if (mGLThreadManager != null) {                          mGLThreadManager.quit(); +                        mGLThreadManager = null;                      }                      if (mCamera != null) {                          mCamera.release(); +                        mCamera = null;                      }                      resetJpegSurfaceFormats(mCallbackOutputs);                      break; @@ -942,14 +972,16 @@ public class RequestThreadManager {       * Quit the request thread, and clean up everything.       */      public void quit() { -        Handler handler = mRequestThread.waitAndGetHandler(); -        handler.sendMessageAtFrontOfQueue(handler.obtainMessage(MSG_CLEANUP)); -        mRequestThread.quitSafely(); -        try { -            mRequestThread.join(); -        } catch (InterruptedException e) { -            Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.", -                    mRequestThread.getName(), mRequestThread.getId())); +        if (!mQuit.getAndSet(true)) {  // Avoid sending messages on dead thread's handler. +            Handler handler = mRequestThread.waitAndGetHandler(); +            handler.sendMessageAtFrontOfQueue(handler.obtainMessage(MSG_CLEANUP)); +            mRequestThread.quitSafely(); +            try { +                mRequestThread.join(); +            } catch (InterruptedException e) { +                Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.", +                        mRequestThread.getName(), mRequestThread.getId())); +            }          }      } |