1 /* 2 * Copyright (C) 2015 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 com.android.camera.one.v2.errorhandling; 18 19 import android.hardware.camera2.CaptureFailure; 20 import android.hardware.camera2.TotalCaptureResult; 21 22 import com.android.camera.debug.Log; 23 import com.android.camera.debug.Logger; 24 import com.android.camera.util.Callback; 25 26 import java.util.List; 27 28 import javax.annotation.ParametersAreNonnullByDefault; 29 30 /** 31 * Listens for repeated capture failure and invokes recovery strategies, 32 * in-order as the repeated failures continue. 33 * <p> 34 * Workaround for bug: 19061883 35 */ 36 @ParametersAreNonnullByDefault 37 final class RepeatFailureDetector extends com.android.camera.one.v2.core.ResponseListener { 38 private final Logger mLog; 39 private final int mConsecutiveFailureThreshold; 40 private final List<FailureHandler> mRecoveryStrategies; 41 private final Callback<String> mRecoverySuccessCallback; 42 /** 43 * Indicates the number of consecutive times repeat failure has been 44 * detected. 45 * <p> 46 * 0 indicates normal operation 47 * <p> 48 * Positive values also indicate the index of the recovery strategy which 49 * has been used. 50 */ 51 private int mFailureLevel; 52 /** 53 * The frame number of the failure which resulted in a recovery strategy 54 * being invoked. This is used to determine if a frame success corresponds 55 * to a frame from before or after the recovery strategy was run. 56 * <p> 57 * This 58 */ 59 private long mFailureFrameNumber; 60 /** 61 * The number of consecutive 62 */ 63 private int mConsecutiveErrorCount; 64 65 /** 66 * @param logFactory Used for logging. 67 * @param consecutiveFailureThreshold The number of consecutive failures to 68 * consider a "repeat failure". 69 * @param recoveryStrategies A list of strategies to try to recover from or 70 * handle (in other ways) a repeat failure. Strategies are 71 * invoked in-order each time the number of consecutive failures 72 * reaches over the threshold. That is, the Nth strategy is 73 * invoked after N * consecutiveFailureThreshold consecutive 74 * failures are detected. 75 * @param recoverySuccessCallback Invoked upon success of a recovery 76 * strategy, with the string name of the recovery strategy which 77 * worked. 78 */ 79 public RepeatFailureDetector(Logger.Factory logFactory, 80 int consecutiveFailureThreshold, List<FailureHandler> recoveryStrategies, 81 Callback<String> recoverySuccessCallback) { 82 mLog = logFactory.create(new Log.Tag("RepeatFailureDtctr")); 83 84 mConsecutiveFailureThreshold = consecutiveFailureThreshold; 85 mRecoveryStrategies = recoveryStrategies; 86 mRecoverySuccessCallback = recoverySuccessCallback; 87 88 mFailureLevel = 0; 89 mConsecutiveErrorCount = 0; 90 mFailureFrameNumber = -1; 91 } 92 93 @Override 94 public void onCompleted(TotalCaptureResult result) { 95 mConsecutiveErrorCount = 0; 96 if (mFailureLevel > 0) { 97 if (result.getFrameNumber() > mFailureFrameNumber) { 98 // Success! Recovery worked, and a frame was completed 99 // successfully. 100 mRecoverySuccessCallback.onCallback(mRecoveryStrategies.get(mFailureLevel) 101 .toString()); 102 mFailureLevel = 0; 103 mFailureFrameNumber = -1; 104 } 105 } 106 } 107 108 @Override 109 public void onFailed(CaptureFailure failure) { 110 if (failure.getReason() == CaptureFailure.REASON_ERROR) { 111 mConsecutiveErrorCount++; 112 mLog.e(String.format("onCaptureFailed() REASON_ERROR: Consecutive error count = %d x" + 113 " %d", mConsecutiveErrorCount, mFailureLevel)); 114 if (mConsecutiveErrorCount >= mConsecutiveFailureThreshold) { 115 mConsecutiveErrorCount = 0; 116 mFailureFrameNumber = failure.getFrameNumber(); 117 if (mFailureLevel < mRecoveryStrategies.size()) { 118 mLog.e(String.format("onCaptureFailed() REASON_ERROR: Repeat failure " + 119 "detected (x%d). Attempting recovery strategy: %s", 120 mConsecutiveErrorCount, mRecoveryStrategies.get(mFailureLevel) 121 .toString())); 122 mRecoveryStrategies.get(mFailureLevel).run(); 123 } 124 mFailureLevel++; 125 } 126 } 127 } 128 } 129