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