| OLD | NEW |
| (Empty) |
| 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 "base/bind.h" | |
| 6 #include "base/location.h" | |
| 7 #include "base/single_thread_task_runner.h" | |
| 8 #include "base/thread_task_runner_handle.h" | |
| 9 #include "chrome/browser/invalidation/gcm_invalidation_bridge.h" | |
| 10 #include "chrome/browser/signin/signin_manager_factory.h" | |
| 11 #include "components/gcm_driver/gcm_driver.h" | |
| 12 #include "components/signin/core/browser/profile_oauth2_token_service.h" | |
| 13 #include "components/signin/core/browser/signin_manager.h" | |
| 14 #include "google_apis/gaia/gaia_constants.h" | |
| 15 #include "google_apis/gaia/identity_provider.h" | |
| 16 | |
| 17 namespace invalidation { | |
| 18 namespace { | |
| 19 // For 3rd party developers SenderId should come from application dashboard when | |
| 20 // server side application is registered with Google. Android invalidations use | |
| 21 // legacy format where gmail account can be specificed. Below value is copied | |
| 22 // from Android. | |
| 23 const char kInvalidationsSenderId[] = "ipc.invalidation@gmail.com"; | |
| 24 // In Android world AppId is provided by operating system and should | |
| 25 // match package name and hash of application. In desktop world these values | |
| 26 // are arbitrary and not verified/enforced by registration service (yet). | |
| 27 const char kInvalidationsAppId[] = "com.google.chrome.invalidations"; | |
| 28 | |
| 29 // Cacheinvalidation specific gcm message keys. | |
| 30 const char kContentKey[] = "content"; | |
| 31 const char kEchoTokenKey[] = "echo-token"; | |
| 32 } // namespace | |
| 33 | |
| 34 // Core should be very simple class that implements GCMNetwrokChannelDelegate | |
| 35 // and passes all calls to GCMInvalidationBridge. All calls should be serialized | |
| 36 // through GCMInvalidationBridge to avoid race conditions. | |
| 37 class GCMInvalidationBridge::Core : public syncer::GCMNetworkChannelDelegate, | |
| 38 public base::NonThreadSafe { | |
| 39 public: | |
| 40 Core(base::WeakPtr<GCMInvalidationBridge> bridge, | |
| 41 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner); | |
| 42 virtual ~Core(); | |
| 43 | |
| 44 // syncer::GCMNetworkChannelDelegate implementation. | |
| 45 virtual void Initialize() OVERRIDE; | |
| 46 virtual void RequestToken(RequestTokenCallback callback) OVERRIDE; | |
| 47 virtual void InvalidateToken(const std::string& token) OVERRIDE; | |
| 48 virtual void Register(RegisterCallback callback) OVERRIDE; | |
| 49 virtual void SetMessageReceiver(MessageCallback callback) OVERRIDE; | |
| 50 | |
| 51 void RequestTokenFinished(RequestTokenCallback callback, | |
| 52 const GoogleServiceAuthError& error, | |
| 53 const std::string& token); | |
| 54 | |
| 55 void RegisterFinished(RegisterCallback callback, | |
| 56 const std::string& registration_id, | |
| 57 gcm::GCMClient::Result result); | |
| 58 | |
| 59 void OnIncomingMessage(const std::string& message, | |
| 60 const std::string& echo_token); | |
| 61 | |
| 62 private: | |
| 63 base::WeakPtr<GCMInvalidationBridge> bridge_; | |
| 64 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner_; | |
| 65 | |
| 66 MessageCallback message_callback_; | |
| 67 | |
| 68 base::WeakPtrFactory<Core> weak_factory_; | |
| 69 | |
| 70 DISALLOW_COPY_AND_ASSIGN(Core); | |
| 71 }; | |
| 72 | |
| 73 GCMInvalidationBridge::Core::Core( | |
| 74 base::WeakPtr<GCMInvalidationBridge> bridge, | |
| 75 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) | |
| 76 : bridge_(bridge), | |
| 77 ui_thread_task_runner_(ui_thread_task_runner), | |
| 78 weak_factory_(this) { | |
| 79 // Core is created on UI thread but all calls happen on IO thread. | |
| 80 DetachFromThread(); | |
| 81 } | |
| 82 | |
| 83 GCMInvalidationBridge::Core::~Core() {} | |
| 84 | |
| 85 void GCMInvalidationBridge::Core::Initialize() { | |
| 86 DCHECK(CalledOnValidThread()); | |
| 87 // Pass core WeapPtr and TaskRunner to GCMInvalidationBridge for it to be able | |
| 88 // to post back. | |
| 89 ui_thread_task_runner_->PostTask( | |
| 90 FROM_HERE, | |
| 91 base::Bind(&GCMInvalidationBridge::CoreInitializationDone, | |
| 92 bridge_, | |
| 93 weak_factory_.GetWeakPtr(), | |
| 94 base::ThreadTaskRunnerHandle::Get())); | |
| 95 } | |
| 96 | |
| 97 void GCMInvalidationBridge::Core::RequestToken(RequestTokenCallback callback) { | |
| 98 DCHECK(CalledOnValidThread()); | |
| 99 ui_thread_task_runner_->PostTask( | |
| 100 FROM_HERE, | |
| 101 base::Bind(&GCMInvalidationBridge::RequestToken, bridge_, callback)); | |
| 102 } | |
| 103 | |
| 104 void GCMInvalidationBridge::Core::InvalidateToken(const std::string& token) { | |
| 105 DCHECK(CalledOnValidThread()); | |
| 106 ui_thread_task_runner_->PostTask( | |
| 107 FROM_HERE, | |
| 108 base::Bind(&GCMInvalidationBridge::InvalidateToken, bridge_, token)); | |
| 109 } | |
| 110 | |
| 111 void GCMInvalidationBridge::Core::Register(RegisterCallback callback) { | |
| 112 DCHECK(CalledOnValidThread()); | |
| 113 ui_thread_task_runner_->PostTask( | |
| 114 FROM_HERE, | |
| 115 base::Bind(&GCMInvalidationBridge::Register, bridge_, callback)); | |
| 116 } | |
| 117 | |
| 118 void GCMInvalidationBridge::Core::SetMessageReceiver(MessageCallback callback) { | |
| 119 message_callback_ = callback; | |
| 120 ui_thread_task_runner_->PostTask( | |
| 121 FROM_HERE, | |
| 122 base::Bind(&GCMInvalidationBridge::SubscribeForIncomingMessages, | |
| 123 bridge_)); | |
| 124 } | |
| 125 | |
| 126 void GCMInvalidationBridge::Core::RequestTokenFinished( | |
| 127 RequestTokenCallback callback, | |
| 128 const GoogleServiceAuthError& error, | |
| 129 const std::string& token) { | |
| 130 DCHECK(CalledOnValidThread()); | |
| 131 callback.Run(error, token); | |
| 132 } | |
| 133 | |
| 134 void GCMInvalidationBridge::Core::RegisterFinished( | |
| 135 RegisterCallback callback, | |
| 136 const std::string& registration_id, | |
| 137 gcm::GCMClient::Result result) { | |
| 138 DCHECK(CalledOnValidThread()); | |
| 139 callback.Run(registration_id, result); | |
| 140 } | |
| 141 | |
| 142 void GCMInvalidationBridge::Core::OnIncomingMessage( | |
| 143 const std::string& message, | |
| 144 const std::string& echo_token) { | |
| 145 DCHECK(!message_callback_.is_null()); | |
| 146 message_callback_.Run(message, echo_token); | |
| 147 } | |
| 148 | |
| 149 GCMInvalidationBridge::GCMInvalidationBridge( | |
| 150 gcm::GCMDriver* gcm_driver, | |
| 151 IdentityProvider* identity_provider) | |
| 152 : OAuth2TokenService::Consumer("gcm_network_channel"), | |
| 153 gcm_driver_(gcm_driver), | |
| 154 identity_provider_(identity_provider), | |
| 155 subscribed_for_incoming_messages_(false), | |
| 156 weak_factory_(this) {} | |
| 157 | |
| 158 GCMInvalidationBridge::~GCMInvalidationBridge() { | |
| 159 if (subscribed_for_incoming_messages_) | |
| 160 gcm_driver_->RemoveAppHandler(kInvalidationsAppId); | |
| 161 } | |
| 162 | |
| 163 scoped_ptr<syncer::GCMNetworkChannelDelegate> | |
| 164 GCMInvalidationBridge::CreateDelegate() { | |
| 165 DCHECK(CalledOnValidThread()); | |
| 166 scoped_ptr<syncer::GCMNetworkChannelDelegate> core(new Core( | |
| 167 weak_factory_.GetWeakPtr(), base::ThreadTaskRunnerHandle::Get())); | |
| 168 return core.Pass(); | |
| 169 } | |
| 170 | |
| 171 void GCMInvalidationBridge::CoreInitializationDone( | |
| 172 base::WeakPtr<Core> core, | |
| 173 scoped_refptr<base::SingleThreadTaskRunner> core_thread_task_runner) { | |
| 174 DCHECK(CalledOnValidThread()); | |
| 175 core_ = core; | |
| 176 core_thread_task_runner_ = core_thread_task_runner; | |
| 177 } | |
| 178 | |
| 179 void GCMInvalidationBridge::RequestToken( | |
| 180 syncer::GCMNetworkChannelDelegate::RequestTokenCallback callback) { | |
| 181 DCHECK(CalledOnValidThread()); | |
| 182 if (access_token_request_ != NULL) { | |
| 183 // Report previous request as cancelled. | |
| 184 GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED); | |
| 185 std::string access_token; | |
| 186 core_thread_task_runner_->PostTask( | |
| 187 FROM_HERE, | |
| 188 base::Bind(&GCMInvalidationBridge::Core::RequestTokenFinished, | |
| 189 core_, | |
| 190 request_token_callback_, | |
| 191 error, | |
| 192 access_token)); | |
| 193 } | |
| 194 request_token_callback_ = callback; | |
| 195 OAuth2TokenService::ScopeSet scopes; | |
| 196 scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope); | |
| 197 access_token_request_ = identity_provider_->GetTokenService()->StartRequest( | |
| 198 identity_provider_->GetActiveAccountId(), scopes, this); | |
| 199 } | |
| 200 | |
| 201 void GCMInvalidationBridge::OnGetTokenSuccess( | |
| 202 const OAuth2TokenService::Request* request, | |
| 203 const std::string& access_token, | |
| 204 const base::Time& expiration_time) { | |
| 205 DCHECK(CalledOnValidThread()); | |
| 206 DCHECK_EQ(access_token_request_, request); | |
| 207 core_thread_task_runner_->PostTask( | |
| 208 FROM_HERE, | |
| 209 base::Bind(&GCMInvalidationBridge::Core::RequestTokenFinished, | |
| 210 core_, | |
| 211 request_token_callback_, | |
| 212 GoogleServiceAuthError::AuthErrorNone(), | |
| 213 access_token)); | |
| 214 request_token_callback_.Reset(); | |
| 215 access_token_request_.reset(); | |
| 216 } | |
| 217 | |
| 218 void GCMInvalidationBridge::OnGetTokenFailure( | |
| 219 const OAuth2TokenService::Request* request, | |
| 220 const GoogleServiceAuthError& error) { | |
| 221 DCHECK(CalledOnValidThread()); | |
| 222 DCHECK_EQ(access_token_request_, request); | |
| 223 core_thread_task_runner_->PostTask( | |
| 224 FROM_HERE, | |
| 225 base::Bind(&GCMInvalidationBridge::Core::RequestTokenFinished, | |
| 226 core_, | |
| 227 request_token_callback_, | |
| 228 error, | |
| 229 std::string())); | |
| 230 request_token_callback_.Reset(); | |
| 231 access_token_request_.reset(); | |
| 232 } | |
| 233 | |
| 234 void GCMInvalidationBridge::InvalidateToken(const std::string& token) { | |
| 235 DCHECK(CalledOnValidThread()); | |
| 236 OAuth2TokenService::ScopeSet scopes; | |
| 237 scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope); | |
| 238 identity_provider_->GetTokenService()->InvalidateToken( | |
| 239 identity_provider_->GetActiveAccountId(), scopes, token); | |
| 240 } | |
| 241 | |
| 242 void GCMInvalidationBridge::Register( | |
| 243 syncer::GCMNetworkChannelDelegate::RegisterCallback callback) { | |
| 244 DCHECK(CalledOnValidThread()); | |
| 245 // No-op if GCMClient is disabled. | |
| 246 if (gcm_driver_ == NULL) | |
| 247 return; | |
| 248 | |
| 249 std::vector<std::string> sender_ids; | |
| 250 sender_ids.push_back(kInvalidationsSenderId); | |
| 251 gcm_driver_->Register(kInvalidationsAppId, | |
| 252 sender_ids, | |
| 253 base::Bind(&GCMInvalidationBridge::RegisterFinished, | |
| 254 weak_factory_.GetWeakPtr(), | |
| 255 callback)); | |
| 256 } | |
| 257 | |
| 258 void GCMInvalidationBridge::RegisterFinished( | |
| 259 syncer::GCMNetworkChannelDelegate::RegisterCallback callback, | |
| 260 const std::string& registration_id, | |
| 261 gcm::GCMClient::Result result) { | |
| 262 DCHECK(CalledOnValidThread()); | |
| 263 core_thread_task_runner_->PostTask( | |
| 264 FROM_HERE, | |
| 265 base::Bind(&GCMInvalidationBridge::Core::RegisterFinished, | |
| 266 core_, | |
| 267 callback, | |
| 268 registration_id, | |
| 269 result)); | |
| 270 } | |
| 271 | |
| 272 void GCMInvalidationBridge::SubscribeForIncomingMessages() { | |
| 273 // No-op if GCMClient is disabled. | |
| 274 if (gcm_driver_ == NULL) | |
| 275 return; | |
| 276 | |
| 277 DCHECK(!subscribed_for_incoming_messages_); | |
| 278 gcm_driver_->AddAppHandler(kInvalidationsAppId, this); | |
| 279 subscribed_for_incoming_messages_ = true; | |
| 280 } | |
| 281 | |
| 282 void GCMInvalidationBridge::ShutdownHandler() { | |
| 283 // Nothing to do. | |
| 284 } | |
| 285 | |
| 286 void GCMInvalidationBridge::OnMessage( | |
| 287 const std::string& app_id, | |
| 288 const gcm::GCMClient::IncomingMessage& message) { | |
| 289 gcm::GCMClient::MessageData::const_iterator it; | |
| 290 std::string content; | |
| 291 std::string echo_token; | |
| 292 it = message.data.find(kContentKey); | |
| 293 if (it != message.data.end()) | |
| 294 content = it->second; | |
| 295 it = message.data.find(kEchoTokenKey); | |
| 296 if (it != message.data.end()) | |
| 297 echo_token = it->second; | |
| 298 | |
| 299 core_thread_task_runner_->PostTask( | |
| 300 FROM_HERE, | |
| 301 base::Bind(&GCMInvalidationBridge::Core::OnIncomingMessage, | |
| 302 core_, | |
| 303 content, | |
| 304 echo_token)); | |
| 305 } | |
| 306 | |
| 307 void GCMInvalidationBridge::OnMessagesDeleted(const std::string& app_id) { | |
| 308 // Cacheinvalidation doesn't use long lived non-collapsable messages with GCM. | |
| 309 // Android implementation of cacheinvalidation doesn't handle MessagesDeleted | |
| 310 // callback so this should be no-op in desktop version as well. | |
| 311 } | |
| 312 | |
| 313 void GCMInvalidationBridge::OnSendError( | |
| 314 const std::string& app_id, | |
| 315 const gcm::GCMClient::SendErrorDetails& send_error_details) { | |
| 316 // cacheinvalidation doesn't send messages over GCM. | |
| 317 NOTREACHED(); | |
| 318 } | |
| 319 | |
| 320 } // namespace invalidation | |
| OLD | NEW |