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.
5 #include "components/gcm_driver/gcm_driver.h"
10 #include "base/files/file_path.h"
11 #include "base/logging.h"
12 #include "components/gcm_driver/gcm_app_handler.h"
16 const size_t kMaxSenders
= 100;
18 InstanceIDHandler::InstanceIDHandler() {
21 InstanceIDHandler::~InstanceIDHandler() {
24 void InstanceIDHandler::DeleteAllTokensForApp(
25 const std::string
& app_id
, const DeleteTokenCallback
& callback
) {
26 DeleteToken(app_id
, "*", "*", callback
);
30 const base::FilePath
& store_path
,
31 const scoped_refptr
<base::SequencedTaskRunner
>& blocking_task_runner
)
32 : weak_ptr_factory_(this) {
33 // The |blocking_task_runner| can be NULL for tests that do not need the
34 // encryption capabilities of the GCMDriver class.
35 if (blocking_task_runner
)
36 encryption_provider_
.Init(store_path
, blocking_task_runner
);
39 GCMDriver::~GCMDriver() {
42 void GCMDriver::Register(const std::string
& app_id
,
43 const std::vector
<std::string
>& sender_ids
,
44 const RegisterCallback
& callback
) {
45 DCHECK(!app_id
.empty());
46 DCHECK(!sender_ids
.empty() && sender_ids
.size() <= kMaxSenders
);
47 DCHECK(!callback
.is_null());
49 GCMClient::Result result
= EnsureStarted(GCMClient::IMMEDIATE_START
);
50 if (result
!= GCMClient::SUCCESS
) {
51 callback
.Run(std::string(), result
);
55 // If previous register operation is still in progress, bail out.
56 if (register_callbacks_
.find(app_id
) != register_callbacks_
.end()) {
57 callback
.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING
);
61 // Normalize the sender IDs by making them sorted.
62 std::vector
<std::string
> normalized_sender_ids
= sender_ids
;
63 std::sort(normalized_sender_ids
.begin(), normalized_sender_ids
.end());
65 register_callbacks_
[app_id
] = callback
;
67 // If previous unregister operation is still in progress, wait until it
68 // finishes. We don't want to throw ASYNC_OPERATION_PENDING when the user
69 // uninstalls an app (ungistering) and then reinstalls the app again
71 std::map
<std::string
, UnregisterCallback
>::iterator unregister_iter
=
72 unregister_callbacks_
.find(app_id
);
73 if (unregister_iter
!= unregister_callbacks_
.end()) {
74 // Replace the original unregister callback with an intermediate callback
75 // that will invoke the original unregister callback and trigger the pending
76 // registration after the unregistration finishes.
77 // Note that some parameters to RegisterAfterUnregister are specified here
78 // when the callback is created (base::Bind supports the partial binding
80 unregister_iter
->second
= base::Bind(
81 &GCMDriver::RegisterAfterUnregister
,
82 weak_ptr_factory_
.GetWeakPtr(),
84 normalized_sender_ids
,
85 unregister_iter
->second
);
89 RegisterImpl(app_id
, normalized_sender_ids
);
92 void GCMDriver::Unregister(const std::string
& app_id
,
93 const UnregisterCallback
& callback
) {
94 UnregisterInternal(app_id
, nullptr /* sender_id */, callback
);
97 void GCMDriver::UnregisterWithSenderId(
98 const std::string
& app_id
,
99 const std::string
& sender_id
,
100 const UnregisterCallback
& callback
) {
101 DCHECK(!sender_id
.empty());
102 UnregisterInternal(app_id
, &sender_id
, callback
);
105 void GCMDriver::UnregisterInternal(const std::string
& app_id
,
106 const std::string
* sender_id
,
107 const UnregisterCallback
& callback
) {
108 DCHECK(!app_id
.empty());
109 DCHECK(!callback
.is_null());
111 GCMClient::Result result
= EnsureStarted(GCMClient::IMMEDIATE_START
);
112 if (result
!= GCMClient::SUCCESS
) {
113 callback
.Run(result
);
117 // If previous un/register operation is still in progress, bail out.
118 if (register_callbacks_
.find(app_id
) != register_callbacks_
.end() ||
119 unregister_callbacks_
.find(app_id
) != unregister_callbacks_
.end()) {
120 callback
.Run(GCMClient::ASYNC_OPERATION_PENDING
);
124 unregister_callbacks_
[app_id
] = callback
;
127 UnregisterWithSenderIdImpl(app_id
, *sender_id
);
129 UnregisterImpl(app_id
);
132 void GCMDriver::Send(const std::string
& app_id
,
133 const std::string
& receiver_id
,
134 const OutgoingMessage
& message
,
135 const SendCallback
& callback
) {
136 DCHECK(!app_id
.empty());
137 DCHECK(!receiver_id
.empty());
138 DCHECK(!callback
.is_null());
140 GCMClient::Result result
= EnsureStarted(GCMClient::IMMEDIATE_START
);
141 if (result
!= GCMClient::SUCCESS
) {
142 callback
.Run(std::string(), result
);
146 // If the message with send ID is still in progress, bail out.
147 std::pair
<std::string
, std::string
> key(app_id
, message
.id
);
148 if (send_callbacks_
.find(key
) != send_callbacks_
.end()) {
149 callback
.Run(message
.id
, GCMClient::INVALID_PARAMETER
);
153 send_callbacks_
[key
] = callback
;
155 SendImpl(app_id
, receiver_id
, message
);
158 void GCMDriver::GetPublicKey(
159 const std::string
& app_id
,
160 const GetPublicKeyCallback
& callback
) {
161 encryption_provider_
.GetPublicKey(app_id
, callback
);
164 void GCMDriver::UnregisterWithSenderIdImpl(const std::string
& app_id
,
165 const std::string
& sender_id
) {
169 void GCMDriver::RegisterFinished(const std::string
& app_id
,
170 const std::string
& registration_id
,
171 GCMClient::Result result
) {
172 std::map
<std::string
, RegisterCallback
>::iterator callback_iter
=
173 register_callbacks_
.find(app_id
);
174 if (callback_iter
== register_callbacks_
.end()) {
175 // The callback could have been removed when the app is uninstalled.
179 RegisterCallback callback
= callback_iter
->second
;
180 register_callbacks_
.erase(callback_iter
);
181 callback
.Run(registration_id
, result
);
184 void GCMDriver::UnregisterFinished(const std::string
& app_id
,
185 GCMClient::Result result
) {
186 std::map
<std::string
, UnregisterCallback
>::iterator callback_iter
=
187 unregister_callbacks_
.find(app_id
);
188 if (callback_iter
== unregister_callbacks_
.end())
191 UnregisterCallback callback
= callback_iter
->second
;
192 unregister_callbacks_
.erase(callback_iter
);
193 callback
.Run(result
);
196 void GCMDriver::SendFinished(const std::string
& app_id
,
197 const std::string
& message_id
,
198 GCMClient::Result result
) {
199 std::map
<std::pair
<std::string
, std::string
>, SendCallback
>::iterator
200 callback_iter
= send_callbacks_
.find(
201 std::pair
<std::string
, std::string
>(app_id
, message_id
));
202 if (callback_iter
== send_callbacks_
.end()) {
203 // The callback could have been removed when the app is uninstalled.
207 SendCallback callback
= callback_iter
->second
;
208 send_callbacks_
.erase(callback_iter
);
209 callback
.Run(message_id
, result
);
212 void GCMDriver::Shutdown() {
213 for (GCMAppHandlerMap::const_iterator iter
= app_handlers_
.begin();
214 iter
!= app_handlers_
.end(); ++iter
) {
215 DVLOG(1) << "Calling ShutdownHandler for: " << iter
->first
;
216 iter
->second
->ShutdownHandler();
218 app_handlers_
.clear();
221 void GCMDriver::AddAppHandler(const std::string
& app_id
,
222 GCMAppHandler
* handler
) {
223 DCHECK(!app_id
.empty());
225 DCHECK_EQ(app_handlers_
.count(app_id
), 0u);
226 app_handlers_
[app_id
] = handler
;
227 DVLOG(1) << "App handler added for: " << app_id
;
230 void GCMDriver::RemoveAppHandler(const std::string
& app_id
) {
231 DCHECK(!app_id
.empty());
232 app_handlers_
.erase(app_id
);
233 DVLOG(1) << "App handler removed for: " << app_id
;
236 GCMAppHandler
* GCMDriver::GetAppHandler(const std::string
& app_id
) {
237 // Look for exact match.
238 GCMAppHandlerMap::const_iterator iter
= app_handlers_
.find(app_id
);
239 if (iter
!= app_handlers_
.end())
242 // Ask the handlers whether they know how to handle it.
243 for (iter
= app_handlers_
.begin(); iter
!= app_handlers_
.end(); ++iter
) {
244 if (iter
->second
->CanHandle(app_id
))
248 return &default_app_handler_
;
251 bool GCMDriver::HasRegisterCallback(const std::string
& app_id
) {
252 return register_callbacks_
.find(app_id
) != register_callbacks_
.end();
255 void GCMDriver::ClearCallbacks() {
256 register_callbacks_
.clear();
257 unregister_callbacks_
.clear();
258 send_callbacks_
.clear();
261 void GCMDriver::RegisterAfterUnregister(
262 const std::string
& app_id
,
263 const std::vector
<std::string
>& normalized_sender_ids
,
264 const UnregisterCallback
& unregister_callback
,
265 GCMClient::Result result
) {
266 // Invoke the original unregister callback.
267 unregister_callback
.Run(result
);
269 // Trigger the pending registration.
270 DCHECK(register_callbacks_
.find(app_id
) != register_callbacks_
.end());
271 RegisterImpl(app_id
, normalized_sender_ids
);