Commit ab93f9f0 authored by Josh Nohle's avatar Josh Nohle Committed by Commit Bot

[DeviceSync v2] Add CryptAuthDeviceNotifier class

Handles the BatchNotifyGroupDevices portion of the CryptAuth v2
DeviceSync protocol, which sends a GCM message--via CryptAuth--to
a subset of devices in the "DeviceSync:BetterTogether" group.

The implementation queues requests made via NotifyDevices() and
processes the requests sequentially. The implementation also handles
timeouts internally, so a callback passed to NotifyDevices() is always
guaranteed to be invoked.

CryptAuthDeviceNotifier::NotifyDevices() will replace the CryptAuth v1
method SoftwareFeatureManager::FindEligibleDevices(), which was used to
notify a phone that it was selected as the multi-device host.

Bug: 951969
Change-Id: I155e35847f5d6d9d99d8cf4477e70819d82d8e21
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1888734
Commit-Queue: Josh Nohle <nohle@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#710817}
parent 868f7128
......@@ -23,6 +23,9 @@ static_library("device_sync") {
"cryptauth_device_manager.h",
"cryptauth_device_manager_impl.cc",
"cryptauth_device_manager_impl.h",
"cryptauth_device_notifier.h",
"cryptauth_device_notifier_impl.cc",
"cryptauth_device_notifier_impl.h",
"cryptauth_device_registry.cc",
"cryptauth_device_registry.h",
"cryptauth_device_registry_impl.cc",
......@@ -170,6 +173,8 @@ static_library("test_support") {
"cryptauth_v2_device_sync_test_devices.h",
"fake_cryptauth_device_manager.cc",
"fake_cryptauth_device_manager.h",
"fake_cryptauth_device_notifier.cc",
"fake_cryptauth_device_notifier.h",
"fake_cryptauth_device_syncer.cc",
"fake_cryptauth_device_syncer.h",
"fake_cryptauth_ecies_encryptor.cc",
......@@ -236,6 +241,7 @@ source_set("unit_tests") {
"cryptauth_client_impl_unittest.cc",
"cryptauth_device_activity_getter_impl_unittest.cc",
"cryptauth_device_manager_impl_unittest.cc",
"cryptauth_device_notifier_impl_unittest.cc",
"cryptauth_device_registry_impl_unittest.cc",
"cryptauth_device_syncer_impl_unittest.cc",
"cryptauth_device_unittest.cc",
......
// Copyright 2019 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_DEVICE_SYNC_CRYPTAUTH_DEVICE_NOTIFIER_H_
#define CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_DEVICE_NOTIFIER_H_
#include <string>
#include "base/callback.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "chromeos/services/device_sync/cryptauth_feature_type.h"
#include "chromeos/services/device_sync/network_request_error.h"
#include "chromeos/services/device_sync/proto/cryptauth_common.pb.h"
namespace chromeos {
namespace device_sync {
// Handles the BatchNotifyGroupDevices portion of the CryptAuth v2 DeviceSync
// protocol, which sends a GCM message--via CryptAuth--to a subset of devices in
// the "DeviceSync:BetterTogether" group.
class CryptAuthDeviceNotifier {
public:
CryptAuthDeviceNotifier() = default;
virtual ~CryptAuthDeviceNotifier() = default;
// Sends a GCM message to devices with Instance IDs |device_ids|. The message
// includes the CryptAuth service--Enrollment or DeviceSync--and the feature
// type--kBetterTogetherHostEnabled, for example--indicating the reason for
// the notification; these are specified by |target_service| and
// |feature_type|, respectively.
virtual void NotifyDevices(
const base::flat_set<std::string>& device_ids,
cryptauthv2::TargetService target_service,
CryptAuthFeatureType feature_type,
base::OnceClosure success_callback,
base::OnceCallback<void(NetworkRequestError)> error_callback) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(CryptAuthDeviceNotifier);
};
} // namespace device_sync
} // namespace chromeos
#endif // CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_DEVICE_NOTIFIER_H_
// Copyright 2019 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_DEVICE_SYNC_CRYPTAUTH_DEVICE_NOTIFIER_IMPL_H_
#define CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_DEVICE_NOTIFIER_IMPL_H_
#include <memory>
#include <ostream>
#include <string>
#include "base/callback.h"
#include "base/containers/flat_set.h"
#include "base/containers/queue.h"
#include "base/macros.h"
#include "base/timer/timer.h"
#include "chromeos/services/device_sync/cryptauth_device_notifier.h"
#include "chromeos/services/device_sync/cryptauth_feature_type.h"
#include "chromeos/services/device_sync/network_request_error.h"
#include "chromeos/services/device_sync/proto/cryptauth_client_app_metadata.pb.h"
#include "chromeos/services/device_sync/proto/cryptauth_common.pb.h"
#include "chromeos/services/device_sync/proto/cryptauth_devicesync.pb.h"
namespace chromeos {
namespace device_sync {
class ClientAppMetadataProvider;
class CryptAuthClient;
class CryptAuthClientFactory;
class CryptAuthGCMManager;
// An implementation of CryptAuthDeviceNotifier, using instances of
// CryptAuthClient to make the BatchNotifyGroupDevices API calls to CryptAuth.
// The requests made via NotifyDevices() are queued and processed sequentially.
// This implementation handles timeouts internally, so a callback passed to
// NotifyDevices() is always guaranteed to be invoked.
class CryptAuthDeviceNotifierImpl : public CryptAuthDeviceNotifier {
public:
class Factory {
public:
static Factory* Get();
static void SetFactoryForTesting(Factory* test_factory);
virtual ~Factory();
virtual std::unique_ptr<CryptAuthDeviceNotifier> BuildInstance(
ClientAppMetadataProvider* client_app_metadata_provider,
CryptAuthClientFactory* client_factory,
CryptAuthGCMManager* gcm_manager,
std::unique_ptr<base::OneShotTimer> timer =
std::make_unique<base::OneShotTimer>());
private:
static Factory* test_factory_;
};
~CryptAuthDeviceNotifierImpl() override;
private:
enum class State {
kIdle,
kWaitingForClientAppMetadata,
kWaitingForBatchNotifyGroupDevicesResponse
};
friend std::ostream& operator<<(std::ostream& stream, const State& state);
static base::Optional<base::TimeDelta> GetTimeoutForState(State state);
struct Request {
Request(const base::flat_set<std::string>& device_ids,
cryptauthv2::TargetService target_service,
CryptAuthFeatureType feature_type,
base::OnceClosure success_callback,
base::OnceCallback<void(NetworkRequestError)> error_callback);
Request(Request&& request);
~Request();
base::flat_set<std::string> device_ids;
cryptauthv2::TargetService target_service;
CryptAuthFeatureType feature_type;
base::OnceClosure success_callback;
base::OnceCallback<void(NetworkRequestError)> error_callback;
};
CryptAuthDeviceNotifierImpl(
ClientAppMetadataProvider* client_app_metadata_provider,
CryptAuthClientFactory* client_factory,
CryptAuthGCMManager* gcm_manager,
std::unique_ptr<base::OneShotTimer> timer);
// CryptAuthDeviceNotifier:
void NotifyDevices(
const base::flat_set<std::string>& device_ids,
cryptauthv2::TargetService target_service,
CryptAuthFeatureType feature_type,
base::OnceClosure success_callback,
base::OnceCallback<void(NetworkRequestError)> error_callback) override;
void SetState(State state);
void OnTimeout();
void ProcessRequestQueue();
void OnClientAppMetadataFetched(
const base::Optional<cryptauthv2::ClientAppMetadata>&
client_app_metadata);
void OnBatchNotifyGroupDevicesSuccess(
const cryptauthv2::BatchNotifyGroupDevicesResponse& response);
void OnBatchNotifyGroupDevicesFailure(NetworkRequestError error);
void FinishAttempt(base::Optional<NetworkRequestError> error);
State state_ = State::kIdle;
base::TimeTicks last_state_change_timestamp_;
base::Optional<cryptauthv2::ClientAppMetadata> client_app_metadata_;
base::queue<Request> pending_requests_;
ClientAppMetadataProvider* client_app_metadata_provider_ = nullptr;
CryptAuthClientFactory* client_factory_ = nullptr;
CryptAuthGCMManager* gcm_manager_ = nullptr;
std::unique_ptr<CryptAuthClient> cryptauth_client_;
std::unique_ptr<base::OneShotTimer> timer_;
base::WeakPtrFactory<CryptAuthDeviceNotifierImpl> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(CryptAuthDeviceNotifierImpl);
};
} // namespace device_sync
} // namespace chromeos
#endif // CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_DEVICE_NOTIFIER_IMPL_H_
// Copyright 2019 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 <utility>
#include "chromeos/services/device_sync/fake_cryptauth_device_notifier.h"
namespace chromeos {
namespace device_sync {
FakeCryptAuthDeviceNotifier::Request::Request(
const base::flat_set<std::string>& device_ids,
cryptauthv2::TargetService target_service,
CryptAuthFeatureType feature_type,
base::OnceClosure success_callback,
base::OnceCallback<void(NetworkRequestError)> error_callback)
: device_ids(device_ids),
target_service(target_service),
feature_type(feature_type),
success_callback(std::move(success_callback)),
error_callback(std::move(error_callback)) {}
FakeCryptAuthDeviceNotifier::Request::Request(Request&& request)
: device_ids(std::move(request.device_ids)),
target_service(request.target_service),
feature_type(request.feature_type),
success_callback(std::move(request.success_callback)),
error_callback(std::move(request.error_callback)) {}
FakeCryptAuthDeviceNotifier::Request::~Request() = default;
FakeCryptAuthDeviceNotifier::FakeCryptAuthDeviceNotifier() = default;
FakeCryptAuthDeviceNotifier::~FakeCryptAuthDeviceNotifier() = default;
void FakeCryptAuthDeviceNotifier::NotifyDevices(
const base::flat_set<std::string>& device_ids,
cryptauthv2::TargetService target_service,
CryptAuthFeatureType feature_type,
base::OnceClosure success_callback,
base::OnceCallback<void(NetworkRequestError)> error_callback) {
requests_.emplace(device_ids, target_service, feature_type,
std::move(success_callback), std::move(error_callback));
}
FakeCryptAuthDeviceNotifierFactory::FakeCryptAuthDeviceNotifierFactory() =
default;
FakeCryptAuthDeviceNotifierFactory::~FakeCryptAuthDeviceNotifierFactory() =
default;
std::unique_ptr<CryptAuthDeviceNotifier>
FakeCryptAuthDeviceNotifierFactory::BuildInstance(
ClientAppMetadataProvider* client_app_metadata_provider,
CryptAuthClientFactory* client_factory,
CryptAuthGCMManager* gcm_manager,
std::unique_ptr<base::OneShotTimer> timer) {
last_client_app_metadata_provider_ = client_app_metadata_provider;
last_client_factory_ = client_factory;
last_gcm_manager_ = gcm_manager;
auto instance = std::make_unique<FakeCryptAuthDeviceNotifier>();
instances_.push_back(instance.get());
return instance;
}
} // namespace device_sync
} // namespace chromeos
// Copyright 2019 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_DEVICE_SYNC_FAKE_CRYPTAUTH_DEVICE_NOTIFIER_H_
#define CHROMEOS_SERVICES_DEVICE_SYNC_FAKE_CRYPTAUTH_DEVICE_NOTIFIER_H_
#include <memory>
#include <string>
#include "base/callback.h"
#include "base/containers/flat_set.h"
#include "base/containers/queue.h"
#include "base/macros.h"
#include "base/timer/timer.h"
#include "chromeos/services/device_sync/cryptauth_device_notifier.h"
#include "chromeos/services/device_sync/cryptauth_device_notifier_impl.h"
#include "chromeos/services/device_sync/network_request_error.h"
#include "chromeos/services/device_sync/proto/cryptauth_common.pb.h"
namespace chromeos {
namespace device_sync {
class ClientAppMetadataProvider;
class CryptAuthClientFactory;
class CryptAuthGCMManager;
class FakeCryptAuthDeviceNotifier : public CryptAuthDeviceNotifier {
public:
struct Request {
Request(const base::flat_set<std::string>& device_ids,
cryptauthv2::TargetService target_service,
CryptAuthFeatureType feature_type,
base::OnceClosure success_callback,
base::OnceCallback<void(NetworkRequestError)> error_callback);
Request(Request&& request);
~Request();
base::flat_set<std::string> device_ids;
cryptauthv2::TargetService target_service;
CryptAuthFeatureType feature_type;
base::OnceClosure success_callback;
base::OnceCallback<void(NetworkRequestError)> error_callback;
};
FakeCryptAuthDeviceNotifier();
~FakeCryptAuthDeviceNotifier() override;
base::queue<Request>& requests() { return requests_; }
private:
// CryptAuthDeviceNotifier:
void NotifyDevices(
const base::flat_set<std::string>& device_ids,
cryptauthv2::TargetService target_service,
CryptAuthFeatureType feature_type,
base::OnceClosure success_callback,
base::OnceCallback<void(NetworkRequestError)> error_callback) override;
base::queue<Request> requests_;
DISALLOW_COPY_AND_ASSIGN(FakeCryptAuthDeviceNotifier);
};
class FakeCryptAuthDeviceNotifierFactory
: public CryptAuthDeviceNotifierImpl::Factory {
public:
FakeCryptAuthDeviceNotifierFactory();
~FakeCryptAuthDeviceNotifierFactory() override;
const std::vector<FakeCryptAuthDeviceNotifier*>& instances() const {
return instances_;
}
const ClientAppMetadataProvider* last_client_app_metadata_provider() const {
return last_client_app_metadata_provider_;
}
const CryptAuthClientFactory* last_client_factory() const {
return last_client_factory_;
}
const CryptAuthGCMManager* last_gcm_manager() const {
return last_gcm_manager_;
}
private:
// CryptAuthDeviceNotifierImpl::Factory:
std::unique_ptr<CryptAuthDeviceNotifier> BuildInstance(
ClientAppMetadataProvider* client_app_metadata_provider,
CryptAuthClientFactory* client_factory,
CryptAuthGCMManager* gcm_manager,
std::unique_ptr<base::OneShotTimer> timer = nullptr) override;
std::vector<FakeCryptAuthDeviceNotifier*> instances_;
ClientAppMetadataProvider* last_client_app_metadata_provider_ = nullptr;
CryptAuthClientFactory* last_client_factory_ = nullptr;
CryptAuthGCMManager* last_gcm_manager_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(FakeCryptAuthDeviceNotifierFactory);
};
} // namespace device_sync
} // namespace chromeos
#endif // CHROMEOS_SERVICES_DEVICE_SYNC_FAKE_CRYPTAUTH_DEVICE_NOTIFIER_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment