File: bluetooth_connection_finder.cc

package info (click to toggle)
chromium-browser 57.0.2987.98-1~deb8u1
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 2,637,852 kB
  • ctags: 2,544,394
  • sloc: cpp: 12,815,961; ansic: 3,676,222; python: 1,147,112; asm: 526,608; java: 523,212; xml: 286,794; perl: 92,654; sh: 86,408; objc: 73,271; makefile: 27,698; cs: 18,487; yacc: 13,031; tcl: 12,957; pascal: 4,875; ml: 4,716; lex: 3,904; sql: 3,862; ruby: 1,982; lisp: 1,508; php: 1,368; exp: 404; awk: 325; csh: 117; jsp: 39; sed: 37
file content (211 lines) | stat: -rw-r--r-- 7,224 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/proximity_auth/bluetooth_connection_finder.h"

#include <utility>

#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/cryptauth/connection.h"
#include "components/proximity_auth/bluetooth_connection.h"
#include "components/proximity_auth/logging/logging.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"

using device::BluetoothAdapter;

namespace proximity_auth {

BluetoothConnectionFinder::BluetoothConnectionFinder(
    const cryptauth::RemoteDevice& remote_device,
    const device::BluetoothUUID& uuid,
    const base::TimeDelta& polling_interval)
    : remote_device_(remote_device),
      uuid_(uuid),
      polling_interval_(polling_interval),
      has_delayed_poll_scheduled_(false),
      weak_ptr_factory_(this) {}

BluetoothConnectionFinder::~BluetoothConnectionFinder() {
  UnregisterAsObserver();
}

void BluetoothConnectionFinder::Find(
    const cryptauth::ConnectionFinder::ConnectionCallback&
        connection_callback) {
  if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
    PA_LOG(WARNING) << "Bluetooth is unsupported on this platform. Aborting.";
    return;
  }

  DCHECK(start_time_.is_null());

  start_time_ = base::TimeTicks::Now();
  connection_callback_ = connection_callback;

  device::BluetoothAdapterFactory::GetAdapter(
      base::Bind(&BluetoothConnectionFinder::OnAdapterInitialized,
                 weak_ptr_factory_.GetWeakPtr()));
}

std::unique_ptr<cryptauth::Connection>
BluetoothConnectionFinder::CreateConnection() {
  return std::unique_ptr<cryptauth::Connection>(
      new BluetoothConnection(remote_device_, uuid_));
}

void BluetoothConnectionFinder::SeekDeviceByAddress(
    const std::string& bluetooth_address,
    const base::Closure& callback,
    const bluetooth_util::ErrorCallback& error_callback) {
  bluetooth_util::SeekDeviceByAddress(
      bluetooth_address, callback, error_callback,
      base::ThreadTaskRunnerHandle::Get().get());
}

bool BluetoothConnectionFinder::IsReadyToPoll() {
  bool is_adapter_available =
      adapter_.get() && adapter_->IsPresent() && adapter_->IsPowered();
  PA_LOG(INFO) << "Readiness: adapter="
               << (is_adapter_available ? "available" : "unavailable");
  return is_adapter_available;
}

void BluetoothConnectionFinder::PollIfReady() {
  if (!IsReadyToPoll())
    return;

  // If there is a pending task to poll at a later time, the time requisite
  // timeout has not yet elapsed since the previous polling attempt. In that
  // case, keep waiting until the delayed task comes in.
  if (has_delayed_poll_scheduled_)
    return;

  // If the |connection_| is pending, wait for it to connect or fail prior to
  // polling again.
  if (connection_ &&
      connection_->status() != cryptauth::Connection::DISCONNECTED)
    return;

  // This SeekDeviceByAddress operation is needed to connect to a device if
  // it is not already known to the adapter.
  if (!adapter_->GetDevice(remote_device_.bluetooth_address)) {
    PA_LOG(INFO) << "Remote device [" << remote_device_.bluetooth_address
                 << "] is not known. "
                 << "Seeking device directly by address...";

    SeekDeviceByAddress(
        remote_device_.bluetooth_address,
        base::Bind(&BluetoothConnectionFinder::OnSeekedDeviceByAddress,
                   weak_ptr_factory_.GetWeakPtr()),
        base::Bind(&BluetoothConnectionFinder::OnSeekedDeviceByAddressError,
                   weak_ptr_factory_.GetWeakPtr()));
  } else {
    PA_LOG(INFO) << "Remote device known, connecting...";
    connection_ = CreateConnection();
    connection_->AddObserver(this);
    connection_->Connect();
  }
}

void BluetoothConnectionFinder::PostDelayedPoll() {
  if (has_delayed_poll_scheduled_) {
    PA_LOG(WARNING) << "Delayed poll already scheduled, skipping.";
    return;
  }

  PA_LOG(INFO) << "Posting delayed poll..";
  has_delayed_poll_scheduled_ = true;
  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
      FROM_HERE, base::Bind(&BluetoothConnectionFinder::OnDelayedPoll,
                            weak_ptr_factory_.GetWeakPtr()),
      polling_interval_);
}

void BluetoothConnectionFinder::OnDelayedPoll() {
  // Note that there is no longer a pending task, and therefore polling is
  // permitted.
  has_delayed_poll_scheduled_ = false;
  PollIfReady();
}

void BluetoothConnectionFinder::OnSeekedDeviceByAddress() {
  // Sanity check that the remote device is now known by the adapter.
  if (adapter_->GetDevice(remote_device_.bluetooth_address))
    PollIfReady();
  else
    PostDelayedPoll();
}

void BluetoothConnectionFinder::OnSeekedDeviceByAddressError(
    const std::string& error_message) {
  PA_LOG(ERROR) << "Failed to seek device: " << error_message;
  PostDelayedPoll();
}

void BluetoothConnectionFinder::UnregisterAsObserver() {
  if (connection_) {
    connection_->RemoveObserver(this);
    // The connection is about to be released or destroyed, so no need to clear
    // it explicitly here.
  }

  if (adapter_.get()) {
    adapter_->RemoveObserver(this);
    adapter_ = NULL;
  }
}

void BluetoothConnectionFinder::OnAdapterInitialized(
    scoped_refptr<BluetoothAdapter> adapter) {
  adapter_ = adapter;
  adapter_->AddObserver(this);
  PollIfReady();
}

void BluetoothConnectionFinder::AdapterPresentChanged(BluetoothAdapter* adapter,
                                                      bool present) {
  PollIfReady();
}

void BluetoothConnectionFinder::AdapterPoweredChanged(BluetoothAdapter* adapter,
                                                      bool powered) {
  PollIfReady();
}

void BluetoothConnectionFinder::OnConnectionStatusChanged(
    cryptauth::Connection* connection,
    cryptauth::Connection::Status old_status,
    cryptauth::Connection::Status new_status) {
  DCHECK_EQ(connection, connection_.get());

  if (connection_->IsConnected()) {
    base::TimeDelta elapsed = base::TimeTicks::Now() - start_time_;
    PA_LOG(WARNING) << "Connection found! Elapsed Time: "
                    << elapsed.InMilliseconds() << "ms.";
    UnregisterAsObserver();

    // If we invoke the callback now, the callback function may install its own
    // observer to |connection_|. Because we are in the
    // cryptauth::ConnectionObserver
    // callstack, this new observer will receive this connection event.
    // Therefore, we need to invoke the callback asynchronously.
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE, base::Bind(&BluetoothConnectionFinder::InvokeCallbackAsync,
                              weak_ptr_factory_.GetWeakPtr()));
  } else if (old_status == cryptauth::Connection::IN_PROGRESS) {
    PA_LOG(WARNING)
        << "Connection failed! Scheduling another polling iteration.";
    PostDelayedPoll();
  }
}

void BluetoothConnectionFinder::InvokeCallbackAsync() {
  connection_callback_.Run(std::move(connection_));
}

}  // namespace proximity_auth