blob: 020d8efd223c04f3b8e518d1833305211dce3f0e [file] [log] [blame]
[email protected]df84c532014-04-25 15:36:541// 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
[email protected]8d41e5a2014-05-28 03:18:495#include "components/gcm_driver/gcm_driver.h"
[email protected]df84c532014-04-25 15:36:546
avi26062922015-12-26 00:14:187#include <stddef.h>
8
[email protected]c27c10792014-06-05 15:27:239#include <algorithm>
10
jianli753282a32015-01-09 02:07:4011#include "base/bind.h"
peterbfa736e2015-07-28 16:19:5512#include "base/files/file_path.h"
[email protected]df84c532014-04-25 15:36:5413#include "base/logging.h"
peter266a2aa42016-02-19 18:51:3914#include "base/metrics/histogram_macros.h"
[email protected]446f73c22014-05-14 20:47:1815#include "components/gcm_driver/gcm_app_handler.h"
[email protected]df84c532014-04-25 15:36:5416
17namespace gcm {
18
peteradd31f62015-10-09 10:18:5219namespace {
20
jianli7a0c9b62015-05-26 23:24:4721const size_t kMaxSenders = 100;
jianli7a0c9b62015-05-26 23:24:4722
peteradd31f62015-10-09 10:18:5223} // namespace
24
jianli7a0c9b62015-05-26 23:24:4725InstanceIDHandler::InstanceIDHandler() {
jianli10018b2d2015-05-11 21:14:1326}
27
jianli7a0c9b62015-05-26 23:24:4728InstanceIDHandler::~InstanceIDHandler() {
jianli10018b2d2015-05-11 21:14:1329}
30
jianlic5f6bd92015-05-28 02:23:4531void InstanceIDHandler::DeleteAllTokensForApp(
32 const std::string& app_id, const DeleteTokenCallback& callback) {
33 DeleteToken(app_id, "*", "*", callback);
34}
35
peterbfa736e2015-07-28 16:19:5536GCMDriver::GCMDriver(
37 const base::FilePath& store_path,
38 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner)
39 : weak_ptr_factory_(this) {
40 // The |blocking_task_runner| can be NULL for tests that do not need the
41 // encryption capabilities of the GCMDriver class.
42 if (blocking_task_runner)
43 encryption_provider_.Init(store_path, blocking_task_runner);
[email protected]9d7e5c02014-05-21 03:09:0344}
45
46GCMDriver::~GCMDriver() {
47}
48
[email protected]c27c10792014-06-05 15:27:2349void GCMDriver::Register(const std::string& app_id,
50 const std::vector<std::string>& sender_ids,
51 const RegisterCallback& callback) {
52 DCHECK(!app_id.empty());
jianli7a0c9b62015-05-26 23:24:4753 DCHECK(!sender_ids.empty() && sender_ids.size() <= kMaxSenders);
[email protected]c27c10792014-06-05 15:27:2354 DCHECK(!callback.is_null());
55
jianlif3e52af42015-01-21 23:18:4756 GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
[email protected]c27c10792014-06-05 15:27:2357 if (result != GCMClient::SUCCESS) {
58 callback.Run(std::string(), result);
59 return;
60 }
61
jianlif17b85a2014-10-29 21:42:3062 // If previous register operation is still in progress, bail out.
63 if (register_callbacks_.find(app_id) != register_callbacks_.end()) {
[email protected]c27c10792014-06-05 15:27:2364 callback.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING);
65 return;
66 }
67
68 // Normalize the sender IDs by making them sorted.
69 std::vector<std::string> normalized_sender_ids = sender_ids;
70 std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end());
71
72 register_callbacks_[app_id] = callback;
73
jianlif17b85a2014-10-29 21:42:3074 // If previous unregister operation is still in progress, wait until it
75 // finishes. We don't want to throw ASYNC_OPERATION_PENDING when the user
76 // uninstalls an app (ungistering) and then reinstalls the app again
77 // (registering).
78 std::map<std::string, UnregisterCallback>::iterator unregister_iter =
79 unregister_callbacks_.find(app_id);
80 if (unregister_iter != unregister_callbacks_.end()) {
81 // Replace the original unregister callback with an intermediate callback
82 // that will invoke the original unregister callback and trigger the pending
83 // registration after the unregistration finishes.
84 // Note that some parameters to RegisterAfterUnregister are specified here
85 // when the callback is created (base::Bind supports the partial binding
86 // of parameters).
87 unregister_iter->second = base::Bind(
88 &GCMDriver::RegisterAfterUnregister,
89 weak_ptr_factory_.GetWeakPtr(),
90 app_id,
91 normalized_sender_ids,
92 unregister_iter->second);
93 return;
94 }
95
[email protected]c27c10792014-06-05 15:27:2396 RegisterImpl(app_id, normalized_sender_ids);
97}
98
99void GCMDriver::Unregister(const std::string& app_id,
100 const UnregisterCallback& callback) {
johnme07b355a2015-02-19 17:00:51101 UnregisterInternal(app_id, nullptr /* sender_id */, callback);
102}
103
104void GCMDriver::UnregisterWithSenderId(
105 const std::string& app_id,
106 const std::string& sender_id,
107 const UnregisterCallback& callback) {
108 DCHECK(!sender_id.empty());
109 UnregisterInternal(app_id, &sender_id, callback);
110}
111
112void GCMDriver::UnregisterInternal(const std::string& app_id,
113 const std::string* sender_id,
114 const UnregisterCallback& callback) {
[email protected]c27c10792014-06-05 15:27:23115 DCHECK(!app_id.empty());
116 DCHECK(!callback.is_null());
117
jianlif3e52af42015-01-21 23:18:47118 GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
[email protected]c27c10792014-06-05 15:27:23119 if (result != GCMClient::SUCCESS) {
120 callback.Run(result);
121 return;
122 }
123
124 // If previous un/register operation is still in progress, bail out.
jianlif17b85a2014-10-29 21:42:30125 if (register_callbacks_.find(app_id) != register_callbacks_.end() ||
126 unregister_callbacks_.find(app_id) != unregister_callbacks_.end()) {
[email protected]c27c10792014-06-05 15:27:23127 callback.Run(GCMClient::ASYNC_OPERATION_PENDING);
128 return;
129 }
130
131 unregister_callbacks_[app_id] = callback;
132
johnme07b355a2015-02-19 17:00:51133 if (sender_id)
134 UnregisterWithSenderIdImpl(app_id, *sender_id);
135 else
136 UnregisterImpl(app_id);
[email protected]c27c10792014-06-05 15:27:23137}
138
139void GCMDriver::Send(const std::string& app_id,
140 const std::string& receiver_id,
mvanouwerkerkf8633deb2015-07-13 11:04:06141 const OutgoingMessage& message,
[email protected]c27c10792014-06-05 15:27:23142 const SendCallback& callback) {
143 DCHECK(!app_id.empty());
144 DCHECK(!receiver_id.empty());
145 DCHECK(!callback.is_null());
146
jianlif3e52af42015-01-21 23:18:47147 GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
[email protected]c27c10792014-06-05 15:27:23148 if (result != GCMClient::SUCCESS) {
149 callback.Run(std::string(), result);
150 return;
151 }
152
153 // If the message with send ID is still in progress, bail out.
154 std::pair<std::string, std::string> key(app_id, message.id);
155 if (send_callbacks_.find(key) != send_callbacks_.end()) {
156 callback.Run(message.id, GCMClient::INVALID_PARAMETER);
157 return;
158 }
159
160 send_callbacks_[key] = callback;
161
162 SendImpl(app_id, receiver_id, message);
163}
164
peter903cde432015-12-21 15:39:50165void GCMDriver::GetEncryptionInfo(
peterbfa736e2015-07-28 16:19:55166 const std::string& app_id,
peter903cde432015-12-21 15:39:50167 const GetEncryptionInfoCallback& callback) {
johnme36ae5802016-05-10 15:46:24168 encryption_provider_.GetEncryptionInfo(app_id, "" /* authorized_entity */,
169 callback);
peterbfa736e2015-07-28 16:19:55170}
171
johnme07b355a2015-02-19 17:00:51172void GCMDriver::UnregisterWithSenderIdImpl(const std::string& app_id,
173 const std::string& sender_id) {
174 NOTREACHED();
175}
176
[email protected]c27c10792014-06-05 15:27:23177void GCMDriver::RegisterFinished(const std::string& app_id,
178 const std::string& registration_id,
179 GCMClient::Result result) {
180 std::map<std::string, RegisterCallback>::iterator callback_iter =
181 register_callbacks_.find(app_id);
182 if (callback_iter == register_callbacks_.end()) {
183 // The callback could have been removed when the app is uninstalled.
184 return;
185 }
186
187 RegisterCallback callback = callback_iter->second;
188 register_callbacks_.erase(callback_iter);
189 callback.Run(registration_id, result);
190}
191
petera4795ae832016-02-17 11:35:27192void GCMDriver::RemoveEncryptionInfoAfterUnregister(const std::string& app_id,
193 GCMClient::Result result) {
194 encryption_provider_.RemoveEncryptionInfo(
johnme36ae5802016-05-10 15:46:24195 app_id, "" /* authorized_entity */,
196 base::Bind(&GCMDriver::UnregisterFinished, weak_ptr_factory_.GetWeakPtr(),
197 app_id, result));
petera4795ae832016-02-17 11:35:27198}
199
[email protected]c27c10792014-06-05 15:27:23200void GCMDriver::UnregisterFinished(const std::string& app_id,
201 GCMClient::Result result) {
202 std::map<std::string, UnregisterCallback>::iterator callback_iter =
203 unregister_callbacks_.find(app_id);
204 if (callback_iter == unregister_callbacks_.end())
205 return;
206
207 UnregisterCallback callback = callback_iter->second;
208 unregister_callbacks_.erase(callback_iter);
209 callback.Run(result);
210}
211
212void GCMDriver::SendFinished(const std::string& app_id,
213 const std::string& message_id,
214 GCMClient::Result result) {
215 std::map<std::pair<std::string, std::string>, SendCallback>::iterator
216 callback_iter = send_callbacks_.find(
217 std::pair<std::string, std::string>(app_id, message_id));
218 if (callback_iter == send_callbacks_.end()) {
219 // The callback could have been removed when the app is uninstalled.
220 return;
221 }
222
223 SendCallback callback = callback_iter->second;
224 send_callbacks_.erase(callback_iter);
225 callback.Run(message_id, result);
226}
227
[email protected]9d7e5c02014-05-21 03:09:03228void GCMDriver::Shutdown() {
[email protected]df84c532014-04-25 15:36:54229 for (GCMAppHandlerMap::const_iterator iter = app_handlers_.begin();
230 iter != app_handlers_.end(); ++iter) {
fgorski83afd872014-10-16 01:11:52231 DVLOG(1) << "Calling ShutdownHandler for: " << iter->first;
[email protected]df84c532014-04-25 15:36:54232 iter->second->ShutdownHandler();
233 }
234 app_handlers_.clear();
[email protected]df84c532014-04-25 15:36:54235}
236
[email protected]530f2162014-05-15 01:05:04237void GCMDriver::AddAppHandler(const std::string& app_id,
238 GCMAppHandler* handler) {
[email protected]df84c532014-04-25 15:36:54239 DCHECK(!app_id.empty());
240 DCHECK(handler);
[email protected]b7176262014-06-18 15:26:29241 DCHECK_EQ(app_handlers_.count(app_id), 0u);
[email protected]df84c532014-04-25 15:36:54242 app_handlers_[app_id] = handler;
fgorski83afd872014-10-16 01:11:52243 DVLOG(1) << "App handler added for: " << app_id;
[email protected]df84c532014-04-25 15:36:54244}
245
[email protected]530f2162014-05-15 01:05:04246void GCMDriver::RemoveAppHandler(const std::string& app_id) {
[email protected]df84c532014-04-25 15:36:54247 DCHECK(!app_id.empty());
[email protected]df84c532014-04-25 15:36:54248 app_handlers_.erase(app_id);
fgorski83afd872014-10-16 01:11:52249 DVLOG(1) << "App handler removed for: " << app_id;
[email protected]df84c532014-04-25 15:36:54250}
251
[email protected]530f2162014-05-15 01:05:04252GCMAppHandler* GCMDriver::GetAppHandler(const std::string& app_id) {
[email protected]b7176262014-06-18 15:26:29253 // Look for exact match.
[email protected]21b77652014-05-31 01:21:09254 GCMAppHandlerMap::const_iterator iter = app_handlers_.find(app_id);
[email protected]b7176262014-06-18 15:26:29255 if (iter != app_handlers_.end())
256 return iter->second;
257
258 // Ask the handlers whether they know how to handle it.
259 for (iter = app_handlers_.begin(); iter != app_handlers_.end(); ++iter) {
260 if (iter->second->CanHandle(app_id))
261 return iter->second;
262 }
263
264 return &default_app_handler_;
[email protected]df84c532014-04-25 15:36:54265}
266
[email protected]c27c10792014-06-05 15:27:23267bool GCMDriver::HasRegisterCallback(const std::string& app_id) {
268 return register_callbacks_.find(app_id) != register_callbacks_.end();
269}
270
271void GCMDriver::ClearCallbacks() {
272 register_callbacks_.clear();
273 unregister_callbacks_.clear();
274 send_callbacks_.clear();
275}
276
peteradd31f62015-10-09 10:18:52277void GCMDriver::DispatchMessage(const std::string& app_id,
278 const IncomingMessage& message) {
peter266a2aa42016-02-19 18:51:39279 encryption_provider_.DecryptMessage(
280 app_id, message, base::Bind(&GCMDriver::DispatchMessageInternal,
281 weak_ptr_factory_.GetWeakPtr(), app_id));
282}
283
284void GCMDriver::DispatchMessageInternal(
285 const std::string& app_id,
286 GCMEncryptionProvider::DecryptionResult result,
287 const IncomingMessage& message) {
288 UMA_HISTOGRAM_ENUMERATION("GCM.Crypto.DecryptMessageResult", result,
289 GCMEncryptionProvider::DECRYPTION_RESULT_LAST + 1);
290
291 switch (result) {
292 case GCMEncryptionProvider::DECRYPTION_RESULT_UNENCRYPTED:
293 case GCMEncryptionProvider::DECRYPTION_RESULT_DECRYPTED:
294 GetAppHandler(app_id)->OnMessage(app_id, message);
295 return;
296 case GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_ENCRYPTION_HEADER:
297 case GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER:
298 case GCMEncryptionProvider::DECRYPTION_RESULT_NO_KEYS:
299 case GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_SHARED_SECRET:
300 case GCMEncryptionProvider::DECRYPTION_RESULT_INVALID_PAYLOAD:
301 RecordDecryptionFailure(app_id, result);
302 return;
peteradd31f62015-10-09 10:18:52303 }
304
peter266a2aa42016-02-19 18:51:39305 NOTREACHED();
peteradd31f62015-10-09 10:18:52306}
307
jianlif17b85a2014-10-29 21:42:30308void GCMDriver::RegisterAfterUnregister(
309 const std::string& app_id,
310 const std::vector<std::string>& normalized_sender_ids,
311 const UnregisterCallback& unregister_callback,
312 GCMClient::Result result) {
313 // Invoke the original unregister callback.
314 unregister_callback.Run(result);
315
316 // Trigger the pending registration.
317 DCHECK(register_callbacks_.find(app_id) != register_callbacks_.end());
318 RegisterImpl(app_id, normalized_sender_ids);
[email protected]c27c10792014-06-05 15:27:23319}
320
[email protected]df84c532014-04-25 15:36:54321} // namespace gcm