blob: 1076dad7b1f2e733567ea8adf49bcc1154a2a350 [file] [log] [blame]
// Copyright 2018 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 CHROMEOS_SERVICES_SECURE_CHANNEL_BLE_ADVERTISER_IMPL_H_
#define CHROMEOS_SERVICES_SECURE_CHANNEL_BLE_ADVERTISER_IMPL_H_
#include <array>
#include <memory>
#include <utility>
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/sequenced_task_runner.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "chromeos/services/secure_channel/ble_advertiser.h"
#include "chromeos/services/secure_channel/ble_constants.h"
#include "chromeos/services/secure_channel/device_id_pair.h"
#include "chromeos/services/secure_channel/public/cpp/shared/connection_priority.h"
namespace base {
class OneShotTimer;
} // namespace base
namespace chromeos {
namespace secure_channel {
class BleServiceDataHelper;
class BleSynchronizerBase;
class ErrorTolerantBleAdvertisement;
class SharedResourceScheduler;
class TimerFactory;
// Concrete BleAdvertiser implementation. Because systems have a limited number
// of BLE advertisement slots, this class limits the number of concurrent
// advertisements to kMaxConcurrentAdvertisements.
//
// This class tracks two types of requests: active requests (i.e., ones who are
// scheduled to be advertising) and queued requests (i.e., ones who are waiting
// for their turn to use a BLE advertisement slot). A request with a higher
// priority is always given an active advertising slot before a class with a
// lower priority. For equal priorities, a round-robin algorithm is used.
//
// An active advertisement remains active until it is removed by the client,
// pre-empted by another request with a higher priority, or until its timeslot
// ends. This class provides kNumSecondsPerAdvertisementTimeslot seconds for
// each timeslot. When a timeslot ends or when a request is replaced by a
// higher-priority request, the delegate is notified. The delegate is not
// notified when a device is explicitly removed.
class BleAdvertiserImpl : public BleAdvertiser {
public:
class Factory {
public:
static Factory* Get();
static void SetFactoryForTesting(Factory* test_factory);
virtual ~Factory();
virtual std::unique_ptr<BleAdvertiser> BuildInstance(
Delegate* delegate,
BleServiceDataHelper* ble_service_data_helper,
BleSynchronizerBase* ble_synchronizer_base,
TimerFactory* timer_factory,
scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner =
base::SequencedTaskRunnerHandle::Get());
private:
static Factory* test_factory_;
};
~BleAdvertiserImpl() override;
private:
friend class SecureChannelBleAdvertiserImplTest;
struct ActiveAdvertisementRequest {
ActiveAdvertisementRequest(DeviceIdPair device_id_pair,
ConnectionPriority connection_priority,
std::unique_ptr<base::OneShotTimer> timer);
virtual ~ActiveAdvertisementRequest();
DeviceIdPair device_id_pair;
ConnectionPriority connection_priority;
std::unique_ptr<base::OneShotTimer> timer;
DISALLOW_COPY_AND_ASSIGN(ActiveAdvertisementRequest);
};
static const int64_t kNumSecondsPerAdvertisementTimeslot;
BleAdvertiserImpl(
Delegate* delegate,
BleServiceDataHelper* ble_service_data_helper,
BleSynchronizerBase* ble_synchronizer_base,
TimerFactory* timer_factory,
scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner);
// BleAdvertiser:
void AddAdvertisementRequest(const DeviceIdPair& request,
ConnectionPriority connection_priority) override;
void UpdateAdvertisementRequestPriority(
const DeviceIdPair& request,
ConnectionPriority connection_priority) override;
void RemoveAdvertisementRequest(const DeviceIdPair& request) override;
bool ReplaceLowPriorityAdvertisementIfPossible(
ConnectionPriority connection_priority);
base::Optional<size_t> GetIndexWithLowerPriority(
ConnectionPriority connection_priority);
void UpdateAdvertisementState();
void AddActiveAdvertisementRequest(size_t index_to_add);
void AttemptToAddActiveAdvertisement(size_t index_to_add);
base::Optional<size_t> GetIndexForActiveRequest(const DeviceIdPair& request);
void StopAdvertisementRequestAndUpdateActiveRequests(
size_t index,
bool replaced_by_higher_priority_advertisement,
bool should_reschedule);
void StopActiveAdvertisement(size_t index);
void OnActiveAdvertisementStopped(size_t index);
// Notifies the delegate of a request's failure to generate an advertisement,
// unless the failed request has already been processed and removed from
// |requests_already_removed_due_to_failed_advertisement_|.
void AttemptToNotifyFailureToGenerateAdvertisement(
const DeviceIdPair& device_id_pair);
BleServiceDataHelper* ble_service_data_helper_;
BleSynchronizerBase* ble_synchronizer_base_;
TimerFactory* timer_factory_;
// For posting tasks to the current base::SequencedTaskRunner.
scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
std::unique_ptr<SharedResourceScheduler> shared_resource_scheduler_;
DeviceIdPairSet all_requests_;
// An array of length kMaxConcurrentAdvertisements, whose elements correspond
// to the active BLE advertisement requests. Elements in this array are
// scheduled to be advertising at this time. However, because stopping
// advertisements is an asynchronous operation, the active requests may not
// necessarily correspond to the active advertisements.
std::array<std::unique_ptr<ActiveAdvertisementRequest>,
kMaxConcurrentAdvertisements>
active_advertisement_requests_;
// An array of length kMaxConcurrentAdvertisements whose elements correspond
// to the active BLE advertisements.
std::array<std::unique_ptr<ErrorTolerantBleAdvertisement>,
kMaxConcurrentAdvertisements>
active_advertisements_;
// If a request fails to generate an advertisement, it is immediately removed
// internally and tracked here. Then, when the delegate failure callback tries
// to clean up the failed advertisement (or something else tries to re-add or
// remove it again), its associated entry in this set will be removed instead.
base::flat_set<DeviceIdPair>
requests_already_removed_due_to_failed_advertisement_;
base::WeakPtrFactory<BleAdvertiserImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(BleAdvertiserImpl);
};
} // namespace secure_channel
} // namespace chromeos
#endif // CHROMEOS_SERVICES_SECURE_CHANNEL_BLE_ADVERTISER_IMPL_H_