am 80780da9: Add protection for controller timeout/failure, maximum number of advertisers, filters etc.

* commit '80780da923f52a6b5a80f8619cf3e735970eaad9':
  Add protection for controller timeout/failure, maximum number of advertisers, filters etc.
diff --git a/src/com/android/bluetooth/gatt/GattService.java b/src/com/android/bluetooth/gatt/GattService.java
index 8031639..9bfd719 100644
--- a/src/com/android/bluetooth/gatt/GattService.java
+++ b/src/com/android/bluetooth/gatt/GattService.java
@@ -88,6 +88,9 @@
     static final int SCAN_FILTER_ENABLED = 1;
     static final int SCAN_FILTER_MODIFIED = 2;
 
+    // TODO: query the number from hardware instead of hard-coded here.
+    private static final int MAX_FILTER_SIZE = 1;
+
     /**
      * Search queue to serialize remote onbject inspection.
      */
@@ -1318,6 +1321,11 @@
             }
             filters.addAll(client.filters);
         }
+        // TODO: find a better way to handle too many filters.
+        if (filters.size() > MAX_FILTER_SIZE) {
+            if (DBG) Log.d(TAG, "filters size > " + MAX_FILTER_SIZE + ", clearing filters");
+            filters = new HashSet<ScanFilter>();
+        }
         return filters;
     }
 
diff --git a/src/com/android/bluetooth/gatt/GattServiceStateMachine.java b/src/com/android/bluetooth/gatt/GattServiceStateMachine.java
index d42b72f..c37d759 100644
--- a/src/com/android/bluetooth/gatt/GattServiceStateMachine.java
+++ b/src/com/android/bluetooth/gatt/GattServiceStateMachine.java
@@ -54,6 +54,13 @@
     static final int ADD_SCAN_FILTER = 16;
     static final int ENABLE_SCAN_FILTER = 17;
 
+    // TODO: This should be queried from hardware.
+    private final int MAX_ADVERTISERS = 4;
+
+    // TODO: Remove this once stack callback is stable.
+    private static final int OPERATION_TIMEOUT = 101;
+    private static final int TIMEOUT_MILLIS = 3000;
+
     private static final String TAG = "GattServiceStateMachine";
     private static final boolean DBG = true;
 
@@ -159,14 +166,13 @@
                     break;
                 case STOP_BLE_SCAN:
                     // Note this should only happen no client is doing scans any more.
-                    gattClientScanFilterClearNative();
                     gattClientScanNative(false);
                     break;
                 case START_ADVERTISING:
                     AdvertiseClient client = (AdvertiseClient) message.obj;
                     if (mAdvertiseClients.containsKey(client.clientIf)) {
                         // do something.
-                        log("advertising already started for client : " + client.clientIf);
+                        loge("advertising already started for client : " + client.clientIf);
                         try {
                             mService.onMultipleAdvertiseCallback(client.clientIf,
                                     AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED);
@@ -176,6 +182,17 @@
                         transitionTo(mIdle);
                         break;
                     }
+                    if (mAdvertiseClients.size() >= MAX_ADVERTISERS) {
+                        loge("too many advertisier, current size : " + mAdvertiseClients.size());
+                        try {
+                            mService.onMultipleAdvertiseCallback(client.clientIf,
+                                    AdvertiseCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS);
+                        } catch (RemoteException e) {
+                            loge("failed to start advertising", e);
+                        }
+                        transitionTo(mIdle);
+                        break;
+                    }
                     newMessage = obtainMessage(ENABLE_ADVERTISING);
                     newMessage.obj = message.obj;
                     sendMessage(newMessage);
@@ -239,6 +256,7 @@
                         hasFilter = true;
                     }
                     gattClientScanFilterClearNative();
+                    sendMessageDelayed(OPERATION_TIMEOUT, TIMEOUT_MILLIS);
                     break;
                 case ADD_SCAN_FILTER:
                     if (mScanFilterQueue.isEmpty()) {
@@ -261,6 +279,10 @@
                     break;
                 case ENABLE_BLE_SCAN:
                     gattClientScanNative(true);
+                    removeMessages(OPERATION_TIMEOUT);
+                    transitionTo(mIdle);
+                    break;
+                case OPERATION_TIMEOUT:
                     transitionTo(mIdle);
                     break;
                 default:
@@ -339,6 +361,7 @@
                     AdvertiseClient client = (AdvertiseClient) message.obj;
                     mAdvertiseClients.put(client.clientIf, client);
                     enableAdvertising(client);
+                    sendMessageDelayed(OPERATION_TIMEOUT, client.clientIf, TIMEOUT_MILLIS);
                     break;
                 case SET_ADVERTISING_DATA:
                     int clientIf = message.arg1;
@@ -348,9 +371,11 @@
                     if (client.scanResponse != null) {
                         setAdvertisingData(clientIf, client.scanResponse, true);
                     }
+                    removeMessages(OPERATION_TIMEOUT);
                     transitionTo(mIdle);
                     break;
                 case CANCEL_ADVERTISING:
+                case OPERATION_TIMEOUT:
                     clientIf = message.arg1;
                     try {
                         mService.onMultipleAdvertiseCallback(clientIf,
diff --git a/src/com/android/bluetooth/gatt/ScanFilterQueue.java b/src/com/android/bluetooth/gatt/ScanFilterQueue.java
index 0858fca..9821c59 100644
--- a/src/com/android/bluetooth/gatt/ScanFilterQueue.java
+++ b/src/com/android/bluetooth/gatt/ScanFilterQueue.java
@@ -18,6 +18,7 @@
 
 import android.bluetooth.le.ScanFilter;
 
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Objects;
@@ -130,7 +131,8 @@
         entry.company = company;
         entry.company_mask = 0xFFFF;
         entry.data = data;
-        entry.data_mask = new byte[0];
+        entry.data_mask = new byte[data.length];
+        Arrays.fill(entry.data_mask, (byte) 0xFF);
         mEntries.add(entry);
     }