OLD | NEW |
| (Empty) |
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 "chrome/browser/services/gcm/gcm_driver.h" | |
6 | |
7 #include <algorithm> | |
8 #include <utility> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/bind_helpers.h" | |
12 #include "base/location.h" | |
13 #include "base/logging.h" | |
14 #include "base/sequenced_task_runner.h" | |
15 #include "base/threading/sequenced_worker_pool.h" | |
16 #include "chrome/common/chrome_version_info.h" | |
17 #include "components/gcm_driver/gcm_app_handler.h" | |
18 #include "components/gcm_driver/gcm_client_factory.h" | |
19 #include "components/gcm_driver/system_encryptor.h" | |
20 #include "google_apis/gaia/oauth2_token_service.h" | |
21 #include "net/url_request/url_request_context_getter.h" | |
22 | |
23 namespace gcm { | |
24 | |
25 // Helper class to save tasks to run until we're ready to execute them. | |
26 class GCMDriver::DelayedTaskController { | |
27 public: | |
28 DelayedTaskController(); | |
29 ~DelayedTaskController(); | |
30 | |
31 // Adds a task that will be invoked once we're ready. | |
32 void AddTask(const base::Closure& task); | |
33 | |
34 // Sets ready status. It is ready only when check-in is completed and | |
35 // the GCMClient is fully initialized. | |
36 void SetReady(); | |
37 | |
38 // Returns true if it is ready to perform tasks. | |
39 bool CanRunTaskWithoutDelay() const; | |
40 | |
41 private: | |
42 void RunTasks(); | |
43 | |
44 // Flag that indicates that GCM is ready. | |
45 bool ready_; | |
46 | |
47 std::vector<base::Closure> delayed_tasks_; | |
48 | |
49 DISALLOW_COPY_AND_ASSIGN(DelayedTaskController); | |
50 }; | |
51 | |
52 GCMDriver::DelayedTaskController::DelayedTaskController() : ready_(false) { | |
53 } | |
54 | |
55 GCMDriver::DelayedTaskController::~DelayedTaskController() { | |
56 } | |
57 | |
58 void GCMDriver::DelayedTaskController::AddTask(const base::Closure& task) { | |
59 delayed_tasks_.push_back(task); | |
60 } | |
61 | |
62 void GCMDriver::DelayedTaskController::SetReady() { | |
63 ready_ = true; | |
64 RunTasks(); | |
65 } | |
66 | |
67 bool GCMDriver::DelayedTaskController::CanRunTaskWithoutDelay() const { | |
68 return ready_; | |
69 } | |
70 | |
71 void GCMDriver::DelayedTaskController::RunTasks() { | |
72 DCHECK(ready_); | |
73 | |
74 for (size_t i = 0; i < delayed_tasks_.size(); ++i) | |
75 delayed_tasks_[i].Run(); | |
76 delayed_tasks_.clear(); | |
77 } | |
78 | |
79 class GCMDriver::IOWorker : public GCMClient::Delegate { | |
80 public: | |
81 // Called on UI thread. | |
82 IOWorker(const scoped_refptr<base::SequencedTaskRunner>& ui_thread, | |
83 const scoped_refptr<base::SequencedTaskRunner>& io_thread); | |
84 virtual ~IOWorker(); | |
85 | |
86 // Overridden from GCMClient::Delegate: | |
87 // Called on IO thread. | |
88 virtual void OnRegisterFinished(const std::string& app_id, | |
89 const std::string& registration_id, | |
90 GCMClient::Result result) OVERRIDE; | |
91 virtual void OnUnregisterFinished(const std::string& app_id, | |
92 GCMClient::Result result) OVERRIDE; | |
93 virtual void OnSendFinished(const std::string& app_id, | |
94 const std::string& message_id, | |
95 GCMClient::Result result) OVERRIDE; | |
96 virtual void OnMessageReceived( | |
97 const std::string& app_id, | |
98 const GCMClient::IncomingMessage& message) OVERRIDE; | |
99 virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE; | |
100 virtual void OnMessageSendError( | |
101 const std::string& app_id, | |
102 const GCMClient::SendErrorDetails& send_error_details) OVERRIDE; | |
103 virtual void OnGCMReady() OVERRIDE; | |
104 virtual void OnActivityRecorded() OVERRIDE; | |
105 | |
106 // Called on IO thread. | |
107 void Initialize( | |
108 scoped_ptr<GCMClientFactory> gcm_client_factory, | |
109 const GCMClient::ChromeBuildInfo& chrome_build_info, | |
110 const base::FilePath& store_path, | |
111 const std::vector<std::string>& account_ids, | |
112 const scoped_refptr<net::URLRequestContextGetter>& request_context, | |
113 const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner); | |
114 void Start(const base::WeakPtr<GCMDriver>& service); | |
115 void Stop(); | |
116 void CheckOut(); | |
117 void Register(const std::string& app_id, | |
118 const std::vector<std::string>& sender_ids); | |
119 void Unregister(const std::string& app_id); | |
120 void Send(const std::string& app_id, | |
121 const std::string& receiver_id, | |
122 const GCMClient::OutgoingMessage& message); | |
123 void GetGCMStatistics(bool clear_logs); | |
124 void SetGCMRecording(bool recording); | |
125 | |
126 // For testing purpose. Can be called from UI thread. Use with care. | |
127 GCMClient* gcm_client_for_testing() const { return gcm_client_.get(); } | |
128 | |
129 private: | |
130 scoped_refptr<base::SequencedTaskRunner> ui_thread_; | |
131 scoped_refptr<base::SequencedTaskRunner> io_thread_; | |
132 | |
133 base::WeakPtr<GCMDriver> service_; | |
134 | |
135 scoped_ptr<GCMClient> gcm_client_; | |
136 | |
137 DISALLOW_COPY_AND_ASSIGN(IOWorker); | |
138 }; | |
139 | |
140 GCMDriver::IOWorker::IOWorker( | |
141 const scoped_refptr<base::SequencedTaskRunner>& ui_thread, | |
142 const scoped_refptr<base::SequencedTaskRunner>& io_thread) | |
143 : ui_thread_(ui_thread), | |
144 io_thread_(io_thread) { | |
145 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
146 } | |
147 | |
148 GCMDriver::IOWorker::~IOWorker() { | |
149 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
150 } | |
151 | |
152 void GCMDriver::IOWorker::Initialize( | |
153 scoped_ptr<GCMClientFactory> gcm_client_factory, | |
154 const GCMClient::ChromeBuildInfo& chrome_build_info, | |
155 const base::FilePath& store_path, | |
156 const std::vector<std::string>& account_ids, | |
157 const scoped_refptr<net::URLRequestContextGetter>& request_context, | |
158 const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) { | |
159 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
160 | |
161 gcm_client_ = gcm_client_factory->BuildInstance(); | |
162 | |
163 gcm_client_->Initialize(chrome_build_info, | |
164 store_path, | |
165 account_ids, | |
166 blocking_task_runner, | |
167 request_context, | |
168 make_scoped_ptr<Encryptor>(new SystemEncryptor), | |
169 this); | |
170 } | |
171 | |
172 void GCMDriver::IOWorker::OnRegisterFinished( | |
173 const std::string& app_id, | |
174 const std::string& registration_id, | |
175 GCMClient::Result result) { | |
176 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
177 | |
178 ui_thread_->PostTask( | |
179 FROM_HERE, | |
180 base::Bind(&GCMDriver::RegisterFinished, service_, app_id, | |
181 registration_id, result)); | |
182 } | |
183 | |
184 void GCMDriver::IOWorker::OnUnregisterFinished(const std::string& app_id, | |
185 GCMClient::Result result) { | |
186 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
187 | |
188 ui_thread_->PostTask( | |
189 FROM_HERE, | |
190 base::Bind(&GCMDriver::UnregisterFinished, service_, app_id, result)); | |
191 } | |
192 | |
193 void GCMDriver::IOWorker::OnSendFinished(const std::string& app_id, | |
194 const std::string& message_id, | |
195 GCMClient::Result result) { | |
196 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
197 | |
198 ui_thread_->PostTask( | |
199 FROM_HERE, | |
200 base::Bind(&GCMDriver::SendFinished, service_, app_id, message_id, | |
201 result)); | |
202 } | |
203 | |
204 void GCMDriver::IOWorker::OnMessageReceived( | |
205 const std::string& app_id, | |
206 const GCMClient::IncomingMessage& message) { | |
207 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
208 | |
209 ui_thread_->PostTask( | |
210 FROM_HERE, | |
211 base::Bind(&GCMDriver::MessageReceived, service_, app_id, message)); | |
212 } | |
213 | |
214 void GCMDriver::IOWorker::OnMessagesDeleted(const std::string& app_id) { | |
215 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
216 | |
217 ui_thread_->PostTask( | |
218 FROM_HERE, | |
219 base::Bind(&GCMDriver::MessagesDeleted, service_, app_id)); | |
220 } | |
221 | |
222 void GCMDriver::IOWorker::OnMessageSendError( | |
223 const std::string& app_id, | |
224 const GCMClient::SendErrorDetails& send_error_details) { | |
225 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
226 | |
227 ui_thread_->PostTask( | |
228 FROM_HERE, | |
229 base::Bind(&GCMDriver::MessageSendError, service_, app_id, | |
230 send_error_details)); | |
231 } | |
232 | |
233 void GCMDriver::IOWorker::OnGCMReady() { | |
234 ui_thread_->PostTask( | |
235 FROM_HERE, | |
236 base::Bind(&GCMDriver::GCMClientReady, service_)); | |
237 } | |
238 | |
239 void GCMDriver::IOWorker::OnActivityRecorded() { | |
240 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
241 // When an activity is recorded, get all the stats and refresh the UI of | |
242 // gcm-internals page. | |
243 GetGCMStatistics(false); | |
244 } | |
245 | |
246 void GCMDriver::IOWorker::Start(const base::WeakPtr<GCMDriver>& service) { | |
247 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
248 | |
249 service_ = service; | |
250 gcm_client_->Start(); | |
251 } | |
252 | |
253 void GCMDriver::IOWorker::Stop() { | |
254 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
255 | |
256 gcm_client_->Stop(); | |
257 } | |
258 | |
259 void GCMDriver::IOWorker::CheckOut() { | |
260 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
261 | |
262 gcm_client_->CheckOut(); | |
263 | |
264 // Note that we still need to keep GCMClient instance alive since the | |
265 // GCMDriver may check in again. | |
266 } | |
267 | |
268 void GCMDriver::IOWorker::Register( | |
269 const std::string& app_id, | |
270 const std::vector<std::string>& sender_ids) { | |
271 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
272 | |
273 gcm_client_->Register(app_id, sender_ids); | |
274 } | |
275 | |
276 void GCMDriver::IOWorker::Unregister(const std::string& app_id) { | |
277 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
278 | |
279 gcm_client_->Unregister(app_id); | |
280 } | |
281 | |
282 void GCMDriver::IOWorker::Send(const std::string& app_id, | |
283 const std::string& receiver_id, | |
284 const GCMClient::OutgoingMessage& message) { | |
285 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
286 | |
287 gcm_client_->Send(app_id, receiver_id, message); | |
288 } | |
289 | |
290 void GCMDriver::IOWorker::GetGCMStatistics(bool clear_logs) { | |
291 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
292 gcm::GCMClient::GCMStatistics stats; | |
293 | |
294 if (gcm_client_.get()) { | |
295 if (clear_logs) | |
296 gcm_client_->ClearActivityLogs(); | |
297 stats = gcm_client_->GetStatistics(); | |
298 } | |
299 | |
300 ui_thread_->PostTask( | |
301 FROM_HERE, | |
302 base::Bind(&GCMDriver::GetGCMStatisticsFinished, service_, stats)); | |
303 } | |
304 | |
305 void GCMDriver::IOWorker::SetGCMRecording(bool recording) { | |
306 DCHECK(io_thread_->RunsTasksOnCurrentThread()); | |
307 gcm::GCMClient::GCMStatistics stats; | |
308 | |
309 if (gcm_client_.get()) { | |
310 gcm_client_->SetRecording(recording); | |
311 stats = gcm_client_->GetStatistics(); | |
312 stats.gcm_client_created = true; | |
313 } | |
314 | |
315 ui_thread_->PostTask( | |
316 FROM_HERE, | |
317 base::Bind(&GCMDriver::GetGCMStatisticsFinished, service_, stats)); | |
318 } | |
319 | |
320 GCMDriver::GCMDriver( | |
321 scoped_ptr<GCMClientFactory> gcm_client_factory, | |
322 scoped_ptr<IdentityProvider> identity_provider, | |
323 const GCMClient::ChromeBuildInfo& chrome_build_info, | |
324 const base::FilePath& store_path, | |
325 const scoped_refptr<net::URLRequestContextGetter>& request_context, | |
326 const scoped_refptr<base::SequencedTaskRunner>& ui_thread, | |
327 const scoped_refptr<base::SequencedTaskRunner>& io_thread, | |
328 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner) | |
329 : gcm_enabled_(true), | |
330 gcm_client_ready_(false), | |
331 identity_provider_(identity_provider.Pass()), | |
332 ui_thread_(ui_thread), | |
333 io_thread_(io_thread), | |
334 weak_ptr_factory_(this) { | |
335 // Get the list of available accounts. | |
336 std::vector<std::string> account_ids; | |
337 #if !defined(OS_ANDROID) | |
338 account_ids = identity_provider_->GetTokenService()->GetAccounts(); | |
339 #endif | |
340 | |
341 // Create and initialize the GCMClient. Note that this does not initiate the | |
342 // GCM check-in. | |
343 io_worker_.reset(new IOWorker(ui_thread, io_thread)); | |
344 io_thread_->PostTask( | |
345 FROM_HERE, | |
346 base::Bind(&GCMDriver::IOWorker::Initialize, | |
347 base::Unretained(io_worker_.get()), | |
348 base::Passed(&gcm_client_factory), | |
349 chrome_build_info, | |
350 store_path, | |
351 account_ids, | |
352 request_context, | |
353 blocking_task_runner)); | |
354 | |
355 identity_provider_->AddObserver(this); | |
356 } | |
357 | |
358 GCMDriver::GCMDriver() | |
359 : gcm_enabled_(true), | |
360 gcm_client_ready_(false), | |
361 weak_ptr_factory_(this) { | |
362 } | |
363 | |
364 GCMDriver::~GCMDriver() { | |
365 } | |
366 | |
367 void GCMDriver::Enable() { | |
368 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
369 | |
370 if (gcm_enabled_) | |
371 return; | |
372 gcm_enabled_ = true; | |
373 | |
374 EnsureStarted(); | |
375 } | |
376 | |
377 void GCMDriver::Disable() { | |
378 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
379 | |
380 if (!gcm_enabled_) | |
381 return; | |
382 gcm_enabled_ = false; | |
383 | |
384 Stop(); | |
385 } | |
386 | |
387 void GCMDriver::Stop() { | |
388 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
389 | |
390 // No need to stop GCM service if not started yet. | |
391 if (account_id_.empty()) | |
392 return; | |
393 | |
394 RemoveCachedData(); | |
395 | |
396 io_thread_->PostTask( | |
397 FROM_HERE, | |
398 base::Bind(&GCMDriver::IOWorker::Stop, | |
399 base::Unretained(io_worker_.get()))); | |
400 } | |
401 | |
402 void GCMDriver::Shutdown() { | |
403 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
404 identity_provider_->RemoveObserver(this); | |
405 for (GCMAppHandlerMap::const_iterator iter = app_handlers_.begin(); | |
406 iter != app_handlers_.end(); ++iter) { | |
407 iter->second->ShutdownHandler(); | |
408 } | |
409 app_handlers_.clear(); | |
410 io_thread_->DeleteSoon(FROM_HERE, io_worker_.release()); | |
411 } | |
412 | |
413 void GCMDriver::AddAppHandler(const std::string& app_id, | |
414 GCMAppHandler* handler) { | |
415 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
416 DCHECK(!app_id.empty()); | |
417 DCHECK(handler); | |
418 DCHECK(app_handlers_.find(app_id) == app_handlers_.end()); | |
419 | |
420 app_handlers_[app_id] = handler; | |
421 | |
422 // Ensures that the GCM service is started when there is an interest. | |
423 EnsureStarted(); | |
424 } | |
425 | |
426 void GCMDriver::RemoveAppHandler(const std::string& app_id) { | |
427 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
428 DCHECK(!app_id.empty()); | |
429 | |
430 app_handlers_.erase(app_id); | |
431 | |
432 // Stops the GCM service when no app intends to consume it. | |
433 if (app_handlers_.empty()) | |
434 Stop(); | |
435 } | |
436 | |
437 void GCMDriver::Register(const std::string& app_id, | |
438 const std::vector<std::string>& sender_ids, | |
439 const RegisterCallback& callback) { | |
440 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
441 DCHECK(!app_id.empty()); | |
442 DCHECK(!sender_ids.empty()); | |
443 DCHECK(!callback.is_null()); | |
444 | |
445 GCMClient::Result result = EnsureStarted(); | |
446 if (result != GCMClient::SUCCESS) { | |
447 callback.Run(std::string(), result); | |
448 return; | |
449 } | |
450 | |
451 // If previous un/register operation is still in progress, bail out. | |
452 if (IsAsyncOperationPending(app_id)) { | |
453 callback.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING); | |
454 return; | |
455 } | |
456 | |
457 register_callbacks_[app_id] = callback; | |
458 | |
459 // Delay the register operation until GCMClient is ready. | |
460 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) { | |
461 delayed_task_controller_->AddTask(base::Bind(&GCMDriver::DoRegister, | |
462 weak_ptr_factory_.GetWeakPtr(), | |
463 app_id, | |
464 sender_ids)); | |
465 return; | |
466 } | |
467 | |
468 DoRegister(app_id, sender_ids); | |
469 } | |
470 | |
471 void GCMDriver::DoRegister(const std::string& app_id, | |
472 const std::vector<std::string>& sender_ids) { | |
473 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
474 std::map<std::string, RegisterCallback>::iterator callback_iter = | |
475 register_callbacks_.find(app_id); | |
476 if (callback_iter == register_callbacks_.end()) { | |
477 // The callback could have been removed when the app is uninstalled. | |
478 return; | |
479 } | |
480 | |
481 // Normalize the sender IDs by making them sorted. | |
482 std::vector<std::string> normalized_sender_ids = sender_ids; | |
483 std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end()); | |
484 | |
485 io_thread_->PostTask( | |
486 FROM_HERE, | |
487 base::Bind(&GCMDriver::IOWorker::Register, | |
488 base::Unretained(io_worker_.get()), | |
489 app_id, | |
490 normalized_sender_ids)); | |
491 } | |
492 | |
493 void GCMDriver::Unregister(const std::string& app_id, | |
494 const UnregisterCallback& callback) { | |
495 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
496 DCHECK(!app_id.empty()); | |
497 DCHECK(!callback.is_null()); | |
498 | |
499 GCMClient::Result result = EnsureStarted(); | |
500 if (result != GCMClient::SUCCESS) { | |
501 callback.Run(result); | |
502 return; | |
503 } | |
504 | |
505 // If previous un/register operation is still in progress, bail out. | |
506 if (IsAsyncOperationPending(app_id)) { | |
507 callback.Run(GCMClient::ASYNC_OPERATION_PENDING); | |
508 return; | |
509 } | |
510 | |
511 unregister_callbacks_[app_id] = callback; | |
512 | |
513 // Delay the unregister operation until GCMClient is ready. | |
514 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) { | |
515 delayed_task_controller_->AddTask(base::Bind(&GCMDriver::DoUnregister, | |
516 weak_ptr_factory_.GetWeakPtr(), | |
517 app_id)); | |
518 return; | |
519 } | |
520 | |
521 DoUnregister(app_id); | |
522 } | |
523 | |
524 void GCMDriver::DoUnregister(const std::string& app_id) { | |
525 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
526 | |
527 // Ask the server to unregister it. There could be a small chance that the | |
528 // unregister request fails. If this occurs, it does not bring any harm since | |
529 // we simply reject the messages/events received from the server. | |
530 io_thread_->PostTask( | |
531 FROM_HERE, | |
532 base::Bind(&GCMDriver::IOWorker::Unregister, | |
533 base::Unretained(io_worker_.get()), | |
534 app_id)); | |
535 } | |
536 | |
537 void GCMDriver::Send(const std::string& app_id, | |
538 const std::string& receiver_id, | |
539 const GCMClient::OutgoingMessage& message, | |
540 const SendCallback& callback) { | |
541 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
542 DCHECK(!app_id.empty()); | |
543 DCHECK(!receiver_id.empty()); | |
544 DCHECK(!callback.is_null()); | |
545 | |
546 GCMClient::Result result = EnsureStarted(); | |
547 if (result != GCMClient::SUCCESS) { | |
548 callback.Run(std::string(), result); | |
549 return; | |
550 } | |
551 | |
552 // If the message with send ID is still in progress, bail out. | |
553 std::pair<std::string, std::string> key(app_id, message.id); | |
554 if (send_callbacks_.find(key) != send_callbacks_.end()) { | |
555 callback.Run(message.id, GCMClient::INVALID_PARAMETER); | |
556 return; | |
557 } | |
558 | |
559 send_callbacks_[key] = callback; | |
560 | |
561 // Delay the send operation until all GCMClient is ready. | |
562 if (!delayed_task_controller_->CanRunTaskWithoutDelay()) { | |
563 delayed_task_controller_->AddTask(base::Bind(&GCMDriver::DoSend, | |
564 weak_ptr_factory_.GetWeakPtr(), | |
565 app_id, | |
566 receiver_id, | |
567 message)); | |
568 return; | |
569 } | |
570 | |
571 DoSend(app_id, receiver_id, message); | |
572 } | |
573 | |
574 void GCMDriver::DoSend(const std::string& app_id, | |
575 const std::string& receiver_id, | |
576 const GCMClient::OutgoingMessage& message) { | |
577 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
578 io_thread_->PostTask( | |
579 FROM_HERE, | |
580 base::Bind(&GCMDriver::IOWorker::Send, | |
581 base::Unretained(io_worker_.get()), | |
582 app_id, | |
583 receiver_id, | |
584 message)); | |
585 } | |
586 | |
587 GCMClient* GCMDriver::GetGCMClientForTesting() const { | |
588 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
589 return io_worker_ ? io_worker_->gcm_client_for_testing() : NULL; | |
590 } | |
591 | |
592 bool GCMDriver::IsStarted() const { | |
593 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
594 return !account_id_.empty(); | |
595 } | |
596 | |
597 bool GCMDriver::IsGCMClientReady() const { | |
598 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
599 return gcm_client_ready_; | |
600 } | |
601 | |
602 void GCMDriver::GetGCMStatistics(const GetGCMStatisticsCallback& callback, | |
603 bool clear_logs) { | |
604 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
605 DCHECK(!callback.is_null()); | |
606 | |
607 request_gcm_statistics_callback_ = callback; | |
608 io_thread_->PostTask( | |
609 FROM_HERE, | |
610 base::Bind(&GCMDriver::IOWorker::GetGCMStatistics, | |
611 base::Unretained(io_worker_.get()), | |
612 clear_logs)); | |
613 } | |
614 | |
615 void GCMDriver::SetGCMRecording(const GetGCMStatisticsCallback& callback, | |
616 bool recording) { | |
617 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
618 | |
619 request_gcm_statistics_callback_ = callback; | |
620 io_thread_->PostTask( | |
621 FROM_HERE, | |
622 base::Bind(&GCMDriver::IOWorker::SetGCMRecording, | |
623 base::Unretained(io_worker_.get()), | |
624 recording)); | |
625 } | |
626 | |
627 void GCMDriver::OnActiveAccountLogin() { | |
628 EnsureStarted(); | |
629 } | |
630 | |
631 void GCMDriver::OnActiveAccountLogout() { | |
632 CheckOut(); | |
633 } | |
634 | |
635 GCMClient::Result GCMDriver::EnsureStarted() { | |
636 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
637 | |
638 if (!gcm_enabled_) | |
639 return GCMClient::GCM_DISABLED; | |
640 | |
641 // Have any app requested the service? | |
642 if (app_handlers_.empty()) | |
643 return GCMClient::UNKNOWN_ERROR; | |
644 | |
645 // Is the user signed in? | |
646 const std::string account_id = identity_provider_->GetActiveAccountId(); | |
647 if (account_id.empty()) | |
648 return GCMClient::NOT_SIGNED_IN; | |
649 | |
650 // CheckIn could be called more than once when: | |
651 // 1) The password changes. | |
652 // 2) Register/send function calls it to ensure CheckIn is done. | |
653 if (account_id_ == account_id) | |
654 return GCMClient::SUCCESS; | |
655 account_id_ = account_id; | |
656 | |
657 DCHECK(!delayed_task_controller_); | |
658 delayed_task_controller_.reset(new DelayedTaskController); | |
659 | |
660 // Note that we need to pass weak pointer again since the existing weak | |
661 // pointer in IOWorker might have been invalidated when check-out occurs. | |
662 io_thread_->PostTask( | |
663 FROM_HERE, | |
664 base::Bind(&GCMDriver::IOWorker::Start, | |
665 base::Unretained(io_worker_.get()), | |
666 weak_ptr_factory_.GetWeakPtr())); | |
667 | |
668 return GCMClient::SUCCESS; | |
669 } | |
670 | |
671 void GCMDriver::RemoveCachedData() { | |
672 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
673 // Remove all the queued tasks since they no longer make sense after | |
674 // GCM service is stopped. | |
675 weak_ptr_factory_.InvalidateWeakPtrs(); | |
676 | |
677 account_id_.clear(); | |
678 gcm_client_ready_ = false; | |
679 delayed_task_controller_.reset(); | |
680 register_callbacks_.clear(); | |
681 send_callbacks_.clear(); | |
682 } | |
683 | |
684 void GCMDriver::CheckOut() { | |
685 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
686 | |
687 // We still proceed with the check-out logic even if the check-in is not | |
688 // initiated in the current session. This will make sure that all the | |
689 // persisted data written previously will get purged. | |
690 | |
691 RemoveCachedData(); | |
692 | |
693 io_thread_->PostTask( | |
694 FROM_HERE, | |
695 base::Bind(&GCMDriver::IOWorker::CheckOut, | |
696 base::Unretained(io_worker_.get()))); | |
697 } | |
698 | |
699 bool GCMDriver::IsAsyncOperationPending(const std::string& app_id) const { | |
700 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
701 return register_callbacks_.find(app_id) != register_callbacks_.end() || | |
702 unregister_callbacks_.find(app_id) != unregister_callbacks_.end(); | |
703 } | |
704 | |
705 void GCMDriver::RegisterFinished(const std::string& app_id, | |
706 const std::string& registration_id, | |
707 GCMClient::Result result) { | |
708 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
709 | |
710 std::map<std::string, RegisterCallback>::iterator callback_iter = | |
711 register_callbacks_.find(app_id); | |
712 if (callback_iter == register_callbacks_.end()) { | |
713 // The callback could have been removed when the app is uninstalled. | |
714 return; | |
715 } | |
716 | |
717 RegisterCallback callback = callback_iter->second; | |
718 register_callbacks_.erase(callback_iter); | |
719 callback.Run(registration_id, result); | |
720 } | |
721 | |
722 void GCMDriver::UnregisterFinished(const std::string& app_id, | |
723 GCMClient::Result result) { | |
724 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
725 | |
726 std::map<std::string, UnregisterCallback>::iterator callback_iter = | |
727 unregister_callbacks_.find(app_id); | |
728 if (callback_iter == unregister_callbacks_.end()) | |
729 return; | |
730 | |
731 UnregisterCallback callback = callback_iter->second; | |
732 unregister_callbacks_.erase(callback_iter); | |
733 callback.Run(result); | |
734 } | |
735 | |
736 void GCMDriver::SendFinished(const std::string& app_id, | |
737 const std::string& message_id, | |
738 GCMClient::Result result) { | |
739 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
740 | |
741 std::map<std::pair<std::string, std::string>, SendCallback>::iterator | |
742 callback_iter = send_callbacks_.find( | |
743 std::pair<std::string, std::string>(app_id, message_id)); | |
744 if (callback_iter == send_callbacks_.end()) { | |
745 // The callback could have been removed when the app is uninstalled. | |
746 return; | |
747 } | |
748 | |
749 SendCallback callback = callback_iter->second; | |
750 send_callbacks_.erase(callback_iter); | |
751 callback.Run(message_id, result); | |
752 } | |
753 | |
754 void GCMDriver::MessageReceived(const std::string& app_id, | |
755 GCMClient::IncomingMessage message) { | |
756 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
757 | |
758 // Drop the event if signed out. | |
759 if (account_id_.empty()) | |
760 return; | |
761 | |
762 GetAppHandler(app_id)->OnMessage(app_id, message); | |
763 } | |
764 | |
765 void GCMDriver::MessagesDeleted(const std::string& app_id) { | |
766 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
767 | |
768 // Drop the event if signed out. | |
769 if (account_id_.empty()) | |
770 return; | |
771 | |
772 GetAppHandler(app_id)->OnMessagesDeleted(app_id); | |
773 } | |
774 | |
775 void GCMDriver::MessageSendError( | |
776 const std::string& app_id, | |
777 const GCMClient::SendErrorDetails& send_error_details) { | |
778 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
779 | |
780 // Drop the event if signed out. | |
781 if (account_id_.empty()) | |
782 return; | |
783 | |
784 GetAppHandler(app_id)->OnSendError(app_id, send_error_details); | |
785 } | |
786 | |
787 void GCMDriver::GCMClientReady() { | |
788 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
789 | |
790 if (gcm_client_ready_) | |
791 return; | |
792 gcm_client_ready_ = true; | |
793 | |
794 delayed_task_controller_->SetReady(); | |
795 } | |
796 | |
797 GCMAppHandler* GCMDriver::GetAppHandler(const std::string& app_id) { | |
798 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
799 | |
800 std::map<std::string, GCMAppHandler*>::const_iterator iter = | |
801 app_handlers_.find(app_id); | |
802 return iter == app_handlers_.end() ? &default_app_handler_ : iter->second; | |
803 } | |
804 | |
805 void GCMDriver::GetGCMStatisticsFinished(GCMClient::GCMStatistics stats) { | |
806 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); | |
807 | |
808 // Normally request_gcm_statistics_callback_ would not be null. | |
809 if (!request_gcm_statistics_callback_.is_null()) | |
810 request_gcm_statistics_callback_.Run(stats); | |
811 else | |
812 LOG(WARNING) << "request_gcm_statistics_callback_ is NULL."; | |
813 } | |
814 | |
815 std::string GCMDriver::SignedInUserName() const { | |
816 if (IsStarted()) | |
817 return identity_provider_->GetActiveUsername(); | |
818 return std::string(); | |
819 } | |
820 | |
821 } // namespace gcm | |
OLD | NEW |