Limit the retry attemps on restarting Bluetooth

* Back off the delay time of resarting Bluetooth when
  there's continous turn on failures.
* Stop to restart Bluetooth if we are seeing back to
  back Bluetooth crashes, so we won't see endless
  diaglogs popping out.

Bug: 144572641
Test: Manual
Change-Id: Ifeffa214256eab61901c123fc88b037fc6d7dd50
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 208b638..798a4c6 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -98,7 +98,7 @@
 
     private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
     //Maximum msec to wait for service restart
-    private static final int SERVICE_RESTART_TIME_MS = 200;
+    private static final int SERVICE_RESTART_TIME_MS = 400;
     //Maximum msec to wait for restart due to error
     private static final int ERROR_RESTART_TIME_MS = 3000;
     //Maximum msec to delay MESSAGE_USER_SWITCHED
@@ -1635,13 +1635,13 @@
                         //     ActivityManager detects it.
                         // The waiting for (b) and (c) is accomplished by
                         // delaying the MESSAGE_RESTART_BLUETOOTH_SERVICE
-                        // message. On slower devices, that delay needs to be
-                        // on the order of (2 * SERVICE_RESTART_TIME_MS).
+                        // message. The delay time is backed off if Bluetooth
+                        // continuously failed to turn on itself.
                         //
                         waitForOnOff(false, true);
                         Message restartMsg =
                                 mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
-                        mHandler.sendMessageDelayed(restartMsg, 2 * SERVICE_RESTART_TIME_MS);
+                        mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
                     }
                     break;
 
@@ -1820,7 +1820,7 @@
                             waitForOnOff(false, true);
                             Message restartMsg =
                                     mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
-                            mHandler.sendMessageDelayed(restartMsg, 2 * SERVICE_RESTART_TIME_MS);
+                            mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
                         }
                     }
                     if (newState == BluetoothAdapter.STATE_ON
@@ -1863,7 +1863,7 @@
                         // Send a Bluetooth Restart message
                         Message restartMsg =
                                 mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
-                        mHandler.sendMessageDelayed(restartMsg, SERVICE_RESTART_TIME_MS);
+                        mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
                     }
 
                     sendBluetoothServiceDownCallback();
@@ -1886,14 +1886,20 @@
                     break;
                 }
                 case MESSAGE_RESTART_BLUETOOTH_SERVICE: {
-                    Slog.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE");
-                    /* Enable without persisting the setting as
-                     it doesnt change when IBluetooth
-                     service restarts */
-                    mEnable = true;
-                    addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTARTED,
-                            mContext.getPackageName(), true);
-                    handleEnable(mQuietEnable);
+                    mErrorRecoveryRetryCounter++;
+                    Slog.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE: retry count="
+                            + mErrorRecoveryRetryCounter);
+                    if (mErrorRecoveryRetryCounter < MAX_ERROR_RESTART_RETRIES) {
+                        /* Enable without persisting the setting as
+                         it doesnt change when IBluetooth
+                         service restarts */
+                        mEnable = true;
+                        addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTARTED,
+                                mContext.getPackageName(), true);
+                        handleEnable(mQuietEnable);
+                    } else {
+                        Slog.e(TAG, "Reach maximum retry to restart Bluetooth!");
+                    }
                     break;
                 }
                 case MESSAGE_TIMEOUT_BIND: {
@@ -2332,13 +2338,9 @@
 
         mEnable = false;
 
-        if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) {
-            // Send a Bluetooth Restart message to reenable bluetooth
-            Message restartMsg = mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
-            mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
-        } else {
-            // todo: notify user to power down and power up phone to make bluetooth work.
-        }
+        // Send a Bluetooth Restart message to reenable bluetooth
+        Message restartMsg = mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
+        mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
     }
 
     private boolean isBluetoothDisallowed() {
@@ -2374,6 +2376,10 @@
         }
     }
 
+    private int getServiceRestartMs() {
+        return (mErrorRecoveryRetryCounter + 1) * SERVICE_RESTART_TIME_MS;
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) {