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