main.cc revision 87222e0e826216c69f6a9a5bfe77689561067474
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#include <base/at_exit.h>
21#include <base/command_line.h>
22#include <base/logging.h>
23#include <base/macros.h>
24#include <base/strings/string_split.h>
25#include <base/strings/string_util.h>
26#include <binder/IPCThreadState.h>
27#include <binder/ProcessState.h>
28
29#include <bluetooth/adapter_state.h>
30#include <bluetooth/binder/IBluetooth.h>
31#include <bluetooth/binder/IBluetoothCallback.h>
32#include <bluetooth/low_energy_constants.h>
33#include <bluetooth/uuid.h>
34
35using namespace std;
36
37using android::sp;
38
39using ipc::binder::IBluetooth;
40using ipc::binder::IBluetoothLowEnergy;
41
42namespace {
43
44#define COLOR_OFF         "\x1B[0m"
45#define COLOR_RED         "\x1B[0;91m"
46#define COLOR_GREEN       "\x1B[0;92m"
47#define COLOR_YELLOW      "\x1B[0;93m"
48#define COLOR_BLUE        "\x1B[0;94m"
49#define COLOR_MAGENTA     "\x1B[0;95m"
50#define COLOR_BOLDGRAY    "\x1B[1;30m"
51#define COLOR_BOLDWHITE   "\x1B[1;37m"
52#define COLOR_BOLDYELLOW  "\x1B[1;93m"
53
54const char kCommandDisable[] = "disable";
55const char kCommandEnable[] = "enable";
56const char kCommandGetState[] = "get-state";
57const char kCommandIsEnabled[] = "is-enabled";
58
59#define CHECK_ARGS_COUNT(args, op, num, msg) \
60  if (!(args.size() op num)) { \
61    PrintError(msg); \
62    return; \
63  }
64#define CHECK_NO_ARGS(args) \
65  CHECK_ARGS_COUNT(args, ==, 0, "Expected no arguments")
66
67// TODO(armansito): Clean up this code. Right now everything is in this
68// monolithic file. We should organize this into different classes for command
69// handling, console output/printing, callback handling, etc.
70// (See http://b/23387611)
71
72// Used to synchronize the printing of the command-line prompt and incoming
73// Binder callbacks.
74std::atomic_bool showing_prompt(false);
75
76// The registered IBluetoothLowEnergy client handle. If |ble_registering| is
77// true then an operation to register the client is in progress.
78std::atomic_bool ble_registering(false);
79std::atomic_int ble_client_if(0);
80
81// True if the remote process has died and we should exit.
82std::atomic_bool should_exit(false);
83
84void PrintPrompt() {
85  cout << COLOR_BLUE "[FCLI] " COLOR_OFF << flush;
86}
87
88void PrintError(const string& message) {
89  cout << COLOR_RED << message << COLOR_OFF << endl;
90}
91
92void PrintOpStatus(const std::string& op, bool status) {
93  cout << COLOR_BOLDWHITE << op << " status: " COLOR_OFF
94       << (status ? (COLOR_GREEN "success") : (COLOR_RED "failure"))
95       << COLOR_OFF << endl << endl;
96}
97
98class CLIBluetoothCallback : public ipc::binder::BnBluetoothCallback {
99 public:
100  CLIBluetoothCallback() = default;
101  ~CLIBluetoothCallback() override = default;
102
103  // IBluetoothCallback overrides:
104  void OnBluetoothStateChange(
105      bluetooth::AdapterState prev_state,
106      bluetooth::AdapterState new_state) override {
107    if (showing_prompt.load())
108      cout << endl;
109    cout << COLOR_BOLDWHITE "Adapter state changed: " COLOR_OFF
110         << COLOR_MAGENTA << AdapterStateToString(prev_state) << COLOR_OFF
111         << COLOR_BOLDWHITE " -> " COLOR_OFF
112         << COLOR_BOLDYELLOW << AdapterStateToString(new_state) << COLOR_OFF
113         << endl << endl;
114    if (showing_prompt.load())
115      PrintPrompt();
116  }
117
118 private:
119  DISALLOW_COPY_AND_ASSIGN(CLIBluetoothCallback);
120};
121
122class CLIBluetoothLowEnergyCallback
123    : public ipc::binder::BnBluetoothLowEnergyCallback {
124 public:
125  CLIBluetoothLowEnergyCallback() = default;
126  ~CLIBluetoothLowEnergyCallback() = default;
127
128  // IBluetoothLowEnergyCallback overrides:
129  void OnClientRegistered(int status, int client_if) override {
130    if (showing_prompt.load())
131      cout << endl;
132    if (status != bluetooth::BLE_STATUS_SUCCESS) {
133      PrintError("Failed to register BLE client");
134    } else {
135      ble_client_if = client_if;
136      cout << COLOR_BOLDWHITE "Registered BLE client with ID: " COLOR_OFF
137           << COLOR_GREEN << client_if << COLOR_OFF << endl << endl;
138    }
139    if (showing_prompt.load())
140      PrintPrompt();
141
142    ble_registering = false;
143  }
144
145  void OnMultiAdvertiseCallback(
146      int status, bool is_start,
147      const bluetooth::AdvertiseSettings& /* settings */) {
148    if (showing_prompt.load())
149      cout << endl;
150
151    std::string op = is_start ? "start" : "stop";
152
153    PrintOpStatus("Advertising " + op, status == bluetooth::BLE_STATUS_SUCCESS);
154
155    if (showing_prompt.load())
156      PrintPrompt();
157  }
158
159 private:
160  DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLowEnergyCallback);
161};
162
163void PrintCommandStatus(bool status) {
164  PrintOpStatus("Command", status);
165}
166
167void PrintFieldAndValue(const string& field, const string& value) {
168  cout << COLOR_BOLDWHITE << field << ": " << COLOR_BOLDYELLOW << value
169       << COLOR_OFF << endl;
170}
171
172void PrintFieldAndBoolValue(const string& field, bool value) {
173  PrintFieldAndValue(field, (value ? "true" : "false"));
174}
175
176void HandleDisable(IBluetooth* bt_iface, const vector<string>& args) {
177  CHECK_NO_ARGS(args);
178  PrintCommandStatus(bt_iface->Disable());
179}
180
181void HandleEnable(IBluetooth* bt_iface, const vector<string>& args) {
182  CHECK_NO_ARGS(args);
183  PrintCommandStatus(bt_iface->Enable());
184}
185
186void HandleGetState(IBluetooth* bt_iface, const vector<string>& args) {
187  CHECK_NO_ARGS(args);
188  bluetooth::AdapterState state = static_cast<bluetooth::AdapterState>(
189      bt_iface->GetState());
190  PrintFieldAndValue("Adapter state", bluetooth::AdapterStateToString(state));
191}
192
193void HandleIsEnabled(IBluetooth* bt_iface, const vector<string>& args) {
194  CHECK_NO_ARGS(args);
195  bool enabled = bt_iface->IsEnabled();
196  PrintFieldAndBoolValue("Adapter enabled", enabled);
197}
198
199void HandleGetLocalAddress(IBluetooth* bt_iface, const vector<string>& args) {
200  CHECK_NO_ARGS(args);
201  string address = bt_iface->GetAddress();
202  PrintFieldAndValue("Adapter address", address);
203}
204
205void HandleSetLocalName(IBluetooth* bt_iface, const vector<string>& args) {
206  CHECK_ARGS_COUNT(args, >=, 1, "No name was given");
207
208  std::string name;
209  for (const auto& arg : args)
210    name += arg + " ";
211
212  base::TrimWhitespaceASCII(name, base::TRIM_TRAILING, &name);
213
214  PrintCommandStatus(bt_iface->SetName(name));
215}
216
217void HandleGetLocalName(IBluetooth* bt_iface, const vector<string>& args) {
218  CHECK_NO_ARGS(args);
219  string name = bt_iface->GetName();
220  PrintFieldAndValue("Adapter name", name);
221}
222
223void HandleAdapterInfo(IBluetooth* bt_iface, const vector<string>& args) {
224  CHECK_NO_ARGS(args);
225
226  cout << COLOR_BOLDWHITE "Adapter Properties: " COLOR_OFF << endl;
227
228  PrintFieldAndValue("\tAddress", bt_iface->GetAddress());
229  PrintFieldAndValue("\tState", bluetooth::AdapterStateToString(
230      static_cast<bluetooth::AdapterState>(bt_iface->GetState())));
231  PrintFieldAndValue("\tName", bt_iface->GetName());
232  PrintFieldAndBoolValue("\tMulti-Adv. supported",
233                         bt_iface->IsMultiAdvertisementSupported());
234}
235
236void HandleSupportsMultiAdv(IBluetooth* bt_iface, const vector<string>& args) {
237  CHECK_NO_ARGS(args);
238
239  bool status = bt_iface->IsMultiAdvertisementSupported();
240  PrintFieldAndBoolValue("Multi-advertisement support", status);
241}
242
243void HandleRegisterBLE(IBluetooth* bt_iface, const vector<string>& args) {
244  CHECK_NO_ARGS(args);
245
246  if (ble_registering.load()) {
247    PrintError("In progress");
248    return;
249  }
250
251  if (ble_client_if.load()) {
252    PrintError("Already registered");
253    return;
254  }
255
256  sp<IBluetoothLowEnergy> ble_iface = bt_iface->GetLowEnergyInterface();
257  if (!ble_iface.get()) {
258    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
259    return;
260  }
261
262  bool status = ble_iface->RegisterClient(new CLIBluetoothLowEnergyCallback());
263  ble_registering = status;
264  PrintCommandStatus(status);
265}
266
267void HandleUnregisterBLE(IBluetooth* bt_iface, const vector<string>& args) {
268  CHECK_NO_ARGS(args);
269
270  if (!ble_client_if.load()) {
271    PrintError("Not registered");
272    return;
273  }
274
275  sp<IBluetoothLowEnergy> ble_iface = bt_iface->GetLowEnergyInterface();
276  if (!ble_iface.get()) {
277    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
278    return;
279  }
280
281  ble_iface->UnregisterClient(ble_client_if.load());
282  ble_client_if = 0;
283  PrintCommandStatus(true);
284}
285
286void HandleUnregisterAllBLE(IBluetooth* bt_iface, const vector<string>& args) {
287  CHECK_NO_ARGS(args);
288
289  sp<IBluetoothLowEnergy> ble_iface = bt_iface->GetLowEnergyInterface();
290  if (!ble_iface.get()) {
291    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
292    return;
293  }
294
295  ble_iface->UnregisterAll();
296  PrintCommandStatus(true);
297}
298
299void HandleStartAdv(IBluetooth* bt_iface, const vector<string>& args) {
300  bool include_name = false;
301  bool include_tx_power = false;
302  bool connectable = false;
303  bool set_manufacturer_data = false;
304  bool set_uuid = false;
305  bluetooth::UUID uuid;
306
307  for (auto iter = args.begin(); iter != args.end(); ++iter) {
308    const std::string& arg = *iter;
309    if (arg == "-n")
310      include_name = true;
311    else if (arg == "-t")
312      include_tx_power = true;
313    else if (arg == "-c")
314      connectable = true;
315    else if (arg == "-m")
316      set_manufacturer_data = true;
317    else if (arg == "-u") {
318      // This flag has a single argument.
319      ++iter;
320      if (iter == args.end()) {
321        PrintError("Expected a UUID after -u");
322        return;
323      }
324
325      std::string uuid_str = *iter;
326      uuid = bluetooth::UUID(uuid_str);
327      if (!uuid.is_valid()) {
328        PrintError("Invalid UUID: " + uuid_str);
329        return;
330      }
331
332      set_uuid = true;
333    }
334    else if (arg == "-h") {
335      const char* kUsage =
336          "Usage: start-adv [flags]\n"
337          "\n"
338          "Flags\n"
339          "\t-n\tInclude device name\n"
340          "\t-t\tInclude TX power\n"
341          "\t-c\tSend connectable adv. packets (default is non-connectable)\n"
342          "\t-m\tInclude random manufacturer data\n"
343          "\t-h\tShow this help message\n";
344      cout << kUsage << endl;
345      return;
346    }
347    else {
348      PrintError("Unrecognized option: " + arg);
349      return;
350    }
351  }
352
353  if (!ble_client_if.load()) {
354    PrintError("BLE not registered");
355    return;
356  }
357
358  sp<IBluetoothLowEnergy> ble_iface = bt_iface->GetLowEnergyInterface();
359  if (!ble_iface.get()) {
360    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
361    return;
362  }
363
364  std::vector<uint8_t> data;
365  if (set_manufacturer_data) {
366    data = {{
367      0x07, bluetooth::kEIRTypeManufacturerSpecificData,
368      0xe0, 0x00,
369      'T', 'e', 's', 't'
370    }};
371  }
372
373  if (set_uuid) {
374    // Determine the type and length bytes.
375    int uuid_size = uuid.GetShortestRepresentationSize();
376    uint8_t type;
377    if (uuid_size == bluetooth::UUID::kNumBytes128)
378      type = bluetooth::kEIRTypeComplete128BitUUIDs;
379    else if (uuid_size == bluetooth::UUID::kNumBytes32)
380      type = bluetooth::kEIRTypeComplete32BitUUIDs;
381    else if (uuid_size == bluetooth::UUID::kNumBytes16)
382      type = bluetooth::kEIRTypeComplete16BitUUIDs;
383    else
384      NOTREACHED() << "Unexpected size: " << uuid_size;
385
386    data.push_back(uuid_size + 1);
387    data.push_back(type);
388
389    auto uuid_bytes = uuid.GetFullLittleEndian();
390    int index = (uuid_size == 16) ? 0 : 12;
391    data.insert(data.end(), uuid_bytes.data() + index,
392                uuid_bytes.data() + index + uuid_size);
393  }
394
395  base::TimeDelta timeout;
396
397  bluetooth::AdvertiseSettings settings(
398      bluetooth::AdvertiseSettings::MODE_LOW_POWER,
399      timeout,
400      bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM,
401      connectable);
402
403  bluetooth::AdvertiseData adv_data(data);
404  adv_data.set_include_device_name(include_name);
405  adv_data.set_include_tx_power_level(include_tx_power);
406
407  bluetooth::AdvertiseData scan_rsp;
408
409  bool status = ble_iface->StartMultiAdvertising(ble_client_if.load(),
410                                                 adv_data, scan_rsp, settings);
411  PrintCommandStatus(status);
412}
413
414void HandleStopAdv(IBluetooth* bt_iface, const vector<string>& args) {
415  if (!ble_client_if.load()) {
416    PrintError("BLE not registered");
417    return;
418  }
419
420  sp<IBluetoothLowEnergy> ble_iface = bt_iface->GetLowEnergyInterface();
421  if (!ble_iface.get()) {
422    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
423    return;
424  }
425
426  bool status = ble_iface->StopMultiAdvertising(ble_client_if.load());
427  PrintCommandStatus(status);
428}
429
430void HandleHelp(IBluetooth* bt_iface, const vector<string>& args);
431
432struct {
433  string command;
434  void (*func)(IBluetooth*, const vector<string>& args);
435  string help;
436} kCommandMap[] = {
437  { "help", HandleHelp, "\t\t\tDisplay this message" },
438  { "disable", HandleDisable, "\t\t\tDisable Bluetooth" },
439  { "enable", HandleEnable, "\t\t\tEnable Bluetooth" },
440  { "get-state", HandleGetState, "\t\tGet the current adapter state" },
441  { "is-enabled", HandleIsEnabled, "\t\tReturn if Bluetooth is enabled" },
442  { "get-local-address", HandleGetLocalAddress,
443    "\tGet the local adapter address" },
444  { "set-local-name", HandleSetLocalName, "\t\tSet the local adapter name" },
445  { "get-local-name", HandleGetLocalName, "\t\tGet the local adapter name" },
446  { "adapter-info", HandleAdapterInfo, "\t\tPrint adapter properties" },
447  { "supports-multi-adv", HandleSupportsMultiAdv,
448    "\tWhether multi-advertisement is currently supported" },
449  { "register-ble", HandleRegisterBLE,
450    "\t\tRegister with the Bluetooth Low Energy interface" },
451  { "unregister-ble", HandleUnregisterBLE,
452    "\t\tUnregister from the Bluetooth Low Energy interface" },
453  { "unregister-all-ble", HandleUnregisterAllBLE,
454    "\tUnregister all clients from the Bluetooth Low Energy interface" },
455  { "start-adv", HandleStartAdv, "\t\tStart advertising (-h for options)" },
456  { "stop-adv", HandleStopAdv, "\t\tStop advertising" },
457  {},
458};
459
460void HandleHelp(IBluetooth* /* bt_iface */, const vector<string>& /* args */) {
461  cout << endl;
462  for (int i = 0; kCommandMap[i].func; i++)
463    cout << "\t" << kCommandMap[i].command << kCommandMap[i].help << endl;
464  cout << endl;
465}
466
467}  // namespace
468
469class BluetoothDeathRecipient : public android::IBinder::DeathRecipient {
470 public:
471  BluetoothDeathRecipient() = default;
472  ~BluetoothDeathRecipient() override = default;
473
474  // android::IBinder::DeathRecipient override:
475  void binderDied(const android::wp<android::IBinder>& /* who */) override {
476    if (showing_prompt.load())
477      cout << endl;
478    cout << COLOR_BOLDWHITE "The Bluetooth daemon has died" COLOR_OFF << endl;
479    cout << "\nPress 'ENTER' to exit." << endl;
480    if (showing_prompt.load())
481      PrintPrompt();
482
483    android::IPCThreadState::self()->stopProcess();
484    should_exit = true;
485  }
486
487 private:
488  DISALLOW_COPY_AND_ASSIGN(BluetoothDeathRecipient);
489};
490
491int main(int argc, char* argv[]) {
492  base::AtExitManager exit_manager;
493  base::CommandLine::Init(argc, argv);
494  logging::LoggingSettings log_settings;
495
496  if (!logging::InitLogging(log_settings)) {
497    LOG(ERROR) << "Failed to set up logging";
498    return EXIT_FAILURE;
499  }
500
501  sp<IBluetooth> bt_iface = IBluetooth::getClientInterface();
502  if (!bt_iface.get()) {
503    LOG(ERROR) << "Failed to obtain handle on IBluetooth";
504    return EXIT_FAILURE;
505  }
506
507  sp<BluetoothDeathRecipient> dr(new BluetoothDeathRecipient());
508  if (android::IInterface::asBinder(bt_iface.get())->linkToDeath(dr) !=
509      android::NO_ERROR) {
510    LOG(ERROR) << "Failed to register DeathRecipient for IBluetooth";
511    return EXIT_FAILURE;
512  }
513
514  // Initialize the Binder process thread pool. We have to set this up,
515  // otherwise, incoming callbacks from IBluetoothCallback will block the main
516  // thread (in other words, we have to do this as we are a "Binder server").
517  android::ProcessState::self()->startThreadPool();
518
519  // Register Adapter state-change callback
520  sp<CLIBluetoothCallback> callback = new CLIBluetoothCallback();
521  bt_iface->RegisterCallback(callback);
522
523  cout << COLOR_BOLDWHITE << "Fluoride Command-Line Interface\n" << COLOR_OFF
524       << endl
525       << "Type \"help\" to see possible commands.\n"
526       << endl;
527
528  while (true) {
529    string command;
530
531    PrintPrompt();
532
533    showing_prompt = true;
534    auto& istream = getline(cin, command);
535    showing_prompt = false;
536
537    if (istream.eof() || should_exit.load()) {
538      cout << "\nExiting" << endl;
539      return EXIT_SUCCESS;
540    }
541
542    if (!istream.good()) {
543      LOG(ERROR) << "An error occured while reading input";
544      return EXIT_FAILURE;
545    }
546
547    vector<string> args;
548    base::SplitString(command, ' ', &args);
549
550    if (args.empty())
551      continue;
552
553    // The first argument is the command while the remaning are what we pass to
554    // the handler functions.
555    command = args[0];
556    args.erase(args.begin());
557
558    bool command_handled = false;
559    for (int i = 0; kCommandMap[i].func && !command_handled; i++) {
560      if (command == kCommandMap[i].command) {
561        kCommandMap[i].func(bt_iface.get(), args);
562        command_handled = true;
563      }
564    }
565
566    if (!command_handled)
567      cout << "Unrecognized command: " << command << endl;
568  }
569
570  return EXIT_SUCCESS;
571}
572