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