main.cc revision 63b0519c3f0d1c0cc523e0e9553c60fc68651acc
1//
2//  Copyright (C) 2015 Google, Inc.
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 <iostream>
18#include <string>
19
20#ifdef BT_LIBCHROME_NDEBUG
21#define NDEBUG 1
22#endif
23
24#include <base/at_exit.h>
25#include <base/command_line.h>
26#include <base/logging.h>
27#include <base/macros.h>
28#include <base/strings/string_number_conversions.h>
29#include <base/strings/string_split.h>
30#include <base/strings/string_util.h>
31#include <binder/IPCThreadState.h>
32#include <binder/IServiceManager.h>
33#include <binder/ProcessState.h>
34
35#include <bluetooth/adapter_state.h>
36#include <android/bluetooth/BnBluetoothCallback.h>
37#include <android/bluetooth/BnBluetoothGattClientCallback.h>
38#include <android/bluetooth/BnBluetoothLowEnergyCallback.h>
39#include <android/bluetooth/IBluetooth.h>
40#include <android/bluetooth/IBluetoothGattClient.h>
41#include <android/bluetooth/IBluetoothLowEnergy.h>
42#include <bluetooth/low_energy_constants.h>
43#include <bluetooth/scan_filter.h>
44#include <bluetooth/scan_settings.h>
45#include <bluetooth/uuid.h>
46
47using namespace std;
48
49using android::sp;
50using android::String8;
51using android::String16;
52using android::binder::Status;
53using android::OK;
54using android::getService;
55
56using android::bluetooth::IBluetooth;
57using android::bluetooth::IBluetoothGattClient;
58using android::bluetooth::IBluetoothLowEnergy;
59
60namespace {
61
62#define COLOR_OFF "\x1B[0m"
63#define COLOR_RED "\x1B[0;91m"
64#define COLOR_GREEN "\x1B[0;92m"
65#define COLOR_YELLOW "\x1B[0;93m"
66#define COLOR_BLUE "\x1B[0;94m"
67#define COLOR_MAGENTA "\x1B[0;95m"
68#define COLOR_BOLDGRAY "\x1B[1;30m"
69#define COLOR_BOLDWHITE "\x1B[1;37m"
70#define COLOR_BOLDYELLOW "\x1B[1;93m"
71#define CLEAR_LINE "\x1B[2K"
72
73#define CHECK_ARGS_COUNT(args, op, num, msg) \
74  if (!((args).size() op num)) {             \
75    PrintError(msg);                         \
76    return;                                  \
77  }
78#define CHECK_NO_ARGS(args) \
79  CHECK_ARGS_COUNT(args, ==, 0, "Expected no arguments")
80
81// TODO(armansito): Clean up this code. Right now everything is in this
82// monolithic file. We should organize this into different classes for command
83// handling, console output/printing, callback handling, etc.
84// (See http://b/23387611)
85
86// Used to synchronize the printing of the command-line prompt and incoming
87// Binder callbacks.
88std::atomic_bool showing_prompt(false);
89
90// The registered IBluetoothLowEnergy client handle. If |ble_registering| is
91// true then an operation to register the client is in progress.
92std::atomic_bool ble_registering(false);
93std::atomic_int ble_client_id(0);
94
95// The registered IBluetoothGattClient client handle. If |gatt_registering| is
96// true then an operation to register the client is in progress.
97std::atomic_bool gatt_registering(false);
98std::atomic_int gatt_client_id(0);
99
100// True if we should dump the scan record bytes for incoming scan results.
101std::atomic_bool dump_scan_record(false);
102
103// True if the remote process has died and we should exit.
104std::atomic_bool should_exit(false);
105
106std::string kServiceName = "bluetooth-service";
107
108void PrintPrompt() { cout << COLOR_BLUE "[FCLI] " COLOR_OFF << flush; }
109
110void PrintError(const string& message) {
111  cout << COLOR_RED << message << COLOR_OFF << endl;
112}
113
114void PrintOpStatus(const std::string& op, bool status) {
115  cout << COLOR_BOLDWHITE << op << " status: " COLOR_OFF
116       << (status ? (COLOR_GREEN "success") : (COLOR_RED "failure"))
117       << COLOR_OFF << endl;
118}
119
120inline void BeginAsyncOut() {
121  if (showing_prompt.load()) cout << CLEAR_LINE << "\r";
122}
123
124inline void EndAsyncOut() {
125  std::flush(cout);
126  if (showing_prompt.load())
127    PrintPrompt();
128  else
129    cout << endl;
130}
131
132class CLIBluetoothCallback : public android::bluetooth::BnBluetoothCallback {
133 public:
134  CLIBluetoothCallback() = default;
135  ~CLIBluetoothCallback() override = default;
136
137  // IBluetoothCallback overrides:
138  Status OnBluetoothStateChange(int32_t prev_state,
139                                int32_t new_state) override {
140    BeginAsyncOut();
141    cout << COLOR_BOLDWHITE "Adapter state changed: " COLOR_OFF << COLOR_MAGENTA
142         << AdapterStateToString(bluetooth::AdapterState(prev_state))
143         << COLOR_OFF << COLOR_BOLDWHITE " -> " COLOR_OFF << COLOR_BOLDYELLOW
144         << AdapterStateToString(bluetooth::AdapterState(new_state))
145         << COLOR_OFF;
146    EndAsyncOut();
147
148    return Status::ok();
149  }
150
151 private:
152  DISALLOW_COPY_AND_ASSIGN(CLIBluetoothCallback);
153};
154
155class CLIBluetoothLowEnergyCallback
156    : public android::bluetooth::BnBluetoothLowEnergyCallback {
157 public:
158  CLIBluetoothLowEnergyCallback() = default;
159  ~CLIBluetoothLowEnergyCallback() override = default;
160
161  // IBluetoothLowEnergyCallback overrides:
162  Status OnClientRegistered(int status, int client_id) override {
163    BeginAsyncOut();
164    if (status != bluetooth::BLE_STATUS_SUCCESS) {
165      PrintError("Failed to register BLE client");
166    } else {
167      ble_client_id = client_id;
168      cout << COLOR_BOLDWHITE "Registered BLE client with ID: " COLOR_OFF
169           << COLOR_GREEN << client_id << COLOR_OFF;
170    }
171    EndAsyncOut();
172
173    ble_registering = false;
174    return Status::ok();
175  }
176
177  Status OnConnectionState(int status, int client_id, const String16& address,
178                           bool connected) override {
179    BeginAsyncOut();
180    cout << COLOR_BOLDWHITE "Connection state: " << COLOR_BOLDYELLOW "["
181         << address << " connected: " << (connected ? "true" : "false") << " ] "
182         << COLOR_BOLDWHITE "- status: " << status
183         << COLOR_BOLDWHITE " - client_id: " << client_id << COLOR_OFF;
184    EndAsyncOut();
185    return Status::ok();
186  }
187
188  Status OnMtuChanged(int status, const String16& address, int mtu) override {
189    BeginAsyncOut();
190    cout << COLOR_BOLDWHITE "MTU changed: " << COLOR_BOLDYELLOW "[" << address
191         << " ] " << COLOR_BOLDWHITE " - status: " << status
192         << COLOR_BOLDWHITE " - mtu: " << mtu << COLOR_OFF;
193    EndAsyncOut();
194    return Status::ok();
195  }
196
197  Status OnScanResult(
198      const android::bluetooth::ScanResult& scan_result) override {
199    BeginAsyncOut();
200    cout << COLOR_BOLDWHITE "Scan result: " << COLOR_BOLDYELLOW "["
201         << scan_result.device_address() << "] "
202         << COLOR_BOLDWHITE "- RSSI: " << scan_result.rssi() << COLOR_OFF;
203
204    if (dump_scan_record) {
205      cout << " - Record: "
206           << base::HexEncode(scan_result.scan_record().data(),
207                              scan_result.scan_record().size());
208    }
209    EndAsyncOut();
210    return Status::ok();
211  }
212
213  Status OnMultiAdvertiseCallback(
214      int status, bool is_start,
215      const android::bluetooth::AdvertiseSettings& /* settings */) {
216    BeginAsyncOut();
217    std::string op = is_start ? "start" : "stop";
218
219    PrintOpStatus("Advertising " + op, status == bluetooth::BLE_STATUS_SUCCESS);
220    EndAsyncOut();
221    return Status::ok();
222  }
223
224 private:
225  DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLowEnergyCallback);
226};
227
228class CLIGattClientCallback
229    : public android::bluetooth::BnBluetoothGattClientCallback {
230 public:
231  CLIGattClientCallback() = default;
232  ~CLIGattClientCallback() override = default;
233
234  // IBluetoothGattClientCallback overrides:
235  Status OnClientRegistered(int status, int client_id) override {
236    BeginAsyncOut();
237    if (status != bluetooth::BLE_STATUS_SUCCESS) {
238      PrintError("Failed to register GATT client");
239    } else {
240      gatt_client_id = client_id;
241      cout << COLOR_BOLDWHITE "Registered GATT client with ID: " COLOR_OFF
242           << COLOR_GREEN << client_id << COLOR_OFF;
243    }
244    EndAsyncOut();
245
246    gatt_registering = false;
247    return Status::ok();
248  }
249
250 private:
251  DISALLOW_COPY_AND_ASSIGN(CLIGattClientCallback);
252};
253
254void PrintCommandStatus(bool status) { PrintOpStatus("Command", status); }
255
256void PrintFieldAndValue(const string& field, const string& value) {
257  cout << COLOR_BOLDWHITE << field << ": " << COLOR_BOLDYELLOW << value
258       << COLOR_OFF << endl;
259}
260
261void PrintFieldAndBoolValue(const string& field, bool value) {
262  PrintFieldAndValue(field, (value ? "true" : "false"));
263}
264
265void HandleDisable(IBluetooth* bt_iface, const vector<string>& args) {
266  CHECK_NO_ARGS(args);
267  bool status;
268  bt_iface->Disable(&status);
269  PrintCommandStatus(status);
270}
271
272void HandleEnable(IBluetooth* bt_iface, const vector<string>& args) {
273  bool is_restricted_mode = false;
274
275  for (auto iter : args) {
276    const std::string& arg = iter;
277    if (arg == "-h") {
278      static const char kUsage[] =
279          "Usage: start-adv [flags]\n"
280          "\n"
281          "Flags:\n"
282          "\t--restricted|-r\tStart in restricted mode\n";
283      cout << kUsage << endl;
284      return;
285    } else if (arg == "--restricted" || arg == "-r") {
286      is_restricted_mode = true;
287    }
288  }
289
290  bool status;
291  bt_iface->Enable(is_restricted_mode, &status);
292  PrintCommandStatus(status);
293}
294
295void HandleGetState(IBluetooth* bt_iface, const vector<string>& args) {
296  CHECK_NO_ARGS(args);
297
298  int32_t st;
299  bt_iface->GetState(&st);
300  bluetooth::AdapterState state = static_cast<bluetooth::AdapterState>(st);
301  PrintFieldAndValue("Adapter state", bluetooth::AdapterStateToString(state));
302}
303
304void HandleIsEnabled(IBluetooth* bt_iface, const vector<string>& args) {
305  CHECK_NO_ARGS(args);
306  bool enabled;
307  bt_iface->IsEnabled(&enabled);
308  PrintFieldAndBoolValue("Adapter enabled", enabled);
309}
310
311void HandleGetLocalAddress(IBluetooth* bt_iface, const vector<string>& args) {
312  CHECK_NO_ARGS(args);
313  String16 address;
314  bt_iface->GetAddress(&address);
315  PrintFieldAndValue("Adapter address", std::string(String8(address).string()));
316}
317
318void HandleSetLocalName(IBluetooth* bt_iface, const vector<string>& args) {
319  CHECK_ARGS_COUNT(args, >=, 1, "No name was given");
320
321  std::string name;
322  for (const auto& arg : args) name += arg + " ";
323
324  base::TrimWhitespaceASCII(name, base::TRIM_TRAILING, &name);
325
326  bool status;
327  bt_iface->SetName(String16(String8(name.c_str())), &status);
328  PrintCommandStatus(status);
329}
330
331void HandleGetLocalName(IBluetooth* bt_iface, const vector<string>& args) {
332  CHECK_NO_ARGS(args);
333  String16 name;
334  bt_iface->GetName(&name);
335  PrintFieldAndValue("Adapter name", std::string(String8(name).string()));
336}
337
338void HandleAdapterInfo(IBluetooth* bt_iface, const vector<string>& args) {
339  CHECK_NO_ARGS(args);
340
341  cout << COLOR_BOLDWHITE "Adapter Properties: " COLOR_OFF << endl;
342
343  String16 address;
344  bt_iface->GetAddress(&address);
345  PrintFieldAndValue("\tAddress", std::string(String8(address).string()));
346
347  int adapter_state;
348  bt_iface->GetState(&adapter_state);
349  PrintFieldAndValue("\tState",
350                     bluetooth::AdapterStateToString(
351                         static_cast<bluetooth::AdapterState>(adapter_state)));
352
353  String16 name;
354  bt_iface->GetName(&name);
355  PrintFieldAndValue("\tName", std::string(String8(name).string()));
356
357  bool multi_adv;
358  bt_iface->IsMultiAdvertisementSupported(&multi_adv);
359  PrintFieldAndBoolValue("\tMulti-Adv. supported", multi_adv);
360}
361
362void HandleSupportsMultiAdv(IBluetooth* bt_iface, const vector<string>& args) {
363  CHECK_NO_ARGS(args);
364
365  bool multi_adv;
366  bt_iface->IsMultiAdvertisementSupported(&multi_adv);
367  PrintFieldAndBoolValue("Multi-advertisement support", multi_adv);
368}
369
370void HandleRegisterBLE(IBluetooth* bt_iface, const vector<string>& args) {
371  CHECK_NO_ARGS(args);
372
373  if (ble_registering.load()) {
374    PrintError("In progress");
375    return;
376  }
377
378  if (ble_client_id.load()) {
379    PrintError("Already registered");
380    return;
381  }
382
383  sp<IBluetoothLowEnergy> ble_iface;
384  bt_iface->GetLowEnergyInterface(&ble_iface);
385  if (!ble_iface.get()) {
386    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
387    return;
388  }
389
390  bool status;
391  ble_iface->RegisterClient(new CLIBluetoothLowEnergyCallback(), &status);
392  ble_registering = status;
393  PrintCommandStatus(status);
394}
395
396void HandleUnregisterBLE(IBluetooth* bt_iface, const vector<string>& args) {
397  CHECK_NO_ARGS(args);
398
399  if (!ble_client_id.load()) {
400    PrintError("Not registered");
401    return;
402  }
403
404  sp<IBluetoothLowEnergy> ble_iface;
405  bt_iface->GetLowEnergyInterface(&ble_iface);
406  if (!ble_iface.get()) {
407    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
408    return;
409  }
410
411  ble_iface->UnregisterClient(ble_client_id.load());
412  ble_client_id = 0;
413  PrintCommandStatus(true);
414}
415
416void HandleUnregisterAllBLE(IBluetooth* bt_iface, const vector<string>& args) {
417  CHECK_NO_ARGS(args);
418
419  sp<IBluetoothLowEnergy> ble_iface;
420  bt_iface->GetLowEnergyInterface(&ble_iface);
421  if (!ble_iface.get()) {
422    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
423    return;
424  }
425
426  ble_iface->UnregisterAll();
427  PrintCommandStatus(true);
428}
429
430void HandleRegisterGATT(IBluetooth* bt_iface, const vector<string>& args) {
431  CHECK_NO_ARGS(args);
432
433  if (gatt_registering.load()) {
434    PrintError("In progress");
435    return;
436  }
437
438  if (gatt_client_id.load()) {
439    PrintError("Already registered");
440    return;
441  }
442
443  sp<IBluetoothGattClient> gatt_iface;
444  bt_iface->GetGattClientInterface(&gatt_iface);
445  if (!gatt_iface.get()) {
446    PrintError("Failed to obtain handle to Bluetooth GATT Client interface");
447    return;
448  }
449
450  bool status;
451  gatt_iface->RegisterClient(new CLIGattClientCallback(), &status);
452  gatt_registering = status;
453  PrintCommandStatus(status);
454}
455
456void HandleUnregisterGATT(IBluetooth* bt_iface, const vector<string>& args) {
457  CHECK_NO_ARGS(args);
458
459  if (!gatt_client_id.load()) {
460    PrintError("Not registered");
461    return;
462  }
463
464  sp<IBluetoothGattClient> gatt_iface;
465  bt_iface->GetGattClientInterface(&gatt_iface);
466  if (!gatt_iface.get()) {
467    PrintError("Failed to obtain handle to Bluetooth GATT Client interface");
468    return;
469  }
470
471  gatt_iface->UnregisterClient(gatt_client_id.load());
472  gatt_client_id = 0;
473  PrintCommandStatus(true);
474}
475
476void HandleStartAdv(IBluetooth* bt_iface, const vector<string>& args) {
477  bool include_name = false;
478  bool include_tx_power = false;
479  bool connectable = false;
480  bool set_manufacturer_data = false;
481  bool set_uuid = false;
482  bluetooth::UUID uuid;
483
484  for (auto iter = args.begin(); iter != args.end(); ++iter) {
485    const std::string& arg = *iter;
486    if (arg == "-n")
487      include_name = true;
488    else if (arg == "-t")
489      include_tx_power = true;
490    else if (arg == "-c")
491      connectable = true;
492    else if (arg == "-m")
493      set_manufacturer_data = true;
494    else if (arg == "-u") {
495      // This flag has a single argument.
496      ++iter;
497      if (iter == args.end()) {
498        PrintError("Expected a UUID after -u");
499        return;
500      }
501
502      std::string uuid_str = *iter;
503      uuid = bluetooth::UUID(uuid_str);
504      if (!uuid.is_valid()) {
505        PrintError("Invalid UUID: " + uuid_str);
506        return;
507      }
508
509      set_uuid = true;
510    } else if (arg == "-h") {
511      static const char kUsage[] =
512          "Usage: start-adv [flags]\n"
513          "\n"
514          "Flags:\n"
515          "\t-n\tInclude device name\n"
516          "\t-t\tInclude TX power\n"
517          "\t-c\tSend connectable adv. packets (default is non-connectable)\n"
518          "\t-m\tInclude random manufacturer data\n"
519          "\t-h\tShow this help message\n";
520      cout << kUsage << endl;
521      return;
522    } else {
523      PrintError("Unrecognized option: " + arg);
524      return;
525    }
526  }
527
528  if (!ble_client_id.load()) {
529    PrintError("BLE not registered");
530    return;
531  }
532
533  sp<IBluetoothLowEnergy> ble_iface;
534  bt_iface->GetLowEnergyInterface(&ble_iface);
535  if (!ble_iface.get()) {
536    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
537    return;
538  }
539
540  std::vector<uint8_t> data;
541  if (set_manufacturer_data) {
542    data = {{0x07, bluetooth::kEIRTypeManufacturerSpecificData, 0xe0, 0x00, 'T',
543             'e', 's', 't'}};
544  }
545
546  if (set_uuid) {
547    // Determine the type and length bytes.
548    int uuid_size = uuid.GetShortestRepresentationSize();
549    uint8_t type;
550    if (uuid_size == bluetooth::UUID::kNumBytes128)
551      type = bluetooth::kEIRTypeComplete128BitUUIDs;
552    else if (uuid_size == bluetooth::UUID::kNumBytes32)
553      type = bluetooth::kEIRTypeComplete32BitUUIDs;
554    else if (uuid_size == bluetooth::UUID::kNumBytes16)
555      type = bluetooth::kEIRTypeComplete16BitUUIDs;
556    else
557      NOTREACHED() << "Unexpected size: " << uuid_size;
558
559    data.push_back(uuid_size + 1);
560    data.push_back(type);
561
562    auto uuid_bytes = uuid.GetFullLittleEndian();
563    int index = (uuid_size == 16) ? 0 : 12;
564    data.insert(data.end(), uuid_bytes.data() + index,
565                uuid_bytes.data() + index + uuid_size);
566  }
567
568  base::TimeDelta timeout;
569
570  bluetooth::AdvertiseSettings settings(
571      bluetooth::AdvertiseSettings::MODE_LOW_POWER, timeout,
572      bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM, connectable);
573
574  bluetooth::AdvertiseData adv_data(data);
575  adv_data.set_include_device_name(include_name);
576  adv_data.set_include_tx_power_level(include_tx_power);
577
578  bluetooth::AdvertiseData scan_rsp;
579
580  bool status;
581  ble_iface->StartMultiAdvertising(ble_client_id.load(), adv_data, scan_rsp,
582                                   settings, &status);
583  PrintCommandStatus(status);
584}
585
586void HandleStopAdv(IBluetooth* bt_iface, const vector<string>& args) {
587  if (!ble_client_id.load()) {
588    PrintError("BLE not registered");
589    return;
590  }
591
592  sp<IBluetoothLowEnergy> ble_iface;
593  bt_iface->GetLowEnergyInterface(&ble_iface);
594  if (!ble_iface.get()) {
595    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
596    return;
597  }
598
599  bool status;
600  ble_iface->StopMultiAdvertising(ble_client_id.load(), &status);
601  PrintCommandStatus(status);
602}
603
604void HandleConnect(IBluetooth* bt_iface, const vector<string>& args) {
605  string address;
606
607  if (args.size() != 1) {
608    PrintError("Expected MAC address as only argument");
609    return;
610  }
611
612  address = args[0];
613
614  if (!ble_client_id.load()) {
615    PrintError("BLE not registered");
616    return;
617  }
618
619  sp<IBluetoothLowEnergy> ble_iface;
620  bt_iface->GetLowEnergyInterface(&ble_iface);
621  if (!ble_iface.get()) {
622    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
623    return;
624  }
625
626  bool status;
627  ble_iface->Connect(ble_client_id.load(),
628                     String16(address.c_str(), address.length()),
629                     false /*  is_direct */, &status);
630
631  PrintCommandStatus(status);
632}
633
634void HandleDisconnect(IBluetooth* bt_iface, const vector<string>& args) {
635  string address;
636
637  if (args.size() != 1) {
638    PrintError("Expected MAC address as only argument");
639    return;
640  }
641
642  address = args[0];
643
644  if (!ble_client_id.load()) {
645    PrintError("BLE not registered");
646    return;
647  }
648
649  sp<IBluetoothLowEnergy> ble_iface;
650  bt_iface->GetLowEnergyInterface(&ble_iface);
651  if (!ble_iface.get()) {
652    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
653    return;
654  }
655
656  bool status;
657  ble_iface->Disconnect(ble_client_id.load(),
658                        String16(address.c_str(), address.length()), &status);
659  PrintCommandStatus(status);
660}
661
662void HandleSetMtu(IBluetooth* bt_iface, const vector<string>& args) {
663  string address;
664  int mtu;
665
666  if (args.size() != 2) {
667    PrintError("Usage: set-mtu [address] [mtu]");
668    return;
669  }
670
671  address = args[0];
672  mtu = std::stoi(args[1]);
673
674  if (mtu < 23) {
675    PrintError("MTU must be 23 or larger");
676    return;
677  }
678
679  if (!ble_client_id.load()) {
680    PrintError("BLE not registered");
681    return;
682  }
683
684  sp<IBluetoothLowEnergy> ble_iface;
685  bt_iface->GetLowEnergyInterface(&ble_iface);
686  if (!ble_iface.get()) {
687    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
688    return;
689  }
690
691  bool status;
692  ble_iface->SetMtu(ble_client_id.load(),
693                    String16(address.c_str(), address.length()), mtu, &status);
694  PrintCommandStatus(status);
695}
696
697void HandleStartLeScan(IBluetooth* bt_iface, const vector<string>& args) {
698  if (!ble_client_id.load()) {
699    PrintError("BLE not registered");
700    return;
701  }
702
703  for (auto arg : args) {
704    if (arg == "-d") {
705      dump_scan_record = true;
706    } else if (arg == "-h") {
707      static const char kUsage[] =
708          "Usage: start-le-scan [flags]\n"
709          "\n"
710          "Flags:\n"
711          "\t-d\tDump scan record\n"
712          "\t-h\tShow this help message\n";
713      cout << kUsage << endl;
714      return;
715    }
716  }
717
718  sp<IBluetoothLowEnergy> ble_iface;
719  bt_iface->GetLowEnergyInterface(&ble_iface);
720  if (!ble_iface.get()) {
721    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
722    return;
723  }
724
725  bluetooth::ScanSettings settings;
726  std::vector<android::bluetooth::ScanFilter> filters;
727
728  bool status;
729  ble_iface->StartScan(ble_client_id.load(), settings, filters, &status);
730  PrintCommandStatus(status);
731}
732
733void HandleStopLeScan(IBluetooth* bt_iface, const vector<string>& args) {
734  if (!ble_client_id.load()) {
735    PrintError("BLE not registered");
736    return;
737  }
738
739  sp<IBluetoothLowEnergy> ble_iface;
740  bt_iface->GetLowEnergyInterface(&ble_iface);
741  if (!ble_iface.get()) {
742    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
743    return;
744  }
745
746  bool status;
747  ble_iface->StopScan(ble_client_id.load(), &status);
748  PrintCommandStatus(status);
749}
750
751void HandleHelp(IBluetooth* bt_iface, const vector<string>& args);
752
753struct {
754  string command;
755  void (*func)(IBluetooth*, const vector<string>& args);
756  string help;
757} kCommandMap[] = {
758    {"help", HandleHelp, "\t\t\tDisplay this message"},
759    {"disable", HandleDisable, "\t\t\tDisable Bluetooth"},
760    {"enable", HandleEnable, "\t\t\tEnable Bluetooth (-h for options)"},
761    {"get-state", HandleGetState, "\t\tGet the current adapter state"},
762    {"is-enabled", HandleIsEnabled, "\t\tReturn if Bluetooth is enabled"},
763    {"get-local-address", HandleGetLocalAddress,
764     "\tGet the local adapter address"},
765    {"set-local-name", HandleSetLocalName, "\t\tSet the local adapter name"},
766    {"get-local-name", HandleGetLocalName, "\t\tGet the local adapter name"},
767    {"adapter-info", HandleAdapterInfo, "\t\tPrint adapter properties"},
768    {"supports-multi-adv", HandleSupportsMultiAdv,
769     "\tWhether multi-advertisement is currently supported"},
770    {"register-ble", HandleRegisterBLE,
771     "\t\tRegister with the Bluetooth Low Energy interface"},
772    {"unregister-ble", HandleUnregisterBLE,
773     "\t\tUnregister from the Bluetooth Low Energy interface"},
774    {"unregister-all-ble", HandleUnregisterAllBLE,
775     "\tUnregister all clients from the Bluetooth Low Energy interface"},
776    {"register-gatt", HandleRegisterGATT,
777     "\t\tRegister with the Bluetooth GATT Client interface"},
778    {"unregister-gatt", HandleUnregisterGATT,
779     "\t\tUnregister from the Bluetooth GATT Client interface"},
780    {"connect-le", HandleConnect, "\t\tConnect to LE device (-h for options)"},
781    {"disconnect-le", HandleDisconnect,
782     "\t\tDisconnect LE device (-h for options)"},
783    {"set-mtu", HandleSetMtu, "\t\tSet MTU (-h for options)"},
784    {"start-adv", HandleStartAdv, "\t\tStart advertising (-h for options)"},
785    {"stop-adv", HandleStopAdv, "\t\tStop advertising"},
786    {"start-le-scan", HandleStartLeScan,
787     "\t\tStart LE device scan (-h for options)"},
788    {"stop-le-scan", HandleStopLeScan, "\t\tStop LE device scan"},
789    {},
790};
791
792void HandleHelp(IBluetooth* /* bt_iface */, const vector<string>& /* args */) {
793  cout << endl;
794  for (int i = 0; kCommandMap[i].func; i++)
795    cout << "\t" << kCommandMap[i].command << kCommandMap[i].help << endl;
796  cout << endl;
797}
798
799const char kExecuteLong[] = "exec";
800const char kExecuteShort[] = "e";
801
802bool ExecuteCommand(sp<IBluetooth> bt_iface, std::string &command) {
803  vector<string> args =
804      base::SplitString(command, " ", base::TRIM_WHITESPACE,
805                        base::SPLIT_WANT_ALL);
806
807  if (args.empty())
808    return true;
809
810  // The first argument is the command while the remaining are what we pass to
811  // the handler functions.
812  command = args[0];
813  args.erase(args.begin());
814
815  for (int i = 0; kCommandMap[i].func; i++) {
816    if (command == kCommandMap[i].command) {
817      kCommandMap[i].func(bt_iface.get(), args);
818      return true;
819    }
820  }
821
822  cout << "Unrecognized command: " << command << endl;
823  return false;
824}
825
826}  // namespace
827
828class BluetoothDeathRecipient : public android::IBinder::DeathRecipient {
829 public:
830  BluetoothDeathRecipient() = default;
831  ~BluetoothDeathRecipient() override = default;
832
833  // android::IBinder::DeathRecipient override:
834  void binderDied(const android::wp<android::IBinder>& /* who */) override {
835    BeginAsyncOut();
836    cout << COLOR_BOLDWHITE "The Bluetooth daemon has died" COLOR_OFF << endl;
837    cout << "\nPress 'ENTER' to exit.";
838    EndAsyncOut();
839
840    android::IPCThreadState::self()->stopProcess();
841    should_exit = true;
842  }
843
844 private:
845  DISALLOW_COPY_AND_ASSIGN(BluetoothDeathRecipient);
846};
847
848
849int main(int argc, char* argv[]) {
850  base::AtExitManager exit_manager;
851  base::CommandLine::Init(argc, argv);
852  logging::LoggingSettings log_settings;
853
854  if (!logging::InitLogging(log_settings)) {
855    LOG(ERROR) << "Failed to set up logging";
856    return EXIT_FAILURE;
857  }
858
859  sp<IBluetooth> bt_iface;
860  status_t status = getService(String16(kServiceName.c_str()), &bt_iface);
861  if (status != OK) {
862    LOG(ERROR) << "Failed to get service binder: '" << kServiceName
863               << "' status=" << status;
864    return EXIT_FAILURE;
865  }
866
867  sp<BluetoothDeathRecipient> dr(new BluetoothDeathRecipient());
868  if (android::IInterface::asBinder(bt_iface.get())->linkToDeath(dr) !=
869      android::NO_ERROR) {
870    LOG(ERROR) << "Failed to register DeathRecipient for IBluetooth";
871    return EXIT_FAILURE;
872  }
873
874  // Initialize the Binder process thread pool. We have to set this up,
875  // otherwise, incoming callbacks from IBluetoothCallback will block the main
876  // thread (in other words, we have to do this as we are a "Binder server").
877  android::ProcessState::self()->startThreadPool();
878
879  // Register Adapter state-change callback
880  sp<CLIBluetoothCallback> callback = new CLIBluetoothCallback();
881  bt_iface->RegisterCallback(callback);
882
883  cout << COLOR_BOLDWHITE << "Fluoride Command-Line Interface\n"
884       << COLOR_OFF << endl
885       << "Type \"help\" to see possible commands.\n"
886       << endl;
887
888  string command;
889
890  // Add commands from the command line, if they exist.
891  auto command_line = base::CommandLine::ForCurrentProcess();
892  if (command_line->HasSwitch(kExecuteLong)) {
893    command += command_line->GetSwitchValueASCII(kExecuteLong);
894  }
895
896  if (command_line->HasSwitch(kExecuteShort)) {
897    if (!command.empty())
898      command += " ; ";
899    command += command_line->GetSwitchValueASCII(kExecuteShort);
900  }
901
902  while (true) {
903    vector<string> commands = base::SplitString(command, ";",
904                                                base::TRIM_WHITESPACE,
905                                                base::SPLIT_WANT_ALL);
906    for (string command : commands) {
907      if (!ExecuteCommand(bt_iface, command))
908        break;
909    }
910
911    commands.clear();
912
913    PrintPrompt();
914
915    showing_prompt = true;
916    auto& istream = getline(cin, command);
917    showing_prompt = false;
918
919    if (istream.eof() || should_exit.load()) {
920      cout << "\nExiting" << endl;
921      return EXIT_SUCCESS;
922    }
923
924    if (!istream.good()) {
925      LOG(ERROR) << "An error occured while reading input";
926      return EXIT_FAILURE;
927    }
928  }
929
930  return EXIT_SUCCESS;
931}
932