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 "components/gcm_driver/fake_gcm_client.h"
6
7 #include <stddef.h>
8
9 #include <algorithm>
10
11 #include "base/bind.h"
12 #include "base/check.h"
13 #include "base/location.h"
14 #include "base/sequenced_task_runner.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/sys_byteorder.h"
18 #include "base/threading/thread_task_runner_handle.h"
19 #include "base/time/time.h"
20 #include "base/timer/timer.h"
21 #include "google_apis/gcm/base/encryptor.h"
22 #include "google_apis/gcm/engine/account_mapping.h"
23 #include "net/base/ip_endpoint.h"
24
25 namespace gcm {
26
27 // static
GenerateGCMRegistrationID(const std::vector<std::string> & sender_ids)28 std::string FakeGCMClient::GenerateGCMRegistrationID(
29 const std::vector<std::string>& sender_ids) {
30 // GCMService normalizes the sender IDs by making them sorted.
31 std::vector<std::string> normalized_sender_ids = sender_ids;
32 std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end());
33
34 // Simulate the registration_id by concaternating all sender IDs.
35 // Set registration_id to empty to denote an error if sender_ids contains a
36 // hint.
37 std::string registration_id;
38 if (sender_ids.size() != 1 ||
39 sender_ids[0].find("error") == std::string::npos) {
40 for (size_t i = 0; i < normalized_sender_ids.size(); ++i) {
41 if (i > 0)
42 registration_id += ",";
43 registration_id += normalized_sender_ids[i];
44 }
45 }
46 return registration_id;
47 }
48
49 // static
GenerateInstanceIDToken(const std::string & authorized_entity,const std::string & scope)50 std::string FakeGCMClient::GenerateInstanceIDToken(
51 const std::string& authorized_entity, const std::string& scope) {
52 if (authorized_entity.find("error") != std::string::npos)
53 return "";
54 std::string token(authorized_entity);
55 token += ",";
56 token += scope;
57 return token;
58 }
59
FakeGCMClient(const scoped_refptr<base::SequencedTaskRunner> & ui_thread,const scoped_refptr<base::SequencedTaskRunner> & io_thread)60 FakeGCMClient::FakeGCMClient(
61 const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
62 const scoped_refptr<base::SequencedTaskRunner>& io_thread)
63 : delegate_(nullptr),
64 started_(false),
65 start_mode_(DELAYED_START),
66 start_mode_overridding_(RESPECT_START_MODE),
67 ui_thread_(ui_thread),
68 io_thread_(io_thread) {}
69
~FakeGCMClient()70 FakeGCMClient::~FakeGCMClient() {
71 }
72
Initialize(const ChromeBuildInfo & chrome_build_info,const base::FilePath & store_path,bool remove_account_mappings_with_email_key,const scoped_refptr<base::SequencedTaskRunner> & blocking_task_runner,scoped_refptr<base::SequencedTaskRunner> io_task_runner,base::RepeatingCallback<void (mojo::PendingReceiver<network::mojom::ProxyResolvingSocketFactory>)> get_socket_factory_callback,const scoped_refptr<network::SharedURLLoaderFactory> & url_loader_factory,network::NetworkConnectionTracker * network_connection_tracker,std::unique_ptr<Encryptor> encryptor,Delegate * delegate)73 void FakeGCMClient::Initialize(
74 const ChromeBuildInfo& chrome_build_info,
75 const base::FilePath& store_path,
76 bool remove_account_mappings_with_email_key,
77 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
78 scoped_refptr<base::SequencedTaskRunner> io_task_runner,
79 base::RepeatingCallback<void(
80 mojo::PendingReceiver<network::mojom::ProxyResolvingSocketFactory>)>
81 get_socket_factory_callback,
82 const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory,
83 network::NetworkConnectionTracker* network_connection_tracker,
84 std::unique_ptr<Encryptor> encryptor,
85 Delegate* delegate) {
86 product_category_for_subtypes_ =
87 chrome_build_info.product_category_for_subtypes;
88 delegate_ = delegate;
89 }
90
Start(StartMode start_mode)91 void FakeGCMClient::Start(StartMode start_mode) {
92 DCHECK(io_thread_->RunsTasksInCurrentSequence());
93
94 if (started_)
95 return;
96
97 if (start_mode == IMMEDIATE_START)
98 start_mode_ = IMMEDIATE_START;
99 if (start_mode_ == DELAYED_START ||
100 start_mode_overridding_ == FORCE_TO_ALWAYS_DELAY_START_GCM) {
101 return;
102 }
103
104 DoStart();
105 }
106
DoStart()107 void FakeGCMClient::DoStart() {
108 started_ = true;
109 base::ThreadTaskRunnerHandle::Get()->PostTask(
110 FROM_HERE,
111 base::BindOnce(&FakeGCMClient::Started, weak_ptr_factory_.GetWeakPtr()));
112 }
113
Stop()114 void FakeGCMClient::Stop() {
115 DCHECK(io_thread_->RunsTasksInCurrentSequence());
116 started_ = false;
117 delegate_->OnDisconnected();
118 }
119
Register(scoped_refptr<RegistrationInfo> registration_info)120 void FakeGCMClient::Register(
121 scoped_refptr<RegistrationInfo> registration_info) {
122 DCHECK(io_thread_->RunsTasksInCurrentSequence());
123
124 std::string registration_id;
125
126 GCMRegistrationInfo* gcm_registration_info =
127 GCMRegistrationInfo::FromRegistrationInfo(registration_info.get());
128 if (gcm_registration_info) {
129 registration_id = GenerateGCMRegistrationID(
130 gcm_registration_info->sender_ids);
131 }
132
133 InstanceIDTokenInfo* instance_id_token_info =
134 InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get());
135 if (instance_id_token_info) {
136 registration_id = GenerateInstanceIDToken(
137 instance_id_token_info->authorized_entity,
138 instance_id_token_info->scope);
139 }
140
141 base::ThreadTaskRunnerHandle::Get()->PostTask(
142 FROM_HERE, base::BindOnce(&FakeGCMClient::RegisterFinished,
143 weak_ptr_factory_.GetWeakPtr(),
144 std::move(registration_info), registration_id));
145 }
146
ValidateRegistration(scoped_refptr<RegistrationInfo> registration_info,const std::string & registration_id)147 bool FakeGCMClient::ValidateRegistration(
148 scoped_refptr<RegistrationInfo> registration_info,
149 const std::string& registration_id) {
150 return true;
151 }
152
Unregister(scoped_refptr<RegistrationInfo> registration_info)153 void FakeGCMClient::Unregister(
154 scoped_refptr<RegistrationInfo> registration_info) {
155 DCHECK(io_thread_->RunsTasksInCurrentSequence());
156
157 base::ThreadTaskRunnerHandle::Get()->PostTask(
158 FROM_HERE,
159 base::BindOnce(&FakeGCMClient::UnregisterFinished,
160 weak_ptr_factory_.GetWeakPtr(), registration_info));
161 }
162
Send(const std::string & app_id,const std::string & receiver_id,const OutgoingMessage & message)163 void FakeGCMClient::Send(const std::string& app_id,
164 const std::string& receiver_id,
165 const OutgoingMessage& message) {
166 DCHECK(io_thread_->RunsTasksInCurrentSequence());
167
168 base::ThreadTaskRunnerHandle::Get()->PostTask(
169 FROM_HERE,
170 base::BindOnce(&FakeGCMClient::SendFinished,
171 weak_ptr_factory_.GetWeakPtr(), app_id, message));
172 }
173
RecordDecryptionFailure(const std::string & app_id,GCMDecryptionResult result)174 void FakeGCMClient::RecordDecryptionFailure(const std::string& app_id,
175 GCMDecryptionResult result) {
176 recorder_.RecordDecryptionFailure(app_id, result);
177 }
178
SetRecording(bool recording)179 void FakeGCMClient::SetRecording(bool recording) {
180 recorder_.set_is_recording(recording);
181 }
182
ClearActivityLogs()183 void FakeGCMClient::ClearActivityLogs() {
184 recorder_.Clear();
185 }
186
GetStatistics() const187 GCMClient::GCMStatistics FakeGCMClient::GetStatistics() const {
188 GCMClient::GCMStatistics statistics;
189 statistics.is_recording = recorder_.is_recording();
190
191 recorder_.CollectActivities(&statistics.recorded_activities);
192 return statistics;
193 }
194
SetAccountTokens(const std::vector<AccountTokenInfo> & account_tokens)195 void FakeGCMClient::SetAccountTokens(
196 const std::vector<AccountTokenInfo>& account_tokens) {
197 }
198
UpdateAccountMapping(const AccountMapping & account_mapping)199 void FakeGCMClient::UpdateAccountMapping(
200 const AccountMapping& account_mapping) {
201 }
202
RemoveAccountMapping(const CoreAccountId & account_id)203 void FakeGCMClient::RemoveAccountMapping(const CoreAccountId& account_id) {}
204
SetLastTokenFetchTime(const base::Time & time)205 void FakeGCMClient::SetLastTokenFetchTime(const base::Time& time) {
206 }
207
UpdateHeartbeatTimer(std::unique_ptr<base::RetainingOneShotTimer> timer)208 void FakeGCMClient::UpdateHeartbeatTimer(
209 std::unique_ptr<base::RetainingOneShotTimer> timer) {}
210
AddInstanceIDData(const std::string & app_id,const std::string & instance_id,const std::string & extra_data)211 void FakeGCMClient::AddInstanceIDData(const std::string& app_id,
212 const std::string& instance_id,
213 const std::string& extra_data) {
214 instance_id_data_[app_id] = make_pair(instance_id, extra_data);
215 }
216
RemoveInstanceIDData(const std::string & app_id)217 void FakeGCMClient::RemoveInstanceIDData(const std::string& app_id) {
218 instance_id_data_.erase(app_id);
219 }
220
GetInstanceIDData(const std::string & app_id,std::string * instance_id,std::string * extra_data)221 void FakeGCMClient::GetInstanceIDData(const std::string& app_id,
222 std::string* instance_id,
223 std::string* extra_data) {
224 auto iter = instance_id_data_.find(app_id);
225 if (iter == instance_id_data_.end()) {
226 instance_id->clear();
227 extra_data->clear();
228 return;
229 }
230
231 *instance_id = iter->second.first;
232 *extra_data = iter->second.second;
233 }
234
AddHeartbeatInterval(const std::string & scope,int interval_ms)235 void FakeGCMClient::AddHeartbeatInterval(const std::string& scope,
236 int interval_ms) {
237 }
238
RemoveHeartbeatInterval(const std::string & scope)239 void FakeGCMClient::RemoveHeartbeatInterval(const std::string& scope) {
240 }
241
PerformDelayedStart()242 void FakeGCMClient::PerformDelayedStart() {
243 DCHECK(ui_thread_->RunsTasksInCurrentSequence());
244
245 io_thread_->PostTask(
246 FROM_HERE,
247 base::BindOnce(&FakeGCMClient::DoStart, weak_ptr_factory_.GetWeakPtr()));
248 }
249
ReceiveMessage(const std::string & app_id,const IncomingMessage & message)250 void FakeGCMClient::ReceiveMessage(const std::string& app_id,
251 const IncomingMessage& message) {
252 DCHECK(ui_thread_->RunsTasksInCurrentSequence());
253
254 io_thread_->PostTask(
255 FROM_HERE,
256 base::BindOnce(&FakeGCMClient::MessageReceived,
257 weak_ptr_factory_.GetWeakPtr(), app_id, message));
258 }
259
DeleteMessages(const std::string & app_id)260 void FakeGCMClient::DeleteMessages(const std::string& app_id) {
261 DCHECK(ui_thread_->RunsTasksInCurrentSequence());
262
263 io_thread_->PostTask(FROM_HERE,
264 base::BindOnce(&FakeGCMClient::MessagesDeleted,
265 weak_ptr_factory_.GetWeakPtr(), app_id));
266 }
267
Started()268 void FakeGCMClient::Started() {
269 delegate_->OnGCMReady(std::vector<AccountMapping>(), base::Time());
270 delegate_->OnConnected(net::IPEndPoint());
271 }
272
RegisterFinished(scoped_refptr<RegistrationInfo> registration_info,const std::string & registrion_id)273 void FakeGCMClient::RegisterFinished(
274 scoped_refptr<RegistrationInfo> registration_info,
275 const std::string& registrion_id) {
276 delegate_->OnRegisterFinished(std::move(registration_info), registrion_id,
277 registrion_id.empty() ? SERVER_ERROR : SUCCESS);
278 }
279
UnregisterFinished(scoped_refptr<RegistrationInfo> registration_info)280 void FakeGCMClient::UnregisterFinished(
281 scoped_refptr<RegistrationInfo> registration_info) {
282 delegate_->OnUnregisterFinished(std::move(registration_info),
283 GCMClient::SUCCESS);
284 }
285
SendFinished(const std::string & app_id,const OutgoingMessage & message)286 void FakeGCMClient::SendFinished(const std::string& app_id,
287 const OutgoingMessage& message) {
288 delegate_->OnSendFinished(app_id, message.id, SUCCESS);
289
290 // Simulate send error if message id contains a hint.
291 if (message.id.find("error") != std::string::npos) {
292 SendErrorDetails send_error_details;
293 send_error_details.message_id = message.id;
294 send_error_details.result = NETWORK_ERROR;
295 send_error_details.additional_data = message.data;
296 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
297 FROM_HERE,
298 base::BindOnce(&FakeGCMClient::MessageSendError,
299 weak_ptr_factory_.GetWeakPtr(), app_id,
300 send_error_details),
301 base::TimeDelta::FromMilliseconds(200));
302 } else if(message.id.find("ack") != std::string::npos) {
303 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
304 FROM_HERE,
305 base::BindOnce(&FakeGCMClient::SendAcknowledgement,
306 weak_ptr_factory_.GetWeakPtr(), app_id, message.id),
307 base::TimeDelta::FromMilliseconds(200));
308 }
309 }
310
MessageReceived(const std::string & app_id,const IncomingMessage & message)311 void FakeGCMClient::MessageReceived(const std::string& app_id,
312 const IncomingMessage& message) {
313 if (delegate_)
314 delegate_->OnMessageReceived(app_id, message);
315 }
316
MessagesDeleted(const std::string & app_id)317 void FakeGCMClient::MessagesDeleted(const std::string& app_id) {
318 if (delegate_)
319 delegate_->OnMessagesDeleted(app_id);
320 }
321
MessageSendError(const std::string & app_id,const GCMClient::SendErrorDetails & send_error_details)322 void FakeGCMClient::MessageSendError(
323 const std::string& app_id,
324 const GCMClient::SendErrorDetails& send_error_details) {
325 if (delegate_)
326 delegate_->OnMessageSendError(app_id, send_error_details);
327 }
328
SendAcknowledgement(const std::string & app_id,const std::string & message_id)329 void FakeGCMClient::SendAcknowledgement(const std::string& app_id,
330 const std::string& message_id) {
331 if (delegate_)
332 delegate_->OnSendAcknowledged(app_id, message_id);
333 }
334
335 } // namespace gcm
336