• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  Copyright 2017  The Android Open Source Project
4  *  Copyright 2014  Broadcom Corporation
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at:
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  *
18  ******************************************************************************/
19 
20 #include <base/bind.h>
21 #include <base/location.h>
22 #include <base/logging.h>
23 #include <base/memory/weak_ptr.h>
24 #include <base/strings/string_number_conversions.h>
25 #include <base/time/time.h>
26 #include <string.h>
27 #include <queue>
28 #include <vector>
29 
30 #include "bt_target.h"
31 #include "device/include/controller.h"
32 #include "osi/include/alarm.h"
33 
34 #include "ble_advertiser.h"
35 #include "ble_advertiser_hci_interface.h"
36 #include "btm_int_types.h"
37 
38 using base::Bind;
39 using base::TimeDelta;
40 using base::TimeTicks;
41 using RegisterCb =
42     base::Callback<void(uint8_t /* inst_id */, uint8_t /* status */)>;
43 using IdTxPowerStatusCb = base::Callback<void(
44     uint8_t /* inst_id */, int8_t /* tx_power */, uint8_t /* status */)>;
45 using SetEnableData = BleAdvertiserHciInterface::SetEnableData;
46 extern void btm_gen_resolvable_private_addr(
47     base::Callback<void(uint8_t[8])> cb);
48 
49 constexpr int ADV_DATA_LEN_MAX = 251;
50 
51 namespace {
52 
is_connectable(uint16_t advertising_event_properties)53 bool is_connectable(uint16_t advertising_event_properties) {
54   return advertising_event_properties & 0x01;
55 }
56 
57 struct AdvertisingInstance {
58   uint8_t inst_id;
59   bool in_use;
60   uint8_t advertising_event_properties;
61   alarm_t* adv_raddr_timer;
62   int8_t tx_power;
63   uint16_t duration;  // 1 unit is 10ms
64   uint8_t maxExtAdvEvents;
65   alarm_t* timeout_timer;
66   uint8_t own_address_type;
67   RawAddress own_address;
68   MultiAdvCb timeout_cb;
69   bool address_update_required;
70   bool periodic_enabled;
71   uint32_t advertising_interval;  // 1 unit is 0.625 ms
72 
73   /* When true, advertising set is enabled, or last scheduled call to "LE Set
74    * Extended Advertising Set Enable" is to enable this advertising set. Any
75    * command scheduled when in this state will execute when the set is enabled,
76    * unless enabling fails.
77    *
78    * When false, advertising set is disabled, or last scheduled call to "LE Set
79    * Extended Advertising Set Enable" is to disable this advertising set. Any
80    * command scheduled when in this state will execute when the set is disabled.
81    */
82   bool enable_status;
83   TimeTicks enable_time;
84 
IsEnabled__anon0a4fe9790111::AdvertisingInstance85   bool IsEnabled() { return enable_status; }
86 
IsConnectable__anon0a4fe9790111::AdvertisingInstance87   bool IsConnectable() { return is_connectable(advertising_event_properties); }
88 
AdvertisingInstance__anon0a4fe9790111::AdvertisingInstance89   AdvertisingInstance(int inst_id)
90       : inst_id(inst_id),
91         in_use(false),
92         advertising_event_properties(0),
93         tx_power(0),
94         duration(0),
95         timeout_timer(nullptr),
96         own_address_type(0),
97         own_address(RawAddress::kEmpty),
98         address_update_required(false),
99         periodic_enabled(false),
100         enable_status(false) {
101     adv_raddr_timer = alarm_new_periodic("btm_ble.adv_raddr_timer");
102   }
103 
~AdvertisingInstance__anon0a4fe9790111::AdvertisingInstance104   ~AdvertisingInstance() {
105     alarm_free(adv_raddr_timer);
106     adv_raddr_timer = nullptr;
107     if (timeout_timer) {
108       alarm_free(timeout_timer);
109       timeout_timer = nullptr;
110     }
111   }
112 };
113 
114 void btm_ble_adv_raddr_timer_timeout(void* data);
115 
DoNothing(uint8_t)116 void DoNothing(uint8_t) {}
DoNothing2(uint8_t,uint8_t)117 void DoNothing2(uint8_t, uint8_t) {}
118 
119 struct closure_data {
120   base::Closure user_task;
121   tracked_objects::Location posted_from;
122 };
123 
alarm_closure_cb(void * p)124 static void alarm_closure_cb(void* p) {
125   closure_data* data = (closure_data*)p;
126   VLOG(1) << "executing timer scheduled at %s" << data->posted_from.ToString();
127   data->user_task.Run();
128   delete data;
129 }
130 
131 // Periodic alarms are not supported, because we clean up data in callback
alarm_set_closure(const tracked_objects::Location & posted_from,alarm_t * alarm,period_ms_t interval_ms,base::Closure user_task)132 void alarm_set_closure(const tracked_objects::Location& posted_from,
133                        alarm_t* alarm, period_ms_t interval_ms,
134                        base::Closure user_task) {
135   closure_data* data = new closure_data;
136   data->posted_from = posted_from;
137   data->user_task = std::move(user_task);
138   VLOG(1) << "scheduling timer %s" << data->posted_from.ToString();
139   alarm_set_on_mloop(alarm, interval_ms, alarm_closure_cb, data);
140 }
141 
142 class BleAdvertisingManagerImpl;
143 
144 /* a temporary type for holding all the data needed in callbacks below*/
145 struct CreatorParams {
146   uint8_t inst_id;
147   base::WeakPtr<BleAdvertisingManagerImpl> self;
148   IdTxPowerStatusCb cb;
149   tBTM_BLE_ADV_PARAMS params;
150   std::vector<uint8_t> advertise_data;
151   std::vector<uint8_t> scan_response_data;
152   tBLE_PERIODIC_ADV_PARAMS periodic_params;
153   std::vector<uint8_t> periodic_data;
154   uint16_t duration;
155   uint8_t maxExtAdvEvents;
156   RegisterCb timeout_cb;
157 };
158 
159 using c_type = std::unique_ptr<CreatorParams>;
160 
161 BleAdvertisingManager* instance;
162 base::WeakPtr<BleAdvertisingManagerImpl> instance_weakptr;
163 
164 class BleAdvertisingManagerImpl
165     : public BleAdvertisingManager,
166       public BleAdvertiserHciInterface::AdvertisingEventObserver {
167  public:
BleAdvertisingManagerImpl(BleAdvertiserHciInterface * interface)168   BleAdvertisingManagerImpl(BleAdvertiserHciInterface* interface)
169       : hci_interface(interface), weak_factory_(this) {
170     hci_interface->ReadInstanceCount(
171         base::Bind(&BleAdvertisingManagerImpl::ReadInstanceCountCb,
172                    weak_factory_.GetWeakPtr()));
173   }
174 
~BleAdvertisingManagerImpl()175   ~BleAdvertisingManagerImpl() { adv_inst.clear(); }
176 
GetOwnAddress(uint8_t inst_id,GetAddressCallback cb)177   void GetOwnAddress(uint8_t inst_id, GetAddressCallback cb) override {
178     cb.Run(adv_inst[inst_id].own_address_type, adv_inst[inst_id].own_address);
179   }
180 
ReadInstanceCountCb(uint8_t instance_count)181   void ReadInstanceCountCb(uint8_t instance_count) {
182     this->inst_count = instance_count;
183     adv_inst.reserve(inst_count);
184     /* Initialize adv instance indices and IDs. */
185     for (uint8_t i = 0; i < inst_count; i++) {
186       adv_inst.emplace_back(i);
187     }
188   }
189 
OnRpaGenerationComplete(base::Callback<void (RawAddress)> cb,uint8_t rand[8])190   void OnRpaGenerationComplete(base::Callback<void(RawAddress)> cb,
191                                uint8_t rand[8]) {
192     VLOG(1) << __func__;
193 
194     RawAddress bda;
195 
196     rand[2] &= (~BLE_RESOLVE_ADDR_MASK);
197     rand[2] |= BLE_RESOLVE_ADDR_MSB;
198 
199     bda.address[2] = rand[0];
200     bda.address[1] = rand[1];
201     bda.address[0] = rand[2];
202 
203     BT_OCTET16 irk;
204     BTM_GetDeviceIDRoot(irk);
205     tSMP_ENC output;
206 
207     if (!SMP_Encrypt(irk, BT_OCTET16_LEN, rand, 3, &output))
208       LOG_ASSERT(false) << "SMP_Encrypt failed";
209 
210     /* set hash to be LSB of rpAddress */
211     bda.address[5] = output.param_buf[0];
212     bda.address[4] = output.param_buf[1];
213     bda.address[3] = output.param_buf[2];
214 
215     cb.Run(bda);
216   }
217 
GenerateRpa(base::Callback<void (RawAddress)> cb)218   void GenerateRpa(base::Callback<void(RawAddress)> cb) {
219     btm_gen_resolvable_private_addr(
220         Bind(&BleAdvertisingManagerImpl::OnRpaGenerationComplete,
221              weak_factory_.GetWeakPtr(), std::move(cb)));
222   }
223 
ConfigureRpa(AdvertisingInstance * p_inst,MultiAdvCb configuredCb)224   void ConfigureRpa(AdvertisingInstance* p_inst, MultiAdvCb configuredCb) {
225     /* Connectable advertising set must be disabled when updating RPA */
226     bool restart = p_inst->IsEnabled() && p_inst->IsConnectable();
227 
228     // If there is any form of timeout on the set, schedule address update when
229     // the set stops, because there is no good way to compute new timeout value.
230     // Maximum duration value is around 10 minutes, so this is safe.
231     if (restart && (p_inst->duration || p_inst->maxExtAdvEvents)) {
232       p_inst->address_update_required = true;
233       configuredCb.Run(0x01);
234       return;
235     }
236 
237     GenerateRpa(Bind(
238         [](AdvertisingInstance* p_inst, MultiAdvCb configuredCb,
239            RawAddress bda) {
240           /* Connectable advertising set must be disabled when updating RPA */
241           bool restart = p_inst->IsEnabled() && p_inst->IsConnectable();
242 
243           if (!instance_weakptr.get()) return;
244           auto hci_interface = instance_weakptr.get()->GetHciInterface();
245 
246           if (restart) {
247             p_inst->enable_status = false;
248             hci_interface->Enable(false, p_inst->inst_id, 0x00, 0x00,
249                                   Bind(DoNothing));
250           }
251 
252           /* set it to controller */
253           hci_interface->SetRandomAddress(
254               p_inst->inst_id, bda,
255               Bind(
256                   [](AdvertisingInstance* p_inst, RawAddress bda,
257                      MultiAdvCb configuredCb, uint8_t status) {
258                     p_inst->own_address = bda;
259                     configuredCb.Run(0x00);
260                   },
261                   p_inst, bda, configuredCb));
262 
263           if (restart) {
264             p_inst->enable_status = true;
265             hci_interface->Enable(true, p_inst->inst_id, 0x00, 0x00,
266                                   Bind(DoNothing));
267           }
268         },
269         p_inst, std::move(configuredCb)));
270   }
271 
RegisterAdvertiser(base::Callback<void (uint8_t,uint8_t)> cb)272   void RegisterAdvertiser(
273       base::Callback<void(uint8_t /* inst_id */, uint8_t /* status */)> cb)
274       override {
275     AdvertisingInstance* p_inst = &adv_inst[0];
276     for (uint8_t i = 0; i < inst_count; i++, p_inst++) {
277       if (p_inst->in_use) continue;
278 
279       p_inst->in_use = true;
280 
281       // set up periodic timer to update address.
282       if (BTM_BleLocalPrivacyEnabled()) {
283         p_inst->own_address_type = BLE_ADDR_RANDOM;
284         GenerateRpa(Bind(
285             [](AdvertisingInstance* p_inst,
286                base::Callback<void(uint8_t /* inst_id */, uint8_t /* status */)>
287                    cb,
288                RawAddress bda) {
289               p_inst->own_address = bda;
290 
291               alarm_set_on_mloop(p_inst->adv_raddr_timer,
292                                  BTM_BLE_PRIVATE_ADDR_INT_MS,
293                                  btm_ble_adv_raddr_timer_timeout, p_inst);
294               cb.Run(p_inst->inst_id, BTM_BLE_MULTI_ADV_SUCCESS);
295             },
296             p_inst, cb));
297       } else {
298         p_inst->own_address_type = BLE_ADDR_PUBLIC;
299         p_inst->own_address = *controller_get_interface()->get_address();
300 
301         cb.Run(p_inst->inst_id, BTM_BLE_MULTI_ADV_SUCCESS);
302       }
303       return;
304     }
305 
306     LOG(INFO) << "no free advertiser instance";
307     cb.Run(0xFF, ADVERTISE_FAILED_TOO_MANY_ADVERTISERS);
308   }
309 
StartAdvertising(uint8_t advertiser_id,MultiAdvCb cb,tBTM_BLE_ADV_PARAMS * params,std::vector<uint8_t> advertise_data,std::vector<uint8_t> scan_response_data,int duration,MultiAdvCb timeout_cb)310   void StartAdvertising(uint8_t advertiser_id, MultiAdvCb cb,
311                         tBTM_BLE_ADV_PARAMS* params,
312                         std::vector<uint8_t> advertise_data,
313                         std::vector<uint8_t> scan_response_data, int duration,
314                         MultiAdvCb timeout_cb) override {
315     /* a temporary type for holding all the data needed in callbacks below*/
316     struct CreatorParams {
317       uint8_t inst_id;
318       base::WeakPtr<BleAdvertisingManagerImpl> self;
319       MultiAdvCb cb;
320       tBTM_BLE_ADV_PARAMS params;
321       std::vector<uint8_t> advertise_data;
322       std::vector<uint8_t> scan_response_data;
323       int duration;
324       MultiAdvCb timeout_cb;
325     };
326 
327     std::unique_ptr<CreatorParams> c;
328     c.reset(new CreatorParams());
329 
330     c->self = weak_factory_.GetWeakPtr();
331     c->cb = std::move(cb);
332     c->params = *params;
333     c->advertise_data = std::move(advertise_data);
334     c->scan_response_data = std::move(scan_response_data);
335     c->duration = duration;
336     c->timeout_cb = std::move(timeout_cb);
337     c->inst_id = advertiser_id;
338 
339     using c_type = std::unique_ptr<CreatorParams>;
340 
341     // this code is intentionally left formatted this way to highlight the
342     // asynchronous flow
343     // clang-format off
344     c->self->SetParameters(c->inst_id, &c->params, Bind(
345       [](c_type c, uint8_t status, int8_t tx_power) {
346         if (!c->self) {
347           LOG(INFO) << "Stack was shut down";
348           return;
349         }
350 
351         if (status) {
352           LOG(ERROR) << "setting parameters failed, status: " << +status;
353           c->cb.Run(status);
354           return;
355         }
356 
357         c->self->adv_inst[c->inst_id].tx_power = tx_power;
358 
359         const RawAddress& rpa = c->self->adv_inst[c->inst_id].own_address;
360         c->self->GetHciInterface()->SetRandomAddress(c->inst_id, rpa, Bind(
361           [](c_type c, uint8_t status) {
362             if (!c->self) {
363               LOG(INFO) << "Stack was shut down";
364               return;
365             }
366 
367             if (status != 0) {
368               LOG(ERROR) << "setting random address failed, status: " << +status;
369               c->cb.Run(status);
370               return;
371             }
372 
373             c->self->SetData(c->inst_id, false, std::move(c->advertise_data), Bind(
374               [](c_type c, uint8_t status) {
375                 if (!c->self) {
376                   LOG(INFO) << "Stack was shut down";
377                   return;
378                 }
379 
380                 if (status != 0) {
381                   LOG(ERROR) << "setting advertise data failed, status: " << +status;
382                   c->cb.Run(status);
383                   return;
384                 }
385 
386                 c->self->SetData(c->inst_id, true, std::move(c->scan_response_data), Bind(
387                   [](c_type c, uint8_t status) {
388                     if (!c->self) {
389                       LOG(INFO) << "Stack was shut down";
390                       return;
391                     }
392 
393                     if (status != 0) {
394                       LOG(ERROR) << "setting scan response data failed, status: " << +status;
395                       c->cb.Run(status);
396                       return;
397                     }
398 
399                     c->self->Enable(c->inst_id, true, c->cb, c->duration, 0, std::move(c->timeout_cb));
400 
401                 }, base::Passed(&c)));
402             }, base::Passed(&c)));
403         }, base::Passed(&c)));
404     }, base::Passed(&c)));
405     // clang-format on
406   }
407 
StartAdvertisingSet(IdTxPowerStatusCb cb,tBTM_BLE_ADV_PARAMS * params,std::vector<uint8_t> advertise_data,std::vector<uint8_t> scan_response_data,tBLE_PERIODIC_ADV_PARAMS * periodic_params,std::vector<uint8_t> periodic_data,uint16_t duration,uint8_t maxExtAdvEvents,RegisterCb timeout_cb)408   void StartAdvertisingSet(IdTxPowerStatusCb cb, tBTM_BLE_ADV_PARAMS* params,
409                            std::vector<uint8_t> advertise_data,
410                            std::vector<uint8_t> scan_response_data,
411                            tBLE_PERIODIC_ADV_PARAMS* periodic_params,
412                            std::vector<uint8_t> periodic_data,
413                            uint16_t duration, uint8_t maxExtAdvEvents,
414                            RegisterCb timeout_cb) override {
415     std::unique_ptr<CreatorParams> c;
416     c.reset(new CreatorParams());
417 
418     c->self = weak_factory_.GetWeakPtr();
419     c->cb = std::move(cb);
420     c->params = *params;
421     c->advertise_data = std::move(advertise_data);
422     c->scan_response_data = std::move(scan_response_data);
423     c->periodic_params = *periodic_params;
424     c->periodic_data = std::move(periodic_data);
425     c->duration = duration;
426     c->maxExtAdvEvents = maxExtAdvEvents;
427     c->timeout_cb = std::move(timeout_cb);
428 
429     // this code is intentionally left formatted this way to highlight the
430     // asynchronous flow
431     // clang-format off
432     c->self->RegisterAdvertiser(Bind(
433       [](c_type c, uint8_t advertiser_id, uint8_t status) {
434         if (!c->self) {
435           LOG(INFO) << "Stack was shut down";
436           return;
437         }
438 
439         if (status != 0) {
440           LOG(ERROR) << " failed, status: " << +status;
441           c->cb.Run(0, 0, status);
442           return;
443         }
444 
445         c->inst_id = advertiser_id;
446 
447         c->self->SetParameters(c->inst_id, &c->params, Bind(
448           [](c_type c, uint8_t status, int8_t tx_power) {
449             if (!c->self) {
450               LOG(INFO) << "Stack was shut down";
451               return;
452             }
453 
454             if (status != 0) {
455               c->self->Unregister(c->inst_id);
456               LOG(ERROR) << "setting parameters failed, status: " << +status;
457               c->cb.Run(0, 0, status);
458               return;
459             }
460 
461             c->self->adv_inst[c->inst_id].tx_power = tx_power;
462 
463             if (c->self->adv_inst[c->inst_id].own_address_type == BLE_ADDR_PUBLIC) {
464               c->self->StartAdvertisingSetAfterAddressPart(std::move(c));
465               return;
466             }
467 
468             //own_address_type == BLE_ADDR_RANDOM
469             const RawAddress& rpa = c->self->adv_inst[c->inst_id].own_address;
470             c->self->GetHciInterface()->SetRandomAddress(c->inst_id, rpa, Bind(
471               [](c_type c, uint8_t status) {
472                 if (!c->self) {
473                   LOG(INFO) << "Stack was shut down";
474                   return;
475                 }
476 
477                 if (status != 0) {
478                   c->self->Unregister(c->inst_id);
479                   LOG(ERROR) << "setting random address failed, status: " << +status;
480                   c->cb.Run(0, 0, status);
481                   return;
482                 }
483 
484                 c->self->StartAdvertisingSetAfterAddressPart(std::move(c));
485           }, base::Passed(&c)));
486         }, base::Passed(&c)));
487     }, base::Passed(&c)));
488     // clang-format on
489   }
490 
StartAdvertisingSetAfterAddressPart(c_type c)491   void StartAdvertisingSetAfterAddressPart(c_type c) {
492     c->self->SetData(
493         c->inst_id, false, std::move(c->advertise_data),
494         Bind(
495             [](c_type c, uint8_t status) {
496               if (!c->self) {
497                 LOG(INFO) << "Stack was shut down";
498                 return;
499               }
500 
501               if (status != 0) {
502                 c->self->Unregister(c->inst_id);
503                 LOG(ERROR) << "setting advertise data failed, status: "
504                            << +status;
505                 c->cb.Run(0, 0, status);
506                 return;
507               }
508 
509               c->self->SetData(
510                   c->inst_id, true, std::move(c->scan_response_data),
511                   Bind(
512                       [](c_type c, uint8_t status) {
513                         if (!c->self) {
514                           LOG(INFO) << "Stack was shut down";
515                           return;
516                         }
517 
518                         if (status != 0) {
519                           c->self->Unregister(c->inst_id);
520                           LOG(ERROR)
521                               << "setting scan response data failed, status: "
522                               << +status;
523                           c->cb.Run(0, 0, status);
524                           return;
525                         }
526 
527                         if (c->periodic_params.enable) {
528                           c->self->StartAdvertisingSetPeriodicPart(
529                               std::move(c));
530                         } else {
531                           c->self->StartAdvertisingSetFinish(std::move(c));
532                         }
533                       },
534                       base::Passed(&c)));
535             },
536             base::Passed(&c)));
537   }
538 
StartAdvertisingSetPeriodicPart(c_type c)539   void StartAdvertisingSetPeriodicPart(c_type c) {
540     // this code is intentionally left formatted this way to highlight the
541     // asynchronous flow
542     // clang-format off
543     c->self->SetPeriodicAdvertisingParameters(c->inst_id, &c->periodic_params, Bind(
544       [](c_type c, uint8_t status) {
545         if (!c->self) {
546           LOG(INFO) << "Stack was shut down";
547           return;
548         }
549 
550         if (status != 0) {
551           c->self->Unregister(c->inst_id);
552           LOG(ERROR) << "setting periodic parameters failed, status: " << +status;
553           c->cb.Run(0, 0, status);
554           return;
555         }
556 
557         c->self->SetPeriodicAdvertisingData(c->inst_id, std::move(c->periodic_data), Bind(
558           [](c_type c, uint8_t status) {
559             if (!c->self) {
560               LOG(INFO) << "Stack was shut down";
561               return;
562             }
563 
564             if (status != 0) {
565               c->self->Unregister(c->inst_id);
566               LOG(ERROR) << "setting periodic parameters failed, status: " << +status;
567               c->cb.Run(0, 0, status);
568               return;
569             }
570 
571             c->self->SetPeriodicAdvertisingEnable(c->inst_id, true, Bind(
572               [](c_type c, uint8_t status) {
573                 if (!c->self) {
574                   LOG(INFO) << "Stack was shut down";
575                   return;
576                 }
577 
578                 if (status != 0) {
579                   c->self->Unregister(c->inst_id);
580                   LOG(ERROR) << "enabling periodic advertising failed, status: " << +status;
581                   c->cb.Run(0, 0, status);
582                   return;
583                 }
584 
585                 c->self->StartAdvertisingSetFinish(std::move(c));
586 
587               }, base::Passed(&c)));
588         }, base::Passed(&c)));
589     }, base::Passed(&c)));
590     // clang-format on
591   }
592 
StartAdvertisingSetFinish(c_type c)593   void StartAdvertisingSetFinish(c_type c) {
594     uint8_t inst_id = c->inst_id;
595     uint16_t duration = c->duration;
596     uint8_t maxExtAdvEvents = c->maxExtAdvEvents;
597     RegisterCb timeout_cb = std::move(c->timeout_cb);
598     base::WeakPtr<BleAdvertisingManagerImpl> self = c->self;
599     MultiAdvCb enable_cb = Bind(
600         [](c_type c, uint8_t status) {
601           if (!c->self) {
602             LOG(INFO) << "Stack was shut down";
603             return;
604           }
605 
606           if (status != 0) {
607             c->self->Unregister(c->inst_id);
608             LOG(ERROR) << "enabling advertiser failed, status: " << +status;
609             c->cb.Run(0, 0, status);
610             return;
611           }
612           int8_t tx_power = c->self->adv_inst[c->inst_id].tx_power;
613           c->cb.Run(c->inst_id, tx_power, status);
614         },
615         base::Passed(&c));
616 
617     self->Enable(inst_id, true, std::move(enable_cb), duration, maxExtAdvEvents,
618                  Bind(std::move(timeout_cb), inst_id));
619   }
620 
EnableWithTimerCb(uint8_t inst_id,MultiAdvCb enable_cb,int duration,MultiAdvCb timeout_cb,uint8_t status)621   void EnableWithTimerCb(uint8_t inst_id, MultiAdvCb enable_cb, int duration,
622                          MultiAdvCb timeout_cb, uint8_t status) {
623     VLOG(1) << __func__ << " inst_id: " << +inst_id;
624     AdvertisingInstance* p_inst = &adv_inst[inst_id];
625 
626     // Run the regular enable callback
627     enable_cb.Run(status);
628 
629     p_inst->timeout_timer = alarm_new("btm_ble.adv_timeout");
630 
631     base::Closure cb = Bind(
632         &BleAdvertisingManagerImpl::Enable, weak_factory_.GetWeakPtr(), inst_id,
633         0 /* disable */, std::move(timeout_cb), 0, 0, base::Bind(DoNothing));
634 
635     // schedule disable when the timeout passes
636     alarm_set_closure(FROM_HERE, p_inst->timeout_timer, duration * 10,
637                       std::move(cb));
638   }
639 
Enable(uint8_t inst_id,bool enable,MultiAdvCb cb,uint16_t duration,uint8_t maxExtAdvEvents,MultiAdvCb timeout_cb)640   void Enable(uint8_t inst_id, bool enable, MultiAdvCb cb, uint16_t duration,
641               uint8_t maxExtAdvEvents, MultiAdvCb timeout_cb) override {
642     VLOG(1) << __func__ << " inst_id: " << +inst_id;
643     if (inst_id >= inst_count) {
644       LOG(ERROR) << "bad instance id " << +inst_id;
645       return;
646     }
647 
648     AdvertisingInstance* p_inst = &adv_inst[inst_id];
649     VLOG(1) << __func__ << " enable: " << enable << ", duration: " << +duration;
650     if (!p_inst->in_use) {
651       LOG(ERROR) << "Invalid or no active instance";
652       cb.Run(BTM_BLE_MULTI_ADV_FAILURE);
653       return;
654     }
655 
656     if (enable && (duration || maxExtAdvEvents)) {
657       p_inst->timeout_cb = std::move(timeout_cb);
658     }
659 
660     p_inst->duration = duration;
661     p_inst->maxExtAdvEvents = maxExtAdvEvents;
662 
663     if (enable && p_inst->address_update_required) {
664       p_inst->address_update_required = false;
665       ConfigureRpa(p_inst, base::Bind(&BleAdvertisingManagerImpl::EnableFinish,
666                                       weak_factory_.GetWeakPtr(), p_inst,
667                                       enable, std::move(cb)));
668       return;
669     }
670 
671     EnableFinish(p_inst, enable, std::move(cb), 0);
672   }
673 
EnableFinish(AdvertisingInstance * p_inst,bool enable,MultiAdvCb cb,uint8_t status)674   void EnableFinish(AdvertisingInstance* p_inst, bool enable, MultiAdvCb cb,
675                     uint8_t status) {
676     MultiAdvCb myCb;
677     if (enable && p_inst->duration) {
678       // TODO(jpawlowski): HCI implementation that can't do duration should
679       // emulate it, not EnableWithTimerCb.
680       myCb = Bind(&BleAdvertisingManagerImpl::EnableWithTimerCb,
681                   weak_factory_.GetWeakPtr(), p_inst->inst_id, std::move(cb),
682                   p_inst->duration, p_inst->timeout_cb);
683     } else {
684       myCb = std::move(cb);
685 
686       if (p_inst->timeout_timer) {
687         alarm_cancel(p_inst->timeout_timer);
688         alarm_free(p_inst->timeout_timer);
689         p_inst->timeout_timer = nullptr;
690       }
691     }
692 
693     if (enable) p_inst->enable_time = TimeTicks::Now();
694     p_inst->enable_status = enable;
695     GetHciInterface()->Enable(enable, p_inst->inst_id, p_inst->duration,
696                               p_inst->maxExtAdvEvents, std::move(myCb));
697   }
698 
SetParameters(uint8_t inst_id,tBTM_BLE_ADV_PARAMS * p_params,ParametersCb cb)699   void SetParameters(uint8_t inst_id, tBTM_BLE_ADV_PARAMS* p_params,
700                      ParametersCb cb) override {
701     VLOG(1) << __func__ << " inst_id: " << +inst_id;
702     if (inst_id >= inst_count) {
703       LOG(ERROR) << "bad instance id " << +inst_id;
704       return;
705     }
706 
707     AdvertisingInstance* p_inst = &adv_inst[inst_id];
708     if (!p_inst->in_use) {
709       LOG(ERROR) << "adv instance not in use" << +inst_id;
710       cb.Run(BTM_BLE_MULTI_ADV_FAILURE, 0);
711       return;
712     }
713 
714     // TODO: disable only if was enabled, currently no use scenario needs
715     // that,
716     // we always set parameters before enabling
717     // GetHciInterface()->Enable(false, inst_id, Bind(DoNothing));
718     p_inst->advertising_event_properties =
719         p_params->advertising_event_properties;
720     p_inst->tx_power = p_params->tx_power;
721     p_inst->advertising_interval = p_params->adv_int_min;
722     const RawAddress& peer_address = RawAddress::kEmpty;
723 
724     GetHciInterface()->SetParameters(
725         p_inst->inst_id, p_params->advertising_event_properties,
726         p_params->adv_int_min, p_params->adv_int_max, p_params->channel_map,
727         p_inst->own_address_type, p_inst->own_address, 0x00, peer_address,
728         p_params->adv_filter_policy, p_inst->tx_power,
729         p_params->primary_advertising_phy, 0x00,
730         p_params->secondary_advertising_phy, 0x01 /* TODO: proper SID */,
731         p_params->scan_request_notification_enable, cb);
732 
733     // TODO: re-enable only if it was enabled, properly call
734     // SetParamsCallback
735     // currently no use scenario needs that
736     // GetHciInterface()->Enable(true, inst_id, BTM_BleUpdateAdvInstParamCb);
737   }
738 
SetData(uint8_t inst_id,bool is_scan_rsp,std::vector<uint8_t> data,MultiAdvCb cb)739   void SetData(uint8_t inst_id, bool is_scan_rsp, std::vector<uint8_t> data,
740                MultiAdvCb cb) override {
741     VLOG(1) << __func__ << " inst_id: " << +inst_id;
742     if (inst_id >= inst_count) {
743       LOG(ERROR) << "bad instance id " << +inst_id;
744       return;
745     }
746 
747     AdvertisingInstance* p_inst = &adv_inst[inst_id];
748     VLOG(1) << "is_scan_rsp = " << is_scan_rsp;
749 
750     if (!is_scan_rsp && is_connectable(p_inst->advertising_event_properties)) {
751       uint8_t flags_val = BTM_GENERAL_DISCOVERABLE;
752 
753       if (p_inst->duration) flags_val = BTM_LIMITED_DISCOVERABLE;
754 
755       std::vector<uint8_t> flags;
756       flags.push_back(2);  // length
757       flags.push_back(HCI_EIR_FLAGS_TYPE);
758       flags.push_back(flags_val);
759 
760       data.insert(data.begin(), flags.begin(), flags.end());
761     }
762 
763     // Find and fill TX Power with the correct value
764     if (data.size()) {
765       size_t i = 0;
766       while (i < data.size()) {
767         uint8_t type = data[i + 1];
768         if (type == HCI_EIR_TX_POWER_LEVEL_TYPE) {
769           data[i + 2] = adv_inst[inst_id].tx_power;
770         }
771         i += data[i] + 1;
772       }
773     }
774 
775     VLOG(1) << "data is: " << base::HexEncode(data.data(), data.size());
776     DivideAndSendData(
777         inst_id, data, cb,
778         base::Bind(&BleAdvertisingManagerImpl::SetDataAdvDataSender,
779                    weak_factory_.GetWeakPtr(), is_scan_rsp));
780   }
781 
SetDataAdvDataSender(uint8_t is_scan_rsp,uint8_t inst_id,uint8_t operation,uint8_t length,uint8_t * data,MultiAdvCb cb)782   void SetDataAdvDataSender(uint8_t is_scan_rsp, uint8_t inst_id,
783                             uint8_t operation, uint8_t length, uint8_t* data,
784                             MultiAdvCb cb) {
785     if (is_scan_rsp)
786       GetHciInterface()->SetScanResponseData(inst_id, operation, 0x01, length,
787                                              data, cb);
788     else
789       GetHciInterface()->SetAdvertisingData(inst_id, operation, 0x01, length,
790                                             data, cb);
791   }
792 
793   using DataSender = base::Callback<void(
794       uint8_t /*inst_id*/, uint8_t /* operation */, uint8_t /* length */,
795       uint8_t* /* data */, MultiAdvCb /* done */)>;
796 
DivideAndSendData(int inst_id,std::vector<uint8_t> data,MultiAdvCb done_cb,DataSender sender)797   void DivideAndSendData(int inst_id, std::vector<uint8_t> data,
798                          MultiAdvCb done_cb, DataSender sender) {
799     DivideAndSendDataRecursively(true, inst_id, std::move(data), 0,
800                                  std::move(done_cb), std::move(sender), 0);
801   }
802 
DivideAndSendDataRecursively(bool isFirst,int inst_id,std::vector<uint8_t> data,int offset,MultiAdvCb done_cb,DataSender sender,uint8_t status)803   static void DivideAndSendDataRecursively(bool isFirst, int inst_id,
804                                            std::vector<uint8_t> data,
805                                            int offset, MultiAdvCb done_cb,
806                                            DataSender sender, uint8_t status) {
807     constexpr uint8_t INTERMEDIATE =
808         0x00;                        // Intermediate fragment of fragmented data
809     constexpr uint8_t FIRST = 0x01;  // First fragment of fragmented data
810     constexpr uint8_t LAST = 0x02;   // Last fragment of fragmented data
811     constexpr uint8_t COMPLETE = 0x03;  // Complete extended advertising data
812 
813     int dataSize = (int)data.size();
814     if (status != 0 || (!isFirst && offset == dataSize)) {
815       /* if we got error writing data, or reached the end of data */
816       done_cb.Run(status);
817       return;
818     }
819 
820     bool moreThanOnePacket = dataSize - offset > ADV_DATA_LEN_MAX;
821     uint8_t operation = isFirst ? moreThanOnePacket ? FIRST : COMPLETE
822                                 : moreThanOnePacket ? INTERMEDIATE : LAST;
823     int length = moreThanOnePacket ? ADV_DATA_LEN_MAX : dataSize - offset;
824     int newOffset = offset + length;
825 
826     sender.Run(
827         inst_id, operation, length, data.data() + offset,
828         Bind(&BleAdvertisingManagerImpl::DivideAndSendDataRecursively, false,
829              inst_id, std::move(data), newOffset, std::move(done_cb), sender));
830   }
831 
SetPeriodicAdvertisingParameters(uint8_t inst_id,tBLE_PERIODIC_ADV_PARAMS * params,MultiAdvCb cb)832   void SetPeriodicAdvertisingParameters(uint8_t inst_id,
833                                         tBLE_PERIODIC_ADV_PARAMS* params,
834                                         MultiAdvCb cb) override {
835     VLOG(1) << __func__ << " inst_id: " << +inst_id;
836 
837     GetHciInterface()->SetPeriodicAdvertisingParameters(
838         inst_id, params->min_interval, params->max_interval,
839         params->periodic_advertising_properties, cb);
840   }
841 
SetPeriodicAdvertisingData(uint8_t inst_id,std::vector<uint8_t> data,MultiAdvCb cb)842   void SetPeriodicAdvertisingData(uint8_t inst_id, std::vector<uint8_t> data,
843                                   MultiAdvCb cb) override {
844     VLOG(1) << __func__ << " inst_id: " << +inst_id;
845 
846     VLOG(1) << "data is: " << base::HexEncode(data.data(), data.size());
847 
848     DivideAndSendData(
849         inst_id, data, cb,
850         base::Bind(&BleAdvertiserHciInterface::SetPeriodicAdvertisingData,
851                    base::Unretained(GetHciInterface())));
852   }
853 
SetPeriodicAdvertisingEnable(uint8_t inst_id,uint8_t enable,MultiAdvCb cb)854   void SetPeriodicAdvertisingEnable(uint8_t inst_id, uint8_t enable,
855                                     MultiAdvCb cb) override {
856     VLOG(1) << __func__ << " inst_id: " << +inst_id << ", enable: " << +enable;
857 
858     AdvertisingInstance* p_inst = &adv_inst[inst_id];
859     if (!p_inst->in_use) {
860       LOG(ERROR) << "Invalid or not active instance";
861       cb.Run(BTM_BLE_MULTI_ADV_FAILURE);
862       return;
863     }
864 
865     MultiAdvCb enable_cb = Bind(
866         [](AdvertisingInstance* p_inst, uint8_t enable, MultiAdvCb cb,
867            uint8_t status) {
868           VLOG(1) << "periodc adv enable cb: inst_id: " << +p_inst->inst_id
869                   << ", enable: " << +enable << ", status: " << std::hex
870                   << +status;
871           if (!status) p_inst->periodic_enabled = enable;
872 
873           cb.Run(status);
874         },
875         p_inst, enable, std::move(cb));
876 
877     GetHciInterface()->SetPeriodicAdvertisingEnable(enable, inst_id,
878                                                     std::move(enable_cb));
879   }
880 
Unregister(uint8_t inst_id)881   void Unregister(uint8_t inst_id) override {
882     AdvertisingInstance* p_inst = &adv_inst[inst_id];
883 
884     VLOG(1) << __func__ << " inst_id: " << +inst_id;
885     if (inst_id >= inst_count) {
886       LOG(ERROR) << "bad instance id " << +inst_id;
887       return;
888     }
889 
890     if (adv_inst[inst_id].IsEnabled()) {
891       p_inst->enable_status = false;
892       GetHciInterface()->Enable(false, inst_id, 0x00, 0x00, Bind(DoNothing));
893     }
894 
895     if (p_inst->periodic_enabled) {
896       p_inst->periodic_enabled = false;
897       GetHciInterface()->SetPeriodicAdvertisingEnable(false, inst_id,
898                                                       Bind(DoNothing));
899     }
900 
901     alarm_cancel(p_inst->adv_raddr_timer);
902     p_inst->in_use = false;
903     GetHciInterface()->RemoveAdvertisingSet(inst_id, Bind(DoNothing));
904     p_inst->address_update_required = false;
905   }
906 
RecomputeTimeout(AdvertisingInstance * inst,TimeTicks now)907   void RecomputeTimeout(AdvertisingInstance* inst, TimeTicks now) {
908     TimeDelta duration = now - inst->enable_time;
909     bool cb_fired = false;
910     if (inst->duration) {
911       int durationDone = (duration.InMilliseconds() / 10);
912       if (durationDone + 1 >= inst->duration) {
913         inst->enable_status = false;
914         inst->timeout_cb.Run(0 /* TODO: STATUS HERE?*/);
915         cb_fired = true;
916       } else {
917         inst->duration = inst->duration - durationDone;
918       }
919     }
920 
921     if (inst->maxExtAdvEvents && !cb_fired) {
922       int eventsDone =
923           (duration.InMilliseconds() / (inst->advertising_interval * 5 / 8));
924 
925       if (eventsDone + 1 >= inst->maxExtAdvEvents) {
926         inst->enable_status = false;
927         inst->timeout_cb.Run(0 /* TODO: STATUS HERE?*/);
928       } else {
929         inst->maxExtAdvEvents = inst->maxExtAdvEvents - eventsDone;
930       }
931     }
932   }
933 
Suspend()934   void Suspend() {
935     std::vector<SetEnableData> sets;
936 
937     for (AdvertisingInstance& inst : adv_inst) {
938       if (!inst.in_use || !inst.enable_status) continue;
939 
940       if (inst.duration || inst.maxExtAdvEvents)
941         RecomputeTimeout(&inst, TimeTicks::Now());
942 
943       sets.emplace_back(SetEnableData{.handle = inst.inst_id});
944     }
945 
946     if (!sets.empty()) GetHciInterface()->Enable(false, sets, Bind(DoNothing));
947   }
948 
Resume()949   void Resume() override {
950     std::vector<SetEnableData> sets;
951 
952     for (const AdvertisingInstance& inst : adv_inst) {
953       if (inst.in_use && inst.enable_status) {
954         sets.emplace_back(SetEnableData{
955             .handle = inst.inst_id,
956             .duration = inst.duration,
957             .max_extended_advertising_events = inst.maxExtAdvEvents});
958       }
959     }
960 
961     if (!sets.empty()) GetHciInterface()->Enable(true, sets, Bind(DoNothing));
962   }
963 
OnAdvertisingSetTerminated(uint8_t status,uint8_t advertising_handle,uint16_t connection_handle,uint8_t num_completed_extended_adv_events)964   void OnAdvertisingSetTerminated(
965       uint8_t status, uint8_t advertising_handle, uint16_t connection_handle,
966       uint8_t num_completed_extended_adv_events) override {
967     AdvertisingInstance* p_inst = &adv_inst[advertising_handle];
968     VLOG(1) << __func__ << "status: " << loghex(status)
969             << ", advertising_handle: " << loghex(advertising_handle)
970             << ", connection_handle: " << loghex(connection_handle);
971 
972     if (status == HCI_ERR_LIMIT_REACHED ||
973         status == HCI_ERR_ADVERTISING_TIMEOUT) {
974       // either duration elapsed, or maxExtAdvEvents reached
975       p_inst->enable_status = false;
976 
977       if (p_inst->timeout_cb.is_null()) {
978         LOG(INFO) << __func__ << "No timeout callback";
979         return;
980       }
981 
982       p_inst->timeout_cb.Run(status);
983       return;
984     }
985 
986     if (BTM_BleLocalPrivacyEnabled() &&
987         advertising_handle <= BTM_BLE_MULTI_ADV_MAX) {
988       btm_acl_update_conn_addr(connection_handle, p_inst->own_address);
989     }
990 
991     VLOG(1) << "reneabling advertising";
992 
993     if (p_inst->in_use) {
994       // TODO(jpawlowski): we don't really allow to do directed advertising
995       // right now. This should probably be removed, check with Andre.
996       if ((p_inst->advertising_event_properties & 0x0C) == 0) {
997         /* directed advertising bits not set */
998 
999         RecomputeTimeout(p_inst, TimeTicks::Now());
1000         if (p_inst->enable_status) {
1001           GetHciInterface()->Enable(true, advertising_handle, p_inst->duration,
1002                                     p_inst->maxExtAdvEvents, Bind(DoNothing));
1003         }
1004 
1005       } else {
1006         /* mark directed adv as disabled if adv has been stopped */
1007         p_inst->in_use = false;
1008       }
1009     }
1010   }
1011 
GetWeakPtr()1012   base::WeakPtr<BleAdvertisingManagerImpl> GetWeakPtr() {
1013     return weak_factory_.GetWeakPtr();
1014   }
1015 
CancelAdvAlarms()1016   void CancelAdvAlarms() {
1017     AdvertisingInstance* p_inst = &adv_inst[0];
1018     for (uint8_t i = 0; i < inst_count; i++, p_inst++) {
1019       if (p_inst->timeout_timer) {
1020         alarm_cancel(p_inst->timeout_timer);
1021       }
1022       if (p_inst->adv_raddr_timer) {
1023         alarm_cancel(p_inst->adv_raddr_timer);
1024       }
1025     }
1026   }
1027 
1028  private:
GetHciInterface()1029   BleAdvertiserHciInterface* GetHciInterface() { return hci_interface; }
1030 
1031   BleAdvertiserHciInterface* hci_interface = nullptr;
1032   std::vector<AdvertisingInstance> adv_inst;
1033   uint8_t inst_count;
1034 
1035   // Member variables should appear before the WeakPtrFactory, to ensure
1036   // that any WeakPtrs are invalidated before its members
1037   // variable's destructors are executed, rendering them invalid.
1038   base::WeakPtrFactory<BleAdvertisingManagerImpl> weak_factory_;
1039 };
1040 
btm_ble_adv_raddr_timer_timeout(void * data)1041 void btm_ble_adv_raddr_timer_timeout(void* data) {
1042   BleAdvertisingManagerImpl* ptr = instance_weakptr.get();
1043   if (ptr) ptr->ConfigureRpa((AdvertisingInstance*)data, base::Bind(DoNothing));
1044 }
1045 }  // namespace
1046 
Initialize(BleAdvertiserHciInterface * interface)1047 void BleAdvertisingManager::Initialize(BleAdvertiserHciInterface* interface) {
1048   instance = new BleAdvertisingManagerImpl(interface);
1049   instance_weakptr = ((BleAdvertisingManagerImpl*)instance)->GetWeakPtr();
1050 }
1051 
IsInitialized()1052 bool BleAdvertisingManager::IsInitialized() { return instance; }
1053 
Get()1054 base::WeakPtr<BleAdvertisingManager> BleAdvertisingManager::Get() {
1055   return instance_weakptr;
1056 };
1057 
CleanUp()1058 void BleAdvertisingManager::CleanUp() {
1059   if (instance_weakptr.get()) instance_weakptr.get()->CancelAdvAlarms();
1060 
1061   delete instance;
1062   instance = nullptr;
1063 };
1064 
1065 /**
1066  * This function initialize the advertising manager.
1067  **/
btm_ble_adv_init()1068 void btm_ble_adv_init() {
1069   BleAdvertiserHciInterface::Initialize();
1070   BleAdvertisingManager::Initialize(BleAdvertiserHciInterface::Get());
1071   BleAdvertiserHciInterface::Get()->SetAdvertisingEventObserver(
1072       (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get().get());
1073 
1074   if (BleAdvertiserHciInterface::Get()->QuirkAdvertiserZeroHandle()) {
1075     // If handle 0 can't be used, register advertiser for it, but never use it.
1076     BleAdvertisingManager::Get().get()->RegisterAdvertiser(Bind(DoNothing2));
1077   }
1078 }
1079 
1080 /*******************************************************************************
1081  *
1082  * Function         btm_ble_multi_adv_cleanup
1083  *
1084  * Description      This function cleans up multi adv control block.
1085  *
1086  * Parameters
1087  * Returns          void
1088  *
1089  ******************************************************************************/
btm_ble_multi_adv_cleanup(void)1090 void btm_ble_multi_adv_cleanup(void) {
1091   BleAdvertisingManager::CleanUp();
1092   BleAdvertiserHciInterface::CleanUp();
1093 }
1094 
1095 // TODO(jpawlowski): Find a nicer way to test RecomputeTimeout without exposing
1096 // AdvertisingInstance
1097 bool timeout_triggered = false;
test_timeout_cb(uint8_t status)1098 void test_timeout_cb(uint8_t status) { timeout_triggered = true; }
1099 
1100 // verify that if duration passed, or is about to pass, recomputation will shut
1101 // down the advertiser completly
testRecomputeTimeout1()1102 void testRecomputeTimeout1() {
1103   auto manager = (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get().get();
1104 
1105   TimeTicks start = TimeTicks::Now();
1106   TimeTicks end = start + TimeDelta::FromMilliseconds(111);
1107   AdvertisingInstance test1(0);
1108   test1.enable_status = true;
1109   test1.enable_time = start;
1110   test1.duration = 12 /*120ms*/;
1111   test1.timeout_cb = Bind(&test_timeout_cb);
1112 
1113   manager->RecomputeTimeout(&test1, end);
1114 
1115   CHECK(timeout_triggered);
1116   timeout_triggered = false;
1117   CHECK(!test1.enable_status);
1118 }
1119 
1120 // verify that duration and maxExtAdvEvents are properly adjusted when
1121 // recomputing.
testRecomputeTimeout2()1122 void testRecomputeTimeout2() {
1123   auto manager = (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get().get();
1124 
1125   TimeTicks start = TimeTicks::Now();
1126   TimeTicks end = start + TimeDelta::FromMilliseconds(250);
1127   AdvertisingInstance test1(0);
1128   test1.enable_status = true;
1129   test1.enable_time = start;
1130   test1.duration = 50 /*500ms*/;
1131   test1.maxExtAdvEvents = 50;
1132   test1.advertising_interval = 16 /* 10 ms */;
1133   test1.timeout_cb = Bind(&test_timeout_cb);
1134 
1135   manager->RecomputeTimeout(&test1, end);
1136 
1137   CHECK(!timeout_triggered);
1138   CHECK(test1.enable_status);
1139   CHECK(test1.duration == 25);
1140   CHECK(test1.maxExtAdvEvents == 25);
1141 }
1142 
1143 // verify that if maxExtAdvEvents were sent, or are close to end, recomputation
1144 // wil shut down the advertiser completly
testRecomputeTimeout3()1145 void testRecomputeTimeout3() {
1146   auto manager = (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get().get();
1147 
1148   TimeTicks start = TimeTicks::Now();
1149   TimeTicks end = start + TimeDelta::FromMilliseconds(495);
1150   AdvertisingInstance test1(0);
1151   test1.enable_status = true;
1152   test1.enable_time = start;
1153   test1.maxExtAdvEvents = 50;
1154   test1.advertising_interval = 16 /* 10 ms */;
1155   test1.timeout_cb = Bind(&test_timeout_cb);
1156 
1157   manager->RecomputeTimeout(&test1, end);
1158 
1159   CHECK(timeout_triggered);
1160   timeout_triggered = false;
1161   CHECK(!test1.enable_status);
1162 }
1163