Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / invalidation / gcm_invalidation_bridge.cc
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/services/gcm/gcm_service.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"
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::GCMService* gcm_service,
151     IdentityProvider* identity_provider)
152     : OAuth2TokenService::Consumer("gcm_network_channel"),
153       gcm_service_(gcm_service),
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_service_->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_service_ == NULL)
247     return;
248
249   std::vector<std::string> sender_ids;
250   sender_ids.push_back(kInvalidationsSenderId);
251   gcm_service_->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_service_ == NULL)
275     return;
276
277   DCHECK(!subscribed_for_incoming_messages_);
278   gcm_service_->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