blob: 6dbd5ea93578e43c1efcf631b4fed5f1906b64bf [file] [log] [blame]
// 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.
#ifndef CONTENT_CHILD_BLUETOOTH_BLUETOOTH_DISPATCHER_H_
#define CONTENT_CHILD_BLUETOOTH_BLUETOOTH_DISPATCHER_H_
#include <stdint.h>
#include <map>
#include <queue>
#include "base/id_map.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "content/common/bluetooth/bluetooth_device.h"
#include "content/public/child/worker_thread.h"
#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h"
#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothError.h"
namespace base {
class MessageLoop;
class TaskRunner;
}
namespace blink {
class WebBluetoothGATTCharacteristic;
}
namespace IPC {
class Message;
}
struct BluetoothCharacteristicRequest;
struct BluetoothPrimaryServiceRequest;
struct BluetoothNotificationsRequest;
namespace content {
class ThreadSafeSender;
// Dispatcher for child process threads which communicates to the browser's
// BluetoothDispatcherHost.
//
// Instances are created for each thread as necessary by WebBluetoothImpl.
//
// Incoming IPC messages are received by the BluetoothMessageFilter and
// directed to the thread specific instance of this class.
// Outgoing messages come from WebBluetoothImpl.
class BluetoothDispatcher : public WorkerThread::Observer {
public:
explicit BluetoothDispatcher(ThreadSafeSender* sender);
~BluetoothDispatcher() override;
// Gets or Creates a BluetoothDispatcher for the current thread.
// |thread_safe_sender| is required when constructing a BluetoothDispatcher.
static BluetoothDispatcher* GetOrCreateThreadSpecificInstance(
ThreadSafeSender* thread_safe_sender);
// IPC Send and Receiving interface, see IPC::Sender and IPC::Listener.
bool Send(IPC::Message* msg);
void OnMessageReceived(const IPC::Message& msg);
// Corresponding to WebBluetoothImpl methods.
void requestDevice(int frame_routing_id,
const blink::WebRequestDeviceOptions& options,
blink::WebBluetoothRequestDeviceCallbacks* callbacks);
void connectGATT(const blink::WebString& device_id,
blink::WebBluetoothConnectGATTCallbacks* callbacks);
void getPrimaryService(
const blink::WebString& device_id,
const blink::WebString& service_uuid,
blink::WebBluetoothGetPrimaryServiceCallbacks* callbacks);
void getCharacteristic(
const blink::WebString& service_instance_id,
const blink::WebString& characteristic_uuid,
blink::WebBluetoothGetCharacteristicCallbacks* callbacks);
void readValue(const blink::WebString& characteristic_instance_id,
blink::WebBluetoothReadValueCallbacks* callbacks);
void writeValue(const blink::WebString& characteristic_instance_id,
const blink::WebVector<uint8_t>& value,
blink::WebBluetoothWriteValueCallbacks*);
void startNotifications(const blink::WebString& characteristic_instance_id,
blink::WebBluetoothGATTCharacteristic* delegate,
blink::WebBluetoothNotificationsCallbacks*);
void stopNotifications(const blink::WebString& characteristic_instance_id,
blink::WebBluetoothGATTCharacteristic* delegate,
blink::WebBluetoothNotificationsCallbacks*);
void characteristicObjectRemoved(
const blink::WebString& characteristic_instance_id,
blink::WebBluetoothGATTCharacteristic* delegate);
void registerCharacteristicObject(
const blink::WebString& characteristic_instance_id,
blink::WebBluetoothGATTCharacteristic* characteristic);
// WorkerThread::Observer implementation.
void WillStopCurrentWorkerThread() override;
enum class NotificationsRequestType { START = 0, STOP = 1 };
private:
// Notifications Queueing Notes:
// To avoid races and sending unnecessary IPC messages we implement
// a queueing system for notification requests. When receiving
// a notification request, the request is immediately queued. If
// there are no other pending requests then the request is processed.
// When a characteristic object gets destroyed BluetoothDispatcher
// gets notified by characteristicObjectRemoved. When this happens
// a stop request should be queued if the characteristic was subscribed
// to notifications.
// Helper functions for notification requests queue:
// Creates a notification request and queues it.
int QueueNotificationRequest(
const std::string& characteristic_instance_id,
blink::WebBluetoothGATTCharacteristic* characteristic,
blink::WebBluetoothNotificationsCallbacks* callbacks,
NotificationsRequestType type);
// Pops the last requests and runs the next request in the queue.
void PopNotificationRequestQueueAndProcessNext(int request_id);
// Checks if there is more than one request in the queue i.e. if there
// are other requests besides the one being processed.
bool HasNotificationRequestResponsePending(
const std::string& characteristic_instance_id);
// Checks if there are any objects subscribed to the characteristic's
// notifications.
bool HasActiveNotificationSubscription(
const std::string& characteristic_instance_id);
// Adds the object to the set of subscribed objects to a characteristic's
// notifications.
void AddToActiveNotificationSubscriptions(
const std::string& characteristic_instance_id,
blink::WebBluetoothGATTCharacteristic* characteristic);
// Removes the object from the set of subscribed object to the
// characteristic's notifications. Returns true if the subscription
// becomes inactive.
bool RemoveFromActiveNotificationSubscriptions(
const std::string& characteristic_instance_id,
blink::WebBluetoothGATTCharacteristic* characteristic);
// The following functions decide whether to resolve the request immediately
// or send an IPC to change the subscription state.
// You should never call these functions if PendingNotificationRequest
// is true since there is currently another request being processed.
void ResolveOrSendStartNotificationRequest(int request_id);
void ResolveOrSendStopNotificationsRequest(int request_id);
// Tells BluetoothDispatcherHost that we are no longer interested in
// events for the characteristic.
//
// TODO(ortuno): We should unregister a characteristic once there are no
// characteristic objects that have listeners attached.
// For now, we call this function when an object gets destroyed. So if there
// are two frames registered for notifications from the same characteristic
// and one of the characteristic objects gets destroyed both will stop
// receiving notifications.
// https://crbug.com/541388
void UnregisterCharacteristicObject(
const blink::WebString& characteristic_instance_id);
// IPC Handlers, see definitions in bluetooth_messages.h.
void OnRequestDeviceSuccess(int thread_id,
int request_id,
const BluetoothDevice& device);
void OnRequestDeviceError(int thread_id,
int request_id,
blink::WebBluetoothError error);
void OnConnectGATTSuccess(int thread_id,
int request_id,
const std::string& message);
void OnConnectGATTError(int thread_id,
int request_id,
blink::WebBluetoothError error);
void OnGetPrimaryServiceSuccess(int thread_id,
int request_id,
const std::string& service_instance_id);
void OnGetPrimaryServiceError(int thread_id,
int request_id,
blink::WebBluetoothError error);
void OnGetCharacteristicSuccess(int thread_id,
int request_id,
const std::string& characteristic_instance_id,
uint32_t characteristic_properties);
void OnGetCharacteristicError(int thread_id,
int request_id,
blink::WebBluetoothError error);
void OnReadValueSuccess(int thread_id,
int request_id,
const std::vector<uint8_t>& value);
void OnReadValueError(int thread_id,
int request_id,
blink::WebBluetoothError error);
void OnWriteValueSuccess(int thread_id, int request_id);
void OnWriteValueError(int thread_id,
int request_id,
blink::WebBluetoothError error);
void OnStartNotificationsSuccess(int thread_id, int request_id);
void OnStartNotificationsError(int thread_id,
int request_id,
blink::WebBluetoothError error);
void OnStopNotificationsSuccess(int thread_id, int request_id);
void OnCharacteristicValueChanged(
int thread_id,
const std::string& characteristic_instance_id,
const std::vector<uint8_t> value);
scoped_refptr<ThreadSafeSender> thread_safe_sender_;
// Map of characteristic_instance_id to a queue of Notification Requests' IDs.
// See "Notifications Queueing Note" above.
std::map<std::string, std::queue<int>> notification_requests_queues_;
// Tracks device requests sent to browser to match replies with callbacks.
// Owns callback objects.
IDMap<blink::WebBluetoothRequestDeviceCallbacks, IDMapOwnPointer>
pending_requests_;
// Tracks requests to connect to a device.
// Owns callback objects.
IDMap<blink::WebBluetoothConnectGATTCallbacks, IDMapOwnPointer>
pending_connect_requests_;
// Tracks requests to get a primary service from a device.
// Owns request objects.
IDMap<BluetoothPrimaryServiceRequest, IDMapOwnPointer>
pending_primary_service_requests_;
// Tracks requests to get a characteristic from a service.
IDMap<BluetoothCharacteristicRequest, IDMapOwnPointer>
pending_characteristic_requests_;
// Tracks requests to read from a characteristics.
IDMap<blink::WebBluetoothReadValueCallbacks, IDMapOwnPointer>
pending_read_value_requests_;
IDMap<blink::WebBluetoothWriteValueCallbacks, IDMapOwnPointer>
pending_write_value_requests_;
IDMap<BluetoothNotificationsRequest, IDMapOwnPointer>
pending_notifications_requests_;
// Map of characteristic_instance_id to a set of
// WebBluetoothGATTCharacteristic pointers. Keeps track of which
// objects are subscribed to notifications.
std::map<std::string, std::set<blink::WebBluetoothGATTCharacteristic*>>
active_notification_subscriptions_;
// Map of characteristic_instance_ids to WebBluetoothGATTCharacteristics.
// Keeps track of what characteristics have listeners.
// TODO(ortuno): We are assuming that there exists a single frame per
// dispatcher, so there could be at most one characteristic object per
// characteristic_instance_id. Change to a set when we support multiple
// frames.
// http://crbug.com/541388
std::map<std::string, blink::WebBluetoothGATTCharacteristic*>
active_characteristics_;
DISALLOW_COPY_AND_ASSIGN(BluetoothDispatcher);
};
} // namespace content
#endif // CONTENT_CHILD_BLUETOOTH_BLUETOOTH_DISPATCHER_H_