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.
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/services/gcm/gcm_driver.h"
11 #include "chrome/browser/signin/signin_manager_factory.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"
17 namespace invalidation
{
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
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";
29 // Cacheinvalidation specific gcm message keys.
30 const char kContentKey
[] = "content";
31 const char kEchoTokenKey
[] = "echo-token";
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
{
40 Core(base::WeakPtr
<GCMInvalidationBridge
> bridge
,
41 scoped_refptr
<base::SingleThreadTaskRunner
> ui_thread_task_runner
);
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
;
51 void RequestTokenFinished(RequestTokenCallback callback
,
52 const GoogleServiceAuthError
& error
,
53 const std::string
& token
);
55 void RegisterFinished(RegisterCallback callback
,
56 const std::string
& registration_id
,
57 gcm::GCMClient::Result result
);
59 void OnIncomingMessage(const std::string
& message
,
60 const std::string
& echo_token
);
63 base::WeakPtr
<GCMInvalidationBridge
> bridge_
;
64 scoped_refptr
<base::SingleThreadTaskRunner
> ui_thread_task_runner_
;
66 MessageCallback message_callback_
;
68 base::WeakPtrFactory
<Core
> weak_factory_
;
70 DISALLOW_COPY_AND_ASSIGN(Core
);
73 GCMInvalidationBridge::Core::Core(
74 base::WeakPtr
<GCMInvalidationBridge
> bridge
,
75 scoped_refptr
<base::SingleThreadTaskRunner
> ui_thread_task_runner
)
77 ui_thread_task_runner_(ui_thread_task_runner
),
79 // Core is created on UI thread but all calls happen on IO thread.
83 GCMInvalidationBridge::Core::~Core() {}
85 void GCMInvalidationBridge::Core::Initialize() {
86 DCHECK(CalledOnValidThread());
87 // Pass core WeapPtr and TaskRunner to GCMInvalidationBridge for it to be able
89 ui_thread_task_runner_
->PostTask(
91 base::Bind(&GCMInvalidationBridge::CoreInitializationDone
,
93 weak_factory_
.GetWeakPtr(),
94 base::ThreadTaskRunnerHandle::Get()));
97 void GCMInvalidationBridge::Core::RequestToken(RequestTokenCallback callback
) {
98 DCHECK(CalledOnValidThread());
99 ui_thread_task_runner_
->PostTask(
101 base::Bind(&GCMInvalidationBridge::RequestToken
, bridge_
, callback
));
104 void GCMInvalidationBridge::Core::InvalidateToken(const std::string
& token
) {
105 DCHECK(CalledOnValidThread());
106 ui_thread_task_runner_
->PostTask(
108 base::Bind(&GCMInvalidationBridge::InvalidateToken
, bridge_
, token
));
111 void GCMInvalidationBridge::Core::Register(RegisterCallback callback
) {
112 DCHECK(CalledOnValidThread());
113 ui_thread_task_runner_
->PostTask(
115 base::Bind(&GCMInvalidationBridge::Register
, bridge_
, callback
));
118 void GCMInvalidationBridge::Core::SetMessageReceiver(MessageCallback callback
) {
119 message_callback_
= callback
;
120 ui_thread_task_runner_
->PostTask(
122 base::Bind(&GCMInvalidationBridge::SubscribeForIncomingMessages
,
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
);
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
);
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
);
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) {}
158 GCMInvalidationBridge::~GCMInvalidationBridge() {
159 if (subscribed_for_incoming_messages_
)
160 gcm_driver_
->RemoveAppHandler(kInvalidationsAppId
);
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()));
171 void GCMInvalidationBridge::CoreInitializationDone(
172 base::WeakPtr
<Core
> core
,
173 scoped_refptr
<base::SingleThreadTaskRunner
> core_thread_task_runner
) {
174 DCHECK(CalledOnValidThread());
176 core_thread_task_runner_
= core_thread_task_runner
;
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(
188 base::Bind(&GCMInvalidationBridge::Core::RequestTokenFinished
,
190 request_token_callback_
,
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);
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(
209 base::Bind(&GCMInvalidationBridge::Core::RequestTokenFinished
,
211 request_token_callback_
,
212 GoogleServiceAuthError::AuthErrorNone(),
214 request_token_callback_
.Reset();
215 access_token_request_
.reset();
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(
225 base::Bind(&GCMInvalidationBridge::Core::RequestTokenFinished
,
227 request_token_callback_
,
230 request_token_callback_
.Reset();
231 access_token_request_
.reset();
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
);
242 void GCMInvalidationBridge::Register(
243 syncer::GCMNetworkChannelDelegate::RegisterCallback callback
) {
244 DCHECK(CalledOnValidThread());
245 // No-op if GCMClient is disabled.
246 if (gcm_driver_
== NULL
)
249 std::vector
<std::string
> sender_ids
;
250 sender_ids
.push_back(kInvalidationsSenderId
);
251 gcm_driver_
->Register(kInvalidationsAppId
,
253 base::Bind(&GCMInvalidationBridge::RegisterFinished
,
254 weak_factory_
.GetWeakPtr(),
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(
265 base::Bind(&GCMInvalidationBridge::Core::RegisterFinished
,
272 void GCMInvalidationBridge::SubscribeForIncomingMessages() {
273 // No-op if GCMClient is disabled.
274 if (gcm_driver_
== NULL
)
277 DCHECK(!subscribed_for_incoming_messages_
);
278 gcm_driver_
->AddAppHandler(kInvalidationsAppId
, this);
279 subscribed_for_incoming_messages_
= true;
282 void GCMInvalidationBridge::ShutdownHandler() {
286 void GCMInvalidationBridge::OnMessage(
287 const std::string
& app_id
,
288 const gcm::GCMClient::IncomingMessage
& message
) {
289 gcm::GCMClient::MessageData::const_iterator it
;
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
;
299 core_thread_task_runner_
->PostTask(
301 base::Bind(&GCMInvalidationBridge::Core::OnIncomingMessage
,
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.
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.
320 } // namespace invalidation