1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "components/gcm_driver/gcm_driver.h" 6 7#include <algorithm> 8 9#include "base/logging.h" 10#include "base/metrics/field_trial.h" 11#include "components/gcm_driver/gcm_app_handler.h" 12 13namespace gcm { 14 15namespace { 16const char kGCMFieldTrialName[] = "GCM"; 17const char kGCMFieldTrialEnabledGroupName[] = "Enabled"; 18} // namespace 19 20// static 21bool GCMDriver::IsAllowedForAllUsers() { 22 std::string group_name = 23 base::FieldTrialList::FindFullName(kGCMFieldTrialName); 24 return group_name == kGCMFieldTrialEnabledGroupName; 25} 26 27GCMDriver::GCMDriver() { 28} 29 30GCMDriver::~GCMDriver() { 31} 32 33void GCMDriver::Register(const std::string& app_id, 34 const std::vector<std::string>& sender_ids, 35 const RegisterCallback& callback) { 36 DCHECK(!app_id.empty()); 37 DCHECK(!sender_ids.empty()); 38 DCHECK(!callback.is_null()); 39 40 GCMClient::Result result = EnsureStarted(); 41 if (result != GCMClient::SUCCESS) { 42 callback.Run(std::string(), result); 43 return; 44 } 45 46 // If previous un/register operation is still in progress, bail out. 47 if (IsAsyncOperationPending(app_id)) { 48 callback.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING); 49 return; 50 } 51 52 // Normalize the sender IDs by making them sorted. 53 std::vector<std::string> normalized_sender_ids = sender_ids; 54 std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end()); 55 56 register_callbacks_[app_id] = callback; 57 58 RegisterImpl(app_id, normalized_sender_ids); 59} 60 61void GCMDriver::Unregister(const std::string& app_id, 62 const UnregisterCallback& callback) { 63 DCHECK(!app_id.empty()); 64 DCHECK(!callback.is_null()); 65 66 GCMClient::Result result = EnsureStarted(); 67 if (result != GCMClient::SUCCESS) { 68 callback.Run(result); 69 return; 70 } 71 72 // If previous un/register operation is still in progress, bail out. 73 if (IsAsyncOperationPending(app_id)) { 74 callback.Run(GCMClient::ASYNC_OPERATION_PENDING); 75 return; 76 } 77 78 unregister_callbacks_[app_id] = callback; 79 80 UnregisterImpl(app_id); 81} 82 83void GCMDriver::Send(const std::string& app_id, 84 const std::string& receiver_id, 85 const GCMClient::OutgoingMessage& message, 86 const SendCallback& callback) { 87 DCHECK(!app_id.empty()); 88 DCHECK(!receiver_id.empty()); 89 DCHECK(!callback.is_null()); 90 91 GCMClient::Result result = EnsureStarted(); 92 if (result != GCMClient::SUCCESS) { 93 callback.Run(std::string(), result); 94 return; 95 } 96 97 // If the message with send ID is still in progress, bail out. 98 std::pair<std::string, std::string> key(app_id, message.id); 99 if (send_callbacks_.find(key) != send_callbacks_.end()) { 100 callback.Run(message.id, GCMClient::INVALID_PARAMETER); 101 return; 102 } 103 104 send_callbacks_[key] = callback; 105 106 SendImpl(app_id, receiver_id, message); 107} 108 109void GCMDriver::RegisterFinished(const std::string& app_id, 110 const std::string& registration_id, 111 GCMClient::Result result) { 112 std::map<std::string, RegisterCallback>::iterator callback_iter = 113 register_callbacks_.find(app_id); 114 if (callback_iter == register_callbacks_.end()) { 115 // The callback could have been removed when the app is uninstalled. 116 return; 117 } 118 119 RegisterCallback callback = callback_iter->second; 120 register_callbacks_.erase(callback_iter); 121 callback.Run(registration_id, result); 122} 123 124void GCMDriver::UnregisterFinished(const std::string& app_id, 125 GCMClient::Result result) { 126 std::map<std::string, UnregisterCallback>::iterator callback_iter = 127 unregister_callbacks_.find(app_id); 128 if (callback_iter == unregister_callbacks_.end()) 129 return; 130 131 UnregisterCallback callback = callback_iter->second; 132 unregister_callbacks_.erase(callback_iter); 133 callback.Run(result); 134} 135 136void GCMDriver::SendFinished(const std::string& app_id, 137 const std::string& message_id, 138 GCMClient::Result result) { 139 std::map<std::pair<std::string, std::string>, SendCallback>::iterator 140 callback_iter = send_callbacks_.find( 141 std::pair<std::string, std::string>(app_id, message_id)); 142 if (callback_iter == send_callbacks_.end()) { 143 // The callback could have been removed when the app is uninstalled. 144 return; 145 } 146 147 SendCallback callback = callback_iter->second; 148 send_callbacks_.erase(callback_iter); 149 callback.Run(message_id, result); 150} 151 152void GCMDriver::Shutdown() { 153 for (GCMAppHandlerMap::const_iterator iter = app_handlers_.begin(); 154 iter != app_handlers_.end(); ++iter) { 155 iter->second->ShutdownHandler(); 156 } 157 app_handlers_.clear(); 158} 159 160void GCMDriver::AddAppHandler(const std::string& app_id, 161 GCMAppHandler* handler) { 162 DCHECK(!app_id.empty()); 163 DCHECK(handler); 164 DCHECK_EQ(app_handlers_.count(app_id), 0u); 165 app_handlers_[app_id] = handler; 166} 167 168void GCMDriver::RemoveAppHandler(const std::string& app_id) { 169 DCHECK(!app_id.empty()); 170 app_handlers_.erase(app_id); 171} 172 173GCMAppHandler* GCMDriver::GetAppHandler(const std::string& app_id) { 174 // Look for exact match. 175 GCMAppHandlerMap::const_iterator iter = app_handlers_.find(app_id); 176 if (iter != app_handlers_.end()) 177 return iter->second; 178 179 // Ask the handlers whether they know how to handle it. 180 for (iter = app_handlers_.begin(); iter != app_handlers_.end(); ++iter) { 181 if (iter->second->CanHandle(app_id)) 182 return iter->second; 183 } 184 185 return &default_app_handler_; 186} 187 188bool GCMDriver::HasRegisterCallback(const std::string& app_id) { 189 return register_callbacks_.find(app_id) != register_callbacks_.end(); 190} 191 192void GCMDriver::ClearCallbacks() { 193 register_callbacks_.clear(); 194 unregister_callbacks_.clear(); 195 send_callbacks_.clear(); 196} 197 198bool GCMDriver::IsAsyncOperationPending(const std::string& app_id) const { 199 return register_callbacks_.find(app_id) != register_callbacks_.end() || 200 unregister_callbacks_.find(app_id) != unregister_callbacks_.end(); 201} 202 203} // namespace gcm 204