You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
4.9 KiB
158 lines
4.9 KiB
//
|
|
// 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/run_loop.h>
|
|
|
|
#include <binder/IPCThreadState.h>
|
|
#include <binder/IServiceManager.h>
|
|
#include <binder/ProcessState.h>
|
|
|
|
#include <android/bluetooth/IBluetooth.h>
|
|
|
|
#include "abstract_message_loop.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.
|
|
btbase::AbstractMessageLoop 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;
|
|
}
|