title: Android 12 - Launching Foreground Service from a background Bluetooth LE scan BroadcastReceiver throws ForegroundServiceStartNotAllowedException
body: <p><strong>Edit: I believe this to be a bug in AOSP.</strong> Please would everyone star <a href="https://issuetracker.google.com/issues/209930562" rel="nofollow noreferrer">this issue</a> so it gets more attention.</p>
  <hr />
  <p>My app records the user's trip while driving a vehicle using a Foreground Service to capture GPS. It's intended to be triggered by the presence of a BLE beacon (or Activity Recognition). This app is designed to run while the app is closed and <strong>works fine</strong> when targeting API 30, but fails with API 31 (Android 12).</p>
  <p>Since targeting API 31 it's being caught by the new <a href="https://developer.android.com/guide/components/foreground-services#background-start-restrictions" rel="nofollow noreferrer">Background Start Restrictions</a> in Android 12 - when attempting to start the service as a result of a BLE scan result, I now get: <code>android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false: service com.example.myapp/com.example.myappsdk.trip.RecordingService</code></p>
  <p>However, both of my use cases for triggering the Foreground Service from the background are <a href="https://developer.android.com/guide/components/foreground-services#background-start-restriction-exemptions" rel="nofollow noreferrer">Permitted Exemptions</a>:</p>
  <ul>
  <li>Your app receives a Bluetooth broadcast that requires the BLUETOOTH_CONNECT or BLUETOOTH_SCAN permissions.</li>
  <li>Your app receives an event that's related to geofencing or activity recognition transition.</li>
  </ul>
  <p>...so I can't understand why this exception is being thrown. The documentation does not describe any particular steps required to make it work.</p>
  <p>This is the code to trigger the BLE scan, it's called by the Application object. At this point the user has explicitly granted the <code>android.permission.BLUETOOTH_SCAN</code> permission at runtime:</p>
  <pre class="lang-java prettyprint-override"><code> BluetoothManager btManager = (BluetoothManager) (appContext.getSystemService(Context.BLUETOOTH_SERVICE));
   ScanSettings settings = new ScanSettings.Builder()
      .setLegacy(false)
      .setScanMode(SCAN_MODE_LOW_LATENCY)
      .setUseHardwareBatchingIfSupported(true)
      .setUseHardwareFilteringIfSupported(true)
      .setReportDelay(5000)
      .build();
   
   List&lt;ScanFilter&gt; filters = new ArrayList&lt;&gt;();
   filters.add(new ScanFilter.Builder().setDeviceAddress(&quot;AB:CD:EF:01:23:45&quot;).build());
   
   Intent intent = new Intent(appContext, BackgroundScanResultReceiver.class);
   intent.setAction(&quot;com.example.BACKGROUND_SCAN_RESULT&quot;);
   int flags;
   if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.S)
        // Must be mutable to allow system to add intent extras
      flags = PendingIntent.FLAG_UPDATE_CURRENT|PendingIntent.FLAG_MUTABLE; 
   else
      flags = PendingIntent.FLAG_UPDATE_CURRENT;
   PendingIntent pi = PendingIntent.getBroadcast(appContext, 1, intent, flags);
   
   BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
   scanner.startScan(filters, settings, appContext, pi);
  </code></pre>
  <p>This is the ResultReceiver which receives the scan results and starts the service:</p>
  <pre class="lang-java prettyprint-override"><code>public class BackgroundScanResultReceiver extends BroadcastReceiver {
      @Override
      public void onReceive(Context context, Intent intent) {        
          List&lt;ScanResult&gt; scanResults = intent.getParcelableArrayListExtra(BluetoothLeScannerCompat.EXTRA_LIST_SCAN_RESULT);        
          for (ScanResult result : scanResults) {
              BluetoothDevice btDevice = result.getDevice();
              if (!btDevice.getAddress().equals(&quot;AB:CD:EF:01:23:45&quot;)) {
                  return;
              }
              Intent recordIntent = new Intent(context, RecordingService.class);
              if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O) {
                  context.startForegroundService(recordIntent); // &lt;-- Exception thrown here when app in Background
              } else {
                  context.startService(recordIntent);
              }
          }
      }
  }
  </code></pre>
  <p>The RecordingService is declared in the manifest like so:</p>
  <pre class="lang-xml prettyprint-override"><code>&lt;service
      android:name=&quot;.trip.RecordingService&quot;
      android:description=&quot;@string/recording_service_description&quot;
      android:enabled=&quot;true&quot;
      android:exported=&quot;false&quot;
      android:foregroundServiceType=&quot;location&quot;
      android:label=&quot;@string/recording_service_label&quot; /&gt;
  </code></pre>
  <p>BroadcastReceiver defined in the manifest as simply:</p>
  <pre class="lang-xml prettyprint-override"><code>&lt;receiver android:name=&quot;.beacon.BackgroundScanResultReceiver&quot;/&gt;
  </code></pre>
  <p>For anyone who may wish to recommend using <code>WorkManager</code> instead, I would point out that Android still recommends using Foreground Services over <code>WorkManager</code> <a href="https://developer.android.com/guide/background#replacing-foregound" rel="nofollow noreferrer">in certain use cases</a> including &quot;Activity Tracking&quot;.</p>
  <p>My BLE scanning is handled by Nordic's <a href="https://github.com/NordicSemiconductor/Android-Scanner-Compat-Library" rel="nofollow noreferrer">Android-Scanner-Compat-Library</a>, but on O+ it's simply a wrapper for the native API. I've tried directly swapping it for the native <code>BluetoothLeScanner</code> which made no difference.</p>
  <p>It appears I'm not the only one encountering this exception in supposedly permitted cases: <a href="https://stackoverflow.com/questions/71583345/how-to-use-activity-recognition-exemptions-to-start-foregroundservice-from-backg">How to use activity recognition Exemptions to start foregroundService from background?</a></p>