1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file.
4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/bind.h"
6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/location.h"
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/single_thread_task_runner.h"
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/thread_task_runner_handle.h"
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/gcm_driver/gcm_driver.h"
10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "components/invalidation/gcm_invalidation_bridge.h"
11effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "components/signin/core/browser/profile_oauth2_token_service.h"
12e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "components/signin/core/browser/signin_manager.h"
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "google_apis/gaia/gaia_constants.h"
140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "google_apis/gaia/identity_provider.h"
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace invalidation {
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace {
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// For 3rd party developers SenderId should come from application dashboard when
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// server side application is registered with Google. Android invalidations use
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// legacy format where gmail account can be specificed. Below value is copied
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// from Android.
22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kInvalidationsSenderId[] = "ipc.invalidation@gmail.com";
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// In Android world AppId is provided by operating system and should
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// match package name and hash of application. In desktop world these values
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// are arbitrary and not verified/enforced by registration service (yet).
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kInvalidationsAppId[] = "com.google.chrome.invalidations";
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Cacheinvalidation specific gcm message keys.
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kContentKey[] = "content";
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kEchoTokenKey[] = "echo-token";
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Core should be very simple class that implements GCMNetwrokChannelDelegate
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// and passes all calls to GCMInvalidationBridge. All calls should be serialized
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// through GCMInvalidationBridge to avoid race conditions.
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class GCMInvalidationBridge::Core : public syncer::GCMNetworkChannelDelegate,
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                    public base::NonThreadSafe {
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public:
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Core(base::WeakPtr<GCMInvalidationBridge> bridge,
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual ~Core();
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // syncer::GCMNetworkChannelDelegate implementation.
446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  virtual void Initialize(ConnectionStateCallback callback) OVERRIDE;
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void RequestToken(RequestTokenCallback callback) OVERRIDE;
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void InvalidateToken(const std::string& token) OVERRIDE;
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void Register(RegisterCallback callback) OVERRIDE;
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void SetMessageReceiver(MessageCallback callback) OVERRIDE;
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void RequestTokenFinished(RequestTokenCallback callback,
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                            const GoogleServiceAuthError& error,
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                            const std::string& token);
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void RegisterFinished(RegisterCallback callback,
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                        const std::string& registration_id,
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                        gcm::GCMClient::Result result);
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void OnIncomingMessage(const std::string& message,
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         const std::string& echo_token);
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  void OnConnectionStateChanged(bool online);
626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private:
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::WeakPtr<GCMInvalidationBridge> bridge_;
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner_;
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  MessageCallback message_callback_;
686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  ConnectionStateCallback connection_state_callback_;
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::WeakPtrFactory<Core> weak_factory_;
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Core);
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)};
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)GCMInvalidationBridge::Core::Core(
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::WeakPtr<GCMInvalidationBridge> bridge,
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner)
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : bridge_(bridge),
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ui_thread_task_runner_(ui_thread_task_runner),
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      weak_factory_(this) {
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Core is created on UI thread but all calls happen on IO thread.
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DetachFromThread();
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)GCMInvalidationBridge::Core::~Core() {}
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void GCMInvalidationBridge::Core::Initialize(ConnectionStateCallback callback) {
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(CalledOnValidThread());
896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  connection_state_callback_ = callback;
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Pass core WeapPtr and TaskRunner to GCMInvalidationBridge for it to be able
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // to post back.
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ui_thread_task_runner_->PostTask(
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FROM_HERE,
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&GCMInvalidationBridge::CoreInitializationDone,
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 bridge_,
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 weak_factory_.GetWeakPtr(),
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 base::ThreadTaskRunnerHandle::Get()));
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::Core::RequestToken(RequestTokenCallback callback) {
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(CalledOnValidThread());
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ui_thread_task_runner_->PostTask(
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FROM_HERE,
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&GCMInvalidationBridge::RequestToken, bridge_, callback));
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::Core::InvalidateToken(const std::string& token) {
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(CalledOnValidThread());
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ui_thread_task_runner_->PostTask(
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FROM_HERE,
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&GCMInvalidationBridge::InvalidateToken, bridge_, token));
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::Core::Register(RegisterCallback callback) {
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(CalledOnValidThread());
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ui_thread_task_runner_->PostTask(
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FROM_HERE,
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&GCMInvalidationBridge::Register, bridge_, callback));
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::Core::SetMessageReceiver(MessageCallback callback) {
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  message_callback_ = callback;
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ui_thread_task_runner_->PostTask(
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FROM_HERE,
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&GCMInvalidationBridge::SubscribeForIncomingMessages,
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 bridge_));
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::Core::RequestTokenFinished(
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    RequestTokenCallback callback,
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const GoogleServiceAuthError& error,
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& token) {
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(CalledOnValidThread());
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  callback.Run(error, token);
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::Core::RegisterFinished(
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    RegisterCallback callback,
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& registration_id,
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    gcm::GCMClient::Result result) {
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(CalledOnValidThread());
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  callback.Run(registration_id, result);
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::Core::OnIncomingMessage(
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& message,
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& echo_token) {
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!message_callback_.is_null());
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  message_callback_.Run(message, echo_token);
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void GCMInvalidationBridge::Core::OnConnectionStateChanged(bool online) {
1536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!connection_state_callback_.is_null()) {
1546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    connection_state_callback_.Run(online);
1556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
1566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
1576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
15823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)GCMInvalidationBridge::GCMInvalidationBridge(
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    gcm::GCMDriver* gcm_driver,
1600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    IdentityProvider* identity_provider)
161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : OAuth2TokenService::Consumer("gcm_network_channel"),
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      gcm_driver_(gcm_driver),
1630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      identity_provider_(identity_provider),
164effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      subscribed_for_incoming_messages_(false),
165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      weak_factory_(this) {}
166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)GCMInvalidationBridge::~GCMInvalidationBridge() {
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (subscribed_for_incoming_messages_) {
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    gcm_driver_->RemoveAppHandler(kInvalidationsAppId);
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    gcm_driver_->RemoveConnectionObserver(this);
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)scoped_ptr<syncer::GCMNetworkChannelDelegate>
175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)GCMInvalidationBridge::CreateDelegate() {
176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(CalledOnValidThread());
177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<syncer::GCMNetworkChannelDelegate> core(new Core(
178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      weak_factory_.GetWeakPtr(), base::ThreadTaskRunnerHandle::Get()));
179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return core.Pass();
180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::CoreInitializationDone(
183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::WeakPtr<Core> core,
184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> core_thread_task_runner) {
185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(CalledOnValidThread());
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  core_ = core;
187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  core_thread_task_runner_ = core_thread_task_runner;
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::RequestToken(
191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    syncer::GCMNetworkChannelDelegate::RequestTokenCallback callback) {
192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(CalledOnValidThread());
193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (access_token_request_ != NULL) {
194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Report previous request as cancelled.
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED);
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    std::string access_token;
197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    core_thread_task_runner_->PostTask(
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        FROM_HERE,
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::Bind(&GCMInvalidationBridge::Core::RequestTokenFinished,
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   core_,
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   request_token_callback_,
202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   error,
203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   access_token));
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request_token_callback_ = callback;
206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  OAuth2TokenService::ScopeSet scopes;
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope);
2080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  access_token_request_ = identity_provider_->GetTokenService()->StartRequest(
2090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      identity_provider_->GetActiveAccountId(), scopes, this);
210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::OnGetTokenSuccess(
213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const OAuth2TokenService::Request* request,
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& access_token,
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::Time& expiration_time) {
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(CalledOnValidThread());
217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK_EQ(access_token_request_, request);
218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  core_thread_task_runner_->PostTask(
219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FROM_HERE,
220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&GCMInvalidationBridge::Core::RequestTokenFinished,
221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 core_,
222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 request_token_callback_,
223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 GoogleServiceAuthError::AuthErrorNone(),
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 access_token));
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request_token_callback_.Reset();
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  access_token_request_.reset();
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::OnGetTokenFailure(
230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const OAuth2TokenService::Request* request,
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const GoogleServiceAuthError& error) {
232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(CalledOnValidThread());
233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK_EQ(access_token_request_, request);
234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  core_thread_task_runner_->PostTask(
235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FROM_HERE,
236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&GCMInvalidationBridge::Core::RequestTokenFinished,
237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 core_,
238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 request_token_callback_,
239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 error,
240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 std::string()));
241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request_token_callback_.Reset();
242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  access_token_request_.reset();
243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::InvalidateToken(const std::string& token) {
246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(CalledOnValidThread());
247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  OAuth2TokenService::ScopeSet scopes;
248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope);
2490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  identity_provider_->GetTokenService()->InvalidateToken(
2500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      identity_provider_->GetActiveAccountId(), scopes, token);
251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::Register(
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    syncer::GCMNetworkChannelDelegate::RegisterCallback callback) {
255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(CalledOnValidThread());
256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // No-op if GCMClient is disabled.
257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (gcm_driver_ == NULL)
258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<std::string> sender_ids;
261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  sender_ids.push_back(kInvalidationsSenderId);
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  gcm_driver_->Register(kInvalidationsAppId,
2635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         sender_ids,
2645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         base::Bind(&GCMInvalidationBridge::RegisterFinished,
2655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                    weak_factory_.GetWeakPtr(),
2665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                    callback));
267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::RegisterFinished(
270a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    syncer::GCMNetworkChannelDelegate::RegisterCallback callback,
271a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& registration_id,
272a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    gcm::GCMClient::Result result) {
273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(CalledOnValidThread());
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  core_thread_task_runner_->PostTask(
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FROM_HERE,
276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&GCMInvalidationBridge::Core::RegisterFinished,
277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 core_,
278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 callback,
279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 registration_id,
280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 result));
281a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::SubscribeForIncomingMessages() {
284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // No-op if GCMClient is disabled.
285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (gcm_driver_ == NULL)
286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!subscribed_for_incoming_messages_);
289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  gcm_driver_->AddAppHandler(kInvalidationsAppId, this);
2901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gcm_driver_->AddConnectionObserver(this);
2916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  core_thread_task_runner_->PostTask(
2926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      FROM_HERE,
2936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      base::Bind(&GCMInvalidationBridge::Core::OnConnectionStateChanged,
2946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                 core_,
2956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                 gcm_driver_->IsConnected()));
2966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
297a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  subscribed_for_incoming_messages_ = true;
298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
30023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void GCMInvalidationBridge::ShutdownHandler() {
30123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Nothing to do.
30223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
30323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
304a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::OnMessage(
305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& app_id,
306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const gcm::GCMClient::IncomingMessage& message) {
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  gcm::GCMClient::MessageData::const_iterator it;
308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string content;
309a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string echo_token;
310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  it = message.data.find(kContentKey);
311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (it != message.data.end())
312a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    content = it->second;
313a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  it = message.data.find(kEchoTokenKey);
314a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (it != message.data.end())
315a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    echo_token = it->second;
316a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
317a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  core_thread_task_runner_->PostTask(
318a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FROM_HERE,
319a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&GCMInvalidationBridge::Core::OnIncomingMessage,
320a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 core_,
321a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 content,
322a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 echo_token));
323a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
324a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
325a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::OnMessagesDeleted(const std::string& app_id) {
326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Cacheinvalidation doesn't use long lived non-collapsable messages with GCM.
327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Android implementation of cacheinvalidation doesn't handle MessagesDeleted
328a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // callback so this should be no-op in desktop version as well.
329a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
330a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
331a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GCMInvalidationBridge::OnSendError(
332a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& app_id,
333a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const gcm::GCMClient::SendErrorDetails& send_error_details) {
334a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // cacheinvalidation doesn't send messages over GCM.
335a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  NOTREACHED();
336a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
337a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void GCMInvalidationBridge::OnSendAcknowledged(
3395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::string& app_id,
3405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::string& message_id) {
3415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // cacheinvalidation doesn't send messages over GCM.
3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  NOTREACHED();
3435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
345f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void GCMInvalidationBridge::OnConnected(const net::IPEndPoint& ip_endpoint) {
3466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  core_thread_task_runner_->PostTask(
3476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      FROM_HERE,
3486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      base::Bind(
3496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          &GCMInvalidationBridge::Core::OnConnectionStateChanged, core_, true));
350f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
351f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
352f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void GCMInvalidationBridge::OnDisconnected() {
3536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  core_thread_task_runner_->PostTask(
3546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      FROM_HERE,
3556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      base::Bind(&GCMInvalidationBridge::Core::OnConnectionStateChanged,
3566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                 core_,
3576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                 false));
358f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
359f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
360f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
361a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace invalidation
362