Commit 37df4568 authored by Jimmy Gong's avatar Jimmy Gong Committed by Commit Bot

Add MessageReceiver

MessageReceiver is responsbile for receiving serialized proto messages,
deserializing the messages, and notifying clients of the updated
messages.

Bug: 1106937
Test: unit_tests
Change-Id: I6d1c75d3f63c27213e3b85b561f6e0c3b4e47161
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419757
Commit-Queue: Jimmy Gong <jimmyxgong@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#809168}
parent 74826cab
......@@ -31,6 +31,10 @@ static_library("phonehub") {
"find_my_device_controller.h",
"find_my_device_controller_impl.cc",
"find_my_device_controller_impl.h",
"message_receiver.cc",
"message_receiver.h",
"message_receiver_impl.cc",
"message_receiver_impl.h",
"message_sender.h",
"message_sender_impl.cc",
"message_sender_impl.h",
......@@ -119,6 +123,7 @@ static_library("test_support") {
sources = [
"fake_connection_manager.cc",
"fake_connection_manager.h",
"fake_message_receiver.h",
"fake_message_sender.cc",
"fake_message_sender.h",
"phone_model_test_util.cc",
......@@ -130,7 +135,10 @@ static_library("test_support") {
":phonehub",
]
deps = [ "//base" ]
deps = [
"//base",
"//chromeos/components/phonehub/proto",
]
}
source_set("unit_tests") {
......@@ -143,6 +151,7 @@ source_set("unit_tests") {
"do_not_disturb_controller_impl_unittest.cc",
"feature_status_provider_impl_unittest.cc",
"find_my_device_controller_impl_unittest.cc",
"message_receiver_unittest.cc",
"message_sender_unittest.cc",
"mutable_phone_model_unittest.cc",
"notification_access_manager_impl_unittest.cc",
......
// Copyright 2020 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_COMPONENTS_PHONEHUB_FAKE_MESSAGE_RECEIVER_H_
#define CHROMEOS_COMPONENTS_PHONEHUB_FAKE_MESSAGE_RECEIVER_H_
#include "chromeos/components/phonehub/message_receiver.h"
#include "chromeos/components/phonehub/proto/phonehub_api.pb.h"
namespace chromeos {
namespace phonehub {
class FakeMessageReceiver : public MessageReceiver {
public:
FakeMessageReceiver() = default;
~FakeMessageReceiver() override = default;
using MessageReceiver::NotifyPhoneStatusSnapshotUpdated;
using MessageReceiver::NotifyPhoneStatusUpdated;
};
} // namespace phonehub
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_PHONEHUB_FAKE_MESSAGE_RECEIVER_H_
// Copyright 2020 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 "chromeos/components/phonehub/message_receiver.h"
namespace chromeos {
namespace phonehub {
MessageReceiver::MessageReceiver() = default;
MessageReceiver::~MessageReceiver() = default;
void MessageReceiver::AddObserver(Observer* observer) {
observer_list_.AddObserver(observer);
}
void MessageReceiver::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
void MessageReceiver::NotifyPhoneStatusSnapshotReceived(
proto::PhoneStatusSnapshot phone_status_snapshot) {
for (auto& observer : observer_list_)
observer.OnPhoneStatusSnapshotReceived(phone_status_snapshot);
}
void MessageReceiver::NotifyPhoneStatusUpdateReceived(
proto::PhoneStatusUpdate phone_status_update) {
for (auto& observer : observer_list_)
observer.OnPhoneStatusUpdateReceived(phone_status_update);
}
} // namespace phonehub
} // namespace chromeos
// Copyright 2020 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_COMPONENTS_PHONEHUB_MESSAGE_RECEIVER_H_
#define CHROMEOS_COMPONENTS_PHONEHUB_MESSAGE_RECEIVER_H_
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "chromeos/components/multidevice/logging/logging.h"
#include "chromeos/components/phonehub/proto/phonehub_api.pb.h"
// Responsible for receiving message updates from the remote phone device.
namespace chromeos {
namespace phonehub {
class MessageReceiver {
public:
class Observer : public base::CheckedObserver {
public:
~Observer() override = default;
// Called when the remote phone's snapshot has been updated which includes
// phone properties and notification updates.
virtual void OnPhoneStatusSnapshotReceived(
proto::PhoneStatusSnapshot phone_status_snapshot) {}
// Called when the remote phone status has been updated. Include phone
// properties, updated notifications, and removed notifications.
virtual void OnPhoneStatusUpdateReceived(
proto::PhoneStatusUpdate phone_status_update) {}
};
MessageReceiver(const MessageReceiver&) = delete;
MessageReceiver& operator=(const MessageReceiver&) = delete;
virtual ~MessageReceiver();
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
protected:
MessageReceiver();
void NotifyPhoneStatusSnapshotReceived(
proto::PhoneStatusSnapshot phone_status_snapshot);
void NotifyPhoneStatusUpdateReceived(
proto::PhoneStatusUpdate phone_status_update);
private:
base::ObserverList<Observer> observer_list_;
};
} // namespace phonehub
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_PHONEHUB_MESSAGE_RECEIVER_H_
\ No newline at end of file
// Copyright 2020 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 "chromeos/components/phonehub/message_receiver_impl.h"
#include "chromeos/components/phonehub/proto/phonehub_api.pb.h"
#include <stdint.h>
#include <string>
#include "base/logging.h"
namespace chromeos {
namespace phonehub {
namespace {
std::string GetMessageTypeName(proto::MessageType message_type) {
switch (message_type) {
case proto::MessageType::PHONE_STATUS_SNAPSHOT:
return "PHONE_STATUS_SNAPSHOT";
case proto::MessageType::PHONE_STATUS_UPDATE:
return "PHONE_STATUS_UPDATE";
case proto::MessageType::UPDATE_NOTIFICATION_MODE_RESPONSE:
return "UPDATE_NOTIFICATION_MODE_RESPONSE";
case proto::MessageType::RING_DEVICE_RESPONSE:
return "RING_DEVICE_RESPONSE";
case proto::MessageType::UPDATE_BATTERY_MODE_RESPONSE:
return "UPDATE_BATTERY_MODE_RESPONSE";
case proto::MessageType::DISMISS_NOTIFICATION_RESPONSE:
return "DISMISS_NOTIFICATION_RESPONSE";
case proto::MessageType::NOTIFICATION_INLINE_REPLY_RESPONSE:
return "NOTIFICATION_INLINE_REPLY_RESPONSE";
case proto::MessageType::SHOW_NOTIFICATION_ACCESS_SETUP_RESPONSE:
return "SHOW_NOTIFICATION_ACCESS_SETUP_RESPONSE";
default:
return "UNKOWN_MESSAGE";
}
}
} // namespace
MessageReceiverImpl::MessageReceiverImpl(ConnectionManager* connection_manager)
: connection_manager_(connection_manager) {
DCHECK(connection_manager_);
connection_manager_->AddObserver(this);
}
MessageReceiverImpl::~MessageReceiverImpl() {
connection_manager_->RemoveObserver(this);
}
void MessageReceiverImpl::OnMessageReceived(const std::string& payload) {
// The first two bytes of |payload| is reserved for the header
// proto::MessageType.
uint16_t* ptr =
reinterpret_cast<uint16_t*>(const_cast<char*>(payload.data()));
proto::MessageType message_type = static_cast<proto::MessageType>(*ptr);
PA_LOG(INFO) << "MessageReceiver received a "
<< GetMessageTypeName(message_type) << " message.";
// Decode the proto message if the message is something we want to notify to
// clients.
if (message_type == proto::MessageType::PHONE_STATUS_SNAPSHOT) {
proto::PhoneStatusSnapshot snapshot_proto;
// Serialized proto is after the first two bytes of |payload|.
if (!snapshot_proto.ParseFromString(payload.substr(2))) {
PA_LOG(ERROR) << "OnMessageReceived() could not deserialize the "
<< "PhoneStatusSnapshot proto message.";
return;
}
NotifyPhoneStatusSnapshotReceived(snapshot_proto);
return;
}
if (message_type == proto::MessageType::PHONE_STATUS_UPDATE) {
proto::PhoneStatusUpdate update_proto;
// Serialized proto is after the first two bytes of |payload|.
if (!update_proto.ParseFromString(payload.substr(2))) {
PA_LOG(ERROR) << "OnMessageReceived() could not deserialize the "
<< "PhoneStatusUpdate proto message.";
return;
}
NotifyPhoneStatusUpdateReceived(update_proto);
return;
}
}
} // namespace phonehub
} // namespace chromeos
// Copyright 2020 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_COMPONENTS_PHONEHUB_MESSAGE_RECEIVER_IMPL_H_
#define CHROMEOS_COMPONENTS_PHONEHUB_MESSAGE_RECEIVER_IMPL_H_
#include "chromeos/components/phonehub/message_receiver.h"
#include "chromeos/components/phonehub/connection_manager.h"
namespace chromeos {
namespace phonehub {
// MessageReceiver implementation that observes all received messages from
// the remote phone and notifies clients of the received messages.
class MessageReceiverImpl : public MessageReceiver,
public ConnectionManager::Observer {
public:
MessageReceiverImpl(ConnectionManager* connection_manager);
~MessageReceiverImpl() override;
private:
// ConnectionManager::Observer:
void OnMessageReceived(const std::string& payload) override;
ConnectionManager* connection_manager_;
};
} // namespace phonehub
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_PHONEHUB_MESSAGE_RECEIVER_IMPL_H_
// Copyright 2020 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 "chromeos/components/phonehub/message_receiver_impl.h"
#include "base/strings/strcat.h"
#include "chromeos/components/phonehub/fake_connection_manager.h"
#include "chromeos/components/phonehub/proto/phonehub_api.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
#include <memory>
namespace chromeos {
namespace phonehub {
namespace {
class FakeObserver : public MessageReceiver::Observer {
public:
FakeObserver() = default;
~FakeObserver() override = default;
size_t snapshot_num_calls() const {
return phone_status_snapshot_updated_num_calls_;
}
size_t status_updated_num_calls() const {
return phone_status_updated_num_calls_;
}
proto::PhoneStatusSnapshot last_snapshot() const { return last_snapshot_; }
proto::PhoneStatusUpdate last_status_update() const {
return last_status_update_;
}
// MessageReceiver::Observer:
void OnPhoneStatusSnapshotReceived(
proto::PhoneStatusSnapshot phone_status_snapshot) override {
last_snapshot_ = phone_status_snapshot;
++phone_status_snapshot_updated_num_calls_;
}
void OnPhoneStatusUpdateReceived(
proto::PhoneStatusUpdate phone_status_update) override {
last_status_update_ = phone_status_update;
++phone_status_updated_num_calls_;
}
private:
size_t phone_status_snapshot_updated_num_calls_ = 0;
size_t phone_status_updated_num_calls_ = 0;
proto::PhoneStatusSnapshot last_snapshot_;
proto::PhoneStatusUpdate last_status_update_;
};
std::string SerializeMessage(proto::MessageType message_type,
const google::protobuf::MessageLite* request) {
// Add two space characters, followed by the serialized proto.
std::string message = base::StrCat({" ", request->SerializeAsString()});
// Replace the first two characters with |message_type| as a 16-bit int.
uint16_t* ptr =
reinterpret_cast<uint16_t*>(const_cast<char*>(message.data()));
*ptr = static_cast<uint16_t>(message_type);
return message;
}
} // namespace
class MessageReceiverImplTest : public testing::Test {
protected:
MessageReceiverImplTest()
: fake_connection_manager_(std::make_unique<FakeConnectionManager>()) {}
MessageReceiverImplTest(const MessageReceiverImplTest&) = delete;
MessageReceiverImplTest& operator=(const MessageReceiverImplTest&) = delete;
~MessageReceiverImplTest() override = default;
void SetUp() override {
message_receiver_ =
std::make_unique<MessageReceiverImpl>(fake_connection_manager_.get());
message_receiver_->AddObserver(&fake_observer_);
}
void TearDown() override {
message_receiver_->RemoveObserver(&fake_observer_);
}
size_t GetNumPhoneStatusSnapshotCalls() const {
return fake_observer_.snapshot_num_calls();
}
size_t GetNumPhoneStatusUpdatedCalls() const {
return fake_observer_.status_updated_num_calls();
}
proto::PhoneStatusSnapshot GetLastSnapshot() const {
return fake_observer_.last_snapshot();
}
proto::PhoneStatusUpdate GetLastStatusUpdate() const {
return fake_observer_.last_status_update();
}
FakeObserver fake_observer_;
std::unique_ptr<FakeConnectionManager> fake_connection_manager_;
std::unique_ptr<MessageReceiverImpl> message_receiver_;
};
TEST_F(MessageReceiverImplTest, OnPhoneStatusSnapshotReceieved) {
const int32_t expected_battery_percentage = 15;
auto expected_phone_properties = std::make_unique<proto::PhoneProperties>();
expected_phone_properties->set_battery_percentage(
expected_battery_percentage);
proto::PhoneStatusSnapshot expected_snapshot;
expected_snapshot.set_allocated_properties(
expected_phone_properties.release());
expected_snapshot.add_notifications();
// Simulate receiving a message.
const std::string expected_message =
SerializeMessage(proto::PHONE_STATUS_SNAPSHOT, &expected_snapshot);
fake_connection_manager_->NotifyMessageReceived(expected_message);
proto::PhoneStatusSnapshot actual_snapshot = GetLastSnapshot();
EXPECT_EQ(1u, GetNumPhoneStatusSnapshotCalls());
EXPECT_EQ(0u, GetNumPhoneStatusUpdatedCalls());
EXPECT_EQ(expected_battery_percentage,
actual_snapshot.properties().battery_percentage());
EXPECT_EQ(1, actual_snapshot.notifications_size());
}
TEST_F(MessageReceiverImplTest, OnPhoneStatusUpdated) {
const int32_t expected_battery_percentage = 15u;
auto expected_phone_properties = std::make_unique<proto::PhoneProperties>();
expected_phone_properties->set_battery_percentage(
expected_battery_percentage);
proto::PhoneStatusUpdate expected_update;
expected_update.set_allocated_properties(expected_phone_properties.release());
expected_update.add_updated_notifications();
const int64_t expected_removed_id = 24u;
expected_update.add_removed_notification_ids(expected_removed_id);
// Simulate receiving a message.
const std::string expected_message =
SerializeMessage(proto::PHONE_STATUS_UPDATE, &expected_update);
fake_connection_manager_->NotifyMessageReceived(expected_message);
proto::PhoneStatusUpdate actual_update = GetLastStatusUpdate();
EXPECT_EQ(0u, GetNumPhoneStatusSnapshotCalls());
EXPECT_EQ(1u, GetNumPhoneStatusUpdatedCalls());
EXPECT_EQ(expected_battery_percentage,
actual_update.properties().battery_percentage());
EXPECT_EQ(1, actual_update.updated_notifications_size());
EXPECT_EQ(expected_removed_id, actual_update.removed_notification_ids()[0]);
}
} // namespace phonehub
} // namespace chromeos
......@@ -9,6 +9,7 @@
#include "chromeos/components/phonehub/do_not_disturb_controller_impl.h"
#include "chromeos/components/phonehub/feature_status_provider_impl.h"
#include "chromeos/components/phonehub/find_my_device_controller_impl.h"
#include "chromeos/components/phonehub/message_receiver_impl.h"
#include "chromeos/components/phonehub/message_sender_impl.h"
#include "chromeos/components/phonehub/mutable_phone_model.h"
#include "chromeos/components/phonehub/notification_access_manager_impl.h"
......@@ -34,6 +35,8 @@ PhoneHubManagerImpl::PhoneHubManagerImpl(
device_sync_client,
multidevice_setup_client,
connection_manager_.get())),
message_receiver_(
std::make_unique<MessageReceiverImpl>(connection_manager_.get())),
message_sender_(
std::make_unique<MessageSenderImpl>(connection_manager_.get())),
connection_scheduler_(std::make_unique<ConnectionSchedulerImpl>(
......@@ -97,6 +100,7 @@ void PhoneHubManagerImpl::Shutdown() {
find_my_device_controller_.reset();
connection_scheduler_.reset();
message_sender_.reset();
message_receiver_.reset();
feature_status_provider_.reset();
connection_manager_.reset();
do_not_disturb_controller_.reset();
......
......@@ -30,6 +30,7 @@ namespace phonehub {
class ConnectionManager;
class MessageSender;
class MessageReceiver;
// Implemented as a KeyedService which is keyed by the primary Profile.
class PhoneHubManagerImpl : public PhoneHubManager, public KeyedService {
......@@ -59,6 +60,7 @@ class PhoneHubManagerImpl : public PhoneHubManager, public KeyedService {
std::unique_ptr<DoNotDisturbController> do_not_disturb_controller_;
std::unique_ptr<ConnectionManager> connection_manager_;
std::unique_ptr<FeatureStatusProvider> feature_status_provider_;
std::unique_ptr<MessageReceiver> message_receiver_;
std::unique_ptr<MessageSender> message_sender_;
std::unique_ptr<ConnectionScheduler> connection_scheduler_;
std::unique_ptr<FindMyDeviceController> find_my_device_controller_;
......
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