[Private GATT] Add API to use a isolated GATT server

Associated / unassociates a server with an advertiser, plumbs
logic into Rust.

Bug: 255880936
Test: CTS
Change-Id: I86a29d0bca54f4f99a2f6fb3c11c5a9384a29f71
diff --git a/android/app/jni/com_android_bluetooth_gatt.cpp b/android/app/jni/com_android_bluetooth_gatt.cpp
index c4d62b7..d061a18 100644
--- a/android/app/jni/com_android_bluetooth_gatt.cpp
+++ b/android/app/jni/com_android_bluetooth_gatt.cpp
@@ -2255,12 +2255,10 @@
                                false, status);
 }
 
-static void startAdvertisingSetNative(JNIEnv* env, jobject object,
-                                      jobject parameters, jbyteArray adv_data,
-                                      jbyteArray scan_resp,
-                                      jobject periodic_parameters,
-                                      jbyteArray periodic_data, jint duration,
-                                      jint maxExtAdvEvents, jint reg_id) {
+static void startAdvertisingSetNative(
+    JNIEnv* env, jobject object, jobject parameters, jbyteArray adv_data,
+    jbyteArray scan_resp, jobject periodic_parameters, jbyteArray periodic_data,
+    jint duration, jint maxExtAdvEvents, jint reg_id, jint server_if) {
   if (!sGattIf) return;
 
   jbyte* scan_resp_data = env->GetByteArrayElements(scan_resp, NULL);
@@ -2284,16 +2282,23 @@
       periodic_data_data, periodic_data_data + periodic_data_len);
   env->ReleaseByteArrayElements(periodic_data, periodic_data_data, JNI_ABORT);
 
-  sGattIf->advertiser->StartAdvertisingSet(
+  auto advertiser_id = sGattIf->advertiser->StartAdvertisingSet(
       reg_id, base::Bind(&ble_advertising_set_started_cb, reg_id), params,
       data_vec, scan_resp_vec, periodicParams, periodic_data_vec, duration,
       maxExtAdvEvents, base::Bind(ble_advertising_set_timeout_cb));
+
+  // tie advertiser ID to server_if
+  if (server_if != 0) {
+    bluetooth::gatt::associate_server_with_advertiser(server_if, advertiser_id);
+  }
 }
 
 static void stopAdvertisingSetNative(JNIEnv* env, jobject object,
                                      jint advertiser_id) {
   if (!sGattIf) return;
 
+  bluetooth::gatt::clear_advertiser(advertiser_id);
+
   sGattIf->advertiser->Unregister(advertiser_id);
 }
 
@@ -2525,7 +2530,7 @@
     {"cleanupNative", "()V", (void*)advertiseCleanupNative},
     {"startAdvertisingSetNative",
      "(Landroid/bluetooth/le/AdvertisingSetParameters;[B[BLandroid/bluetooth/"
-     "le/PeriodicAdvertisingParameters;[BIII)V",
+     "le/PeriodicAdvertisingParameters;[BIIII)V",
      (void*)startAdvertisingSetNative},
     {"getOwnAddressNative", "(I)V", (void*)getOwnAddressNative},
     {"stopAdvertisingSetNative", "(I)V", (void*)stopAdvertisingSetNative},
diff --git a/android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java b/android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java
index f1c83b3..6f52e74 100644
--- a/android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java
+++ b/android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java
@@ -206,7 +206,7 @@
 
     void startAdvertisingSet(AdvertisingSetParameters parameters, AdvertiseData advertiseData,
             AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters,
-            AdvertiseData periodicData, int duration, int maxExtAdvEvents,
+            AdvertiseData periodicData, int duration, int maxExtAdvEvents, int serverIf,
             IAdvertisingSetCallback callback) {
         AdvertisingSetDeathRecipient deathRecipient = new AdvertisingSetDeathRecipient(callback);
         IBinder binder = toBinder(callback);
@@ -236,7 +236,8 @@
                     scanResponse, periodicParameters, periodicData, duration, maxExtAdvEvents);
 
             startAdvertisingSetNative(parameters, advDataBytes, scanResponseBytes,
-                    periodicParameters, periodicDataBytes, duration, maxExtAdvEvents, cbId);
+                    periodicParameters, periodicDataBytes, duration, maxExtAdvEvents, cbId,
+                    serverIf);
 
         } catch (IllegalArgumentException e) {
             try {
@@ -534,7 +535,7 @@
     private native void startAdvertisingSetNative(AdvertisingSetParameters parameters,
             byte[] advertiseData, byte[] scanResponse,
             PeriodicAdvertisingParameters periodicParameters, byte[] periodicData, int duration,
-            int maxExtAdvEvents, int regId);
+            int maxExtAdvEvents, int regId, int serverIf);
 
     private native void getOwnAddressNative(int advertiserId);
 
diff --git a/android/app/src/com/android/bluetooth/gatt/GattService.java b/android/app/src/com/android/bluetooth/gatt/GattService.java
index 7feb07f..75abb9b 100644
--- a/android/app/src/com/android/bluetooth/gatt/GattService.java
+++ b/android/app/src/com/android/bluetooth/gatt/GattService.java
@@ -24,7 +24,6 @@
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.app.Service;
-import android.content.Context;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothGatt;
@@ -54,8 +53,9 @@
 import android.companion.CompanionDeviceManager;
 import android.content.AttributionSource;
 import android.content.Intent;
-import android.content.pm.PackageManager.PackageInfoFlags;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManager.PackageInfoFlags;
+import android.content.res.Resources;
 import android.net.MacAddress;
 import android.os.Binder;
 import android.os.Build;
@@ -102,8 +102,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
 
-import android.content.res.Resources;
-
 /**
  * Provides Bluetooth Gatt profile, as a service in
  * the Bluetooth application.
@@ -1441,11 +1439,12 @@
         public void startAdvertisingSet(AdvertisingSetParameters parameters,
                 AdvertiseData advertiseData, AdvertiseData scanResponse,
                 PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData,
-                int duration, int maxExtAdvEvents, IAdvertisingSetCallback callback,
+                int duration, int maxExtAdvEvents, int serverIf, IAdvertisingSetCallback callback,
                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
             try {
                 startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
-                        periodicData, duration, maxExtAdvEvents, callback, attributionSource);
+                        periodicData, duration, maxExtAdvEvents, serverIf, callback,
+                        attributionSource);
                 receiver.send(null);
             } catch (RuntimeException e) {
                 receiver.propagateException(e);
@@ -1454,14 +1453,14 @@
         private void startAdvertisingSet(AdvertisingSetParameters parameters,
                 AdvertiseData advertiseData, AdvertiseData scanResponse,
                 PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData,
-                int duration, int maxExtAdvEvents, IAdvertisingSetCallback callback,
+                int duration, int maxExtAdvEvents, int serverIf, IAdvertisingSetCallback callback,
                 AttributionSource attributionSource) {
             GattService service = getService();
             if (service == null) {
                 return;
             }
             service.startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
-                    periodicData, duration, maxExtAdvEvents, callback, attributionSource);
+                    periodicData, duration, maxExtAdvEvents, serverIf, callback, attributionSource);
         }
 
         @Override
@@ -3383,17 +3382,18 @@
     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
     void startAdvertisingSet(AdvertisingSetParameters parameters, AdvertiseData advertiseData,
             AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters,
-            AdvertiseData periodicData, int duration, int maxExtAdvEvents,
+            AdvertiseData periodicData, int duration, int maxExtAdvEvents, int serverIf,
             IAdvertisingSetCallback callback, AttributionSource attributionSource) {
         if (!Utils.checkAdvertisePermissionForDataDelivery(
                 this, attributionSource, "GattService startAdvertisingSet")) {
             return;
         }
-        if (parameters.getOwnAddressType() != AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT) {
+        if (parameters.getOwnAddressType() != AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT
+                || serverIf != 0) {
             Utils.enforceBluetoothPrivilegedPermission(this);
         }
         mAdvertiseManager.startAdvertisingSet(parameters, advertiseData, scanResponse,
-                periodicParameters, periodicData, duration, maxExtAdvEvents, callback);
+                periodicParameters, periodicData, duration, maxExtAdvEvents, serverIf, callback);
     }
 
     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseManagerTest.java
index eca9508..74d0e64 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseManagerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseManagerTest.java
@@ -88,7 +88,7 @@
         doNothing().when(mBinder).linkToDeath(any(), eq(0));
 
         mAdvertiseManager.startAdvertisingSet(parameters, advertiseData, scanResponse,
-                periodicParameters, periodicData, duration, maxExtAdvEvents, mCallback);
+                periodicParameters, periodicData, duration, maxExtAdvEvents, 0, mCallback);
 
         mAdvertiserId = AdvertiseManager.sTempRegistrationId;
     }
diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java
index 283a098..f85dc0a 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java
@@ -589,15 +589,16 @@
         AdvertiseData periodicData = new AdvertiseData.Builder().build();
         int duration = 1;
         int maxExtAdvEvents = 2;
+        int serverIf = 3;
         IAdvertisingSetCallback callback = mock(IAdvertisingSetCallback.class);
 
         mBinder.startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
-                periodicData, duration, maxExtAdvEvents, callback,
+                periodicData, duration, maxExtAdvEvents, serverIf, callback,
                 mAttributionSource, SynchronousResultReceiver.get());
 
         verify(mService).startAdvertisingSet(parameters, advertiseData, scanResponse,
-                periodicParameters, periodicData, duration, maxExtAdvEvents, callback,
-                mAttributionSource);
+                periodicParameters, periodicData, duration, maxExtAdvEvents,
+                serverIf, callback, mAttributionSource);
     }
 
     @Test
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 23eccd2..21b167f 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -958,6 +958,10 @@
     method @NonNull public android.bluetooth.le.AdvertisingSetParameters.Builder setOwnAddressType(int);
   }
 
+  public final class BluetoothLeAdvertiser {
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT}) public void startAdvertisingSet(@NonNull android.bluetooth.le.AdvertisingSetParameters, @Nullable android.bluetooth.le.AdvertiseData, @Nullable android.bluetooth.le.AdvertiseData, @Nullable android.bluetooth.le.PeriodicAdvertisingParameters, @Nullable android.bluetooth.le.AdvertiseData, int, int, @Nullable android.bluetooth.BluetoothGattServer, @Nullable android.bluetooth.le.AdvertisingSetCallback, @NonNull android.os.Handler);
+  }
+
   public final class BluetoothLeScanner {
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(android.os.WorkSource, android.bluetooth.le.ScanCallback);
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.os.WorkSource, android.bluetooth.le.ScanCallback);
diff --git a/framework/java/android/bluetooth/BluetoothGattServer.java b/framework/java/android/bluetooth/BluetoothGattServer.java
index 75261bc..b5e18de 100644
--- a/framework/java/android/bluetooth/BluetoothGattServer.java
+++ b/framework/java/android/bluetooth/BluetoothGattServer.java
@@ -455,6 +455,15 @@
     }
 
     /**
+     * Get the identifier of the BluetoothGattServer, or 0 if it is closed
+     *
+     * @hide
+     */
+    public int getServerIf() {
+        return mServerIf;
+    }
+
+    /**
      * Returns a characteristic with given handle.
      *
      * @hide
diff --git a/framework/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/framework/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 342da41..9e8dcde 100644
--- a/framework/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/framework/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -18,11 +18,15 @@
 
 import static android.bluetooth.le.BluetoothLeUtils.getSyncTimeout;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresNoPermission;
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGattServer;
 import android.bluetooth.BluetoothUuid;
 import android.bluetooth.IBluetoothGatt;
 import android.bluetooth.IBluetoothManager;
@@ -374,10 +378,65 @@
     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
     public void startAdvertisingSet(AdvertisingSetParameters parameters,
             AdvertiseData advertiseData, AdvertiseData scanResponse,
-            PeriodicAdvertisingParameters periodicParameters,
-            AdvertiseData periodicData, int duration,
-            int maxExtendedAdvertisingEvents, AdvertisingSetCallback callback,
+            PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData,
+            int duration, int maxExtendedAdvertisingEvents, AdvertisingSetCallback callback,
             Handler handler) {
+        startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
+                periodicData, duration, maxExtendedAdvertisingEvents, null, callback, handler);
+    }
+
+    /**
+     * Creates a new advertising set. If operation succeed, device will start advertising. This
+     * method returns immediately, the operation status is delivered through
+     * {@code callback.onAdvertisingSetStarted()}.
+     *
+     * <p>If the {@code gattServer} is provided, connections to this advertisement will only see
+     * the services/characteristics in this server, rather than the union of all GATT
+     * services (across all opened servers).
+     *
+     * @param parameters Advertising set parameters.
+     * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link
+     * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable,
+     * three bytes will be added for flags.
+     * @param scanResponse Scan response associated with the advertisement data. Size must not
+     * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}
+     * @param periodicParameters Periodic advertisng parameters. If null, periodic advertising will
+     * not be started.
+     * @param periodicData Periodic advertising data. Size must not exceed {@link
+     * BluetoothAdapter#getLeMaximumAdvertisingDataLength}
+     * @param duration advertising duration, in 10ms unit. Valid range is from 1 (10ms) to 65535
+     * (655,350 ms). 0 means advertising should continue until stopped.
+     * @param maxExtendedAdvertisingEvents maximum number of extended advertising events the
+     * controller shall attempt to send prior to terminating the extended advertising, even if the
+     * duration has not expired. Valid range is from 1 to 255. 0 means no maximum.
+     * @param gattServer the GATT server that will "own" connections derived from this advertising
+     * set.
+     * @param callback Callback for advertising set.
+     * @param handler Thread upon which the callbacks will be invoked.
+     * @throws IllegalArgumentException When any of the data parameter exceed the maximum allowable
+     * size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising
+     * feature is made when it's not supported by the controller, or when
+     * maxExtendedAdvertisingEvents is used on a controller that doesn't support the LE Extended
+     * Advertising
+     *
+     * @hide
+     */
+    @SystemApi
+    @SuppressLint("ExecutorRegistration")
+    @RequiresBluetoothAdvertisePermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+            android.Manifest.permission.BLUETOOTH_ADVERTISE,
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+    })
+    public void
+            startAdvertisingSet(@NonNull AdvertisingSetParameters parameters,
+            @Nullable AdvertiseData advertiseData, @Nullable AdvertiseData scanResponse,
+            @Nullable PeriodicAdvertisingParameters periodicParameters,
+            @Nullable AdvertiseData periodicData, int duration,
+            int maxExtendedAdvertisingEvents, @Nullable BluetoothGattServer gattServer,
+            @Nullable AdvertisingSetCallback callback,
+            @SuppressLint("ListenerLast") @NonNull Handler handler) {
         BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
         if (callback == null) {
             throw new IllegalArgumentException("callback cannot be null");
@@ -470,14 +529,18 @@
         try {
             final SynchronousResultReceiver recv = SynchronousResultReceiver.get();
             gatt.startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
-                    periodicData, duration, maxExtendedAdvertisingEvents, wrapped,
-                    mAttributionSource, recv);
+                    periodicData, duration, maxExtendedAdvertisingEvents,
+                    gattServer == null ? 0 : gattServer.getServerIf(), wrapped, mAttributionSource,
+                    recv);
             recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
         } catch (TimeoutException | RemoteException e) {
             Log.e(TAG, "Failed to start advertising set - ", e);
             postStartSetFailure(handler, callback,
                     AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
             return;
+        } catch (SecurityException e) {
+            mCallbackWrappers.remove(callback);
+            throw e;
         }
     }
 
diff --git a/system/binder/android/bluetooth/IBluetoothGatt.aidl b/system/binder/android/bluetooth/IBluetoothGatt.aidl
index d3ccc25..d8e877d 100644
--- a/system/binder/android/bluetooth/IBluetoothGatt.aidl
+++ b/system/binder/android/bluetooth/IBluetoothGatt.aidl
@@ -67,7 +67,7 @@
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)")
     void startAdvertisingSet(in AdvertisingSetParameters parameters, in AdvertiseData advertiseData,
                                 in AdvertiseData scanResponse, in PeriodicAdvertisingParameters periodicParameters,
-                                in AdvertiseData periodicData, in int duration, in int maxExtAdvEvents,
+                                in AdvertiseData periodicData, in int duration, in int maxExtAdvEvents, in int gattServerIf,
                                 in IAdvertisingSetCallback callback, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)")
     void stopAdvertisingSet(in IAdvertisingSetCallback callback, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
diff --git a/system/btif/src/btif_ble_advertiser.cc b/system/btif/src/btif_ble_advertiser.cc
index c86d956..9e17774 100644
--- a/system/btif/src/btif_ble_advertiser.cc
+++ b/system/btif/src/btif_ble_advertiser.cc
@@ -190,17 +190,17 @@
              timeout_s * 100, jni_thread_wrapper(FROM_HERE, timeout_cb)));
   }
 
-  void StartAdvertisingSet(int reg_id, IdTxPowerStatusCallback cb,
-                           AdvertiseParameters params,
-                           std::vector<uint8_t> advertise_data,
-                           std::vector<uint8_t> scan_response_data,
-                           PeriodicAdvertisingParameters periodic_params,
-                           std::vector<uint8_t> periodic_data,
-                           uint16_t duration, uint8_t maxExtAdvEvents,
-                           IdStatusCallback timeout_cb) override {
+  uint8_t StartAdvertisingSet(int reg_id, IdTxPowerStatusCallback cb,
+                              AdvertiseParameters params,
+                              std::vector<uint8_t> advertise_data,
+                              std::vector<uint8_t> scan_response_data,
+                              PeriodicAdvertisingParameters periodic_params,
+                              std::vector<uint8_t> periodic_data,
+                              uint16_t duration, uint8_t maxExtAdvEvents,
+                              IdStatusCallback timeout_cb) override {
     VLOG(1) << __func__;
 
-    if (!BleAdvertisingManager::IsInitialized()) return;
+    if (!BleAdvertisingManager::IsInitialized()) return {};
     tBTM_BLE_ADV_PARAMS* p_params = new tBTM_BLE_ADV_PARAMS;
     parseParams(p_params, params);
 
@@ -215,6 +215,8 @@
              std::move(scan_response_data), base::Owned(p_periodic_params),
              std::move(periodic_data), duration, maxExtAdvEvents,
              jni_thread_wrapper(FROM_HERE, timeout_cb)));
+
+    return {};
   }
 
   void SetPeriodicAdvertisingParameters(
diff --git a/system/include/hardware/ble_advertiser.h b/system/include/hardware/ble_advertiser.h
index f18937e..38b3f4e 100644
--- a/system/include/hardware/ble_advertiser.h
+++ b/system/include/hardware/ble_advertiser.h
@@ -118,8 +118,10 @@
   /** Start the advertising set. This include registering, setting all
    * parameters and data, and enabling it. |register_cb| is called when the set
    * is advertising. |timeout_cb| is called when the timeout_s have passed.
-   * |reg_id| is the callback id assigned from upper layer */
-  virtual void StartAdvertisingSet(
+   * |reg_id| is the callback id assigned from upper layer
+   *
+   * @return The advertising set ID (at the HCI layer) */
+  virtual uint8_t StartAdvertisingSet(
       int reg_id, IdTxPowerStatusCallback register_cb,
       AdvertiseParameters params, std::vector<uint8_t> advertise_data,
       std::vector<uint8_t> scan_response_data,
diff --git a/system/main/shim/le_advertising_manager.cc b/system/main/shim/le_advertising_manager.cc
index 5881bdb..83866f8 100644
--- a/system/main/shim/le_advertising_manager.cc
+++ b/system/main/shim/le_advertising_manager.cc
@@ -161,14 +161,14 @@
         set_terminated_callback, bluetooth::shim::GetGdShimHandler());
   }
 
-  void StartAdvertisingSet(int reg_id, IdTxPowerStatusCallback register_cb,
-                           AdvertiseParameters params,
-                           std::vector<uint8_t> advertise_data,
-                           std::vector<uint8_t> scan_response_data,
-                           PeriodicAdvertisingParameters periodic_params,
-                           std::vector<uint8_t> periodic_data,
-                           uint16_t duration, uint8_t maxExtAdvEvents,
-                           IdStatusCallback timeout_cb) {
+  uint8_t StartAdvertisingSet(int reg_id, IdTxPowerStatusCallback register_cb,
+                              AdvertiseParameters params,
+                              std::vector<uint8_t> advertise_data,
+                              std::vector<uint8_t> scan_response_data,
+                              PeriodicAdvertisingParameters periodic_params,
+                              std::vector<uint8_t> periodic_data,
+                              uint16_t duration, uint8_t maxExtAdvEvents,
+                              IdStatusCallback timeout_cb) {
     LOG(INFO) << __func__ << " in shim layer";
 
     bluetooth::hci::AdvertisingConfig config{};
@@ -228,6 +228,8 @@
 
     BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Le advert started",
                    base::StringPrintf("advert_id:%d", reg_id));
+
+    return id;
   }
 
   void SetPeriodicAdvertisingParameters(
diff --git a/system/rust/src/gatt/ffi.rs b/system/rust/src/gatt/ffi.rs
index b21e462..29fbe6f 100644
--- a/system/rust/src/gatt/ffi.rs
+++ b/system/rust/src/gatt/ffi.rs
@@ -14,7 +14,7 @@
 };
 
 use super::{
-    arbiter::with_arbiter,
+    arbiter::{self, with_arbiter},
     channel::AttTransport,
     ids::{AdvertiserId, AttHandle, ConnectionId, ServerId, TransportIndex},
     server::gatt_database::{AttPermissions, GattCharacteristicWithHandle, GattServiceWithHandle},
@@ -94,6 +94,10 @@
 
         // connection
         fn is_connection_isolated(conn_id: u16) -> bool;
+
+        // arbitration
+        fn associate_server_with_advertiser(server_id: u8, advertiser_id: u8);
+        fn clear_advertiser(advertiser_id: u8);
     }
 }
 
@@ -239,6 +243,24 @@
     with_arbiter(|arbiter| arbiter.is_connection_isolated(ConnectionId(conn_id)))
 }
 
+fn associate_server_with_advertiser(server_id: u8, advertiser_id: u8) {
+    if !rust_event_loop_is_enabled() {
+        return;
+    }
+
+    arbiter::with_arbiter(move |arbiter| {
+        arbiter.associate_server_with_advertiser(ServerId(server_id), AdvertiserId(advertiser_id))
+    })
+}
+
+fn clear_advertiser(advertiser_id: u8) {
+    if !rust_event_loop_is_enabled() {
+        return;
+    }
+
+    arbiter::with_arbiter(move |arbiter| arbiter.clear_advertiser(AdvertiserId(advertiser_id)))
+}
+
 #[cfg(test)]
 mod test {
     use super::*;
diff --git a/system/service/test/low_energy_advertiser_unittest.cc b/system/service/test/low_energy_advertiser_unittest.cc
index ca03340..297d9d7 100644
--- a/system/service/test/low_energy_advertiser_unittest.cc
+++ b/system/service/test/low_energy_advertiser_unittest.cc
@@ -60,13 +60,13 @@
                     AdvertiseParameters, std::vector<uint8_t>,
                     std::vector<uint8_t>, int, StatusCallback));
   MOCK_METHOD10(StartAdvertisingSet,
-                void(int reg_id, IdTxPowerStatusCallback cb,
-                     AdvertiseParameters params,
-                     std::vector<uint8_t> advertise_data,
-                     std::vector<uint8_t> scan_response_data,
-                     PeriodicAdvertisingParameters periodic_params,
-                     std::vector<uint8_t> periodic_data, uint16_t duration,
-                     uint8_t maxExtAdvEvents, IdStatusCallback timeout_cb));
+                uint8_t(int reg_id, IdTxPowerStatusCallback cb,
+                        AdvertiseParameters params,
+                        std::vector<uint8_t> advertise_data,
+                        std::vector<uint8_t> scan_response_data,
+                        PeriodicAdvertisingParameters periodic_params,
+                        std::vector<uint8_t> periodic_data, uint16_t duration,
+                        uint8_t maxExtAdvEvents, IdStatusCallback timeout_cb));
   MOCK_METHOD3(SetPeriodicAdvertisingParameters,
                void(int, PeriodicAdvertisingParameters, StatusCallback));
   MOCK_METHOD3(SetPeriodicAdvertisingData,