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"
9 #include "base/logging.h"
10 #include "base/metrics/field_trial.h"
11 #include "components/gcm_driver/gcm_app_handler.h"
16 const char kGCMFieldTrialName
[] = "GCM";
17 const char kGCMFieldTrialEnabledGroupName
[] = "Enabled";
21 bool GCMDriver::IsAllowedForAllUsers() {
22 std::string group_name
=
23 base::FieldTrialList::FindFullName(kGCMFieldTrialName
);
24 return group_name
== kGCMFieldTrialEnabledGroupName
;
27 GCMDriver::GCMDriver() : weak_ptr_factory_(this) {
30 GCMDriver::~GCMDriver() {
33 void GCMDriver::Register(const std::string
& app_id
,
34 const std::vector
<std::string
>& sender_ids
,
35 const RegisterCallback
& callback
) {
36 DCHECK(!app_id
.empty());
37 DCHECK(!sender_ids
.empty());
38 DCHECK(!callback
.is_null());
40 GCMClient::Result result
= EnsureStarted();
41 if (result
!= GCMClient::SUCCESS
) {
42 callback
.Run(std::string(), result
);
46 // If previous register operation is still in progress, bail out.
47 if (register_callbacks_
.find(app_id
) != register_callbacks_
.end()) {
48 callback
.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING
);
52 // Normalize the sender IDs by making them sorted.
53 std::vector
<std::string
> normalized_sender_ids
= sender_ids
;
54 std::sort(normalized_sender_ids
.begin(), normalized_sender_ids
.end());
56 register_callbacks_
[app_id
] = callback
;
58 // If previous unregister operation is still in progress, wait until it
59 // finishes. We don't want to throw ASYNC_OPERATION_PENDING when the user
60 // uninstalls an app (ungistering) and then reinstalls the app again
62 std::map
<std::string
, UnregisterCallback
>::iterator unregister_iter
=
63 unregister_callbacks_
.find(app_id
);
64 if (unregister_iter
!= unregister_callbacks_
.end()) {
65 // Replace the original unregister callback with an intermediate callback
66 // that will invoke the original unregister callback and trigger the pending
67 // registration after the unregistration finishes.
68 // Note that some parameters to RegisterAfterUnregister are specified here
69 // when the callback is created (base::Bind supports the partial binding
71 unregister_iter
->second
= base::Bind(
72 &GCMDriver::RegisterAfterUnregister
,
73 weak_ptr_factory_
.GetWeakPtr(),
75 normalized_sender_ids
,
76 unregister_iter
->second
);
80 RegisterImpl(app_id
, normalized_sender_ids
);
83 void GCMDriver::Unregister(const std::string
& app_id
,
84 const UnregisterCallback
& callback
) {
85 DCHECK(!app_id
.empty());
86 DCHECK(!callback
.is_null());
88 GCMClient::Result result
= EnsureStarted();
89 if (result
!= GCMClient::SUCCESS
) {
94 // If previous un/register operation is still in progress, bail out.
95 if (register_callbacks_
.find(app_id
) != register_callbacks_
.end() ||
96 unregister_callbacks_
.find(app_id
) != unregister_callbacks_
.end()) {
97 callback
.Run(GCMClient::ASYNC_OPERATION_PENDING
);
101 unregister_callbacks_
[app_id
] = callback
;
103 UnregisterImpl(app_id
);
106 void GCMDriver::Send(const std::string
& app_id
,
107 const std::string
& receiver_id
,
108 const GCMClient::OutgoingMessage
& message
,
109 const SendCallback
& callback
) {
110 DCHECK(!app_id
.empty());
111 DCHECK(!receiver_id
.empty());
112 DCHECK(!callback
.is_null());
114 GCMClient::Result result
= EnsureStarted();
115 if (result
!= GCMClient::SUCCESS
) {
116 callback
.Run(std::string(), result
);
120 // If the message with send ID is still in progress, bail out.
121 std::pair
<std::string
, std::string
> key(app_id
, message
.id
);
122 if (send_callbacks_
.find(key
) != send_callbacks_
.end()) {
123 callback
.Run(message
.id
, GCMClient::INVALID_PARAMETER
);
127 send_callbacks_
[key
] = callback
;
129 SendImpl(app_id
, receiver_id
, message
);
132 void GCMDriver::RegisterFinished(const std::string
& app_id
,
133 const std::string
& registration_id
,
134 GCMClient::Result result
) {
135 std::map
<std::string
, RegisterCallback
>::iterator callback_iter
=
136 register_callbacks_
.find(app_id
);
137 if (callback_iter
== register_callbacks_
.end()) {
138 // The callback could have been removed when the app is uninstalled.
142 RegisterCallback callback
= callback_iter
->second
;
143 register_callbacks_
.erase(callback_iter
);
144 callback
.Run(registration_id
, result
);
147 void GCMDriver::UnregisterFinished(const std::string
& app_id
,
148 GCMClient::Result result
) {
149 std::map
<std::string
, UnregisterCallback
>::iterator callback_iter
=
150 unregister_callbacks_
.find(app_id
);
151 if (callback_iter
== unregister_callbacks_
.end())
154 UnregisterCallback callback
= callback_iter
->second
;
155 unregister_callbacks_
.erase(callback_iter
);
156 callback
.Run(result
);
159 void GCMDriver::SendFinished(const std::string
& app_id
,
160 const std::string
& message_id
,
161 GCMClient::Result result
) {
162 std::map
<std::pair
<std::string
, std::string
>, SendCallback
>::iterator
163 callback_iter
= send_callbacks_
.find(
164 std::pair
<std::string
, std::string
>(app_id
, message_id
));
165 if (callback_iter
== send_callbacks_
.end()) {
166 // The callback could have been removed when the app is uninstalled.
170 SendCallback callback
= callback_iter
->second
;
171 send_callbacks_
.erase(callback_iter
);
172 callback
.Run(message_id
, result
);
175 void GCMDriver::Shutdown() {
176 for (GCMAppHandlerMap::const_iterator iter
= app_handlers_
.begin();
177 iter
!= app_handlers_
.end(); ++iter
) {
178 DVLOG(1) << "Calling ShutdownHandler for: " << iter
->first
;
179 iter
->second
->ShutdownHandler();
181 app_handlers_
.clear();
184 void GCMDriver::AddAppHandler(const std::string
& app_id
,
185 GCMAppHandler
* handler
) {
186 DCHECK(!app_id
.empty());
188 DCHECK_EQ(app_handlers_
.count(app_id
), 0u);
189 app_handlers_
[app_id
] = handler
;
190 DVLOG(1) << "App handler added for: " << app_id
;
193 void GCMDriver::RemoveAppHandler(const std::string
& app_id
) {
194 DCHECK(!app_id
.empty());
195 app_handlers_
.erase(app_id
);
196 DVLOG(1) << "App handler removed for: " << app_id
;
199 GCMAppHandler
* GCMDriver::GetAppHandler(const std::string
& app_id
) {
200 // Look for exact match.
201 GCMAppHandlerMap::const_iterator iter
= app_handlers_
.find(app_id
);
202 if (iter
!= app_handlers_
.end())
205 // Ask the handlers whether they know how to handle it.
206 for (iter
= app_handlers_
.begin(); iter
!= app_handlers_
.end(); ++iter
) {
207 if (iter
->second
->CanHandle(app_id
))
211 return &default_app_handler_
;
214 bool GCMDriver::HasRegisterCallback(const std::string
& app_id
) {
215 return register_callbacks_
.find(app_id
) != register_callbacks_
.end();
218 void GCMDriver::ClearCallbacks() {
219 register_callbacks_
.clear();
220 unregister_callbacks_
.clear();
221 send_callbacks_
.clear();
224 void GCMDriver::RegisterAfterUnregister(
225 const std::string
& app_id
,
226 const std::vector
<std::string
>& normalized_sender_ids
,
227 const UnregisterCallback
& unregister_callback
,
228 GCMClient::Result result
) {
229 // Invoke the original unregister callback.
230 unregister_callback
.Run(result
);
232 // Trigger the pending registration.
233 DCHECK(register_callbacks_
.find(app_id
) != register_callbacks_
.end());
234 RegisterImpl(app_id
, normalized_sender_ids
);