[Bluetooth] Prevent crash in BLE advertising
[platform/core/api/webapi-plugins.git] / src / bluetooth / bluetooth_le_adapter.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
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 #include "bluetooth/bluetooth_le_adapter.h"
18
19 #include "common/logger.h"
20 #include "common/tools.h"
21
22 #include "bluetooth/bluetooth_instance.h"
23 #include "bluetooth/bluetooth_le_device.h"
24 #include "bluetooth/bluetooth_privilege.h"
25 #include "bluetooth/bluetooth_util.h"
26 using common::optional;
27
28 namespace extension {
29 namespace bluetooth {
30
31 namespace {
32
33 const std::string kData = "data";
34 const std::string kUuid = "uuid";
35 const std::string kUuids = "uuids";
36 const std::string kSolicitationUuids = "solicitationuuids";
37 const std::string kServiceData = "serviceData";
38 const std::string kServicesData = "servicesData";
39
40 class ParsedDataHolder {
41  public:
42   ParsedDataHolder() : valid_(false) {
43     ScopeLogger();
44   }
45   virtual ~ParsedDataHolder() {
46     ScopeLogger();
47   }
48
49   bool valid() const {
50     return valid_;
51   }
52
53  protected:
54   void set_valid() {
55     valid_ = true;
56   }
57
58  private:
59   bool valid_;
60 };
61
62 class HexData {
63  public:
64   HexData() : length_(0) {
65   }
66
67   void Parse(const std::string& d) {
68     ScopeLogger();
69     const char* p_data = d.c_str();
70     int size = d.length();
71     if (size > 2 && (d.find("0x", 0) == 0 || d.find("0X", 0) == 0)) {
72       p_data += 2;
73       size -= 2;
74     }
75     length_ = size / 2;
76     pointer_.reset(new char[length_]);
77     common::tools::HexToBin(p_data, size, (unsigned char*)pointer(), length_);
78   }
79
80   const char* pointer() const {
81     return pointer_.get();
82   }
83
84   int length() const {
85     return length_;
86   }
87
88  private:
89   std::unique_ptr<char[]> pointer_;
90   int length_;
91 };
92
93 class BluetoothLEServiceData : public ParsedDataHolder {
94  public:
95   const UUID& uuid() const {
96     return uuid_;
97   }
98
99   const HexData& data() const {
100     return data_;
101   }
102
103   static optional<BluetoothLEServiceData> Construct(const picojson::value& service_data_obj) {
104     ScopeLogger();
105
106     const auto& data = service_data_obj.get(kData);
107     const auto& uuid_str = service_data_obj.get(kUuid);
108     if (!data.is<std::string>() || !uuid_str.is<std::string>()) {
109       LoggerE("Invalid data type in service data");
110       return {};
111     }
112
113     auto uuid = UUID::create(uuid_str.get<std::string>());
114     if (!uuid) {
115       return {};
116     }
117
118     LoggerD("BluetoohtLEServiceData: %s : %s", uuid_str.get<std::string>().c_str(), data.get<std::string>().c_str());
119     return BluetoothLEServiceData{std::move(*uuid), data.get<std::string>()};
120   }
121
122  private:
123   BluetoothLEServiceData(UUID&& uuid, const std::string& data_str) : uuid_{std::move(uuid)} {
124     ScopeLogger("UUID: %s, data_str: %s", uuid_.uuid_128_bit.c_str(), data_str.c_str());
125
126     data_.Parse(data_str);
127
128     set_valid();
129   }
130
131   const UUID uuid_;
132   HexData data_;
133 };
134
135 class BluetoothLEManufacturerData : public ParsedDataHolder {
136  public:
137   const std::string& id() const {
138     return id_;
139   }
140
141   const HexData& data() const {
142     return data_;
143   }
144
145   static bool Construct(const picojson::value& obj, BluetoothLEManufacturerData* out) {
146     ScopeLogger();
147     if (!obj.is<picojson::object>() || !ParseId(obj, out) || !ParseData(obj, out)) {
148       return false;
149     }
150
151     out->set_valid();
152
153     return true;
154   }
155
156  private:
157   static bool ParseId(const picojson::value& obj, BluetoothLEManufacturerData* out) {
158     ScopeLogger();
159     const auto& id = obj.get("id");
160     if (id.is<std::string>()) {
161       out->id_ = id.get<std::string>();
162     } else {
163       return false;
164     }
165
166     return true;
167   }
168
169   static bool ParseData(const picojson::value& obj, BluetoothLEManufacturerData* out) {
170     ScopeLogger();
171
172     const auto& val_data = obj.get("data");
173
174     if (val_data.is<std::string>()) {
175       out->data_.Parse(val_data.get<std::string>());
176       return true;
177     } else {
178       return false;
179     }
180   }
181
182   std::string id_;
183   HexData data_;
184 };
185
186 class BluetoothLEAdvertiseData : public ParsedDataHolder {
187  public:
188   BluetoothLEAdvertiseData()
189       : ParsedDataHolder(),
190         include_name_(false),
191         appearance_(0),  // 0 means unknown
192         include_tx_power_level_(false) {
193     ScopeLogger();
194   }
195
196   bool include_name() const {
197     return include_name_;
198   }
199
200   const std::vector<UUID>& service_uuids() const {
201     return service_uuids_;
202   }
203
204   const std::vector<UUID>& solicitation_uuids() const {
205     return solicitation_uuids_;
206   }
207
208   int appearance() const {
209     return appearance_;
210   }
211
212   bool include_tx_power_level() const {
213     return include_tx_power_level_;
214   }
215
216   const std::vector<BluetoothLEServiceData>& service_data() const {
217     return service_data_;
218   }
219
220   const BluetoothLEManufacturerData& manufacturer_data() const {
221     return manufacturer_data_;
222   }
223
224   static bool Construct(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
225     ScopeLogger();
226     if (!obj.is<picojson::object>() || !ParseIncludeName(obj, out) ||
227         !ParseServiceUUIDs(obj, out) || !ParseSolicitationUUIDs(obj, out) ||
228         !ParseAppearance(obj, out) || !ParseIncludeTxPowerLevel(obj, out) ||
229         !ParseServiceData(obj, out) || !ParseManufacturerData(obj, out)) {
230       return false;
231     }
232
233     out->set_valid();
234
235     return true;
236   }
237
238  private:
239   static bool ParseIncludeName(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
240     ScopeLogger();
241     const auto& include_name = obj.get("includeName");
242     if (include_name.is<bool>()) {
243       out->include_name_ = include_name.get<bool>();
244     } else if (!include_name.is<picojson::null>()) {
245       return false;
246     }
247
248     return true;
249   }
250
251   static bool ParseServiceUUIDs(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
252     ScopeLogger();
253     const auto& service_uuids = obj.get(kUuids);
254     if (service_uuids.is<picojson::array>()) {
255       for (const auto& uuid : service_uuids.get<picojson::array>()) {
256         if (!uuid.is<std::string>()) {
257           LoggerE("uuid is not a string");
258           return false;
259         }
260
261         auto uuid_obj = UUID::create(uuid.get<std::string>());
262         if (uuid_obj) {
263           out->service_uuids_.push_back(*uuid_obj);
264         } else {
265           return false;
266         }
267       }
268     } else if (!service_uuids.is<picojson::null>()) {
269       LoggerE("Invalid service_uuids type");
270       return false;
271     }
272
273     return true;
274   }
275
276   static bool ParseSolicitationUUIDs(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
277     ScopeLogger();
278     const auto& solicitation_uuids = obj.get(kSolicitationUuids);
279     if (solicitation_uuids.is<picojson::array>()) {
280       for (const auto& uuid : solicitation_uuids.get<picojson::array>()) {
281         if (!uuid.is<std::string>()) {
282           LoggerE("uuid is not a string");
283           return false;
284         }
285
286         auto uuid_obj = UUID::create(uuid.get<std::string>());
287         if (uuid_obj) {
288           out->solicitation_uuids_.push_back(*uuid_obj);
289         } else {
290           return false;
291         }
292       }
293     } else if (!solicitation_uuids.is<picojson::null>()) {
294       return false;
295     }
296
297     return true;
298   }
299
300   static bool ParseAppearance(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
301     ScopeLogger();
302     const auto& appearance = obj.get("appearance");
303     if (appearance.is<double>()) {
304       out->appearance_ = static_cast<decltype(appearance_)>(appearance.get<double>());
305     } else if (!appearance.is<picojson::null>()) {
306       return false;
307     }
308
309     return true;
310   }
311
312   static bool ParseIncludeTxPowerLevel(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
313     ScopeLogger();
314     const auto& include_tx_power_level = obj.get("includeTxPowerLevel");
315     if (include_tx_power_level.is<bool>()) {
316       out->include_tx_power_level_ = include_tx_power_level.get<bool>();
317     } else if (!include_tx_power_level.is<picojson::null>()) {
318       return false;
319     }
320
321     return true;
322   }
323
324   static bool ParseServiceData(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
325     ScopeLogger();
326
327     const auto& service_data_obj = obj.get(kServiceData);
328     const auto& services_data_obj = obj.get(kServicesData);
329
330     if (service_data_obj.is<picojson::null>() && services_data_obj.is<picojson::null>()) {
331       LoggerD("Service data is null");
332       return true;
333     }
334
335     // check servicesData first and append services to a vector (higher priority)
336     if (!services_data_obj.is<picojson::null>() && services_data_obj.is<picojson::array>()) {
337       LoggerD("Parsing service data array");
338       for (auto single_service : services_data_obj.get<picojson::array>()) {
339         auto service_data = BluetoothLEServiceData::Construct(single_service);
340         if (!service_data) {
341           return false;
342         }
343         out->service_data_.emplace_back(std::move(*service_data));
344       }
345       return true;
346     } else if (!service_data_obj.is<picojson::null>() && service_data_obj.is<picojson::object>()) {
347       LoggerD("Parsing single service data");
348       auto service_data = BluetoothLEServiceData::Construct(service_data_obj);
349       if (!service_data) {
350         return false;
351       }
352       out->service_data_.emplace_back(std::move(*service_data));
353       return true;
354     }
355     return false;
356   }
357
358   static bool ParseManufacturerData(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
359     ScopeLogger();
360     const auto& manufacturer_data = obj.get("manufacturerData");
361     BluetoothLEManufacturerData data;
362     if (BluetoothLEManufacturerData::Construct(manufacturer_data, &data)) {
363       out->manufacturer_data_ = std::move(data);
364     } else if (!manufacturer_data.is<picojson::null>()) {
365       return false;
366     }
367
368     return true;
369   }
370
371   bool include_name_;
372   std::vector<UUID> service_uuids_;
373   std::vector<UUID> solicitation_uuids_;
374   int appearance_;
375   bool include_tx_power_level_;
376   std::vector<BluetoothLEServiceData> service_data_;
377   BluetoothLEManufacturerData manufacturer_data_;
378 };
379
380 // utility functions
381
382 bool ToBool(bt_adapter_le_state_e state) {
383   return (BT_ADAPTER_LE_ENABLED == state) ? true : false;
384 }
385
386 // constants
387 const std::string kAction = "action";
388 // scan-related
389 const std::string kOnScanSuccess = "onsuccess";
390 const std::string kOnScanError = "onerror";
391 const std::string kScanEvent = "BluetoothLEScanCallback";
392 // advertise-related
393 const std::string kOnAdvertiseState = "onstate";
394 const std::string kOnAdvertiseError = "onerror";
395 const std::string kAdvertiseEvent = "BluetoothLEAdvertiseCallback";
396
397 }  // namespace
398
399 using common::ErrorCode;
400 using common::PlatformResult;
401 using common::tools::ReportError;
402 using common::tools::ReportSuccess;
403
404 BluetoothLEAdapter::BluetoothLEAdapter(BluetoothInstance& instance)
405     : instance_(instance), enabled_(false), scanning_(false), bt_advertiser_(nullptr) {
406   ScopeLogger();
407
408   bt_adapter_le_state_e le_state = BT_ADAPTER_LE_DISABLED;
409
410   int ret = bt_adapter_le_get_state(&le_state);
411
412   if (BT_ERROR_NONE == ret) {
413     enabled_ = ToBool(le_state);
414
415     ret = bt_adapter_le_set_state_changed_cb(OnStateChanged, this);
416     if (BT_ERROR_NONE != ret) {
417       LoggerE("Failed to register BTLE state changed listener.");
418     }
419   } else {
420     LoggerE("Failed to obtain current state of BTLE.");
421   }
422 }
423
424 BluetoothLEAdapter::~BluetoothLEAdapter() {
425   ScopeLogger();
426   bt_adapter_le_unset_state_changed_cb();
427   if (scanning_) {
428     bt_adapter_le_stop_scan();
429   }
430   if (bt_advertiser_) {
431     bt_adapter_le_stop_advertising(bt_advertiser_);
432     bt_adapter_le_destroy_advertiser(bt_advertiser_);
433   }
434 }
435
436 void BluetoothLEAdapter::StartScan(const picojson::value& data, picojson::object& out) {
437   ScopeLogger();
438   CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
439                                               &out);
440
441   int ret = bt_adapter_le_start_scan(OnScanResult, this);
442
443   if (BT_ERROR_NONE != ret) {
444     if (BT_ERROR_NOW_IN_PROGRESS == ret) {
445       LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Scan already in progress"),
446                         &out, ("Scan in progress %d (%s)", ret, get_error_message(ret)));
447     } else {
448       // other errors are reported asynchronously
449       picojson::value value = picojson::value(picojson::object());
450       picojson::object* data_obj = &value.get<picojson::object>();
451       data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanError)));
452       LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to start scan"), data_obj,
453                         ("Failed to start scan: %d (%s)", ret, get_error_message(ret)));
454       instance_.FireEvent(kScanEvent, value);
455     }
456   } else {
457     scanning_ = true;
458     ReportSuccess(out);
459   }
460 }
461
462 void BluetoothLEAdapter::StopScan(const picojson::value& data, picojson::object& out) {
463   ScopeLogger();
464   CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
465                                               &out);
466
467   int ret = bt_adapter_le_stop_scan();
468
469   if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
470     LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to stop scan"), &out,
471                       ("Failed to stop scan: %d (%s)", ret, get_error_message(ret)));
472   } else {
473     scanning_ = false;
474     ReportSuccess(out);
475   }
476 }
477
478 void BluetoothLEAdapter::IsScanning(picojson::object& out) {
479   ScopeLogger();
480
481   bool is_scanning;
482   int ret = bt_adapter_le_is_discovering(&is_scanning);
483
484   if (BT_ERROR_NONE != ret) {
485     LogAndReportError(
486         PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to check for scanning in progress"), &out,
487         ("Failed to check for scanning in progress: %d (%s)", ret, get_error_message(ret)));
488   } else {
489     scanning_ = is_scanning;
490     ReportSuccess(picojson::value(is_scanning), out);
491   }
492 }
493
494 void BluetoothLEAdapter::StartAdvertise(const picojson::value& data, picojson::object& out) {
495   ScopeLogger();
496   CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
497                                               &out);
498
499   const auto& json_advertise_data = data.get("advertiseData");
500   const auto& json_packet_type = data.get("packetType");
501   const auto& json_mode = data.get("mode");
502   const auto& json_connectable = data.get("connectable");
503
504   if (!json_advertise_data.is<picojson::object>() || !json_packet_type.is<std::string>() ||
505       !json_mode.is<std::string>() || !json_connectable.is<bool>()) {
506     LogAndReportError(PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected parameter type"),
507                       &out);
508     return;
509   }
510
511   BluetoothLEAdvertiseData advertise_data;
512   if (!BluetoothLEAdvertiseData::Construct(json_advertise_data, &advertise_data)) {
513     LogAndReportError(
514         PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of advertise data"), &out);
515     return;
516   }
517
518   bt_adapter_le_packet_type_e packet_type = BT_ADAPTER_LE_PACKET_ADVERTISING;
519   {
520     const auto& str_packet_type = json_packet_type.get<std::string>();
521     if ("ADVERTISE" == str_packet_type) {
522       packet_type = BT_ADAPTER_LE_PACKET_ADVERTISING;
523     } else if ("SCAN_RESPONSE" == str_packet_type) {
524       packet_type = BT_ADAPTER_LE_PACKET_SCAN_RESPONSE;
525     } else {
526       LogAndReportError(
527           PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of packet type"), &out,
528           ("Wrong packet_type: %s", str_packet_type.c_str()));
529       return;
530     }
531   }
532
533   bt_adapter_le_advertising_mode_e mode = BT_ADAPTER_LE_ADVERTISING_MODE_BALANCED;
534   {
535     const auto& str_mode = json_mode.get<std::string>();
536     if ("BALANCED" == str_mode) {
537       mode = BT_ADAPTER_LE_ADVERTISING_MODE_BALANCED;
538     } else if ("LOW_LATENCY" == str_mode) {
539       mode = BT_ADAPTER_LE_ADVERTISING_MODE_LOW_LATENCY;
540     } else if ("LOW_ENERGY" == str_mode) {
541       mode = BT_ADAPTER_LE_ADVERTISING_MODE_LOW_ENERGY;
542     } else {
543       LogAndReportError(PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of mode"),
544                         &out, ("Wrong mode: %s", str_mode.c_str()));
545       return;
546     }
547   }
548
549   if (nullptr != bt_advertiser_) {
550     LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Advertise already in progress"),
551                       &out);
552     return;
553   }
554
555   bt_advertiser_h advertiser = nullptr;
556
557   int ret = bt_adapter_le_create_advertiser(&advertiser);
558   if (BT_ERROR_NONE != ret) {
559     LogAndReportError(
560         util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
561         ("bt_adapter_le_create_advertiser() failed with: %d, (%s)", ret, get_error_message(ret)));
562     return;
563   }
564
565   std::unique_ptr<std::remove_pointer<bt_advertiser_h>::type, int (*)(bt_advertiser_h)>
566       advertiser_ptr(advertiser,
567                      &bt_adapter_le_destroy_advertiser);  // automatically release the memory
568
569   // configure advertiser
570   if (advertise_data.include_name()) {
571     ret = bt_adapter_le_set_advertising_device_name(advertiser, packet_type,
572                                                     advertise_data.include_name());
573     if (BT_ERROR_NONE != ret) {
574       LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
575                         ("bt_adapter_le_set_advertising_device_name() failed with: %d (%s)", ret,
576                          get_error_message(ret)));
577       return;
578     }
579   }
580
581   for (const auto& uuid : advertise_data.service_uuids()) {
582     /*
583      * This native function accepts 16 or 128 bit UUIDs.
584      * To handle also 32 bit UUIDs, we pass all UUIDs in their canonical form.
585      *
586      * Note:
587      * The documentation of Native Bluetooth API says, this function advertises 128-bit UUIDs,
588      * that have 32-bit equivalents in the full 128-bit form.
589      * However, as of the day of writing this comment, packets advertised
590      * by the device contain these UUIDs in their 32-bit formats,
591      * i.e. AD fields with 0x04 («Incomplete List of 32-bit Service Class UUIDs») type.
592      * For example, "12345678-0000-1000-8000-00805F9B34FB" is advertised as "12345678".
593      */
594     ret = bt_adapter_le_add_advertising_service_uuid(advertiser, packet_type,
595                                                      uuid.uuid_128_bit.c_str());
596     if (BT_ERROR_NONE != ret) {
597       LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
598                         ("bt_adapter_le_add_advertising_service_uuid() failed with: %d (%s)", ret,
599                          get_error_message(ret)));
600       return;
601     }
602   }
603
604   for (const auto& uuid : advertise_data.solicitation_uuids()) {
605     /*
606      * This native function accepts 16 or 128 bit UUIDs.
607      * To handle also 32 bit UUIDs, we pass all UUIDs in their canonical form.
608      *
609      * Note:
610      * The documentation of Native Bluetooth API says, it advertises 128-bit UUIDs,
611      * that have 32-bit equivalents in the full 128-bit form.
612      * However, as of the day of writing this comment, packets advertised
613      * by the device contain these UUIDs in their 32-bit formats,
614      * i.e. AD fields with 0x1F («List of 32-bit Service Solicitation UUIDs») type.
615      * For example, "12345678-0000-1000-8000-00805F9B34FB" is advertised as "12345678".
616      */
617     ret = bt_adapter_le_add_advertising_service_solicitation_uuid(advertiser, packet_type,
618                                                                   uuid.uuid_128_bit.c_str());
619     if (BT_ERROR_NONE != ret) {
620       LogAndReportError(
621           util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
622           ("bt_adapter_le_add_advertising_service_solicitation_uuid() failed with: %d (%s)", ret,
623            get_error_message(ret)));
624       return;
625     }
626   }
627
628   ret = bt_adapter_le_set_advertising_appearance(advertiser, packet_type,
629                                                  advertise_data.appearance());
630   if (BT_ERROR_NONE != ret) {
631     LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
632                       ("bt_adapter_le_set_advertising_appearance() failed with: %d (%s)", ret,
633                        get_error_message(ret)));
634     return;
635   }
636
637   if (advertise_data.include_tx_power_level()) {
638     ret = bt_adapter_le_set_advertising_tx_power_level(advertiser, packet_type,
639                                                        advertise_data.include_tx_power_level());
640     if (BT_ERROR_NONE != ret) {
641       LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
642                         ("bt_adapter_le_set_advertising_tx_power_level() failed with: %d (%s)", ret,
643                          get_error_message(ret)));
644       return;
645     }
646   }
647
648   if (advertise_data.service_data().empty()) {
649     LoggerD("service data is empty");
650   } else {
651     for (const auto& service_data_obj : advertise_data.service_data()) {
652       ret = bt_adapter_le_add_advertising_service_data(
653           advertiser, packet_type, service_data_obj.uuid().ShortestPossibleFormat().c_str(),
654           service_data_obj.data().pointer(), service_data_obj.data().length());
655       if (BT_ERROR_NONE != ret) {
656         std::string error_message = "Failed to create advertiser";
657         if (BT_ERROR_QUOTA_EXCEEDED == ret && !service_data_obj.uuid().To16Bit()) {
658           error_message =
659               "Failed to start advertising: only 16 bit values of BluetoothLEServiceData::uuid are "
660               "supported";
661         } else if (BT_ERROR_ALREADY_DONE == ret) {  // in case of duplicated advertiser data report it with correct message
662           LogAndReportError(util::GetBluetoothError(BT_ERROR_INVALID_PARAMETER, "Duplicated advertiser data"), &out,
663                           ("bt_adapter_le_set_advertising_device_name() failed with: %d (%s)", ret,
664                           get_error_message(ret)));
665           return;
666         }
667
668         LogAndReportError(util::GetBluetoothError(ret, error_message), &out,
669                           ("bt_adapter_le_add_advertising_service_data() failed with: %d (%s)", ret,
670                            get_error_message(ret)));
671         return;
672       }
673     }
674   }
675
676   const auto& manufacturer_data = advertise_data.manufacturer_data();
677   if (manufacturer_data.id().empty() && nullptr == manufacturer_data.data().pointer()) {
678     LoggerD("manufacturerData is empty");
679   } else {
680     if (manufacturer_data.valid()) {
681       ret = bt_adapter_le_add_advertising_manufacturer_data(
682           advertiser, packet_type, atoi(manufacturer_data.id().c_str()),
683           manufacturer_data.data().pointer(), manufacturer_data.data().length());
684       if (BT_ERROR_NONE != ret) {
685         LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
686                           ("bt_adapter_le_add_advertising_manufacturer_data() failed with: %d (%s)",
687                            ret, get_error_message(ret)));
688         return;
689       }
690     }
691   }
692
693   ret = bt_adapter_le_set_advertising_mode(advertiser, mode);
694   if (BT_ERROR_NONE != ret) {
695     LogAndReportError(
696         util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
697         ("bt_adapter_le_set_advertising_mode() failed with: %d (%s)", ret, get_error_message(ret)));
698     return;
699   }
700
701   ret = bt_adapter_le_set_advertising_connectable(advertiser, json_connectable.get<bool>());
702   if (BT_ERROR_NONE != ret) {
703     LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
704                       ("bt_adapter_le_set_advertising_connectable() failed with: %d (%s)", ret,
705                        get_error_message(ret)));
706     return;
707   }
708
709   // advertiser is ready, let's start advertising
710   ret = bt_adapter_le_start_advertising_new(advertiser, OnAdvertiseResult, this);
711   if (BT_ERROR_NONE != ret) {
712     if (BT_ERROR_NOW_IN_PROGRESS == ret) {
713       LogAndReportError(
714           PlatformResult(ErrorCode::INVALID_STATE_ERR, "Advertise already in progress"), &out,
715           ("bt_adapter_le_start_advertising_new error: %d (%s)", ret, get_error_message(ret)));
716       return;
717     }
718
719     LogAndReportError(util::GetBluetoothError(ret, "Failed to start advertising"), &out,
720                       ("bt_adapter_le_start_advertising_new() failed with: %d (%s)", ret,
721                        get_error_message(ret)));
722     return;
723   }
724
725   // everything went well, we want to store the pointer, so unique_ptr should no longer manage the
726   // memory
727   bt_advertiser_ = advertiser_ptr.release();
728   ReportSuccess(out);
729 }
730
731 void BluetoothLEAdapter::StopAdvertise(const picojson::value& data, picojson::object& out) {
732   ScopeLogger();
733   CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
734                                               &out);
735
736   if (nullptr != bt_advertiser_) {
737     int ret = bt_adapter_le_stop_advertising(bt_advertiser_);
738     if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
739       LogAndReportError(
740           PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to stop advertising"), &out,
741           ("bt_adapter_le_stop_advertising() failed with: %d (%s)", ret, get_error_message(ret)));
742       return;
743     }
744
745     bt_advertiser_ = nullptr;
746   } else {
747     LoggerD("Advertising is not in progress");
748   }
749
750   ReportSuccess(out);
751 }
752
753 void BluetoothLEAdapter::OnStateChanged(int result, bt_adapter_le_state_e adapter_le_state,
754                                         void* user_data) {
755   ScopeLogger();
756
757   auto adapter = static_cast<BluetoothLEAdapter*>(user_data);
758
759   if (!adapter) {
760     LoggerE("user_data is NULL");
761     return;
762   }
763
764   adapter->enabled_ = ToBool(adapter_le_state);
765 }
766
767 void BluetoothLEAdapter::OnScanResult(int result, bt_adapter_le_device_scan_result_info_s* info,
768                                       void* user_data) {
769   ScopeLogger("result: %d, info: %p, data: %p", result, info, user_data);
770
771   auto adapter = static_cast<BluetoothLEAdapter*>(user_data);
772
773   if (!adapter) {
774     LoggerE("user_data is NULL");
775     return;
776   }
777
778   picojson::value value = picojson::value(picojson::object());
779   picojson::object* data_obj = &value.get<picojson::object>();
780
781   if (BT_ERROR_NONE != result) {
782     LogAndReportError(util::GetBluetoothError(result, "Error during scanning"), data_obj,
783                       ("Error during scanning: %d (%s)", result, get_error_message(result)));
784     data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanError)));
785   } else {
786     // this is probably capi-network-bluetooth error: when scan is stopped info has 0x1 value
787     if (nullptr != info && reinterpret_cast<void*>(0x1) != info) {
788       // device found
789       LoggerD("Device found");
790       picojson::value data{picojson::object{}};
791       const auto& ret = BluetoothLEDevice::ToJson(info, &data.get<picojson::object>());
792       if (ret) {
793         data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanSuccess)));
794         data_obj->insert(std::make_pair(kData, data));
795       } else {
796         LogAndReportError(ret, data_obj, ("Failed to parse Bluetooth LE device"));
797         data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanError)));
798       }
799     }
800   }
801
802   adapter->instance_.FireEvent(kScanEvent, value);
803 }
804
805 void BluetoothLEAdapter::OnAdvertiseResult(int result, bt_advertiser_h advertiser,
806                                            bt_adapter_le_advertising_state_e adv_state,
807                                            void* user_data) {
808   ScopeLogger("result: %d, advertiser: %p, adv_state: %d, user_data: %p", result, advertiser,
809               adv_state, user_data);
810
811   auto adapter = static_cast<BluetoothLEAdapter*>(user_data);
812
813   if (!adapter) {
814     LoggerE("user_data is NULL");
815     return;
816   }
817
818   picojson::value value = picojson::value(picojson::object());
819   picojson::object* data_obj = &value.get<picojson::object>();
820
821   if (BT_ERROR_NONE != result) {
822     LogAndReportError(util::GetBluetoothError(result, "Error during advertising"), data_obj,
823                       ("Error during advertising: %d (%s)", result, get_error_message(result)));
824     data_obj->insert(std::make_pair(kAction, picojson::value(kOnAdvertiseError)));
825   } else {
826     const char* state = (BT_ADAPTER_LE_ADVERTISING_STARTED == adv_state) ? "STARTED" : "STOPPED";
827     LoggerD("Advertise state is: %s", state);
828     data_obj->insert(std::make_pair(kAction, picojson::value(kOnAdvertiseState)));
829     ReportSuccess(picojson::value(state), *data_obj);
830     if (adv_state == BT_ADAPTER_LE_ADVERTISING_STOPPED) {
831       LoggerD("Advertiser destroy");
832       int ret = bt_adapter_le_destroy_advertiser(advertiser);
833       /*
834        * Destruction of advertiser should not fail.
835        * If it does, we only log the info and set the pointer to nullptr
836        * anyway to let the user start new advertising in the future.
837        */
838       adapter->bt_advertiser_ = nullptr;
839       if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
840         LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to destroy advertiser"),
841                           data_obj, ("bt_adapter_le_destroy_advertiser() failed with: %d (%s)", ret,
842                                      get_error_message(ret)));
843         return;
844       }
845       LoggerD("bt_adapter_le_destroy_advertiser(): SUCCESS");
846     }
847   }
848
849   adapter->instance_.FireEvent(kAdvertiseEvent, value);
850 }
851
852 }  // namespace bluetooth
853 }  // namespace extension