Merge the 2021-02-05 SPL branch from AOSP-Partner

* security-aosp-pi-release:
  Check permission before sending batch scan result
  Check if advertiserId value matches valid advertiser
  Pass whether the local device is an atv device to the native layer to determine whether to include pairing dialogs for justworks and encryption only LE pairing

Change-Id: I4682bf8a75e7e290e5254227ac35927b0d48e596
diff --git a/jni/com_android_bluetooth_btservice_AdapterService.cpp b/jni/com_android_bluetooth_btservice_AdapterService.cpp
index 976e388..f88a675 100644
--- a/jni/com_android_bluetooth_btservice_AdapterService.cpp
+++ b/jni/com_android_bluetooth_btservice_AdapterService.cpp
@@ -685,7 +685,7 @@
   }
 }
 
-static bool initNative(JNIEnv* env, jobject obj) {
+static bool initNative(JNIEnv* env, jobject obj, jboolean isAtvDevice) {
   ALOGV("%s", __func__);
 
   android_bluetooth_UidTraffic.clazz =
@@ -699,7 +699,7 @@
     return JNI_FALSE;
   }
 
-  int ret = sBluetoothInterface->init(&sBluetoothCallbacks);
+  int ret = sBluetoothInterface->init(&sBluetoothCallbacks, isAtvDevice == JNI_TRUE ? 1 : 0);
   if (ret != BT_STATUS_SUCCESS) {
     ALOGE("Error while setting the callbacks: %d\n", ret);
     sBluetoothInterface = NULL;
@@ -1220,7 +1220,7 @@
 static JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */
     {"classInitNative", "()V", (void*)classInitNative},
-    {"initNative", "()Z", (void*)initNative},
+    {"initNative", "(Z)Z", (void*)initNative},
     {"cleanupNative", "()V", (void*)cleanupNative},
     {"enableNative", "(Z)Z", (void*)enableNative},
     {"disableNative", "()Z", (void*)disableNative},
diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java
index 8a4c856..c0772dd 100644
--- a/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/src/com/android/bluetooth/btservice/AdapterService.java
@@ -376,7 +376,11 @@
         mAdapterProperties = new AdapterProperties(this);
         mAdapterStateMachine = AdapterState.make(this);
         mJniCallbacks = new JniCallbacks(this, mAdapterProperties);
-        initNative();
+
+        // Android TV doesn't show consent dialogs for just works and encryption only le pairing
+        boolean isAtvDevice = getApplicationContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_LEANBACK_ONLY);
+        initNative(isAtvDevice);
         mNativeAvailable = true;
         mCallbacks = new RemoteCallbackList<IBluetoothCallback>();
         //Load the name and address
@@ -2541,7 +2545,7 @@
 
     static native void classInitNative();
 
-    native boolean initNative();
+    native boolean initNative(boolean isAtvDevice);
 
     native void cleanupNative();
 
diff --git a/src/com/android/bluetooth/gatt/AdvertiseManager.java b/src/com/android/bluetooth/gatt/AdvertiseManager.java
index 85917a4..b76d861 100644
--- a/src/com/android/bluetooth/gatt/AdvertiseManager.java
+++ b/src/com/android/bluetooth/gatt/AdvertiseManager.java
@@ -217,7 +217,7 @@
 
         Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
         if (entry == null) {
-            Log.i(TAG, "onOwnAddressRead() - bad advertiserId " + advertiserId);
+            Log.w(TAG, "onOwnAddressRead() - bad advertiserId " + advertiserId);
             return;
         }
 
@@ -226,6 +226,11 @@
     }
 
     void getOwnAddress(int advertiserId) {
+        Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
+        if (entry == null) {
+            Log.w(TAG, "getOwnAddress() - bad advertiserId " + advertiserId);
+            return;
+        }
         getOwnAddressNative(advertiserId);
     }
 
@@ -260,37 +265,72 @@
     }
 
     void enableAdvertisingSet(int advertiserId, boolean enable, int duration, int maxExtAdvEvents) {
+        Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
+        if (entry == null) {
+            Log.w(TAG, "enableAdvertisingSet() - bad advertiserId " + advertiserId);
+            return;
+        }
         enableAdvertisingSetNative(advertiserId, enable, duration, maxExtAdvEvents);
     }
 
     void setAdvertisingData(int advertiserId, AdvertiseData data) {
+        Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
+        if (entry == null) {
+            Log.w(TAG, "setAdvertisingData() - bad advertiserId " + advertiserId);
+            return;
+        }
         String deviceName = AdapterService.getAdapterService().getName();
         setAdvertisingDataNative(advertiserId,
                 AdvertiseHelper.advertiseDataToBytes(data, deviceName));
     }
 
     void setScanResponseData(int advertiserId, AdvertiseData data) {
+        Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
+        if (entry == null) {
+            Log.w(TAG, "setScanResponseData() - bad advertiserId " + advertiserId);
+            return;
+        }
         String deviceName = AdapterService.getAdapterService().getName();
         setScanResponseDataNative(advertiserId,
                 AdvertiseHelper.advertiseDataToBytes(data, deviceName));
     }
 
     void setAdvertisingParameters(int advertiserId, AdvertisingSetParameters parameters) {
+        Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
+        if (entry == null) {
+            Log.w(TAG, "setAdvertisingParameters() - bad advertiserId " + advertiserId);
+            return;
+        }
         setAdvertisingParametersNative(advertiserId, parameters);
     }
 
     void setPeriodicAdvertisingParameters(int advertiserId,
             PeriodicAdvertisingParameters parameters) {
+        Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
+        if (entry == null) {
+            Log.w(TAG, "setPeriodicAdvertisingParameters() - bad advertiserId " + advertiserId);
+            return;
+        }
         setPeriodicAdvertisingParametersNative(advertiserId, parameters);
     }
 
     void setPeriodicAdvertisingData(int advertiserId, AdvertiseData data) {
+        Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
+        if (entry == null) {
+            Log.w(TAG, "setPeriodicAdvertisingData() - bad advertiserId " + advertiserId);
+            return;
+        }
         String deviceName = AdapterService.getAdapterService().getName();
         setPeriodicAdvertisingDataNative(advertiserId,
                 AdvertiseHelper.advertiseDataToBytes(data, deviceName));
     }
 
     void setPeriodicAdvertisingEnable(int advertiserId, boolean enable) {
+        Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
+        if (entry == null) {
+            Log.w(TAG, "setPeriodicAdvertisingEnable() - bad advertiserId " + advertiserId);
+            return;
+        }
         setPeriodicAdvertisingEnableNative(advertiserId, enable);
     }
 
diff --git a/src/com/android/bluetooth/gatt/GattService.java b/src/com/android/bluetooth/gatt/GattService.java
index fd8551a..0c9135b 100644
--- a/src/com/android/bluetooth/gatt/GattService.java
+++ b/src/com/android/bluetooth/gatt/GattService.java
@@ -1531,6 +1531,15 @@
         mScanManager.callbackDone(clientIf, status);
     }
 
+    ScanClient findBatchScanClientById(int scannerId) {
+        for (ScanClient client : mScanManager.getBatchScanQueue()) {
+            if (client.scannerId == scannerId) {
+                return client;
+            }
+        }
+        return null;
+    }
+
     void onBatchScanReports(int status, int scannerId, int reportType, int numRecords,
             byte[] recordData) throws RemoteException {
         if (DBG) {
@@ -1545,6 +1554,18 @@
             if (app == null) {
                 return;
             }
+
+            ScanClient client = findBatchScanClientById(scannerId);
+            if (client == null) {
+                return;
+            }
+
+            // Do no report if location mode is OFF or the client has no location permission
+            // PEERS_MAC_ADDRESS permission holders always get results
+            if (!hasScanResultPermission(client)) {
+                return;
+            }
+
             if (app.callback != null) {
                 app.callback.onBatchScanResults(new ArrayList<ScanResult>(results));
             } else {
@@ -1586,6 +1607,13 @@
         if (app == null) {
             return;
         }
+
+        // Do no report if location mode is OFF or the client has no location permission
+        // PEERS_MAC_ADDRESS permission holders always get results
+        if (!hasScanResultPermission(client)) {
+            return;
+        }
+
         if (client.filters == null || client.filters.isEmpty()) {
             sendBatchScanResults(app, client, new ArrayList<ScanResult>(allResults));
             // TODO: Question to reviewer: Shouldn't there be a return here?
diff --git a/tests/unit/src/com/android/bluetooth/btservice/ProfileServiceTest.java b/tests/unit/src/com/android/bluetooth/btservice/ProfileServiceTest.java
index ca20fc3..becb2f2 100644
--- a/tests/unit/src/com/android/bluetooth/btservice/ProfileServiceTest.java
+++ b/tests/unit/src/com/android/bluetooth/btservice/ProfileServiceTest.java
@@ -95,7 +95,7 @@
 
         mProfiles = Config.getSupportedProfiles();
 
-        mMockAdapterService.initNative();
+        mMockAdapterService.initNative(false);
 
         TestUtils.setAdapterService(mMockAdapterService);