Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8efac2e5 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add Suspend/Resume for advertising" into oc-mr1-dev

parents 4ed6344b c316eb19
Loading
Loading
Loading
Loading
+27 −14
Original line number Diff line number Diff line
@@ -206,12 +206,18 @@ class BleAdvertiserVscHciInterfaceImpl : public BleAdvertiserHciInterface {
               command_complete);
  }

  void Enable(uint8_t enable, uint8_t handle, uint16_t duration,
              uint8_t max_extended_advertising_events,
  void Enable(uint8_t enable, std::vector<SetEnableData> sets,
              status_cb command_complete) override {
    VLOG(1) << __func__;

    if (max_extended_advertising_events) {
    if (sets.size() != 1) {
      LOG(ERROR) << "Trying to enable multiple sets in VSC implemenetation!";
      command_complete.Run(HCI_ERR_ILLEGAL_PARAMETER_FMT);
      return;
    }
    SetEnableData& set = sets[0];

    if (set.max_extended_advertising_events) {
      command_complete.Run(HCI_ERR_ILLEGAL_PARAMETER_FMT);
      return;
    }
@@ -222,7 +228,7 @@ class BleAdvertiserVscHciInterfaceImpl : public BleAdvertiserHciInterface {
    uint8_t* pp = param;
    UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_ENB);
    UINT8_TO_STREAM(pp, enable);
    UINT8_TO_STREAM(pp, handle);
    UINT8_TO_STREAM(pp, set.handle);

    SendAdvCmd(FROM_HERE, (uint8_t)BTM_BLE_MULTI_ADV_ENB_LEN, param,
               command_complete);
@@ -403,12 +409,18 @@ class BleAdvertiserLegacyHciInterfaceImpl : public BleAdvertiserHciInterface {
               HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD, command_complete);
  }

  void Enable(uint8_t enable, uint8_t handle, uint16_t duration,
              uint8_t max_extended_advertising_events,
  void Enable(uint8_t enable, std::vector<SetEnableData> sets,
              status_cb command_complete) override {
    VLOG(1) << __func__;

    if (max_extended_advertising_events) {
    if (sets.size() != 1) {
      LOG(ERROR) << "Trying to enable multiple sets in legacy implemenetation!";
      command_complete.Run(HCI_ERR_ILLEGAL_PARAMETER_FMT);
      return;
    }

    SetEnableData& set = sets[0];
    if (set.max_extended_advertising_events) {
      command_complete.Run(HCI_ERR_ILLEGAL_PARAMETER_FMT);
      return;
    }
@@ -563,23 +575,24 @@ class BleAdvertiserHciExtendedImpl : public BleAdvertiserHciInterface {
               LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_LEN, command_complete);
  }

  void Enable(uint8_t enable, uint8_t handle, uint16_t duration,
              uint8_t max_extended_advertising_events,
  void Enable(uint8_t enable, std::vector<SetEnableData> sets,
              status_cb command_complete) override {
    VLOG(1) << __func__;

    /* cmd_length = header_size + num_of_of_advertiser * size_per_advertiser */
    const uint16_t cmd_length = 2 + 1 * 4;
    const uint16_t cmd_length = 2 + sets.size() * 4;
    uint8_t param[cmd_length];
    memset(param, 0, cmd_length);

    uint8_t* pp = param;
    UINT8_TO_STREAM(pp, enable);
    UINT8_TO_STREAM(pp, 0x01);  // just one set

    UINT8_TO_STREAM(pp, handle);
    UINT16_TO_STREAM(pp, duration);
    UINT8_TO_STREAM(pp, max_extended_advertising_events);
    UINT8_TO_STREAM(pp, sets.size());
    for (const SetEnableData& set : sets) {
      UINT8_TO_STREAM(pp, set.handle);
      UINT16_TO_STREAM(pp, set.duration);
      UINT8_TO_STREAM(pp, set.max_extended_advertising_events);
    }

    SendAdvCmd(FROM_HERE, HCI_LE_SET_EXT_ADVERTISING_ENABLE, param, cmd_length,
               command_complete);
+19 −2
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#define BLE_ADVERTISER_HCI_INTERFACE_H

#include <base/bind.h>
#include <vector>
#include "stack/include/bt_types.h"

/* This class is an abstraction of HCI commands used for managing
@@ -70,9 +71,25 @@ class BleAdvertiserHciInterface {
  virtual void SetRandomAddress(uint8_t handle,
                                const RawAddress& random_address,
                                status_cb command_complete) = 0;
  virtual void Enable(uint8_t enable, uint8_t handle, uint16_t duration,
                      uint8_t max_extended_advertising_events,

  struct SetEnableData {
    uint8_t handle;
    uint16_t duration;
    uint8_t max_extended_advertising_events;
  };
  virtual void Enable(uint8_t enable, std::vector<SetEnableData> sets,
                      status_cb command_complete) = 0;

  void Enable(uint8_t enable, uint8_t handle, uint16_t duration,
              uint8_t max_extended_advertising_events,
              status_cb command_complete) {
    std::vector<SetEnableData> enableData;
    enableData.emplace_back(SetEnableData{
        .handle = handle,
        .duration = duration,
        .max_extended_advertising_events = max_extended_advertising_events});
    Enable(enable, enableData, command_complete);
  };
  virtual void SetPeriodicAdvertisingParameters(uint8_t handle,
                                                uint16_t periodic_adv_int_min,
                                                uint16_t periodic_adv_int_max,
+156 −18
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <base/bind.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <base/time/time.h>
#include <string.h>
#include <queue>
#include <vector>
@@ -33,10 +34,13 @@
#include "btm_int_types.h"

using base::Bind;
using base::TimeDelta;
using base::TimeTicks;
using RegisterCb =
    base::Callback<void(uint8_t /* inst_id */, uint8_t /* status */)>;
using IdTxPowerStatusCb = base::Callback<void(
    uint8_t /* inst_id */, int8_t /* tx_power */, uint8_t /* status */)>;
using SetEnableData = BleAdvertiserHciInterface::SetEnableData;
extern void btm_gen_resolvable_private_addr(
    base::Callback<void(uint8_t[8])> cb);

@@ -54,7 +58,7 @@ struct AdvertisingInstance {
  uint8_t advertising_event_properties;
  alarm_t* adv_raddr_timer;
  int8_t tx_power;
  uint16_t duration;
  uint16_t duration;  // 1 unit is 10ms
  uint8_t maxExtAdvEvents;
  alarm_t* timeout_timer;
  uint8_t own_address_type;
@@ -62,6 +66,7 @@ struct AdvertisingInstance {
  MultiAdvCb timeout_cb;
  bool address_update_required;
  bool periodic_enabled;
  uint32_t advertising_interval;  // 1 unit is 0.625 ms

  /* When true, advertising set is enabled, or last scheduled call to "LE Set
   * Extended Advertising Set Enable" is to enable this advertising set. Any
@@ -73,6 +78,7 @@ struct AdvertisingInstance {
   * command scheduled when in this state will execute when the set is disabled.
   */
  bool enable_status;
  TimeTicks enable_time;

  bool IsEnabled() { return enable_status; }

@@ -392,7 +398,6 @@ class BleAdvertisingManagerImpl
    c->maxExtAdvEvents = maxExtAdvEvents;
    c->timeout_cb = std::move(timeout_cb);


    // this code is intentionally left formatted this way to highlight the
    // asynchronous flow
    // clang-format off
@@ -575,27 +580,27 @@ class BleAdvertisingManagerImpl

  void EnableFinish(AdvertisingInstance* p_inst, bool enable, MultiAdvCb cb,
                    uint8_t status) {
    MultiAdvCb myCb;
    if (enable && p_inst->duration) {
      p_inst->enable_status = enable;
      // TODO(jpawlowski): HCI implementation that can't do duration should
      // emulate it, not EnableWithTimerCb.
      GetHciInterface()->Enable(
          enable, p_inst->inst_id, p_inst->duration, p_inst->maxExtAdvEvents,
          Bind(&BleAdvertisingManagerImpl::EnableWithTimerCb,
      myCb = Bind(&BleAdvertisingManagerImpl::EnableWithTimerCb,
                  base::Unretained(this), p_inst->inst_id, std::move(cb),
               p_inst->duration, p_inst->timeout_cb));

                  p_inst->duration, p_inst->timeout_cb);
    } else {
      myCb = std::move(cb);

      if (p_inst->timeout_timer) {
        alarm_cancel(p_inst->timeout_timer);
        alarm_free(p_inst->timeout_timer);
        p_inst->timeout_timer = nullptr;
      }
    }

    if (enable) p_inst->enable_time = TimeTicks::Now();
    p_inst->enable_status = enable;
    GetHciInterface()->Enable(enable, p_inst->inst_id, p_inst->duration,
                                p_inst->maxExtAdvEvents, std::move(cb));
    }
                              p_inst->maxExtAdvEvents, std::move(myCb));
  }

  void SetParameters(uint8_t inst_id, tBTM_BLE_ADV_PARAMS* p_params,
@@ -613,12 +618,14 @@ class BleAdvertisingManagerImpl
      return;
    }

    // TODO: disable only if was enabled, currently no use scenario needs that,
    // TODO: disable only if was enabled, currently no use scenario needs
    // that,
    // we always set parameters before enabling
    // GetHciInterface()->Enable(false, inst_id, Bind(DoNothing));
    p_inst->advertising_event_properties =
        p_params->advertising_event_properties;
    p_inst->tx_power = p_params->tx_power;
    p_inst->advertising_interval = p_params->adv_int_min;
    const RawAddress& peer_address = RawAddress::kEmpty;

    GetHciInterface()->SetParameters(
@@ -804,6 +811,63 @@ class BleAdvertisingManagerImpl
    p_inst->address_update_required = false;
  }

  void RecomputeTimeout(AdvertisingInstance* inst, TimeTicks now) {
    TimeDelta duration = now - inst->enable_time;
    bool cb_fired = false;
    if (inst->duration) {
      int durationDone = (duration.InMilliseconds() / 10);
      if (durationDone + 1 >= inst->duration) {
        inst->enable_status = false;
        inst->timeout_cb.Run(0 /* TODO: STATUS HERE?*/);
        cb_fired = true;
      } else {
        inst->duration = inst->duration - durationDone;
      }
    }

    if (inst->maxExtAdvEvents && !cb_fired) {
      int eventsDone =
          (duration.InMilliseconds() / (inst->advertising_interval * 5 / 8));

      if (eventsDone + 1 >= inst->maxExtAdvEvents) {
        inst->enable_status = false;
        inst->timeout_cb.Run(0 /* TODO: STATUS HERE?*/);
      } else {
        inst->maxExtAdvEvents = inst->maxExtAdvEvents - eventsDone;
      }
    }
  }

  void Suspend() {
    std::vector<SetEnableData> sets;

    for (AdvertisingInstance& inst : adv_inst) {
      if (!inst.in_use || !inst.enable_status) continue;

      if (inst.duration || inst.maxExtAdvEvents)
        RecomputeTimeout(&inst, TimeTicks::Now());

      sets.emplace_back(SetEnableData{.handle = inst.inst_id});
    }

    if (!sets.empty()) GetHciInterface()->Enable(false, sets, Bind(DoNothing));
  }

  void Resume() override {
    std::vector<SetEnableData> sets;

    for (const AdvertisingInstance& inst : adv_inst) {
      if (inst.in_use && inst.enable_status) {
        sets.emplace_back(SetEnableData{
            .handle = inst.inst_id,
            .duration = inst.duration,
            .max_extended_advertising_events = inst.maxExtAdvEvents});
      }
    }

    if (!sets.empty()) GetHciInterface()->Enable(true, sets, Bind(DoNothing));
  }

  void OnAdvertisingSetTerminated(
      uint8_t status, uint8_t advertising_handle, uint16_t connection_handle,
      uint8_t num_completed_extended_adv_events) override {
@@ -835,10 +899,15 @@ class BleAdvertisingManagerImpl
    if (p_inst->in_use == true) {
      // TODO(jpawlowski): we don't really allow to do directed advertising
      // right now. This should probably be removed, check with Andre.
      if ((p_inst->advertising_event_properties & 0x0C) ==
          0 /* directed advertising bits not set */) {
        GetHciInterface()->Enable(true, advertising_handle, 0x00, 0x00,
                                  Bind(DoNothing));
      if ((p_inst->advertising_event_properties & 0x0C) == 0) {
        /* directed advertising bits not set */

        RecomputeTimeout(p_inst, TimeTicks::Now());
        if (p_inst->enable_status) {
          GetHciInterface()->Enable(true, advertising_handle, p_inst->duration,
                                    p_inst->maxExtAdvEvents, Bind(DoNothing));
        }

      } else {
        /* mark directed adv as disabled if adv has been stopped */
        p_inst->in_use = false;
@@ -907,3 +976,72 @@ void btm_ble_multi_adv_cleanup(void) {
  BleAdvertisingManager::CleanUp();
  BleAdvertiserHciInterface::CleanUp();
}

// TODO(jpawlowski): Find a nicer way to test RecomputeTimeout without exposing
// AdvertisingInstance
bool timeout_triggered = false;
void test_timeout_cb(uint8_t status) { timeout_triggered = true; }

// verify that if duration passed, or is about to pass, recomputation will shut
// down the advertiser completly
void testRecomputeTimeout1() {
  auto manager = (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get();

  TimeTicks start = TimeTicks::Now();
  TimeTicks end = start + TimeDelta::FromMilliseconds(111);
  AdvertisingInstance test1(0);
  test1.enable_status = true;
  test1.enable_time = start;
  test1.duration = 12 /*120ms*/;
  test1.timeout_cb = Bind(&test_timeout_cb);

  manager->RecomputeTimeout(&test1, end);

  CHECK(timeout_triggered == true);
  timeout_triggered = false;
  CHECK(test1.enable_status == false);
}

// verify that duration and maxExtAdvEvents are properly adjusted when
// recomputing.
void testRecomputeTimeout2() {
  auto manager = (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get();

  TimeTicks start = TimeTicks::Now();
  TimeTicks end = start + TimeDelta::FromMilliseconds(250);
  AdvertisingInstance test1(0);
  test1.enable_status = true;
  test1.enable_time = start;
  test1.duration = 50 /*500ms*/;
  test1.maxExtAdvEvents = 50;
  test1.advertising_interval = 16 /* 10 ms */;
  test1.timeout_cb = Bind(&test_timeout_cb);

  manager->RecomputeTimeout(&test1, end);

  CHECK(timeout_triggered == false);
  CHECK(test1.enable_status == true);
  CHECK(test1.duration == 25);
  CHECK(test1.maxExtAdvEvents == 25);
}

// verify that if maxExtAdvEvents were sent, or are close to end, recomputation
// wil shut down the advertiser completly
void testRecomputeTimeout3() {
  auto manager = (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get();

  TimeTicks start = TimeTicks::Now();
  TimeTicks end = start + TimeDelta::FromMilliseconds(495);
  AdvertisingInstance test1(0);
  test1.enable_status = true;
  test1.enable_time = start;
  test1.maxExtAdvEvents = 50;
  test1.advertising_interval = 16 /* 10 ms */;
  test1.timeout_cb = Bind(&test_timeout_cb);

  manager->RecomputeTimeout(&test1, end);

  CHECK(timeout_triggered == true);
  timeout_triggered = false;
  CHECK(test1.enable_status == false);
}
+15 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include "bt_target.h"

#if (BLE_PRIVACY_SPT == TRUE)
#include "ble_advertiser.h"
#include "bt_types.h"
#include "btm_int.h"
#include "btu.h"
@@ -526,6 +527,13 @@ bool btm_ble_suspend_resolving_list_activity(void) {
    p_ble_cb->suspended_rl_state |= BTM_BLE_RL_ADV;
  }

  // If it's non-VSC implementation, suspend
  if (BleAdvertisingManager::Get() &&
      (controller_get_interface()->supports_ble_extended_advertising() ||
       BTM_BleMaxMultiAdvInstanceCount() == 0)) {
    BleAdvertisingManager::Get()->Suspend();
  }

  if (BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) {
    btm_ble_stop_scan();
    p_ble_cb->suspended_rl_state |= BTM_BLE_RL_SCAN;
@@ -553,6 +561,13 @@ void btm_ble_resume_resolving_list_activity(void) {

  if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_ADV) btm_ble_start_adv();

  // If it's non-VSC implementation, resume
  if (BleAdvertisingManager::Get() &&
      (controller_get_interface()->supports_ble_extended_advertising() ||
       BTM_BleMaxMultiAdvInstanceCount() == 0)) {
    BleAdvertisingManager::Get()->Resume();
  }

  if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_SCAN) btm_ble_start_scan();

  if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_INIT) btm_ble_resume_bg_conn();
+10 −3
Original line number Diff line number Diff line
@@ -146,6 +146,13 @@ class BleAdvertisingManager {
  /*  This function disable a Multi-ADV instance */
  virtual void Unregister(uint8_t inst_id) = 0;

  /* When resolving list is used, we need to suspend and resume all advertising
   * instances for the time of operation. Suspend() saves current state,
   * Resume() resumes the advertising.
   */
  virtual void Suspend() = 0;
  virtual void Resume() = 0;

  /* This method is a member of BleAdvertiserHciInterface, and is exposed here
   * just for tests. It should never be called from upper layers*/
  virtual void OnAdvertisingSetTerminated(
Loading