1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bluetooth.gatt; 18 19 import static com.android.bluetooth.gatt.AdvertiseHelper.advertiseDataToBytes; 20 21 import android.app.ActivityManager; 22 import android.bluetooth.le.AdvertiseCallback; 23 import android.bluetooth.le.AdvertiseData; 24 import android.bluetooth.le.AdvertisingSetParameters; 25 import android.bluetooth.le.IAdvertisingSetCallback; 26 import android.bluetooth.le.PeriodicAdvertisingParameters; 27 import android.content.AttributionSource; 28 import android.content.pm.PackageManager; 29 import android.os.Binder; 30 import android.os.Handler; 31 import android.os.IBinder; 32 import android.os.Looper; 33 import android.os.RemoteException; 34 import android.util.Log; 35 36 import com.android.bluetooth.Utils; 37 import com.android.bluetooth.btservice.AdapterService; 38 import com.android.bluetooth.flags.Flags; 39 import com.android.internal.annotations.VisibleForTesting; 40 41 import java.util.HashMap; 42 import java.util.Map; 43 import java.util.concurrent.CompletableFuture; 44 import java.util.concurrent.ExecutionException; 45 import java.util.concurrent.TimeUnit; 46 import java.util.concurrent.TimeoutException; 47 48 /** Manages Bluetooth LE advertising operations. */ 49 public class AdvertiseManager { 50 private static final String TAG = 51 GattServiceConfig.TAG_PREFIX + AdvertiseManager.class.getSimpleName(); 52 53 private static final long RUN_SYNC_WAIT_TIME_MS = 2000L; 54 55 private final Map<IBinder, AdvertiserInfo> mAdvertisers = new HashMap<>(); 56 57 private final AdapterService mService; 58 private final AdvertiseManagerNativeInterface mNativeInterface; 59 private final AdvertiseBinder mAdvertiseBinder; 60 private final AdvertiserMap mAdvertiserMap; 61 private final ActivityManager mActivityManager; 62 private final Handler mHandler; 63 64 private volatile boolean mIsAvailable = true; 65 @VisibleForTesting int mTempRegistrationId = -1; 66 AdvertiseManager(AdapterService service, Looper advertiseLooper)67 AdvertiseManager(AdapterService service, Looper advertiseLooper) { 68 this( 69 service, 70 advertiseLooper, 71 AdvertiseManagerNativeInterface.getInstance(), 72 new AdvertiserMap()); 73 } 74 75 @VisibleForTesting AdvertiseManager( AdapterService service, Looper advertiseLooper, AdvertiseManagerNativeInterface nativeInterface, AdvertiserMap advertiserMap)76 AdvertiseManager( 77 AdapterService service, 78 Looper advertiseLooper, 79 AdvertiseManagerNativeInterface nativeInterface, 80 AdvertiserMap advertiserMap) { 81 Log.d(TAG, "advertise manager created"); 82 mService = service; 83 mNativeInterface = nativeInterface; 84 mAdvertiserMap = advertiserMap; 85 mActivityManager = mService.getSystemService(ActivityManager.class); 86 mNativeInterface.init(this); 87 mHandler = new Handler(advertiseLooper); 88 mAdvertiseBinder = new AdvertiseBinder(service, this); 89 } 90 cleanup()91 void cleanup() { 92 Log.d(TAG, "cleanup()"); 93 mIsAvailable = false; 94 mHandler.removeCallbacksAndMessages(null); 95 forceRunSyncOnAdvertiseThread( 96 () -> { 97 mAdvertiserMap.clear(); 98 mAdvertiseBinder.cleanup(); 99 mNativeInterface.cleanup(); 100 mAdvertisers.clear(); 101 }); 102 } 103 dump(StringBuilder sb)104 void dump(StringBuilder sb) { 105 forceRunSyncOnAdvertiseThread(() -> mAdvertiserMap.dump(sb)); 106 } 107 getBinder()108 AdvertiseBinder getBinder() { 109 return mAdvertiseBinder; 110 } 111 AdvertiserInfo( Integer id, AdvertisingSetDeathRecipient deathRecipient, IAdvertisingSetCallback callback)112 private record AdvertiserInfo( 113 /* When id is negative, the registration is ongoing. When the registration finishes, id 114 * becomes equal to advertiser_id */ 115 Integer id, 116 AdvertisingSetDeathRecipient deathRecipient, 117 IAdvertisingSetCallback callback) {} 118 119 private interface CallbackWrapper { call()120 void call() throws RemoteException; 121 } 122 toBinder(IAdvertisingSetCallback e)123 IBinder toBinder(IAdvertisingSetCallback e) { 124 return e.asBinder(); 125 } 126 127 class AdvertisingSetDeathRecipient implements IBinder.DeathRecipient { 128 public IAdvertisingSetCallback callback; 129 private final String mPackageName; 130 AdvertisingSetDeathRecipient(IAdvertisingSetCallback callback, String packageName)131 AdvertisingSetDeathRecipient(IAdvertisingSetCallback callback, String packageName) { 132 this.callback = callback; 133 this.mPackageName = packageName; 134 } 135 136 @Override binderDied()137 public void binderDied() { 138 Log.d(TAG, "Binder is dead - unregistering advertising set (" + mPackageName + ")!"); 139 doOnAdvertiseThread(() -> stopAdvertisingSet(callback)); 140 } 141 } 142 findAdvertiser(int advertiserId)143 private Map.Entry<IBinder, AdvertiserInfo> findAdvertiser(int advertiserId) { 144 return mAdvertisers.entrySet().stream() 145 .filter(e -> e.getValue().id == advertiserId) 146 .findFirst() 147 .orElse(null); 148 } 149 onAdvertisingSetStarted(int regId, int advertiserId, int txPower, int status)150 void onAdvertisingSetStarted(int regId, int advertiserId, int txPower, int status) { 151 Log.d( 152 TAG, 153 "onAdvertisingSetStarted() - regId=" 154 + regId 155 + ", advertiserId=" 156 + advertiserId 157 + ", status=" 158 + status); 159 checkThread(); 160 161 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(regId); 162 if (entry == null) { 163 Log.i(TAG, "onAdvertisingSetStarted() - no callback found for regId " + regId); 164 // Advertising set was stopped before it was properly registered. 165 mNativeInterface.stopAdvertisingSet(advertiserId); 166 return; 167 } 168 169 AdvertisingSetDeathRecipient deathRecipient = entry.getValue().deathRecipient; 170 IAdvertisingSetCallback callback = entry.getValue().callback; 171 if (status == 0) { 172 entry.setValue(new AdvertiserInfo(advertiserId, deathRecipient, callback)); 173 mAdvertiserMap.setAdvertiserIdByRegId(regId, advertiserId); 174 } else { 175 IBinder binder = entry.getKey(); 176 binder.unlinkToDeath(deathRecipient, 0); 177 mAdvertisers.remove(binder); 178 179 AppAdvertiseStats stats = mAdvertiserMap.getAppAdvertiseStatsById(regId); 180 if (stats != null) { 181 stats.recordAdvertiseStop(mAdvertisers.size()); 182 stats.recordAdvertiseErrorCount(status); 183 } 184 mAdvertiserMap.removeAppAdvertiseStats(regId); 185 } 186 187 sendToCallback( 188 advertiserId, 189 () -> 190 callback.onAdvertisingSetStarted( 191 mAdvertiseBinder, advertiserId, txPower, status)); 192 } 193 onAdvertisingEnabled(int advertiserId, boolean enable, int status)194 void onAdvertisingEnabled(int advertiserId, boolean enable, int status) { 195 Log.d( 196 TAG, 197 "onAdvertisingSetEnabled() - advertiserId=" 198 + advertiserId 199 + ", enable=" 200 + enable 201 + ", status=" 202 + status); 203 checkThread(); 204 205 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId); 206 if (entry == null) { 207 Log.i( 208 TAG, 209 "onAdvertisingSetEnable() - no callback found for advertiserId " 210 + advertiserId); 211 return; 212 } 213 214 IAdvertisingSetCallback callback = entry.getValue().callback; 215 sendToCallback( 216 advertiserId, () -> callback.onAdvertisingEnabled(advertiserId, enable, status)); 217 218 if (!enable && status != 0) { 219 AppAdvertiseStats stats = mAdvertiserMap.getAppAdvertiseStatsById(advertiserId); 220 if (stats != null) { 221 stats.recordAdvertiseStop(mAdvertisers.size()); 222 } 223 } 224 } 225 fetchAppForegroundState(int id)226 private void fetchAppForegroundState(int id) { 227 PackageManager packageManager = mService.getPackageManager(); 228 if (mActivityManager == null || packageManager == null) { 229 return; 230 } 231 int appUid = Binder.getCallingUid(); 232 String[] packages = packageManager.getPackagesForUid(appUid); 233 if (packages == null || packages.length == 0) { 234 return; 235 } 236 int importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED; 237 for (String packageName : packages) { 238 importance = Math.min(importance, mActivityManager.getPackageImportance(packageName)); 239 } 240 AppAdvertiseStats stats = mAdvertiserMap.getAppAdvertiseStatsById(id); 241 if (stats != null) { 242 stats.setAppImportance(importance); 243 } 244 } 245 startAdvertisingSet( AdvertisingSetParameters parameters, AdvertiseData advertiseData, AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData, int duration, int maxExtAdvEvents, int serverIf, IAdvertisingSetCallback callback, AttributionSource attrSource)246 void startAdvertisingSet( 247 AdvertisingSetParameters parameters, 248 AdvertiseData advertiseData, 249 AdvertiseData scanResponse, 250 PeriodicAdvertisingParameters periodicParameters, 251 AdvertiseData periodicData, 252 int duration, 253 int maxExtAdvEvents, 254 int serverIf, 255 IAdvertisingSetCallback callback, 256 AttributionSource attrSource) { 257 checkThread(); 258 // If we are using an isolated server, force usage of an NRPA 259 if (serverIf != 0 260 && parameters.getOwnAddressType() 261 != AdvertisingSetParameters.ADDRESS_TYPE_RANDOM_NON_RESOLVABLE) { 262 Log.w(TAG, "Cannot advertise an isolated GATT server using a resolvable address"); 263 try { 264 callback.onAdvertisingSetStarted( 265 mAdvertiseBinder, 266 0x00, 267 0x00, 268 AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR); 269 } catch (RemoteException exception) { 270 Log.e(TAG, "Failed to callback:" + Log.getStackTraceString(exception)); 271 } 272 return; 273 } 274 275 int appUid = Binder.getCallingUid(); 276 String packageName = null; 277 if (mService.getPackageManager() != null) { 278 packageName = mService.getPackageManager().getNameForUid(appUid); 279 } 280 if (packageName == null) { 281 packageName = "Unknown package name (UID: " + appUid + ")"; 282 } 283 AdvertisingSetDeathRecipient deathRecipient = 284 new AdvertisingSetDeathRecipient(callback, packageName); 285 IBinder binder = toBinder(callback); 286 try { 287 binder.linkToDeath(deathRecipient, 0); 288 } catch (RemoteException e) { 289 throw new IllegalArgumentException("Can't link to advertiser's death"); 290 } 291 292 final String deviceName = mService.getName(); 293 try { 294 byte[] advDataBytes = advertiseDataToBytes(advertiseData, deviceName); 295 byte[] scanResponseBytes = advertiseDataToBytes(scanResponse, deviceName); 296 byte[] periodicDataBytes = advertiseDataToBytes(periodicData, deviceName); 297 298 int cbId = --mTempRegistrationId; 299 mAdvertisers.put(binder, new AdvertiserInfo(cbId, deathRecipient, callback)); 300 301 Log.d(TAG, "startAdvertisingSet() - reg_id=" + cbId + ", callback: " + binder); 302 303 mAdvertiserMap.addAppAdvertiseStats(cbId, mService, attrSource); 304 fetchAppForegroundState(cbId); 305 mAdvertiserMap.recordAdvertiseStart( 306 cbId, 307 parameters, 308 advertiseData, 309 scanResponse, 310 periodicParameters, 311 periodicData, 312 duration, 313 maxExtAdvEvents); 314 315 mNativeInterface.startAdvertisingSet( 316 parameters, 317 advDataBytes, 318 scanResponseBytes, 319 periodicParameters, 320 periodicDataBytes, 321 duration, 322 maxExtAdvEvents, 323 cbId, 324 serverIf); 325 326 } catch (IllegalArgumentException e) { 327 try { 328 binder.unlinkToDeath(deathRecipient, 0); 329 callback.onAdvertisingSetStarted( 330 mAdvertiseBinder, 331 0x00, 332 0x00, 333 AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE); 334 } catch (RemoteException exception) { 335 Log.e(TAG, "Failed to callback:" + Log.getStackTraceString(exception)); 336 } 337 } 338 } 339 onOwnAddressRead(int advertiserId, int addressType, String address)340 void onOwnAddressRead(int advertiserId, int addressType, String address) { 341 Log.d(TAG, "onOwnAddressRead() advertiserId=" + advertiserId); 342 checkThread(); 343 344 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId); 345 if (entry == null) { 346 Log.w(TAG, "onOwnAddressRead() - bad advertiserId " + advertiserId); 347 return; 348 } 349 350 IAdvertisingSetCallback callback = entry.getValue().callback; 351 sendToCallback( 352 advertiserId, () -> callback.onOwnAddressRead(advertiserId, addressType, address)); 353 } 354 getOwnAddress(int advertiserId)355 void getOwnAddress(int advertiserId) { 356 checkThread(); 357 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId); 358 if (entry == null) { 359 Log.w(TAG, "getOwnAddress() - bad advertiserId " + advertiserId); 360 return; 361 } 362 mNativeInterface.getOwnAddress(advertiserId); 363 } 364 stopAdvertisingSet(IAdvertisingSetCallback callback)365 void stopAdvertisingSet(IAdvertisingSetCallback callback) { 366 checkThread(); 367 IBinder binder = toBinder(callback); 368 Log.d(TAG, "stopAdvertisingSet() " + binder); 369 370 AdvertiserInfo adv = mAdvertisers.remove(binder); 371 if (adv == null) { 372 Log.e(TAG, "stopAdvertisingSet() - no client found for callback"); 373 return; 374 } 375 376 Integer advertiserId = adv.id; 377 binder.unlinkToDeath(adv.deathRecipient, 0); 378 379 if (advertiserId < 0) { 380 Log.i(TAG, "stopAdvertisingSet() - advertiser not finished registration yet"); 381 // Advertiser will be freed once initiated in onAdvertisingSetStarted() 382 return; 383 } 384 385 mNativeInterface.stopAdvertisingSet(advertiserId); 386 387 try { 388 callback.onAdvertisingSetStopped(advertiserId); 389 } catch (RemoteException e) { 390 Log.i(TAG, "error sending onAdvertisingSetStopped callback", e); 391 } 392 393 mAdvertiserMap.recordAdvertiseStop(advertiserId); 394 } 395 enableAdvertisingSet(int advertiserId, boolean enable, int duration, int maxExtAdvEvents)396 void enableAdvertisingSet(int advertiserId, boolean enable, int duration, int maxExtAdvEvents) { 397 checkThread(); 398 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId); 399 if (entry == null) { 400 Log.w(TAG, "enableAdvertisingSet() - bad advertiserId " + advertiserId); 401 return; 402 } 403 fetchAppForegroundState(advertiserId); 404 mNativeInterface.enableAdvertisingSet(advertiserId, enable, duration, maxExtAdvEvents); 405 406 mAdvertiserMap.enableAdvertisingSet(advertiserId, enable, duration, maxExtAdvEvents); 407 } 408 setAdvertisingData(int advertiserId, AdvertiseData data)409 void setAdvertisingData(int advertiserId, AdvertiseData data) { 410 checkThread(); 411 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId); 412 if (entry == null) { 413 Log.w(TAG, "setAdvertisingData() - bad advertiserId " + advertiserId); 414 return; 415 } 416 final String deviceName = mService.getName(); 417 try { 418 mNativeInterface.setAdvertisingData( 419 advertiserId, advertiseDataToBytes(data, deviceName)); 420 421 mAdvertiserMap.setAdvertisingData(advertiserId, data); 422 } catch (IllegalArgumentException e) { 423 try { 424 onAdvertisingDataSet( 425 advertiserId, AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE); 426 } catch (Exception exception) { 427 Log.e(TAG, "Failed to callback:" + Log.getStackTraceString(exception)); 428 } 429 } 430 } 431 setScanResponseData(int advertiserId, AdvertiseData data)432 void setScanResponseData(int advertiserId, AdvertiseData data) { 433 checkThread(); 434 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId); 435 if (entry == null) { 436 Log.w(TAG, "setScanResponseData() - bad advertiserId " + advertiserId); 437 return; 438 } 439 final String deviceName = mService.getName(); 440 try { 441 mNativeInterface.setScanResponseData( 442 advertiserId, advertiseDataToBytes(data, deviceName)); 443 444 mAdvertiserMap.setScanResponseData(advertiserId, data); 445 } catch (IllegalArgumentException e) { 446 try { 447 onScanResponseDataSet( 448 advertiserId, AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE); 449 } catch (Exception exception) { 450 Log.e(TAG, "Failed to callback:" + Log.getStackTraceString(exception)); 451 } 452 } 453 } 454 setAdvertisingParameters(int advertiserId, AdvertisingSetParameters parameters)455 void setAdvertisingParameters(int advertiserId, AdvertisingSetParameters parameters) { 456 checkThread(); 457 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId); 458 if (entry == null) { 459 Log.w(TAG, "setAdvertisingParameters() - bad advertiserId " + advertiserId); 460 return; 461 } 462 mNativeInterface.setAdvertisingParameters(advertiserId, parameters); 463 464 mAdvertiserMap.setAdvertisingParameters(advertiserId, parameters); 465 } 466 setPeriodicAdvertisingParameters( int advertiserId, PeriodicAdvertisingParameters parameters)467 void setPeriodicAdvertisingParameters( 468 int advertiserId, PeriodicAdvertisingParameters parameters) { 469 checkThread(); 470 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId); 471 if (entry == null) { 472 Log.w(TAG, "setPeriodicAdvertisingParameters() - bad advertiserId " + advertiserId); 473 return; 474 } 475 mNativeInterface.setPeriodicAdvertisingParameters(advertiserId, parameters); 476 477 mAdvertiserMap.setPeriodicAdvertisingParameters(advertiserId, parameters); 478 } 479 setPeriodicAdvertisingData(int advertiserId, AdvertiseData data)480 void setPeriodicAdvertisingData(int advertiserId, AdvertiseData data) { 481 checkThread(); 482 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId); 483 if (entry == null) { 484 Log.w(TAG, "setPeriodicAdvertisingData() - bad advertiserId " + advertiserId); 485 return; 486 } 487 final String deviceName = mService.getName(); 488 try { 489 mNativeInterface.setPeriodicAdvertisingData( 490 advertiserId, advertiseDataToBytes(data, deviceName)); 491 492 mAdvertiserMap.setPeriodicAdvertisingData(advertiserId, data); 493 } catch (IllegalArgumentException e) { 494 try { 495 onPeriodicAdvertisingDataSet( 496 advertiserId, AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE); 497 } catch (Exception exception) { 498 Log.e(TAG, "Failed to callback:" + Log.getStackTraceString(exception)); 499 } 500 } 501 } 502 setPeriodicAdvertisingEnable(int advertiserId, boolean enable)503 void setPeriodicAdvertisingEnable(int advertiserId, boolean enable) { 504 checkThread(); 505 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId); 506 if (entry == null) { 507 Log.w(TAG, "setPeriodicAdvertisingEnable() - bad advertiserId " + advertiserId); 508 return; 509 } 510 mNativeInterface.setPeriodicAdvertisingEnable(advertiserId, enable); 511 } 512 onAdvertisingDataSet(int advertiserId, int status)513 void onAdvertisingDataSet(int advertiserId, int status) { 514 checkThread(); 515 Log.d(TAG, "onAdvertisingDataSet() advertiserId=" + advertiserId + ", status=" + status); 516 517 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId); 518 if (entry == null) { 519 Log.i(TAG, "onAdvertisingDataSet() - bad advertiserId " + advertiserId); 520 return; 521 } 522 523 IAdvertisingSetCallback callback = entry.getValue().callback; 524 sendToCallback(advertiserId, () -> callback.onAdvertisingDataSet(advertiserId, status)); 525 } 526 onScanResponseDataSet(int advertiserId, int status)527 void onScanResponseDataSet(int advertiserId, int status) { 528 checkThread(); 529 Log.d(TAG, "onScanResponseDataSet() advertiserId=" + advertiserId + ", status=" + status); 530 531 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId); 532 if (entry == null) { 533 Log.i(TAG, "onScanResponseDataSet() - bad advertiserId " + advertiserId); 534 return; 535 } 536 537 IAdvertisingSetCallback callback = entry.getValue().callback; 538 sendToCallback(advertiserId, () -> callback.onScanResponseDataSet(advertiserId, status)); 539 } 540 onAdvertisingParametersUpdated(int advertiserId, int txPower, int status)541 void onAdvertisingParametersUpdated(int advertiserId, int txPower, int status) { 542 Log.d( 543 TAG, 544 "onAdvertisingParametersUpdated() advertiserId=" 545 + advertiserId 546 + ", txPower=" 547 + txPower 548 + ", status=" 549 + status); 550 checkThread(); 551 552 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId); 553 if (entry == null) { 554 Log.i(TAG, "onAdvertisingParametersUpdated() - bad advertiserId " + advertiserId); 555 return; 556 } 557 558 IAdvertisingSetCallback callback = entry.getValue().callback; 559 sendToCallback( 560 advertiserId, 561 () -> callback.onAdvertisingParametersUpdated(advertiserId, txPower, status)); 562 } 563 onPeriodicAdvertisingParametersUpdated(int advertiserId, int status)564 void onPeriodicAdvertisingParametersUpdated(int advertiserId, int status) { 565 Log.d( 566 TAG, 567 "onPeriodicAdvertisingParametersUpdated() advertiserId=" 568 + advertiserId 569 + ", status=" 570 + status); 571 checkThread(); 572 573 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId); 574 if (entry == null) { 575 Log.i( 576 TAG, 577 "onPeriodicAdvertisingParametersUpdated() - bad advertiserId " + advertiserId); 578 return; 579 } 580 581 IAdvertisingSetCallback callback = entry.getValue().callback; 582 sendToCallback( 583 advertiserId, 584 () -> callback.onPeriodicAdvertisingParametersUpdated(advertiserId, status)); 585 } 586 onPeriodicAdvertisingDataSet(int advertiserId, int status)587 void onPeriodicAdvertisingDataSet(int advertiserId, int status) { 588 Log.d( 589 TAG, 590 "onPeriodicAdvertisingDataSet() advertiserId=" 591 + advertiserId 592 + ", status=" 593 + status); 594 checkThread(); 595 596 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId); 597 if (entry == null) { 598 Log.i(TAG, "onPeriodicAdvertisingDataSet() - bad advertiserId " + advertiserId); 599 return; 600 } 601 602 IAdvertisingSetCallback callback = entry.getValue().callback; 603 sendToCallback( 604 advertiserId, () -> callback.onPeriodicAdvertisingDataSet(advertiserId, status)); 605 } 606 onPeriodicAdvertisingEnabled(int advertiserId, boolean enable, int status)607 void onPeriodicAdvertisingEnabled(int advertiserId, boolean enable, int status) { 608 Log.d( 609 TAG, 610 "onPeriodicAdvertisingEnabled() advertiserId=" 611 + advertiserId 612 + ", status=" 613 + status); 614 615 Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId); 616 if (entry == null) { 617 Log.i(TAG, "onAdvertisingSetEnable() - bad advertiserId " + advertiserId); 618 return; 619 } 620 checkThread(); 621 622 IAdvertisingSetCallback callback = entry.getValue().callback; 623 sendToCallback( 624 advertiserId, 625 () -> callback.onPeriodicAdvertisingEnabled(advertiserId, enable, status)); 626 627 AppAdvertiseStats stats = mAdvertiserMap.getAppAdvertiseStatsById(advertiserId); 628 if (stats != null) { 629 stats.onPeriodicAdvertiseEnabled(enable); 630 } 631 } 632 doOnAdvertiseThread(Runnable r)633 void doOnAdvertiseThread(Runnable r) { 634 if (mIsAvailable) { 635 if (Flags.advertiseThread()) { 636 boolean posted = 637 mHandler.post( 638 () -> { 639 if (mIsAvailable) { 640 r.run(); 641 } 642 }); 643 if (!posted) { 644 Log.w(TAG, "Unable to post async task"); 645 } 646 } else { 647 r.run(); 648 } 649 } 650 } 651 forceRunSyncOnAdvertiseThread(Runnable r)652 private void forceRunSyncOnAdvertiseThread(Runnable r) { 653 if (!Flags.advertiseThread()) { 654 r.run(); 655 return; 656 } 657 final CompletableFuture<Void> future = new CompletableFuture<>(); 658 boolean posted = 659 mHandler.postAtFrontOfQueue( 660 () -> { 661 r.run(); 662 future.complete(null); 663 }); 664 if (!posted) { 665 Log.w(TAG, "Unable to post sync task"); 666 return; 667 } 668 try { 669 future.get(RUN_SYNC_WAIT_TIME_MS, TimeUnit.MILLISECONDS); 670 } catch (InterruptedException | TimeoutException | ExecutionException e) { 671 Log.w(TAG, "Unable to complete sync task: " + e); 672 } 673 } 674 checkThread()675 private void checkThread() { 676 if (Flags.advertiseThread() 677 && !mHandler.getLooper().isCurrentThread() 678 && !Utils.isInstrumentationTestMode()) { 679 throw new IllegalStateException("Not on advertise thread"); 680 } 681 } 682 sendToCallback(int advertiserId, CallbackWrapper wrapper)683 private static void sendToCallback(int advertiserId, CallbackWrapper wrapper) { 684 try { 685 wrapper.call(); 686 } catch (RemoteException e) { 687 Log.i(TAG, "RemoteException in callback for advertiserId: " + advertiserId); 688 } 689 } 690 } 691