Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / components / 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 "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::SubscribeForIncomingMessages() {
284   // No-op if GCMClient is disabled.
285   if (gcm_driver_ == NULL)
286     return;
287
288   DCHECK(!subscribed_for_incoming_messages_);
289   gcm_driver_->AddAppHandler(kInvalidationsAppId, this);
290   gcm_driver_->AddConnectionObserver(this);
291   core_thread_task_runner_->PostTask(
292       FROM_HERE,
293       base::Bind(&GCMInvalidationBridge::Core::OnConnectionStateChanged,
294                  core_,
295                  gcm_driver_->IsConnected()));
296
297   subscribed_for_incoming_messages_ = true;
298 }
299
300 void GCMInvalidationBridge::ShutdownHandler() {
301   // Nothing to do.
302 }
303
304 void GCMInvalidationBridge::OnMessage(
305     const std::string& app_id,
306     const gcm::GCMClient::IncomingMessage& message) {
307   gcm::GCMClient::MessageData::const_iterator it;
308   std::string content;
309   std::string echo_token;
310   it = message.data.find(kContentKey);
311   if (it != message.data.end())
312     content = it->second;
313   it = message.data.find(kEchoTokenKey);
314   if (it != message.data.end())
315     echo_token = it->second;
316
317   core_thread_task_runner_->PostTask(
318       FROM_HERE,
319       base::Bind(&GCMInvalidationBridge::Core::OnIncomingMessage,
320                  core_,
321                  content,
322                  echo_token));
323 }
324
325 void GCMInvalidationBridge::OnMessagesDeleted(const std::string& app_id) {
326   // Cacheinvalidation doesn't use long lived non-collapsable messages with GCM.
327   // Android implementation of cacheinvalidation doesn't handle MessagesDeleted
328   // callback so this should be no-op in desktop version as well.
329 }
330
331 void GCMInvalidationBridge::OnSendError(
332     const std::string& app_id,
333     const gcm::GCMClient::SendErrorDetails& send_error_details) {
334   // cacheinvalidation doesn't send messages over GCM.
335   NOTREACHED();
336 }
337
338 void GCMInvalidationBridge::OnSendAcknowledged(
339     const std::string& app_id,
340     const std::string& message_id) {
341   // cacheinvalidation doesn't send messages over GCM.
342   NOTREACHED();
343 }
344
345 void GCMInvalidationBridge::OnConnected(const net::IPEndPoint& ip_endpoint) {
346   core_thread_task_runner_->PostTask(
347       FROM_HERE,
348       base::Bind(
349           &GCMInvalidationBridge::Core::OnConnectionStateChanged, core_, true));
350 }
351
352 void GCMInvalidationBridge::OnDisconnected() {
353   core_thread_task_runner_->PostTask(
354       FROM_HERE,
355       base::Bind(&GCMInvalidationBridge::Core::OnConnectionStateChanged,
356                  core_,
357                  false));
358 }
359
360
361 }  // namespace invalidation