Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / invalidation / gcm_network_channel_delegate_impl.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/callback.h"
7 #include "base/location.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/invalidation/gcm_network_channel_delegate_impl.h"
13 #include "chrome/browser/profiles/profile_manager.h"
14 #include "chrome/browser/services/gcm/gcm_profile_service.h"
15 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
16 #include "chrome/browser/signin/profile_oauth2_token_service.h"
17 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
18 #include "chrome/browser/signin/profile_oauth2_token_service_request.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "google_apis/gaia/gaia_constants.h"
21
22 namespace invalidation {
23
24 namespace {
25
26 // For 3rd party developers SenderId should come from application dashboard when
27 // server side application is registered with Google. Android invalidations use
28 // legacy format where gmail account can be specificed. Below value is copied
29 // from Android.
30 const char kInvalidationsSenderId[] = "ipc.invalidation@gmail.com";
31 // In Android world AppId and Cert are provided by operating system and should
32 // match package name and hash of application. In desktop world these values
33 // are arbitrary and not verified/enforced by registration service (yet).
34 const char kInvalidationsAppId[] = "com.google.chrome.invalidations";
35 const char kInvalidationsCert[] = "ABC";
36
37 // In each call to Register object of RegisterCall will be created.
38 // Its purpose is to pass context (profile and callback) around between threads
39 // and async call to GCMProfilkeService::Register.
40 class RegisterCall : public base::RefCountedThreadSafe<RegisterCall> {
41  public:
42   RegisterCall(Profile* profile,
43                syncer::GCMNetworkChannelDelegate::RegisterCallback callback);
44
45   void RegisterOnUIThread();
46
47   void RegisterFinishedOnUIThread(const std::string& registration_id,
48                                   gcm::GCMClient::Result result);
49   void RegisterFinished(const std::string& registration_id,
50                         gcm::GCMClient::Result result);
51
52  private:
53   friend class base::RefCountedThreadSafe<RegisterCall>;
54   virtual ~RegisterCall();
55
56   Profile* profile_;
57   syncer::GCMNetworkChannelDelegate::RegisterCallback callback_;
58   scoped_refptr<base::SingleThreadTaskRunner> origin_thread_task_runner_;
59
60   DISALLOW_COPY_AND_ASSIGN(RegisterCall);
61 };
62
63 RegisterCall::RegisterCall(
64     Profile* profile,
65     syncer::GCMNetworkChannelDelegate::RegisterCallback callback)
66     : profile_(profile),
67       callback_(callback),
68       origin_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
69
70 RegisterCall::~RegisterCall() {}
71
72 void RegisterCall::RegisterOnUIThread() {
73   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
74   // No-op if Profile was destroyed or GCMClient is disabled.
75   if (!g_browser_process->profile_manager()->IsValidProfile(profile_))
76     return;
77
78   gcm::GCMProfileService* gcm_profile_service =
79       gcm::GCMProfileServiceFactory::GetForProfile(profile_);
80   if (gcm_profile_service == NULL)
81     return;
82
83   std::vector<std::string> sender_ids;
84   sender_ids.push_back(kInvalidationsSenderId);
85   gcm_profile_service->Register(
86       kInvalidationsAppId,
87       sender_ids,
88       kInvalidationsCert,
89       base::Bind(&RegisterCall::RegisterFinishedOnUIThread, this));
90 }
91
92 void RegisterCall::RegisterFinishedOnUIThread(
93     const std::string& registration_id,
94     gcm::GCMClient::Result result) {
95   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
96   origin_thread_task_runner_->PostTask(
97       FROM_HERE,
98       base::Bind(
99           &RegisterCall::RegisterFinished, this, registration_id, result));
100 }
101
102 void RegisterCall::RegisterFinished(const std::string& registration_id,
103                                     gcm::GCMClient::Result result) {
104   DCHECK(origin_thread_task_runner_->BelongsToCurrentThread());
105   callback_.Run(registration_id, result);
106 }
107
108 }  // namespace
109
110 GCMNetworkChannelDelegateImpl::GCMNetworkChannelDelegateImpl(Profile* profile)
111     : OAuth2TokenService::Consumer("gcm_network_channel"),
112       profile_(profile),
113       ui_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
114   // Stash account_id. It is needed in RequestToken call on IO thread.
115   ProfileOAuth2TokenService* oauth2_token_service =
116       ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
117   account_id_ = oauth2_token_service->GetPrimaryAccountId();
118 }
119
120 GCMNetworkChannelDelegateImpl::~GCMNetworkChannelDelegateImpl() {}
121
122 void GCMNetworkChannelDelegateImpl::Register(RegisterCallback callback) {
123   scoped_refptr<RegisterCall> call(new RegisterCall(profile_, callback));
124   ui_thread_task_runner_->PostTask(
125       FROM_HERE, base::Bind(&RegisterCall::RegisterOnUIThread, call));
126 }
127
128 void GCMNetworkChannelDelegateImpl::RequestToken(
129     RequestTokenCallback callback) {
130   if (access_token_request_ != NULL) {
131     // Report previous request as cancelled.
132     GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED);
133     std::string access_token;
134     base::MessageLoop::current()->PostTask(
135         FROM_HERE, base::Bind(request_token_callback_, error, access_token));
136   }
137   request_token_callback_ = callback;
138   OAuth2TokenService::ScopeSet scopes;
139   scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope);
140   access_token_request_.reset(ProfileOAuth2TokenServiceRequest::CreateAndStart(
141       profile_, account_id_, scopes, this));
142 }
143
144 void GCMNetworkChannelDelegateImpl::InvalidateToken(const std::string& token) {
145   ui_thread_task_runner_->PostTask(
146       FROM_HERE,
147       base::Bind(&GCMNetworkChannelDelegateImpl::InvalidateTokenOnUIThread,
148                  profile_,
149                  token));
150 }
151
152 void GCMNetworkChannelDelegateImpl::OnGetTokenSuccess(
153     const OAuth2TokenService::Request* request,
154     const std::string& access_token,
155     const base::Time& expiration_time) {
156   DCHECK_EQ(access_token_request_, request);
157   request_token_callback_.Run(GoogleServiceAuthError::AuthErrorNone(),
158                               access_token);
159   request_token_callback_.Reset();
160   access_token_request_.reset();
161 }
162
163 void GCMNetworkChannelDelegateImpl::OnGetTokenFailure(
164     const OAuth2TokenService::Request* request,
165     const GoogleServiceAuthError& error) {
166   DCHECK_EQ(access_token_request_, request);
167   request_token_callback_.Run(error, std::string());
168   request_token_callback_.Reset();
169   access_token_request_.reset();
170 }
171
172 void GCMNetworkChannelDelegateImpl::InvalidateTokenOnUIThread(
173     Profile* profile,
174     const std::string& token) {
175   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
176   if (!g_browser_process->profile_manager()->IsValidProfile(profile))
177     return;
178
179   ProfileOAuth2TokenService* oauth2_token_service =
180       ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
181   std::string account_id = oauth2_token_service->GetPrimaryAccountId();
182   OAuth2TokenService::ScopeSet scopes;
183   scopes.insert(GaiaConstants::kGoogleTalkOAuth2Scope);
184   oauth2_token_service->InvalidateToken(account_id, scopes, token);
185 }
186
187 }  // namespace invalidation