// // Copyright 2015 Google, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include <base/at_exit.h> #include <base/bind.h> #include <base/command_line.h> #include <base/location.h> #include <base/logging.h> #include <base/message_loop/message_loop.h> #include <base/run_loop.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/ProcessState.h> #include <android/bluetooth/IBluetooth.h> #include "heart_rate_server.h" using android::sp; using android::OK; using android::bluetooth::IBluetooth; using android::getService; namespace { std::string kServiceName = "bluetooth-service"; void QuitMessageLoop() { base::RunLoop().Quit(); } // Handles the case where the Bluetooth process dies. class BluetoothDeathRecipient : public android::IBinder::DeathRecipient { public: explicit BluetoothDeathRecipient( scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) : main_task_runner_(main_task_runner) {} ~BluetoothDeathRecipient() override = default; // android::IBinder::DeathRecipient override: void binderDied(const android::wp<android::IBinder>& /* who */) override { LOG(ERROR) << "The Bluetooth daemon has died. Aborting."; // binderDied executes on a dedicated thread. We need to stop the main loop // on the main thread so we post a message to it here. The main loop only // runs on the main thread. main_task_runner_->PostTask(FROM_HERE, base::Bind(&QuitMessageLoop)); android::IPCThreadState::self()->stopProcess(); } private: scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; }; } // namespace int main(int argc, char* argv[]) { base::AtExitManager exit_manager; base::CommandLine::Init(argc, argv); logging::LoggingSettings log_settings; // Initialize global logging based on command-line parameters (this is a // libchrome pattern). if (!logging::InitLogging(log_settings)) { LOG(ERROR) << "Failed to set up logging"; return EXIT_FAILURE; } // Set up a message loop so that we can schedule timed Heart Rate // notifications. base::MessageLoop main_loop; LOG(INFO) << "Starting GATT Heart Rate Service sample"; sp<IBluetooth> bluetooth; status_t status = getService(String16(kServiceName.c_str()), &bluetooth); if (status != OK) { LOG(ERROR) << "Failed to get service binder: '" << kServiceName << "' status=" << status; return EXIT_FAILURE; } // Bluetooth needs to be enabled for our demo to work. bool enabled; bluetooth->IsEnabled(&enabled); if (!enabled) { LOG(ERROR) << "Bluetooth is not enabled."; return EXIT_FAILURE; } // Register for death notifications on the IBluetooth binder. This let's us // handle the case where the Bluetooth daemon process (bluetoothtbd) dies // outside of our control. sp<BluetoothDeathRecipient> dr( new BluetoothDeathRecipient(main_loop.task_runner())); if (android::IInterface::asBinder(bluetooth.get())->linkToDeath(dr) != android::NO_ERROR) { LOG(ERROR) << "Failed to register DeathRecipient for IBluetooth"; return EXIT_FAILURE; } // Initialize the Binder process thread pool. We have to set this up, // otherwise, incoming callbacks from the Bluetooth daemon would block the // main thread (in other words, we have to do this as we are a "Binder // server"). android::ProcessState::self()->startThreadPool(); // heart_rate::HeartRateServer notifies success or failure asynchronously // using a closure, so we set up a lambda for that here. auto callback = [&](bool success) { if (success) { LOG(INFO) << "Heart Rate service started successfully"; return; } LOG(ERROR) << "Starting Heart Rate server failed asynchronously"; base::RunLoop().QuitWhenIdle(); }; bool advertise = base::CommandLine::ForCurrentProcess()->HasSwitch("advertise"); // Create the Heart Rate server. std::unique_ptr<heart_rate::HeartRateServer> hr( new heart_rate::HeartRateServer(bluetooth, main_loop.task_runner(), advertise)); if (!hr->Run(callback)) { LOG(ERROR) << "Failed to start Heart Rate server"; return EXIT_FAILURE; } // Run the main loop on the main process thread. Binder callbacks will be // received in dedicated threads set up by the ProcessState::startThreadPool // call above but we use this main loop for sending out heart rate // notifications. base::RunLoop().Run(); LOG(INFO) << "Exiting"; return EXIT_SUCCESS; }