blob: 53445d8f1515ac7ee309309b5ae0441adfe36961 [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.
#include "components/invalidation/impl/fcm_network_handler.h"
#include "base/base64url.h"
#include "base/callback.h"
#include "base/observer_list.h"
#include "base/task/post_task.h"
#include "build/build_config.h"
#include "components/gcm_driver/gcm_driver.h"
#include "components/gcm_driver/gcm_profile_service.h"
#include "components/gcm_driver/instance_id/instance_id.h"
#include "components/gcm_driver/instance_id/instance_id_driver.h"
#include "components/invalidation/public/invalidator_state.h"
using instance_id::InstanceID;
namespace syncer {
namespace {
const char kInvalidationsAppId[] = "com.google.chrome.fcm.invalidations";
const char kInvalidationGCMSenderId[] = "8181035976";
const char kContentKey[] = "data";
// OAuth2 Scope passed to getToken to obtain GCM registration tokens.
// Must match Java GoogleCloudMessaging.INSTANCE_ID_SCOPE.
const char kGCMScope[] = "GCM";
} // namespace
FCMNetworkHandler::FCMNetworkHandler(
gcm::GCMDriver* gcm_driver,
instance_id::InstanceIDDriver* instance_id_driver)
: gcm_driver_(gcm_driver),
instance_id_driver_(instance_id_driver),
weak_ptr_factory_(this) {}
FCMNetworkHandler::~FCMNetworkHandler() {
StopListening();
}
void FCMNetworkHandler::StartListening() {
instance_id_driver_->GetInstanceID(kInvalidationsAppId)
->GetToken(kInvalidationGCMSenderId, kGCMScope,
/*options=*/std::map<std::string, std::string>(),
base::BindRepeating(&FCMNetworkHandler::DidRetrieveToken,
weak_ptr_factory_.GetWeakPtr()));
gcm_driver_->AddAppHandler(kInvalidationsAppId, this);
}
void FCMNetworkHandler::StopListening() {
if (gcm_driver_->GetAppHandler(kInvalidationsAppId))
gcm_driver_->RemoveAppHandler(kInvalidationsAppId);
}
void FCMNetworkHandler::DidRetrieveToken(const std::string& subscription_token,
InstanceID::Result result) {
switch (result) {
case InstanceID::SUCCESS:
DeliverToken(subscription_token);
return;
case InstanceID::INVALID_PARAMETER:
case InstanceID::DISABLED:
case InstanceID::ASYNC_OPERATION_PENDING:
case InstanceID::SERVER_ERROR:
case InstanceID::UNKNOWN_ERROR:
case InstanceID::NETWORK_ERROR:
DLOG(WARNING) << "Messaging subscription failed; InstanceID::Result = "
<< result;
UpdateGcmChannelState(false);
break;
}
}
void FCMNetworkHandler::UpdateGcmChannelState(bool online) {
if (gcm_channel_online_ == online)
return;
gcm_channel_online_ = online;
NotifyChannelStateChange(gcm_channel_online_ ? INVALIDATIONS_ENABLED
: TRANSIENT_INVALIDATION_ERROR);
}
void FCMNetworkHandler::ShutdownHandler() {}
void FCMNetworkHandler::OnStoreReset() {}
void FCMNetworkHandler::OnMessage(const std::string& app_id,
const gcm::IncomingMessage& message) {
DCHECK_EQ(app_id, kInvalidationsAppId);
std::string content;
auto it = message.data.find(kContentKey);
if (it != message.data.end())
content = it->second;
if (content.empty()) {
return;
}
// TODO(melandory): check if content is empty and report.
// TODO(melandory): decode base64 and report in case it is invalid.
// TODO(melandory): parse proto and record histogram in case of invalid proto.
// TODO(melandory): report histogram in case of success.
UpdateGcmChannelState(true);
DeliverIncomingMessage(content);
}
void FCMNetworkHandler::OnMessagesDeleted(const std::string& app_id) {
// TODO(melandory): consider notifyint the client that messages were
// deleted. So the client can act on it, e.g. in case of sync request
// GetUpdates from the server.
}
void FCMNetworkHandler::OnSendError(
const std::string& app_id,
const gcm::GCMClient::SendErrorDetails& details) {
// Should never be called because we don't send GCM messages to
// the server.
NOTREACHED() << "FCMNetworkHandler doesn't send GCM messages.";
}
void FCMNetworkHandler::OnSendAcknowledged(const std::string& app_id,
const std::string& message_id) {
// Should never be called because we don't send GCM messages to
// the server.
NOTREACHED() << "FCMNetworkHandler doesn't send GCM messages.";
}
} // namespace syncer