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/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"
22 namespace invalidation {
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
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";
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> {
42 RegisterCall(Profile* profile,
43 syncer::GCMNetworkChannelDelegate::RegisterCallback callback);
45 void RegisterOnUIThread();
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);
53 friend class base::RefCountedThreadSafe<RegisterCall>;
54 virtual ~RegisterCall();
57 syncer::GCMNetworkChannelDelegate::RegisterCallback callback_;
58 scoped_refptr<base::SingleThreadTaskRunner> origin_thread_task_runner_;
60 DISALLOW_COPY_AND_ASSIGN(RegisterCall);
63 RegisterCall::RegisterCall(
65 syncer::GCMNetworkChannelDelegate::RegisterCallback callback)
68 origin_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
70 RegisterCall::~RegisterCall() {}
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_))
78 gcm::GCMProfileService* gcm_profile_service =
79 gcm::GCMProfileServiceFactory::GetForProfile(profile_);
80 if (gcm_profile_service == NULL)
83 std::vector<std::string> sender_ids;
84 sender_ids.push_back(kInvalidationsSenderId);
85 gcm_profile_service->Register(
89 base::Bind(&RegisterCall::RegisterFinishedOnUIThread, this));
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(
99 &RegisterCall::RegisterFinished, this, registration_id, result));
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);
110 GCMNetworkChannelDelegateImpl::GCMNetworkChannelDelegateImpl(Profile* profile)
111 : OAuth2TokenService::Consumer("gcm_network_channel"),
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();
120 GCMNetworkChannelDelegateImpl::~GCMNetworkChannelDelegateImpl() {}
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));
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));
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));
144 void GCMNetworkChannelDelegateImpl::InvalidateToken(const std::string& token) {
145 ui_thread_task_runner_->PostTask(
147 base::Bind(&GCMNetworkChannelDelegateImpl::InvalidateTokenOnUIThread,
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(),
159 request_token_callback_.Reset();
160 access_token_request_.reset();
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();
172 void GCMNetworkChannelDelegateImpl::InvalidateTokenOnUIThread(
174 const std::string& token) {
175 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
176 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
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);
187 } // namespace invalidation