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