1 // Copyright 2020 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/nearby_sharing/nearby_sharing_service_impl.h"
6
7 #include <utility>
8
9 #include "ash/public/cpp/session/session_controller.h"
10 #include "base/barrier_closure.h"
11 #include "base/bind.h"
12 #include "base/files/file.h"
13 #include "base/logging.h"
14 #include "base/numerics/checked_math.h"
15 #include "base/rand_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/system/sys_info.h"
18 #include "base/task/post_task.h"
19 #include "base/task_runner_util.h"
20 #include "base/threading/sequenced_task_runner_handle.h"
21 #include "chrome/browser/download/download_prefs.h"
22 #include "chrome/browser/nearby_sharing/certificates/common.h"
23 #include "chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.h"
24 #include "chrome/browser/nearby_sharing/certificates/nearby_share_encrypted_metadata_key.h"
25 #include "chrome/browser/nearby_sharing/client/nearby_share_client_impl.h"
26 #include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h"
27 #include "chrome/browser/nearby_sharing/constants.h"
28 #include "chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl.h"
29 #include "chrome/browser/nearby_sharing/fast_initiation_manager.h"
30 #include "chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl.h"
31 #include "chrome/browser/nearby_sharing/logging/logging.h"
32 #include "chrome/browser/nearby_sharing/nearby_connections_manager.h"
33 #include "chrome/browser/nearby_sharing/nearby_share_default_device_name.h"
34 #include "chrome/browser/nearby_sharing/nearby_share_metrics_logger.h"
35 #include "chrome/browser/nearby_sharing/paired_key_verification_runner.h"
36 #include "chrome/browser/nearby_sharing/transfer_metadata.h"
37 #include "chrome/browser/nearby_sharing/transfer_metadata_builder.h"
38 #include "chrome/browser/profiles/profile.h"
39 #include "chrome/browser/signin/identity_manager_factory.h"
40 #include "chrome/services/sharing/public/cpp/advertisement.h"
41 #include "chrome/services/sharing/public/cpp/conversions.h"
42 #include "chromeos/services/nearby/public/mojom/nearby_connections_types.mojom.h"
43 #include "chromeos/services/nearby/public/mojom/nearby_share_target_types.mojom.h"
44 #include "components/prefs/pref_service.h"
45 #include "content/public/browser/download_manager.h"
46 #include "content/public/browser/storage_partition.h"
47 #include "crypto/random.h"
48 #include "device/bluetooth/bluetooth_adapter_factory.h"
49 #include "services/network/public/cpp/shared_url_loader_factory.h"
50 #include "url/gurl.h"
51
52 namespace {
53
54 constexpr base::TimeDelta kBackgroundAdvertisementRotationDelayMin =
55 base::TimeDelta::FromMinutes(12);
56 constexpr base::TimeDelta kBackgroundAdvertisementRotationDelayMax =
57 base::TimeDelta::FromMinutes(15);
58 constexpr base::TimeDelta kInvalidateSurfaceStateDelayAfterTransferDone =
59 base::TimeDelta::FromMilliseconds(3000);
60
61 // Used to hash a token into a 4 digit string.
62 constexpr int kHashModulo = 9973;
63 constexpr int kHashBaseMultiplier = 31;
64
ReceiveSurfaceStateToString(NearbySharingService::ReceiveSurfaceState state)65 std::string ReceiveSurfaceStateToString(
66 NearbySharingService::ReceiveSurfaceState state) {
67 switch (state) {
68 case NearbySharingService::ReceiveSurfaceState::kForeground:
69 return "FOREGROUND";
70 case NearbySharingService::ReceiveSurfaceState::kBackground:
71 return "BACKGROUND";
72 case NearbySharingService::ReceiveSurfaceState::kUnknown:
73 return "UNKNOWN";
74 }
75 }
76
SendSurfaceStateToString(NearbySharingService::SendSurfaceState state)77 std::string SendSurfaceStateToString(
78 NearbySharingService::SendSurfaceState state) {
79 switch (state) {
80 case NearbySharingService::SendSurfaceState::kForeground:
81 return "FOREGROUND";
82 case NearbySharingService::SendSurfaceState::kBackground:
83 return "BACKGROUND";
84 case NearbySharingService::SendSurfaceState::kUnknown:
85 return "UNKNOWN";
86 }
87 }
88
PowerLevelToString(PowerLevel level)89 std::string PowerLevelToString(PowerLevel level) {
90 switch (level) {
91 case PowerLevel::kLowPower:
92 return "LOW_POWER";
93 case PowerLevel::kMediumPower:
94 return "MEDIUM_POWER";
95 case PowerLevel::kHighPower:
96 return "HIGH_POWER";
97 case PowerLevel::kUnknown:
98 return "UNKNOWN";
99 }
100 }
101
GetDeviceName(const sharing::mojom::AdvertisementPtr & advertisement,const base::Optional<NearbyShareDecryptedPublicCertificate> & certificate)102 base::Optional<std::string> GetDeviceName(
103 const sharing::mojom::AdvertisementPtr& advertisement,
104 const base::Optional<NearbyShareDecryptedPublicCertificate>& certificate) {
105 DCHECK(advertisement);
106
107 // Device name is always included when visible to everyone.
108 if (advertisement->device_name)
109 return *(advertisement->device_name);
110
111 // For contacts only advertisements, we can't do anything without the
112 // certificate.
113 if (!certificate || !certificate->unencrypted_metadata().has_device_name())
114 return base::nullopt;
115
116 return certificate->unencrypted_metadata().device_name();
117 }
118
GetDeviceId(const std::string & endpoint_id,const base::Optional<NearbyShareDecryptedPublicCertificate> & certificate)119 std::string GetDeviceId(
120 const std::string& endpoint_id,
121 const base::Optional<NearbyShareDecryptedPublicCertificate>& certificate) {
122 if (!certificate || certificate->id().empty())
123 return endpoint_id;
124
125 return std::string(certificate->id().begin(), certificate->id().end());
126 }
127
ToFourDigitString(const base::Optional<std::vector<uint8_t>> & bytes)128 base::Optional<std::string> ToFourDigitString(
129 const base::Optional<std::vector<uint8_t>>& bytes) {
130 if (!bytes)
131 return base::nullopt;
132
133 int hash = 0;
134 int multiplier = 1;
135 for (uint8_t byte : *bytes) {
136 // Java bytes are signed two's complement so cast to use the correct sign.
137 hash = (hash + static_cast<int8_t>(byte) * multiplier) % kHashModulo;
138 multiplier = (multiplier * kHashBaseMultiplier) % kHashModulo;
139 }
140
141 return base::StringPrintf("%04d", std::abs(hash));
142 }
143
IsOutOfStorage(base::FilePath file_path,int64_t storage_required,base::Optional<int64_t> free_disk_space_for_testing)144 bool IsOutOfStorage(base::FilePath file_path,
145 int64_t storage_required,
146 base::Optional<int64_t> free_disk_space_for_testing) {
147 int64_t free_space = free_disk_space_for_testing.value_or(
148 base::SysInfo::AmountOfFreeDiskSpace(file_path));
149 return free_space < storage_required;
150 }
151
DoAttachmentsExceedThreshold(const ShareTarget & share_target,int64_t threshold)152 bool DoAttachmentsExceedThreshold(const ShareTarget& share_target,
153 int64_t threshold) {
154 for (const auto& attachment : share_target.text_attachments) {
155 if (attachment.size() > threshold)
156 return false;
157
158 threshold -= attachment.size();
159 }
160
161 for (const auto& attachment : share_target.file_attachments) {
162 if (attachment.size() > threshold)
163 return false;
164
165 threshold -= attachment.size();
166 }
167
168 return true;
169 }
170
CheckFileSizeForDataUsagePreference(DataUsage client_preference,const ShareTarget & share_target)171 DataUsage CheckFileSizeForDataUsagePreference(DataUsage client_preference,
172 const ShareTarget& share_target) {
173 if (client_preference == DataUsage::kOffline)
174 return client_preference;
175
176 if (DoAttachmentsExceedThreshold(share_target, kOnlineFileSizeLimitBytes))
177 return DataUsage::kOffline;
178
179 return client_preference;
180 }
181
GeneratePayloadId()182 int64_t GeneratePayloadId() {
183 int64_t payload_id = 0;
184 crypto::RandBytes(&payload_id, sizeof(payload_id));
185 return payload_id;
186 }
187
188 // Wraps a call to OnTransferUpdate() to filter any updates after receiving a
189 // final status.
190 class TransferUpdateDecorator : public TransferUpdateCallback {
191 public:
192 using Callback = base::RepeatingCallback<void(const ShareTarget&,
193 const TransferMetadata&)>;
194
TransferUpdateDecorator(Callback callback)195 explicit TransferUpdateDecorator(Callback callback)
196 : callback_(std::move(callback)) {}
197 TransferUpdateDecorator(const TransferUpdateDecorator&) = delete;
198 TransferUpdateDecorator& operator=(const TransferUpdateDecorator&) = delete;
199 ~TransferUpdateDecorator() override = default;
200
OnTransferUpdate(const ShareTarget & share_target,const TransferMetadata & transfer_metadata)201 void OnTransferUpdate(const ShareTarget& share_target,
202 const TransferMetadata& transfer_metadata) override {
203 NS_LOG(VERBOSE) << __func__ << ": Transfer update decorator: "
204 << "Transfer update for share target with ID "
205 << share_target.id << ": "
206 << TransferMetadata::StatusToString(
207 transfer_metadata.status());
208 if (got_final_status_) {
209 // If we already got a final status, we can ignore any subsequent final
210 // statuses caused by race conditions.
211 return;
212 }
213 got_final_status_ = transfer_metadata.is_final_status();
214 callback_.Run(share_target, transfer_metadata);
215 }
216
217 private:
218 bool got_final_status_ = false;
219 Callback callback_;
220 };
221
222 } // namespace
223
NearbySharingServiceImpl(PrefService * prefs,NotificationDisplayService * notification_display_service,Profile * profile,std::unique_ptr<NearbyConnectionsManager> nearby_connections_manager,NearbyProcessManager * process_manager,std::unique_ptr<PowerClient> power_client)224 NearbySharingServiceImpl::NearbySharingServiceImpl(
225 PrefService* prefs,
226 NotificationDisplayService* notification_display_service,
227 Profile* profile,
228 std::unique_ptr<NearbyConnectionsManager> nearby_connections_manager,
229 NearbyProcessManager* process_manager,
230 std::unique_ptr<PowerClient> power_client)
231 : profile_(profile),
232 nearby_connections_manager_(std::move(nearby_connections_manager)),
233 process_manager_(process_manager),
234 power_client_(std::move(power_client)),
235 http_client_factory_(std::make_unique<NearbyShareClientFactoryImpl>(
236 IdentityManagerFactory::GetForProfile(profile),
237 profile->GetURLLoaderFactory(),
238 &nearby_share_http_notifier_)),
239 local_device_data_manager_(
240 NearbyShareLocalDeviceDataManagerImpl::Factory::Create(
241 prefs,
242 http_client_factory_.get(),
243 GetNearbyShareDefaultDeviceName(profile_))),
244 contact_manager_(NearbyShareContactManagerImpl::Factory::Create(
245 prefs,
246 http_client_factory_.get(),
247 local_device_data_manager_.get(),
248 profile->GetProfileUserName())),
249 certificate_manager_(NearbyShareCertificateManagerImpl::Factory::Create(
250 local_device_data_manager_.get(),
251 contact_manager_.get(),
252 prefs,
253 content::BrowserContext::GetDefaultStoragePartition(profile)
254 ->GetProtoDatabaseProvider(),
255 profile->GetPath(),
256 http_client_factory_.get())),
257 settings_(prefs, local_device_data_manager_.get()) {
258 DCHECK(profile_);
259 DCHECK(nearby_connections_manager_);
260 DCHECK(power_client_);
261
262 RecordNearbyShareEnabledMetric(prefs);
263
264 #if defined(OS_CHROMEOS)
265 auto* session_controller = ash::SessionController::Get();
266 if (session_controller) {
267 is_screen_locked_ = session_controller->IsScreenLocked();
268 session_controller->AddObserver(this);
269 }
270 #endif // OS_CHROMEOS
271
272 nearby_process_observer_.Add(process_manager_);
273 power_client_->AddObserver(this);
274 certificate_manager_->AddObserver(this);
275
276 settings_.AddSettingsObserver(settings_receiver_.BindNewPipeAndPassRemote());
277
278 GetBluetoothAdapter();
279
280 nearby_notification_manager_ = std::make_unique<NearbyNotificationManager>(
281 notification_display_service, this, prefs, profile_);
282
283 if (settings_.GetEnabled()) {
284 local_device_data_manager_->Start();
285 contact_manager_->Start();
286 certificate_manager_->Start();
287 }
288 }
289
~NearbySharingServiceImpl()290 NearbySharingServiceImpl::~NearbySharingServiceImpl() {
291 // Make sure the service has been shut down properly before.
292 DCHECK(!nearby_notification_manager_);
293 DCHECK(!bluetooth_adapter_ || !bluetooth_adapter_->HasObserver(this));
294 }
295
Shutdown()296 void NearbySharingServiceImpl::Shutdown() {
297 // Before we clean up, lets give observers a heads up we are shutting down.
298 for (auto& observer : observers_) {
299 observer.OnShutdown();
300 }
301 observers_.Clear();
302
303 // Clear in-progress transfers.
304 ClearOutgoingShareTargetInfoMap();
305 incoming_share_target_info_map_.clear();
306
307 StopAdvertising();
308 StopFastInitiationAdvertising();
309 StopScanning();
310 nearby_connections_manager_->Shutdown();
311
312 // Destroy NearbyNotificationManager as its profile has been shut down.
313 nearby_notification_manager_.reset();
314
315 // Stop listening to NearbyProcessManager events and stop the utility process.
316 nearby_process_observer_.Remove(process_manager_);
317 if (process_manager_->IsActiveProfile(profile_))
318 process_manager_->StopProcess(profile_);
319
320 power_client_->RemoveObserver(this);
321 certificate_manager_->RemoveObserver(this);
322
323 // TODO(crbug/1147652): The call to update the advertising interval is
324 // removed to prevent a Bluez crash. We need to either reduce the global
325 // advertising interval asynchronously and wait for the result or use the
326 // updated API referenced in the bug which allows setting a per-advertisement
327 // interval.
328
329 if (bluetooth_adapter_)
330 bluetooth_adapter_->RemoveObserver(this);
331
332 #if defined(OS_CHROMEOS)
333 auto* session_controller = ash::SessionController::Get();
334 if (session_controller)
335 session_controller->RemoveObserver(this);
336 #endif // OS_CHROMEOS
337
338 foreground_receive_callbacks_.Clear();
339 background_receive_callbacks_.Clear();
340 foreground_send_transfer_callbacks_.Clear();
341 foreground_send_discovery_callbacks_.Clear();
342 background_send_transfer_callbacks_.Clear();
343 background_send_discovery_callbacks_.Clear();
344
345 last_incoming_metadata_.reset();
346 last_outgoing_metadata_.reset();
347 attachment_info_map_.clear();
348 mutual_acceptance_timeout_alarm_.Cancel();
349 disconnection_timeout_alarms_.clear();
350
351 is_transferring_ = false;
352 is_receiving_files_ = false;
353 is_sending_files_ = false;
354 is_connecting_ = false;
355
356 settings_receiver_.reset();
357
358 if (settings_.GetEnabled()) {
359 local_device_data_manager_->Stop();
360 contact_manager_->Stop();
361 certificate_manager_->Stop();
362 }
363
364 process_shutdown_pending_timer_.Stop();
365 rotate_background_advertisement_timer_.Stop();
366
367 // |profile_| has now been shut down so we shouldn't use it anymore.
368 profile_ = nullptr;
369 }
370
AddObserver(NearbySharingService::Observer * observer)371 void NearbySharingServiceImpl::AddObserver(
372 NearbySharingService::Observer* observer) {
373 observers_.AddObserver(observer);
374 }
375
RemoveObserver(NearbySharingService::Observer * observer)376 void NearbySharingServiceImpl::RemoveObserver(
377 NearbySharingService::Observer* observer) {
378 observers_.RemoveObserver(observer);
379 }
380
HasObserver(NearbySharingService::Observer * observer)381 bool NearbySharingServiceImpl::HasObserver(
382 NearbySharingService::Observer* observer) {
383 return observers_.HasObserver(observer);
384 }
385
RegisterSendSurface(TransferUpdateCallback * transfer_callback,ShareTargetDiscoveredCallback * discovery_callback,SendSurfaceState state)386 NearbySharingService::StatusCodes NearbySharingServiceImpl::RegisterSendSurface(
387 TransferUpdateCallback* transfer_callback,
388 ShareTargetDiscoveredCallback* discovery_callback,
389 SendSurfaceState state) {
390 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
391 DCHECK(transfer_callback);
392 DCHECK(discovery_callback);
393 DCHECK_NE(state, SendSurfaceState::kUnknown);
394
395 if (foreground_send_transfer_callbacks_.HasObserver(transfer_callback) ||
396 background_send_transfer_callbacks_.HasObserver(transfer_callback)) {
397 NS_LOG(VERBOSE) << __func__
398 << ": RegisterSendSurface failed. Already registered for a "
399 "different state.";
400 return StatusCodes::kError;
401 }
402
403 if (state == SendSurfaceState::kForeground) {
404 foreground_send_transfer_callbacks_.AddObserver(transfer_callback);
405 foreground_send_discovery_callbacks_.AddObserver(discovery_callback);
406 } else {
407 background_send_transfer_callbacks_.AddObserver(transfer_callback);
408 background_send_discovery_callbacks_.AddObserver(discovery_callback);
409 }
410
411 if (is_receiving_files_) {
412 UnregisterSendSurface(transfer_callback, discovery_callback);
413 NS_LOG(VERBOSE)
414 << __func__
415 << ": Ignore registering (and unregistering if registered) send "
416 "surface because we're currently receiving files.";
417 return StatusCodes::kTransferAlreadyInProgress;
418 }
419
420 // If the share sheet to be registered is a foreground surface, let it catch
421 // up with most recent transfer metadata immediately.
422 if (state == SendSurfaceState::kForeground && last_outgoing_metadata_) {
423 // When a new share sheet is registered, we want to immediately show the
424 // in-progress bar.
425 discovery_callback->OnShareTargetDiscovered(last_outgoing_metadata_->first);
426 transfer_callback->OnTransferUpdate(last_outgoing_metadata_->first,
427 last_outgoing_metadata_->second);
428 }
429
430 // Sync down data from Nearby server when the sending flow starts, making our
431 // best effort to have fresh contact and certificate data. There is no need to
432 // wait for these calls to finish. The periodic server requests will typically
433 // be sufficient, but we don't want the user to be blocked for hours waiting
434 // for a periodic sync.
435 if (state == SendSurfaceState::kForeground && !last_outgoing_metadata_) {
436 NS_LOG(VERBOSE)
437 << __func__
438 << ": Downloading local device data, contacts, and certificates from "
439 << "Nearby server at start of sending flow.";
440 local_device_data_manager_->DownloadDeviceData();
441 contact_manager_->DownloadContacts();
442 certificate_manager_->DownloadPublicCertificates();
443 }
444
445 // Let newly registered send surface catch up with discovered share targets
446 // from current scanning session.
447 for (const std::pair<std::string, ShareTarget>& item :
448 outgoing_share_target_map_) {
449 discovery_callback->OnShareTargetDiscovered(item.second);
450 }
451
452 NS_LOG(VERBOSE) << __func__
453 << ": A SendSurface has been registered for state: "
454 << SendSurfaceStateToString(state);
455 InvalidateSendSurfaceState();
456 return StatusCodes::kOk;
457 }
458
459 NearbySharingService::StatusCodes
UnregisterSendSurface(TransferUpdateCallback * transfer_callback,ShareTargetDiscoveredCallback * discovery_callback)460 NearbySharingServiceImpl::UnregisterSendSurface(
461 TransferUpdateCallback* transfer_callback,
462 ShareTargetDiscoveredCallback* discovery_callback) {
463 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
464 DCHECK(transfer_callback);
465 DCHECK(discovery_callback);
466 if (!foreground_send_transfer_callbacks_.HasObserver(transfer_callback) &&
467 !background_send_transfer_callbacks_.HasObserver(transfer_callback)) {
468 NS_LOG(VERBOSE)
469 << __func__
470 << ": unregisterSendSurface failed. Unknown TransferUpdateCallback";
471 return StatusCodes::kError;
472 }
473
474 if (foreground_send_transfer_callbacks_.might_have_observers() &&
475 last_outgoing_metadata_ &&
476 last_outgoing_metadata_->second.is_final_status()) {
477 // We already saw the final status in the foreground
478 // Nullify it so the next time the user opens sharing, it starts the UI from
479 // the beginning
480 last_outgoing_metadata_.reset();
481 }
482
483 SendSurfaceState state = SendSurfaceState::kUnknown;
484 if (foreground_send_transfer_callbacks_.HasObserver(transfer_callback)) {
485 foreground_send_transfer_callbacks_.RemoveObserver(transfer_callback);
486 foreground_send_discovery_callbacks_.RemoveObserver(discovery_callback);
487 state = SendSurfaceState::kForeground;
488 } else {
489 background_send_transfer_callbacks_.RemoveObserver(transfer_callback);
490 background_send_discovery_callbacks_.RemoveObserver(discovery_callback);
491 state = SendSurfaceState::kBackground;
492 }
493
494 // Displays the most recent payload status processed by foreground surfaces on
495 // background surfaces.
496 if (!foreground_send_transfer_callbacks_.might_have_observers() &&
497 last_outgoing_metadata_) {
498 for (TransferUpdateCallback& background_transfer_callback :
499 background_send_transfer_callbacks_) {
500 background_transfer_callback.OnTransferUpdate(
501 last_outgoing_metadata_->first, last_outgoing_metadata_->second);
502 }
503 }
504
505 NS_LOG(VERBOSE) << __func__ << ": A SendSurface has been unregistered: "
506 << SendSurfaceStateToString(state);
507 InvalidateSurfaceState();
508 return StatusCodes::kOk;
509 }
510
511 NearbySharingService::StatusCodes
RegisterReceiveSurface(TransferUpdateCallback * transfer_callback,ReceiveSurfaceState state)512 NearbySharingServiceImpl::RegisterReceiveSurface(
513 TransferUpdateCallback* transfer_callback,
514 ReceiveSurfaceState state) {
515 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
516 DCHECK(transfer_callback);
517 DCHECK_NE(state, ReceiveSurfaceState::kUnknown);
518
519 if (is_sending_files_) {
520 UnregisterReceiveSurface(transfer_callback);
521 NS_LOG(VERBOSE)
522 << __func__
523 << ": Ignore registering (and unregistering if registered) receive "
524 "surface, because we're currently sending files.";
525 return StatusCodes::kTransferAlreadyInProgress;
526 }
527
528 // We specifically allow re-registring with out error so it is clear to caller
529 // that the transfer_callback is currently registered.
530 if (GetReceiveCallbacksFromState(state).HasObserver(transfer_callback)) {
531 NS_LOG(VERBOSE) << __func__
532 << ": transfer callback already registered, ignoring";
533 return StatusCodes::kOk;
534 } else if (foreground_receive_callbacks_.HasObserver(transfer_callback) ||
535 background_receive_callbacks_.HasObserver(transfer_callback)) {
536 NS_LOG(ERROR)
537 << __func__
538 << ": transfer callback already registered but for a different state.";
539 return StatusCodes::kError;
540 }
541
542 // If the receive surface to be registered is a foreground surface, let it
543 // catch up with most recent transfer metadata immediately.
544 if (state == ReceiveSurfaceState::kForeground && last_incoming_metadata_) {
545 transfer_callback->OnTransferUpdate(last_incoming_metadata_->first,
546 last_incoming_metadata_->second);
547 }
548
549 GetReceiveCallbacksFromState(state).AddObserver(transfer_callback);
550
551 NS_LOG(VERBOSE) << __func__ << ": A ReceiveSurface("
552 << ReceiveSurfaceStateToString(state)
553 << ") has been registered";
554 InvalidateReceiveSurfaceState();
555 return StatusCodes::kOk;
556 }
557
558 NearbySharingService::StatusCodes
UnregisterReceiveSurface(TransferUpdateCallback * transfer_callback)559 NearbySharingServiceImpl::UnregisterReceiveSurface(
560 TransferUpdateCallback* transfer_callback) {
561 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
562 DCHECK(transfer_callback);
563 bool is_foreground =
564 foreground_receive_callbacks_.HasObserver(transfer_callback);
565 bool is_background =
566 background_receive_callbacks_.HasObserver(transfer_callback);
567 if (!is_foreground && !is_background) {
568 NS_LOG(VERBOSE)
569 << __func__
570 << ": Unknown transfer callback was un-registered, ignoring.";
571 // We intentionally allow this be successful so the caller can be sure
572 // they are not registered anymore.
573 return StatusCodes::kOk;
574 }
575
576 if (foreground_receive_callbacks_.might_have_observers() &&
577 last_incoming_metadata_ &&
578 last_incoming_metadata_->second.is_final_status()) {
579 // We already saw the final status in the foreground.
580 // Nullify it so the next time the user opens sharing, it starts the UI from
581 // the beginning
582 last_incoming_metadata_.reset();
583 }
584
585 if (is_foreground) {
586 foreground_receive_callbacks_.RemoveObserver(transfer_callback);
587 } else {
588 background_receive_callbacks_.RemoveObserver(transfer_callback);
589 }
590
591 // Displays the most recent payload status processed by foreground surfaces on
592 // background surface.
593 if (!foreground_receive_callbacks_.might_have_observers() &&
594 last_incoming_metadata_) {
595 for (TransferUpdateCallback& background_callback :
596 background_receive_callbacks_) {
597 background_callback.OnTransferUpdate(last_incoming_metadata_->first,
598 last_incoming_metadata_->second);
599 }
600 }
601
602 NS_LOG(VERBOSE) << __func__ << ": A ReceiveSurface("
603 << (is_foreground ? "foreground" : "background")
604 << ") has been unregistered";
605 InvalidateSurfaceState();
606 return StatusCodes::kOk;
607 }
608
609 NearbySharingService::StatusCodes
ClearForegroundReceiveSurfaces()610 NearbySharingServiceImpl::ClearForegroundReceiveSurfaces() {
611 std::vector<TransferUpdateCallback*> fg_receivers;
612 for (auto& callback : foreground_receive_callbacks_)
613 fg_receivers.push_back(&callback);
614
615 StatusCodes status = StatusCodes::kOk;
616 for (TransferUpdateCallback* callback : fg_receivers) {
617 if (UnregisterReceiveSurface(callback) != StatusCodes::kOk)
618 status = StatusCodes::kError;
619 }
620 return status;
621 }
622
IsInHighVisibility()623 bool NearbySharingServiceImpl::IsInHighVisibility() {
624 return in_high_visibility;
625 }
626
SendAttachments(const ShareTarget & share_target,std::vector<std::unique_ptr<Attachment>> attachments)627 NearbySharingService::StatusCodes NearbySharingServiceImpl::SendAttachments(
628 const ShareTarget& share_target,
629 std::vector<std::unique_ptr<Attachment>> attachments) {
630 if (!is_scanning_) {
631 NS_LOG(WARNING) << __func__
632 << ": Failed to send attachments. Not scanning.";
633 return StatusCodes::kError;
634 }
635
636 // |is_scanning_| means at least one send transfer callback.
637 DCHECK(foreground_send_transfer_callbacks_.might_have_observers() ||
638 background_send_transfer_callbacks_.might_have_observers());
639 // |is_scanning_| and |is_transferring_| are mutually exclusive.
640 DCHECK(!is_transferring_);
641
642 ShareTargetInfo* info = GetShareTargetInfo(share_target);
643 if (!info || !info->endpoint_id()) {
644 // TODO(crbug.com/1119276): Support scanning for unknown share targets.
645 NS_LOG(WARNING) << __func__
646 << ": Failed to send attachments. Unknown ShareTarget.";
647 return StatusCodes::kError;
648 }
649
650 ShareTarget share_target_copy = share_target;
651 for (std::unique_ptr<Attachment>& attachment : attachments) {
652 DCHECK(attachment);
653 attachment->MoveToShareTarget(share_target_copy);
654 }
655
656 if (!share_target_copy.has_attachments()) {
657 NS_LOG(WARNING) << __func__ << ": No attachments to send.";
658 return StatusCodes::kError;
659 }
660
661 // For sending advertisement from scanner, the request advertisement should
662 // always be visible to everyone.
663 base::Optional<std::vector<uint8_t>> endpoint_info =
664 CreateEndpointInfo(local_device_data_manager_->GetDeviceName());
665 if (!endpoint_info) {
666 NS_LOG(WARNING) << __func__ << ": Could not create local endpoint info.";
667 return StatusCodes::kError;
668 }
669
670 info->set_transfer_update_callback(std::make_unique<TransferUpdateDecorator>(
671 base::BindRepeating(&NearbySharingServiceImpl::OnOutgoingTransferUpdate,
672 weak_ptr_factory_.GetWeakPtr())));
673
674 OnTransferStarted(/*is_incoming=*/false);
675 is_connecting_ = true;
676 InvalidateSendSurfaceState();
677
678 // Send process initialized successfully, from now on status updated will be
679 // sent out via OnOutgoingTransferUpdate().
680 info->transfer_update_callback()->OnTransferUpdate(
681 share_target_copy, TransferMetadataBuilder()
682 .set_status(TransferMetadata::Status::kConnecting)
683 .build());
684
685 CreatePayloads(std::move(share_target_copy),
686 base::BindOnce(&NearbySharingServiceImpl::OnCreatePayloads,
687 weak_ptr_factory_.GetWeakPtr(),
688 std::move(*endpoint_info)));
689
690 return StatusCodes::kOk;
691 }
692
Accept(const ShareTarget & share_target,StatusCodesCallback status_codes_callback)693 void NearbySharingServiceImpl::Accept(
694 const ShareTarget& share_target,
695 StatusCodesCallback status_codes_callback) {
696 ShareTargetInfo* info = GetShareTargetInfo(share_target);
697 if (!info || !info->connection()) {
698 NS_LOG(WARNING) << __func__ << ": Accept invoked for unknown share target";
699 std::move(status_codes_callback).Run(StatusCodes::kOutOfOrderApiCall);
700 return;
701 }
702
703 base::Optional<std::pair<ShareTarget, TransferMetadata>> metadata =
704 share_target.is_incoming ? last_incoming_metadata_
705 : last_outgoing_metadata_;
706 if (!metadata || metadata->second.status() !=
707 TransferMetadata::Status::kAwaitingLocalConfirmation) {
708 std::move(status_codes_callback).Run(StatusCodes::kOutOfOrderApiCall);
709 return;
710 }
711
712 if (share_target.is_incoming) {
713 ReceivePayloads(share_target, std::move(status_codes_callback));
714 return;
715 }
716
717 std::move(status_codes_callback).Run(SendPayloads(share_target));
718 }
719
Reject(const ShareTarget & share_target,StatusCodesCallback status_codes_callback)720 void NearbySharingServiceImpl::Reject(
721 const ShareTarget& share_target,
722 StatusCodesCallback status_codes_callback) {
723 ShareTargetInfo* info = GetShareTargetInfo(share_target);
724 if (!info || !info->connection()) {
725 NS_LOG(WARNING) << __func__ << ": Reject invoked for unknown share target";
726 std::move(status_codes_callback).Run(StatusCodes::kOutOfOrderApiCall);
727 return;
728 }
729 NearbyConnection* connection = info->connection();
730
731 base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
732 FROM_HERE,
733 base::BindOnce(&NearbySharingServiceImpl::CloseConnection,
734 weak_ptr_factory_.GetWeakPtr(), share_target),
735 kIncomingRejectionDelay);
736
737 connection->SetDisconnectionListener(
738 base::BindOnce(&NearbySharingServiceImpl::UnregisterShareTarget,
739 weak_ptr_factory_.GetWeakPtr(), share_target));
740
741 WriteResponse(*connection, sharing::nearby::ConnectionResponseFrame::REJECT);
742 NS_LOG(VERBOSE) << __func__
743 << ": Successfully wrote a rejection response frame";
744
745 if (info->transfer_update_callback()) {
746 info->transfer_update_callback()->OnTransferUpdate(
747 share_target, TransferMetadataBuilder()
748 .set_status(TransferMetadata::Status::kRejected)
749 .build());
750 }
751
752 std::move(status_codes_callback).Run(StatusCodes::kOk);
753 }
754
Cancel(const ShareTarget & share_target,StatusCodesCallback status_codes_callback)755 void NearbySharingServiceImpl::Cancel(
756 const ShareTarget& share_target,
757 StatusCodesCallback status_codes_callback) {
758 NS_LOG(INFO) << __func__ << ": User canceled transfer";
759 DoCancel(share_target, std::move(status_codes_callback),
760 /*write_cancel_frame=*/true);
761 }
762
DoCancel(ShareTarget share_target,StatusCodesCallback status_codes_callback,bool write_cancel_frame)763 void NearbySharingServiceImpl::DoCancel(
764 ShareTarget share_target,
765 StatusCodesCallback status_codes_callback,
766 bool write_cancel_frame) {
767 ShareTargetInfo* info = GetShareTargetInfo(share_target);
768 if (!info || !info->endpoint_id()) {
769 NS_LOG(ERROR) << __func__
770 << ": Cancel invoked for unknown share target, returning "
771 "kOutOfOrderApiCall";
772 // Make sure to clean up files just in case.
773 RemoveIncomingPayloads(share_target);
774 std::move(status_codes_callback).Run(StatusCodes::kOutOfOrderApiCall);
775 return;
776 }
777
778 // Cancel all ongoing payload transfers before invoking the transfer update
779 // callback. Invoking the transfer update callback first could result in
780 // payload cleanup before we have a chance to cancel the payload via Nearby
781 // Connections, and the payload tracker might not receive the expected
782 // cancellation signals. Also, note that there might not be any ongoing
783 // payload transfer, for example, if a connection has not been established
784 // yet.
785 for (int64_t attachment_id : share_target.GetAttachmentIds()) {
786 base::Optional<int64_t> payload_id = GetAttachmentPayloadId(attachment_id);
787 if (payload_id) {
788 nearby_connections_manager_->Cancel(*payload_id);
789 }
790 }
791
792 // Inform the user that the transfer has been cancelled before disconnecting
793 // because subsequent disconnections might be interpreted as failure. The
794 // TransferUpdateDecorator will ignore subsequent statuses in favor of this
795 // cancelled status. Note that the transfer update callback might have already
796 // been invoked as a result of the payload cancellations above, but again,
797 // superfluous status updates are handled gracefully by the
798 // TransferUpdateDecorator.
799 if (info->transfer_update_callback()) {
800 info->transfer_update_callback()->OnTransferUpdate(
801 share_target, TransferMetadataBuilder()
802 .set_status(TransferMetadata::Status::kCancelled)
803 .build());
804 }
805
806 // If a connection exists, close the connection after a short delay that
807 // allows for final processing by the other device. Otherwise, disconnect from
808 // endpoint id directly. Note: A share attempt can be cancelled by the user
809 // before a connection is fully established, in which case, info->connection()
810 // will be null.
811 if (info->connection()) {
812 info->connection()->SetDisconnectionListener(
813 base::BindOnce(&NearbySharingServiceImpl::UnregisterShareTarget,
814 weak_ptr_factory_.GetWeakPtr(), share_target));
815 base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
816 FROM_HERE,
817 base::BindOnce(&NearbySharingServiceImpl::CloseConnection,
818 weak_ptr_factory_.GetWeakPtr(), share_target),
819 kIncomingCancelDelay);
820
821 if (write_cancel_frame) {
822 WriteCancel(*info->connection());
823 }
824 } else {
825 nearby_connections_manager_->Disconnect(*info->endpoint_id());
826 UnregisterShareTarget(share_target);
827 }
828
829 std::move(status_codes_callback).Run(StatusCodes::kOk);
830 }
831
Open(const ShareTarget & share_target,StatusCodesCallback status_codes_callback)832 void NearbySharingServiceImpl::Open(const ShareTarget& share_target,
833 StatusCodesCallback status_codes_callback) {
834 std::move(status_codes_callback).Run(StatusCodes::kOk);
835 }
836
GetNotificationDelegate(const std::string & notification_id)837 NearbyNotificationDelegate* NearbySharingServiceImpl::GetNotificationDelegate(
838 const std::string& notification_id) {
839 if (!nearby_notification_manager_)
840 return nullptr;
841
842 return nearby_notification_manager_->GetNotificationDelegate(notification_id);
843 }
844
GetSettings()845 NearbyShareSettings* NearbySharingServiceImpl::GetSettings() {
846 return &settings_;
847 }
848
GetHttpNotifier()849 NearbyShareHttpNotifier* NearbySharingServiceImpl::GetHttpNotifier() {
850 return &nearby_share_http_notifier_;
851 }
852
853 NearbyShareLocalDeviceDataManager*
GetLocalDeviceDataManager()854 NearbySharingServiceImpl::GetLocalDeviceDataManager() {
855 return local_device_data_manager_.get();
856 }
857
GetContactManager()858 NearbyShareContactManager* NearbySharingServiceImpl::GetContactManager() {
859 return contact_manager_.get();
860 }
861
862 NearbyShareCertificateManager*
GetCertificateManager()863 NearbySharingServiceImpl::GetCertificateManager() {
864 return certificate_manager_.get();
865 }
866
OnNearbyProfileChanged(Profile * profile)867 void NearbySharingServiceImpl::OnNearbyProfileChanged(Profile* profile) {
868 // TODO(crbug.com/1084576): Notify UI about the new active profile.
869 if (profile) {
870 NS_LOG(VERBOSE) << __func__ << ": Active Nearby profile changed to: "
871 << profile->GetProfileUserName();
872 } else {
873 NS_LOG(VERBOSE) << __func__ << ": Active Nearby profile cleared";
874 }
875 InvalidateSurfaceState();
876 }
877
OnNearbyProcessStarted()878 void NearbySharingServiceImpl::OnNearbyProcessStarted() {
879 DCHECK(profile_);
880 if (process_manager_->IsActiveProfile(profile_)) {
881 NS_LOG(VERBOSE) << __func__ << ": Nearby process started for profile: "
882 << profile_->GetProfileUserName();
883 }
884 }
885
OnNearbyProcessStopped()886 void NearbySharingServiceImpl::OnNearbyProcessStopped() {
887 DCHECK(profile_);
888 InvalidateSurfaceState();
889 if (process_manager_->IsActiveProfile(profile_)) {
890 NS_LOG(VERBOSE) << __func__ << ": Nearby process stopped for profile: "
891 << profile_->GetProfileUserName();
892 }
893 }
894
OnIncomingConnection(const std::string & endpoint_id,const std::vector<uint8_t> & endpoint_info,NearbyConnection * connection)895 void NearbySharingServiceImpl::OnIncomingConnection(
896 const std::string& endpoint_id,
897 const std::vector<uint8_t>& endpoint_info,
898 NearbyConnection* connection) {
899 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
900 DCHECK(connection);
901 DCHECK(profile_);
902
903 // Sync down data from Nearby server when the receiving flow starts, making
904 // our best effort to have fresh contact and certificate data. There is no
905 // need to wait for these calls to finish. The periodic server requests will
906 // typically be sufficient, but we don't want the user to be blocked for hours
907 // waiting for a periodic sync.
908 NS_LOG(VERBOSE)
909 << __func__
910 << ": Downloading local device data, contacts, and certificates from "
911 << "Nearby server at start of receiving flow.";
912 local_device_data_manager_->DownloadDeviceData();
913 contact_manager_->DownloadContacts();
914 certificate_manager_->DownloadPublicCertificates();
915
916 ShareTarget placeholder_share_target;
917 placeholder_share_target.is_incoming = true;
918 ShareTargetInfo& share_target_info =
919 GetOrCreateShareTargetInfo(placeholder_share_target, endpoint_id);
920 share_target_info.set_connection(connection);
921
922 connection->SetDisconnectionListener(
923 base::BindOnce(&NearbySharingServiceImpl::RefreshUIOnDisconnection,
924 weak_ptr_factory_.GetWeakPtr(), placeholder_share_target));
925
926 process_manager_->GetOrStartNearbySharingDecoder(profile_)
927 ->DecodeAdvertisement(
928 endpoint_info,
929 base::BindOnce(
930 &NearbySharingServiceImpl::OnIncomingAdvertisementDecoded,
931 weak_ptr_factory_.GetWeakPtr(), endpoint_id,
932 std::move(placeholder_share_target)));
933 }
934
FlushMojoForTesting()935 void NearbySharingServiceImpl::FlushMojoForTesting() {
936 settings_receiver_.FlushForTesting();
937 }
938
OnEnabledChanged(bool enabled)939 void NearbySharingServiceImpl::OnEnabledChanged(bool enabled) {
940 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
941 if (enabled) {
942 NS_LOG(VERBOSE) << __func__ << ": Nearby sharing enabled!";
943 local_device_data_manager_->Start();
944 contact_manager_->Start();
945 certificate_manager_->Start();
946 } else {
947 NS_LOG(VERBOSE) << __func__ << ": Nearby sharing disabled!";
948 StopAdvertising();
949 StopScanning();
950 nearby_connections_manager_->Shutdown();
951 local_device_data_manager_->Stop();
952 contact_manager_->Stop();
953 certificate_manager_->Stop();
954 }
955 InvalidateSurfaceState();
956 }
957
OnDeviceNameChanged(const std::string & device_name)958 void NearbySharingServiceImpl::OnDeviceNameChanged(
959 const std::string& device_name) {
960 NS_LOG(VERBOSE) << __func__ << ": Nearby sharing device name changed to "
961 << device_name;
962 // TODO(vecore): handle device name change
963 }
964
OnDataUsageChanged(DataUsage data_usage)965 void NearbySharingServiceImpl::OnDataUsageChanged(DataUsage data_usage) {
966 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
967 NS_LOG(VERBOSE) << __func__ << ": Nearby sharing data usage changed to "
968 << data_usage;
969
970 if (advertising_power_level_ != PowerLevel::kUnknown)
971 StopAdvertising();
972
973 InvalidateSurfaceState();
974 }
975
OnVisibilityChanged(Visibility new_visibility)976 void NearbySharingServiceImpl::OnVisibilityChanged(Visibility new_visibility) {
977 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
978 NS_LOG(VERBOSE) << __func__ << ": Nearby sharing visibility changed to "
979 << new_visibility;
980 if (advertising_power_level_ != PowerLevel::kUnknown)
981 StopAdvertising();
982
983 InvalidateSurfaceState();
984 }
985
OnAllowedContactsChanged(const std::vector<std::string> & allowed_contacts)986 void NearbySharingServiceImpl::OnAllowedContactsChanged(
987 const std::vector<std::string>& allowed_contacts) {
988 NS_LOG(VERBOSE) << __func__ << ": Nearby sharing visible contacts changed";
989 // TODO(vecore): handle visible contacts change
990 }
991
OnPublicCertificatesDownloaded()992 void NearbySharingServiceImpl::OnPublicCertificatesDownloaded() {
993 // TODO(https://crbug.com/1152158): Possibly restart scanning after public
994 // certificates are downloaded.
995 }
996
OnPrivateCertificatesChanged()997 void NearbySharingServiceImpl::OnPrivateCertificatesChanged() {
998 // If we are currently advertising, restart advertising using the updated
999 // private certificates.
1000 if (rotate_background_advertisement_timer_.IsRunning()) {
1001 NS_LOG(VERBOSE)
1002 << __func__
1003 << ": Private certificates changed; rotating background advertisement.";
1004 rotate_background_advertisement_timer_.FireNow();
1005 }
1006 }
1007
OnEndpointDiscovered(const std::string & endpoint_id,const std::vector<uint8_t> & endpoint_info)1008 void NearbySharingServiceImpl::OnEndpointDiscovered(
1009 const std::string& endpoint_id,
1010 const std::vector<uint8_t>& endpoint_info) {
1011 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1012 DCHECK(profile_);
1013 if (!is_scanning_) {
1014 NS_LOG(VERBOSE)
1015 << __func__
1016 << ": Ignoring discovered endpoint because we're no longer scanning";
1017 return;
1018 }
1019
1020 process_manager_->GetOrStartNearbySharingDecoder(profile_)
1021 ->DecodeAdvertisement(
1022 endpoint_info,
1023 base::BindOnce(
1024 &NearbySharingServiceImpl::OnOutgoingAdvertisementDecoded,
1025 weak_ptr_factory_.GetWeakPtr(), endpoint_id));
1026 }
1027
OnEndpointLost(const std::string & endpoint_id)1028 void NearbySharingServiceImpl::OnEndpointLost(const std::string& endpoint_id) {
1029 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1030 if (!is_scanning_) {
1031 NS_LOG(VERBOSE)
1032 << __func__
1033 << ": Ignoring lost endpoint because we're no longer scanning";
1034 return;
1035 }
1036
1037 RemoveOutgoingShareTargetWithEndpointId(endpoint_id);
1038 }
1039
OnLockStateChanged(bool locked)1040 void NearbySharingServiceImpl::OnLockStateChanged(bool locked) {
1041 NS_LOG(VERBOSE) << __func__ << ": Screen lock state changed. (" << locked
1042 << ")";
1043 is_screen_locked_ = locked;
1044 InvalidateSurfaceState();
1045 }
1046
AdapterPresentChanged(device::BluetoothAdapter * adapter,bool present)1047 void NearbySharingServiceImpl::AdapterPresentChanged(
1048 device::BluetoothAdapter* adapter,
1049 bool present) {
1050 NS_LOG(VERBOSE) << "Bluetooth present changed: " << present;
1051 InvalidateSurfaceState();
1052 }
1053
AdapterPoweredChanged(device::BluetoothAdapter * adapter,bool powered)1054 void NearbySharingServiceImpl::AdapterPoweredChanged(
1055 device::BluetoothAdapter* adapter,
1056 bool powered) {
1057 NS_LOG(VERBOSE) << "Bluetooth powered changed: " << powered;
1058 InvalidateSurfaceState();
1059 }
1060
SuspendImminent()1061 void NearbySharingServiceImpl::SuspendImminent() {
1062 NS_LOG(VERBOSE) << __func__ << ": Suspend imminent.";
1063 InvalidateSurfaceState();
1064 }
1065
SuspendDone()1066 void NearbySharingServiceImpl::SuspendDone() {
1067 NS_LOG(VERBOSE) << __func__ << ": Suspend done.";
1068 InvalidateSurfaceState();
1069 }
1070
1071 base::ObserverList<TransferUpdateCallback>&
GetReceiveCallbacksFromState(ReceiveSurfaceState state)1072 NearbySharingServiceImpl::GetReceiveCallbacksFromState(
1073 ReceiveSurfaceState state) {
1074 switch (state) {
1075 case ReceiveSurfaceState::kForeground:
1076 return foreground_receive_callbacks_;
1077 case ReceiveSurfaceState::kBackground:
1078 return background_receive_callbacks_;
1079 case ReceiveSurfaceState::kUnknown:
1080 NOTREACHED();
1081 return foreground_receive_callbacks_;
1082 }
1083 }
1084
IsVisibleInBackground(Visibility visibility)1085 bool NearbySharingServiceImpl::IsVisibleInBackground(Visibility visibility) {
1086 return visibility == Visibility::kAllContacts ||
1087 visibility == Visibility::kSelectedContacts;
1088 }
1089
1090 const base::Optional<std::vector<uint8_t>>
CreateEndpointInfo(const base::Optional<std::string> & device_name)1091 NearbySharingServiceImpl::CreateEndpointInfo(
1092 const base::Optional<std::string>& device_name) {
1093 std::vector<uint8_t> salt;
1094 std::vector<uint8_t> encrypted_key;
1095
1096 nearby_share::mojom::Visibility visibility = settings_.GetVisibility();
1097 if (visibility == Visibility::kAllContacts ||
1098 visibility == Visibility::kSelectedContacts) {
1099 base::Optional<NearbyShareEncryptedMetadataKey> encrypted_metadata_key =
1100 certificate_manager_->EncryptPrivateCertificateMetadataKey(visibility);
1101 if (encrypted_metadata_key) {
1102 salt = encrypted_metadata_key->salt();
1103 encrypted_key = encrypted_metadata_key->encrypted_key();
1104 } else {
1105 NS_LOG(WARNING) << __func__
1106 << ": Failed to encrypt private certificate metadata key "
1107 << "for advertisement.";
1108 }
1109 }
1110
1111 if (salt.empty() || encrypted_key.empty()) {
1112 // Generate random metadata key.
1113 salt = GenerateRandomBytes(sharing::Advertisement::kSaltSize);
1114 encrypted_key = GenerateRandomBytes(
1115 sharing::Advertisement::kMetadataEncryptionKeyHashByteSize);
1116 }
1117
1118 nearby_share::mojom::ShareTargetType device_type =
1119 nearby_share::mojom::ShareTargetType::kLaptop;
1120
1121 std::unique_ptr<sharing::Advertisement> advertisement =
1122 sharing::Advertisement::NewInstance(
1123 std::move(salt), std::move(encrypted_key), device_type, device_name);
1124 if (advertisement) {
1125 return advertisement->ToEndpointInfo();
1126 } else {
1127 return base::nullopt;
1128 }
1129 }
1130
GetBluetoothAdapter()1131 void NearbySharingServiceImpl::GetBluetoothAdapter() {
1132 auto* adapter_factory = device::BluetoothAdapterFactory::Get();
1133 if (!adapter_factory->IsBluetoothSupported())
1134 return;
1135
1136 // Because this will be called from the constructor, GetAdapter() may call
1137 // OnGetBluetoothAdapter() immediately which can cause problems during tests
1138 // since the class is not fully constructed yet.
1139 base::SequencedTaskRunnerHandle::Get()->PostTask(
1140 FROM_HERE,
1141 base::BindOnce(
1142 &device::BluetoothAdapterFactory::GetAdapter,
1143 base::Unretained(adapter_factory),
1144 base::BindOnce(&NearbySharingServiceImpl::OnGetBluetoothAdapter,
1145 weak_ptr_factory_.GetWeakPtr())));
1146 }
1147
OnGetBluetoothAdapter(scoped_refptr<device::BluetoothAdapter> adapter)1148 void NearbySharingServiceImpl::OnGetBluetoothAdapter(
1149 scoped_refptr<device::BluetoothAdapter> adapter) {
1150 bluetooth_adapter_ = adapter;
1151 bluetooth_adapter_->AddObserver(this);
1152
1153 // TODO(crbug/1147652): The call to update the advertising interval is
1154 // removed to prevent a Bluez crash. We need to either reduce the global
1155 // advertising interval asynchronously and wait for the result or use the
1156 // updated API referenced in the bug which allows setting a per-advertisement
1157 // interval.
1158
1159 // TODO(crbug.com/1132469): This was added to fix an issue where advertising
1160 // was not starting on sign-in. Add a unit test to cover this case.
1161 InvalidateSurfaceState();
1162 }
1163
StartFastInitiationAdvertising()1164 void NearbySharingServiceImpl::StartFastInitiationAdvertising() {
1165 NS_LOG(VERBOSE) << __func__ << ": Starting fast initiation advertising.";
1166
1167 fast_initiation_manager_ =
1168 FastInitiationManager::Factory::Create(bluetooth_adapter_);
1169
1170 // TODO(crbug/1147652): The call to update the advertising interval is
1171 // removed to prevent a Bluez crash. We need to either reduce the global
1172 // advertising interval asynchronously and wait for the result or use the
1173 // updated API referenced in the bug which allows setting a per-advertisement
1174 // interval.
1175
1176 // TODO(crbug.com/1100686): Determine whether to call StartAdvertising() with
1177 // kNotify or kSilent.
1178 fast_initiation_manager_->StartAdvertising(
1179 FastInitiationManager::FastInitType::kNotify,
1180 base::BindOnce(
1181 &NearbySharingServiceImpl::OnStartFastInitiationAdvertising,
1182 weak_ptr_factory_.GetWeakPtr()),
1183 base::BindOnce(
1184 &NearbySharingServiceImpl::OnStartFastInitiationAdvertisingError,
1185 weak_ptr_factory_.GetWeakPtr()));
1186 }
1187
OnStartFastInitiationAdvertising()1188 void NearbySharingServiceImpl::OnStartFastInitiationAdvertising() {
1189 // TODO(hansenmichael): Do not invoke
1190 // |register_send_surface_callback_| until Nearby Connections
1191 // scanning is kicked off.
1192 NS_LOG(VERBOSE) << "Started advertising FastInitiation.";
1193 }
1194
OnStartFastInitiationAdvertisingError()1195 void NearbySharingServiceImpl::OnStartFastInitiationAdvertisingError() {
1196 fast_initiation_manager_.reset();
1197 NS_LOG(ERROR) << "Failed to start FastInitiation advertising.";
1198 }
1199
StopFastInitiationAdvertising()1200 void NearbySharingServiceImpl::StopFastInitiationAdvertising() {
1201 if (!fast_initiation_manager_) {
1202 NS_LOG(VERBOSE)
1203 << "Can't stop advertising FastInitiation. Not advertising.";
1204 return;
1205 }
1206
1207 fast_initiation_manager_->StopAdvertising(
1208 base::BindOnce(&NearbySharingServiceImpl::OnStopFastInitiationAdvertising,
1209 weak_ptr_factory_.GetWeakPtr()));
1210 }
1211
OnStopFastInitiationAdvertising()1212 void NearbySharingServiceImpl::OnStopFastInitiationAdvertising() {
1213 fast_initiation_manager_.reset();
1214 NS_LOG(VERBOSE) << "Stopped advertising FastInitiation";
1215
1216 // TODO(crbug/1147652): The call to update the advertising interval is
1217 // removed to prevent a Bluez crash. We need to either reduce the global
1218 // advertising interval asynchronously and wait for the result or use the
1219 // updated API referenced in the bug which allows setting a per-advertisement
1220 // interval.
1221 }
1222
OnOutgoingAdvertisementDecoded(const std::string & endpoint_id,sharing::mojom::AdvertisementPtr advertisement)1223 void NearbySharingServiceImpl::OnOutgoingAdvertisementDecoded(
1224 const std::string& endpoint_id,
1225 sharing::mojom::AdvertisementPtr advertisement) {
1226 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1227 if (!advertisement) {
1228 NS_LOG(VERBOSE) << __func__
1229 << ": Failed to parse discovered advertisement.";
1230 return;
1231 }
1232
1233 // Now we will report endpoints met before in NearbyConnectionsManager.
1234 // Check outgoingShareTargetInfoMap first and pass the same shareTarget if we
1235 // found one.
1236
1237 // Looking for the ShareTarget based on endpoint id.
1238 if (outgoing_share_target_map_.find(endpoint_id) !=
1239 outgoing_share_target_map_.end()) {
1240 return;
1241 }
1242
1243 // Once we get the advertisement, the first thing to do is decrypt the
1244 // certificate.
1245 NearbyShareEncryptedMetadataKey encrypted_metadata_key(
1246 advertisement->salt, advertisement->encrypted_metadata_key);
1247 GetCertificateManager()->GetDecryptedPublicCertificate(
1248 std::move(encrypted_metadata_key),
1249 base::BindOnce(&NearbySharingServiceImpl::OnOutgoingDecryptedCertificate,
1250 weak_ptr_factory_.GetWeakPtr(), endpoint_id,
1251 std::move(advertisement)));
1252 }
1253
OnOutgoingDecryptedCertificate(const std::string & endpoint_id,sharing::mojom::AdvertisementPtr advertisement,base::Optional<NearbyShareDecryptedPublicCertificate> certificate)1254 void NearbySharingServiceImpl::OnOutgoingDecryptedCertificate(
1255 const std::string& endpoint_id,
1256 sharing::mojom::AdvertisementPtr advertisement,
1257 base::Optional<NearbyShareDecryptedPublicCertificate> certificate) {
1258 // Check again for this endpoint id, to avoid race conditions.
1259 if (outgoing_share_target_map_.find(endpoint_id) !=
1260 outgoing_share_target_map_.end()) {
1261 return;
1262 }
1263
1264 // The certificate provides the device name, in order to create a ShareTarget
1265 // to represent this remote device.
1266 base::Optional<ShareTarget> share_target = CreateShareTarget(
1267 endpoint_id, std::move(advertisement), std::move(certificate),
1268 /*is_incoming=*/false);
1269 if (!share_target) {
1270 NS_LOG(VERBOSE) << __func__
1271 << ": Failed to convert advertisement to share target from "
1272 "discovered advertisement. Ignoring endpoint.";
1273 return;
1274 }
1275
1276 // Update the endpoint id for the share target.
1277 NS_LOG(VERBOSE) << __func__
1278 << ": An endpoint has been discovered, with an advertisement "
1279 "containing a valid share target.";
1280
1281 // Notifies the user that we discovered a device.
1282 for (ShareTargetDiscoveredCallback& discovery_callback :
1283 foreground_send_discovery_callbacks_) {
1284 discovery_callback.OnShareTargetDiscovered(*share_target);
1285 }
1286 for (ShareTargetDiscoveredCallback& discovery_callback :
1287 background_send_discovery_callbacks_) {
1288 discovery_callback.OnShareTargetDiscovered(*share_target);
1289 }
1290
1291 NS_LOG(VERBOSE) << __func__ << ": Reported OnShareTargetDiscovered "
1292 << (base::Time::Now() - scanning_start_timestamp_);
1293
1294 // TODO(crbug/1108348) CachingManager should cache known and non-external
1295 // share targets.
1296 }
1297
IsBluetoothPresent() const1298 bool NearbySharingServiceImpl::IsBluetoothPresent() const {
1299 return bluetooth_adapter_.get() && bluetooth_adapter_->IsPresent();
1300 }
1301
IsBluetoothPowered() const1302 bool NearbySharingServiceImpl::IsBluetoothPowered() const {
1303 return IsBluetoothPresent() && bluetooth_adapter_->IsPowered();
1304 }
1305
HasAvailableConnectionMediums()1306 bool NearbySharingServiceImpl::HasAvailableConnectionMediums() {
1307 // Check if Wifi or Ethernet LAN is off. Advertisements won't work, so
1308 // disable them, unless bluetooth is known to be enabled. Not all platforms
1309 // have bluetooth, so wifi LAN is a platform-agnostic check.
1310 net::NetworkChangeNotifier::ConnectionType connection_type =
1311 net::NetworkChangeNotifier::GetConnectionType();
1312 bool hasNetworkConnection =
1313 connection_type ==
1314 net::NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI ||
1315 connection_type ==
1316 net::NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET;
1317 return IsBluetoothPowered() || (kIsWifiLanSupported && hasNetworkConnection);
1318 }
1319
InvalidateSurfaceState()1320 void NearbySharingServiceImpl::InvalidateSurfaceState() {
1321 InvalidateSendSurfaceState();
1322 InvalidateReceiveSurfaceState();
1323 if (ShouldStopNearbyProcess()) {
1324 // We need to debounce the call to shut down the process in case this state
1325 // is temporary (we don't want to the thrash the process). Any advertisment,
1326 // scanning or transfering will stop this timer from triggering.
1327 NS_LOG(INFO) << __func__
1328 << ": Scheduling process shutdown if not needed in 15 seconds";
1329 // NOTE: Using base::Unretained is safe because if shutdown_pending_timer_
1330 // goes out of scope the timer will be canceled.
1331 process_shutdown_pending_timer_.Start(
1332 FROM_HERE, base::TimeDelta::FromSeconds(15),
1333 base::BindOnce(&NearbySharingServiceImpl::OnProcessShutdownTimerFired,
1334 base::Unretained(this)));
1335 } else {
1336 process_shutdown_pending_timer_.Stop();
1337 }
1338 }
1339
ShouldStopNearbyProcess()1340 bool NearbySharingServiceImpl::ShouldStopNearbyProcess() {
1341 // Nothing to do if we're shutting down the profile.
1342 if (!profile_)
1343 return false;
1344
1345 // Cannot stop process without being the active profile.
1346 if (!process_manager_->IsActiveProfile(profile_))
1347 return false;
1348
1349 // We're currently advertising.
1350 if (advertising_power_level_ != PowerLevel::kUnknown)
1351 return false;
1352
1353 // We're currently discovering.
1354 if (is_scanning_)
1355 return false;
1356
1357 // We're currently attempting to connect to a remote device.
1358 if (is_connecting_)
1359 return false;
1360
1361 // We're currently sending or receiving a file.
1362 if (is_transferring_)
1363 return false;
1364
1365 // We're not using NearbyConnections, should stop the process.
1366 return true;
1367 }
1368
OnProcessShutdownTimerFired()1369 void NearbySharingServiceImpl::OnProcessShutdownTimerFired() {
1370 if (ShouldStopNearbyProcess()) {
1371 NS_LOG(INFO) << __func__
1372 << ": Shutdown Process timer fired, shutting down process";
1373 process_manager_->StopProcess(profile_);
1374 }
1375 }
1376
InvalidateSendSurfaceState()1377 void NearbySharingServiceImpl::InvalidateSendSurfaceState() {
1378 InvalidateScanningState();
1379 InvalidateFastInitiationAdvertising();
1380 }
1381
InvalidateScanningState()1382 void NearbySharingServiceImpl::InvalidateScanningState() {
1383 // Nothing to do if we're shutting down the profile.
1384 if (!profile_)
1385 return;
1386
1387 if (power_client_->IsSuspended()) {
1388 StopScanning();
1389 NS_LOG(VERBOSE) << __func__
1390 << ": Stopping discovery because the system is suspended.";
1391 return;
1392 }
1393
1394 if (!process_manager_->IsActiveProfile(profile_)) {
1395 NS_LOG(VERBOSE) << __func__
1396 << ": Stopping discovery because profile was not active: "
1397 << profile_->GetProfileUserName();
1398 StopScanning();
1399 return;
1400 }
1401
1402 // Screen is off. Do no work.
1403 if (is_screen_locked_) {
1404 StopScanning();
1405 NS_LOG(VERBOSE) << __func__
1406 << ": Stopping discovery because the screen is locked.";
1407 return;
1408 }
1409
1410 if (!HasAvailableConnectionMediums()) {
1411 StopScanning();
1412 NS_LOG(VERBOSE)
1413 << __func__
1414 << ": Stopping scanning because both bluetooth and wifi LAN are "
1415 "disabled.";
1416 return;
1417 }
1418
1419 // Nearby Sharing is disabled. Don't advertise.
1420 if (!settings_.GetEnabled()) {
1421 StopScanning();
1422 NS_LOG(VERBOSE)
1423 << __func__
1424 << ": Stopping discovery because Nearby Sharing is disabled.";
1425 return;
1426 }
1427
1428 if (is_transferring_ || is_connecting_) {
1429 StopScanning();
1430 NS_LOG(VERBOSE)
1431 << __func__
1432 << ": Stopping discovery because we're currently in the midst of a "
1433 "transfer.";
1434 return;
1435 }
1436
1437 if (!foreground_send_transfer_callbacks_.might_have_observers()) {
1438 StopScanning();
1439 NS_LOG(VERBOSE)
1440 << __func__
1441 << ": Stopping discovery because no scanning surface has been "
1442 "registered.";
1443 return;
1444 }
1445
1446 process_shutdown_pending_timer_.Stop();
1447 // Screen is on, Bluetooth is enabled, and Nearby Sharing is enabled! Start
1448 // discovery.
1449 StartScanning();
1450 }
1451
InvalidateFastInitiationAdvertising()1452 void NearbySharingServiceImpl::InvalidateFastInitiationAdvertising() {
1453 // Nothing to do if we're shutting down the profile.
1454 if (!profile_)
1455 return;
1456
1457 if (power_client_->IsSuspended()) {
1458 StopFastInitiationAdvertising();
1459 NS_LOG(VERBOSE)
1460 << __func__
1461 << ": Stopping fast init advertising because the system is suspended.";
1462 return;
1463 }
1464
1465 if (!process_manager_->IsActiveProfile(profile_)) {
1466 StopFastInitiationAdvertising();
1467 NS_LOG(VERBOSE)
1468 << __func__
1469 << ": Stopping fast init advertising because profile was not active: "
1470 << profile_->GetProfileUserName();
1471 return;
1472 }
1473
1474 // Screen is off. Do no work.
1475 if (is_screen_locked_) {
1476 StopFastInitiationAdvertising();
1477 NS_LOG(VERBOSE)
1478 << __func__
1479 << ": Stopping fast init advertising because the screen is locked.";
1480 return;
1481 }
1482
1483 if (!IsBluetoothPowered()) {
1484 StopFastInitiationAdvertising();
1485 NS_LOG(VERBOSE) << __func__
1486 << ": Stopping fast init advertising because both "
1487 "bluetooth is disabled.";
1488 return;
1489 }
1490
1491 // Nearby Sharing is disabled. Don't fast init advertise.
1492 if (!settings_.GetEnabled()) {
1493 StopFastInitiationAdvertising();
1494 NS_LOG(VERBOSE) << __func__
1495 << ": Stopping fast init advertising because Nearby "
1496 "Sharing is disabled.";
1497 return;
1498 }
1499
1500 if (!foreground_send_transfer_callbacks_.might_have_observers()) {
1501 StopFastInitiationAdvertising();
1502 NS_LOG(VERBOSE) << __func__
1503 << ": Stopping fast init advertising because no send "
1504 "surface is registered.";
1505 return;
1506 }
1507
1508 if (fast_initiation_manager_) {
1509 NS_LOG(VERBOSE)
1510 << "Failed to advertise FastInitiation. Already advertising.";
1511 return;
1512 }
1513
1514 process_shutdown_pending_timer_.Stop();
1515
1516 StartFastInitiationAdvertising();
1517 }
1518
InvalidateReceiveSurfaceState()1519 void NearbySharingServiceImpl::InvalidateReceiveSurfaceState() {
1520 InvalidateAdvertisingState();
1521 // TODO(b/161889067) InvalidateFastInitScan();
1522 }
1523
InvalidateAdvertisingState()1524 void NearbySharingServiceImpl::InvalidateAdvertisingState() {
1525 // Nothing to do if we're shutting down the profile.
1526 if (!profile_)
1527 return;
1528
1529 if (power_client_->IsSuspended()) {
1530 StopAdvertising();
1531 NS_LOG(VERBOSE)
1532 << __func__
1533 << ": Stopping advertising because the system is suspended.";
1534 return;
1535 }
1536
1537 if (!process_manager_->IsActiveProfile(profile_)) {
1538 NS_LOG(VERBOSE) << __func__
1539 << ": Stopping advertising because profile was not active: "
1540 << profile_->GetProfileUserName();
1541 StopAdvertising();
1542 return;
1543 }
1544
1545 // Screen is off. Do no work.
1546 if (is_screen_locked_) {
1547 StopAdvertising();
1548 NS_LOG(VERBOSE) << __func__
1549 << ": Stopping advertising because the screen is locked.";
1550 return;
1551 }
1552
1553 if (!HasAvailableConnectionMediums()) {
1554 StopAdvertising();
1555 NS_LOG(VERBOSE)
1556 << __func__
1557 << ": Stopping advertising because both bluetooth and wifi LAN are "
1558 "disabled.";
1559 return;
1560 }
1561
1562 // Nearby Sharing is disabled. Don't advertise.
1563 if (!settings_.GetEnabled()) {
1564 StopAdvertising();
1565 NS_LOG(VERBOSE)
1566 << __func__
1567 << ": Stopping advertising because Nearby Sharing is disabled.";
1568 return;
1569 }
1570
1571 // We're scanning for other nearby devices. Don't advertise.
1572 if (is_scanning_) {
1573 StopAdvertising();
1574 NS_LOG(VERBOSE)
1575 << __func__
1576 << ": Stopping advertising because we're scanning for other devices.";
1577 return;
1578 }
1579
1580 if (is_transferring_) {
1581 StopAdvertising();
1582 NS_LOG(VERBOSE)
1583 << __func__
1584 << ": Stopping advertising because we're currently in the midst of "
1585 "a transfer.";
1586 return;
1587 }
1588
1589 if (!foreground_receive_callbacks_.might_have_observers() &&
1590 !background_receive_callbacks_.might_have_observers()) {
1591 StopAdvertising();
1592 NS_LOG(VERBOSE)
1593 << __func__
1594 << ": Stopping advertising because no receive surface is registered.";
1595 return;
1596 }
1597
1598 if (!IsVisibleInBackground(settings_.GetVisibility()) &&
1599 !foreground_receive_callbacks_.might_have_observers()) {
1600 StopAdvertising();
1601 NS_LOG(VERBOSE)
1602 << __func__
1603 << ": Stopping advertising because no high power receive surface "
1604 "is registered and device is visible to NO_ONE.";
1605 return;
1606 }
1607
1608 process_shutdown_pending_timer_.Stop();
1609
1610 PowerLevel power_level;
1611 if (foreground_receive_callbacks_.might_have_observers()) {
1612 power_level = PowerLevel::kHighPower;
1613 // TODO(crbug/1100367) handle fast init
1614 // } else if (isFastInitDeviceNearby) {
1615 // power_level = PowerLevel::kMediumPower;
1616 } else {
1617 power_level = PowerLevel::kLowPower;
1618 }
1619
1620 DataUsage data_usage = settings_.GetDataUsage();
1621 if (advertising_power_level_ != PowerLevel::kUnknown) {
1622 if (power_level == advertising_power_level_) {
1623 NS_LOG(VERBOSE)
1624 << __func__
1625 << ": Failed to advertise because we're already advertising with "
1626 "power level "
1627 << PowerLevelToString(advertising_power_level_)
1628 << " and data usage preference " << data_usage;
1629 return;
1630 }
1631
1632 StopAdvertising();
1633 NS_LOG(VERBOSE) << __func__ << ": Restart advertising with power level "
1634 << PowerLevelToString(power_level)
1635 << " and data usage preference " << data_usage;
1636 }
1637
1638 base::Optional<std::string> device_name;
1639 if (foreground_receive_callbacks_.might_have_observers())
1640 device_name = local_device_data_manager_->GetDeviceName();
1641
1642 // Starts advertising through Nearby Connections. Caller is expected to ensure
1643 // |listener| remains valid until StopAdvertising is called.
1644 base::Optional<std::vector<uint8_t>> endpoint_info =
1645 CreateEndpointInfo(device_name);
1646 if (!endpoint_info) {
1647 NS_LOG(VERBOSE) << __func__
1648 << ": Unable to advertise since could not parse the "
1649 "endpoint info from the advertisement.";
1650 return;
1651 }
1652
1653 // TODO(crbug/1147652): The call to update the advertising interval is
1654 // removed to prevent a Bluez crash. We need to either reduce the global
1655 // advertising interval asynchronously and wait for the result or use the
1656 // updated API referenced in the bug which allows setting a per-advertisement
1657 // interval.
1658
1659 nearby_connections_manager_->StartAdvertising(
1660 *endpoint_info,
1661 /*listener=*/this, power_level, data_usage,
1662 base::BindOnce(&NearbySharingServiceImpl::OnStartAdvertisingResult,
1663 weak_ptr_factory_.GetWeakPtr(), device_name.has_value()));
1664
1665 advertising_power_level_ = power_level;
1666 NS_LOG(VERBOSE) << __func__
1667 << ": StartAdvertising requested over Nearby Connections: "
1668 << " power level: " << PowerLevelToString(power_level)
1669 << " visibility: " << settings_.GetVisibility()
1670 << " data usage: " << data_usage << " device name: "
1671 << device_name.value_or("** no device name **");
1672
1673 ScheduleRotateBackgroundAdvertisementTimer();
1674 }
1675
StopAdvertising()1676 void NearbySharingServiceImpl::StopAdvertising() {
1677 SetInHighVisibility(false);
1678 if (advertising_power_level_ == PowerLevel::kUnknown) {
1679 NS_LOG(VERBOSE)
1680 << __func__
1681 << ": Failed to stop advertising because we weren't advertising";
1682 return;
1683 }
1684
1685 nearby_connections_manager_->StopAdvertising();
1686 advertising_power_level_ = PowerLevel::kUnknown;
1687
1688 // TODO(crbug/1147652): The call to update the advertising interval is
1689 // removed to prevent a Bluez crash. We need to either reduce the global
1690 // advertising interval asynchronously and wait for the result or use the
1691 // updated API referenced in the bug which allows setting a per-advertisement
1692 // interval.
1693
1694 NS_LOG(VERBOSE) << __func__ << ": Advertising has stopped";
1695 }
1696
StartScanning()1697 void NearbySharingServiceImpl::StartScanning() {
1698 DCHECK(profile_);
1699 DCHECK(!power_client_->IsSuspended());
1700 DCHECK(settings_.GetEnabled());
1701 DCHECK(!is_screen_locked_);
1702 DCHECK(HasAvailableConnectionMediums());
1703 DCHECK(foreground_send_transfer_callbacks_.might_have_observers());
1704
1705 if (is_scanning_) {
1706 NS_LOG(VERBOSE) << __func__
1707 << ": Failed to scan because we're currently scanning.";
1708 return;
1709 }
1710
1711 scanning_start_timestamp_ = base::Time::Now();
1712 is_scanning_ = true;
1713 InvalidateReceiveSurfaceState();
1714
1715 ClearOutgoingShareTargetInfoMap();
1716
1717 nearby_connections_manager_->StartDiscovery(
1718 /*listener=*/this, settings_.GetDataUsage(),
1719 base::BindOnce([](NearbyConnectionsManager::ConnectionsStatus status) {
1720 NS_LOG(VERBOSE) << __func__
1721 << ": Scanning start attempted over Nearby Connections "
1722 "with result "
1723 << status;
1724 }));
1725
1726 InvalidateSendSurfaceState();
1727 NS_LOG(VERBOSE) << __func__ << ": Scanning has started";
1728 }
1729
StopScanning()1730 NearbySharingService::StatusCodes NearbySharingServiceImpl::StopScanning() {
1731 if (!is_scanning_) {
1732 NS_LOG(VERBOSE) << __func__
1733 << ": Failed to stop scanning because weren't scanning.";
1734 return StatusCodes::kStatusAlreadyStopped;
1735 }
1736
1737 nearby_connections_manager_->StopDiscovery();
1738 is_scanning_ = false;
1739
1740 // Note: We don't know if we stopped scanning in preparation to send a file,
1741 // or we stopped because the user left the page. We'll invalidate after a
1742 // short delay.
1743 base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
1744 FROM_HERE,
1745 base::BindOnce(&NearbySharingServiceImpl::InvalidateSurfaceState,
1746 weak_ptr_factory_.GetWeakPtr()),
1747 kInvalidateDelay);
1748
1749 NS_LOG(VERBOSE) << __func__ << ": Scanning has stopped.";
1750 return StatusCodes::kOk;
1751 }
1752
ScheduleRotateBackgroundAdvertisementTimer()1753 void NearbySharingServiceImpl::ScheduleRotateBackgroundAdvertisementTimer() {
1754 uint64_t delayRangeMilliseconds = base::checked_cast<uint64_t>(
1755 kBackgroundAdvertisementRotationDelayMax.InMilliseconds() -
1756 kBackgroundAdvertisementRotationDelayMin.InMilliseconds());
1757 uint64_t delayMilliseconds =
1758 base::RandGenerator(delayRangeMilliseconds) +
1759 base::checked_cast<uint64_t>(
1760 kBackgroundAdvertisementRotationDelayMin.InMilliseconds());
1761 rotate_background_advertisement_timer_.Start(
1762 FROM_HERE,
1763 base::TimeDelta::FromMilliseconds(
1764 base::checked_cast<uint64_t>(delayMilliseconds)),
1765 base::BindOnce(
1766 &NearbySharingServiceImpl::OnRotateBackgroundAdvertisementTimerFired,
1767 weak_ptr_factory_.GetWeakPtr()));
1768 }
1769
OnRotateBackgroundAdvertisementTimerFired()1770 void NearbySharingServiceImpl::OnRotateBackgroundAdvertisementTimerFired() {
1771 if (foreground_receive_callbacks_.might_have_observers()) {
1772 ScheduleRotateBackgroundAdvertisementTimer();
1773 } else {
1774 StopAdvertising();
1775 InvalidateSurfaceState();
1776 }
1777 }
1778
RemoveOutgoingShareTargetWithEndpointId(const std::string & endpoint_id)1779 void NearbySharingServiceImpl::RemoveOutgoingShareTargetWithEndpointId(
1780 const std::string& endpoint_id) {
1781 auto it = outgoing_share_target_map_.find(endpoint_id);
1782 if (it == outgoing_share_target_map_.end())
1783 return;
1784
1785 NS_LOG(VERBOSE) << __func__ << ": Removing (endpoint_id=" << it->first
1786 << ", share_target.id=" << it->second.id
1787 << ") from outgoing share target map";
1788 ShareTarget share_target = std::move(it->second);
1789 outgoing_share_target_map_.erase(it);
1790
1791 auto info_it = outgoing_share_target_info_map_.find(share_target.id);
1792 if (info_it != outgoing_share_target_info_map_.end()) {
1793 file_handler_.ReleaseFilePayloads(info_it->second.ExtractFilePayloads());
1794 outgoing_share_target_info_map_.erase(info_it);
1795 }
1796
1797 for (ShareTargetDiscoveredCallback& discovery_callback :
1798 foreground_send_discovery_callbacks_) {
1799 discovery_callback.OnShareTargetLost(share_target);
1800 }
1801 for (ShareTargetDiscoveredCallback& discovery_callback :
1802 background_send_discovery_callbacks_) {
1803 discovery_callback.OnShareTargetLost(share_target);
1804 }
1805
1806 NS_LOG(VERBOSE) << __func__ << ": Reported OnShareTargetLost";
1807 }
1808
OnTransferComplete()1809 void NearbySharingServiceImpl::OnTransferComplete() {
1810 bool was_sending_files = is_sending_files_;
1811 is_receiving_files_ = false;
1812 is_transferring_ = false;
1813 is_sending_files_ = false;
1814
1815 NS_LOG(VERBOSE) << __func__
1816 << ": NearbySharing state change transfer finished";
1817 // Files transfer is done! Receivers can immediately cancel, but senders
1818 // should add a short delay to ensure the final in-flight packet(s) make
1819 // it to the remote device.
1820 base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
1821 FROM_HERE,
1822 base::BindOnce(&NearbySharingServiceImpl::InvalidateSurfaceState,
1823 weak_ptr_factory_.GetWeakPtr()),
1824 was_sending_files ? kInvalidateSurfaceStateDelayAfterTransferDone
1825 : base::TimeDelta());
1826 }
1827
OnTransferStarted(bool is_incoming)1828 void NearbySharingServiceImpl::OnTransferStarted(bool is_incoming) {
1829 is_transferring_ = true;
1830 if (is_incoming) {
1831 is_receiving_files_ = true;
1832 } else {
1833 is_sending_files_ = true;
1834 }
1835 InvalidateSurfaceState();
1836 }
1837
ReceivePayloads(ShareTarget share_target,StatusCodesCallback status_codes_callback)1838 void NearbySharingServiceImpl::ReceivePayloads(
1839 ShareTarget share_target,
1840 StatusCodesCallback status_codes_callback) {
1841 DCHECK(profile_);
1842 mutual_acceptance_timeout_alarm_.Cancel();
1843
1844 base::FilePath download_path =
1845 DownloadPrefs::FromDownloadManager(
1846 content::BrowserContext::GetDownloadManager(profile_))
1847 ->DownloadPath();
1848
1849 // Register payload path for all valid file payloads.
1850 base::flat_map<int64_t, base::FilePath> valid_file_payloads;
1851 for (auto& file : share_target.file_attachments) {
1852 base::Optional<int64_t> payload_id = GetAttachmentPayloadId(file.id());
1853 if (!payload_id) {
1854 NS_LOG(WARNING)
1855 << __func__
1856 << ": Failed to register payload path for attachment id - "
1857 << file.id();
1858 continue;
1859 }
1860
1861 base::FilePath file_path = download_path.AppendASCII(file.file_name());
1862 valid_file_payloads.emplace(file.id(), std::move(file_path));
1863 }
1864
1865 auto aggregated_success = std::make_unique<bool>(true);
1866 bool* aggregated_success_ptr = aggregated_success.get();
1867
1868 if (valid_file_payloads.empty()) {
1869 OnPayloadPathsRegistered(share_target, std::move(aggregated_success),
1870 std::move(status_codes_callback));
1871 return;
1872 }
1873
1874 auto all_paths_registered_callback = base::BarrierClosure(
1875 valid_file_payloads.size(),
1876 base::BindOnce(&NearbySharingServiceImpl::OnPayloadPathsRegistered,
1877 weak_ptr_factory_.GetWeakPtr(), share_target,
1878 std::move(aggregated_success),
1879 std::move(status_codes_callback)));
1880
1881 for (const auto& payload : valid_file_payloads) {
1882 base::Optional<int64_t> payload_id = GetAttachmentPayloadId(payload.first);
1883 DCHECK(payload_id);
1884
1885 file_handler_.GetUniquePath(
1886 payload.second,
1887 base::BindOnce(
1888 &NearbySharingServiceImpl::OnUniquePathFetched,
1889 weak_ptr_factory_.GetWeakPtr(), payload.first, *payload_id,
1890 base::BindOnce(
1891 &NearbySharingServiceImpl::OnPayloadPathRegistered,
1892 weak_ptr_factory_.GetWeakPtr(),
1893 base::ScopedClosureRunner(all_paths_registered_callback),
1894 aggregated_success_ptr)));
1895 }
1896 }
1897
SendPayloads(const ShareTarget & share_target)1898 NearbySharingService::StatusCodes NearbySharingServiceImpl::SendPayloads(
1899 const ShareTarget& share_target) {
1900 NS_LOG(VERBOSE) << __func__ << ": Preparing to send payloads to "
1901 << share_target.device_name;
1902 ShareTargetInfo* info = GetShareTargetInfo(share_target);
1903 if (!info || !info->connection()) {
1904 NS_LOG(WARNING) << "Failed to send payload due to missing connection.";
1905 return StatusCodes::kOutOfOrderApiCall;
1906 }
1907 if (!info->transfer_update_callback()) {
1908 NS_LOG(WARNING) << "Failed to send payload due to missing transfer update "
1909 "callback. Disconnecting.";
1910 info->connection()->Close();
1911 return StatusCodes::kOutOfOrderApiCall;
1912 }
1913
1914 info->transfer_update_callback()->OnTransferUpdate(
1915 share_target,
1916 TransferMetadataBuilder()
1917 .set_token(info->token())
1918 .set_status(TransferMetadata::Status::kAwaitingRemoteAcceptance)
1919 .build());
1920
1921 if (!info->endpoint_id()) {
1922 info->transfer_update_callback()->OnTransferUpdate(
1923 share_target, TransferMetadataBuilder()
1924 .set_status(TransferMetadata::Status::kFailed)
1925 .build());
1926 info->connection()->Close();
1927 NS_LOG(WARNING) << "Failed to send payload due to missing endpoint id.";
1928 return StatusCodes::kOutOfOrderApiCall;
1929 }
1930
1931 ReceiveConnectionResponse(share_target);
1932 return StatusCodes::kOk;
1933 }
1934
OnUniquePathFetched(int64_t attachment_id,int64_t payload_id,base::OnceCallback<void (location::nearby::connections::mojom::Status)> callback,base::FilePath path)1935 void NearbySharingServiceImpl::OnUniquePathFetched(
1936 int64_t attachment_id,
1937 int64_t payload_id,
1938 base::OnceCallback<void(location::nearby::connections::mojom::Status)>
1939 callback,
1940 base::FilePath path) {
1941 attachment_info_map_[attachment_id].file_path = path;
1942 nearby_connections_manager_->RegisterPayloadPath(payload_id, path,
1943 std::move(callback));
1944 }
1945
OnPayloadPathRegistered(base::ScopedClosureRunner closure_runner,bool * aggregated_success,location::nearby::connections::mojom::Status status)1946 void NearbySharingServiceImpl::OnPayloadPathRegistered(
1947 base::ScopedClosureRunner closure_runner,
1948 bool* aggregated_success,
1949 location::nearby::connections::mojom::Status status) {
1950 if (status != location::nearby::connections::mojom::Status::kSuccess)
1951 *aggregated_success = false;
1952 }
1953
OnPayloadPathsRegistered(const ShareTarget & share_target,std::unique_ptr<bool> aggregated_success,StatusCodesCallback status_codes_callback)1954 void NearbySharingServiceImpl::OnPayloadPathsRegistered(
1955 const ShareTarget& share_target,
1956 std::unique_ptr<bool> aggregated_success,
1957 StatusCodesCallback status_codes_callback) {
1958 DCHECK(aggregated_success);
1959 if (!*aggregated_success) {
1960 NS_LOG(WARNING)
1961 << __func__
1962 << ": Not all payload paths could be registered successfully.";
1963 std::move(status_codes_callback).Run(StatusCodes::kError);
1964 return;
1965 }
1966
1967 ShareTargetInfo* info = GetShareTargetInfo(share_target);
1968 if (!info || !info->connection()) {
1969 NS_LOG(WARNING) << __func__ << ": Accept invoked for unknown share target";
1970 std::move(status_codes_callback).Run(StatusCodes::kOutOfOrderApiCall);
1971 return;
1972 }
1973 NearbyConnection* connection = info->connection();
1974
1975 if (!info->transfer_update_callback()) {
1976 NS_LOG(WARNING) << __func__
1977 << ": Accept invoked for share target without transfer "
1978 "update callback. Disconnecting.";
1979 connection->Close();
1980 std::move(status_codes_callback).Run(StatusCodes::kOutOfOrderApiCall);
1981 return;
1982 }
1983
1984 info->set_payload_tracker(std::make_unique<PayloadTracker>(
1985 share_target, attachment_info_map_,
1986 base::BindRepeating(&NearbySharingServiceImpl::OnPayloadTransferUpdate,
1987 weak_ptr_factory_.GetWeakPtr())));
1988
1989 // Register status listener for all payloads.
1990 for (int64_t attachment_id : share_target.GetAttachmentIds()) {
1991 base::Optional<int64_t> payload_id = GetAttachmentPayloadId(attachment_id);
1992 if (!payload_id) {
1993 NS_LOG(WARNING) << __func__
1994 << ": Failed to retrieve payload for attachment id - "
1995 << attachment_id;
1996 continue;
1997 }
1998
1999 NS_LOG(VERBOSE) << __func__
2000 << ": Started listening for progress on payload - "
2001 << *payload_id;
2002
2003 nearby_connections_manager_->RegisterPayloadStatusListener(
2004 *payload_id, info->payload_tracker());
2005
2006 NS_LOG(VERBOSE) << __func__
2007 << ": Accepted incoming files from share target - "
2008 << share_target.device_name;
2009 }
2010
2011 WriteResponse(*connection, sharing::nearby::ConnectionResponseFrame::ACCEPT);
2012 NS_LOG(VERBOSE) << __func__ << ": Successfully wrote response frame";
2013
2014 info->transfer_update_callback()->OnTransferUpdate(
2015 share_target,
2016 TransferMetadataBuilder()
2017 .set_status(TransferMetadata::Status::kAwaitingRemoteAcceptance)
2018 .set_token(info->token())
2019 .build());
2020
2021 base::Optional<std::string> endpoint_id = info->endpoint_id();
2022 if (endpoint_id) {
2023 nearby_connections_manager_->UpgradeBandwidth(*endpoint_id);
2024 } else {
2025 NS_LOG(WARNING) << __func__
2026 << ": Failed to initiate bandwidth upgrade. No endpoint_id "
2027 "found for target - "
2028 << share_target.device_name;
2029 std::move(status_codes_callback).Run(StatusCodes::kOutOfOrderApiCall);
2030 return;
2031 }
2032
2033 std::move(status_codes_callback).Run(StatusCodes::kOk);
2034 }
2035
OnOutgoingConnection(const ShareTarget & share_target,NearbyConnection * connection)2036 void NearbySharingServiceImpl::OnOutgoingConnection(
2037 const ShareTarget& share_target,
2038 NearbyConnection* connection) {
2039 OutgoingShareTargetInfo* info = GetOutgoingShareTargetInfo(share_target);
2040 if (!info || !info->endpoint_id() || !connection) {
2041 NS_LOG(WARNING) << __func__
2042 << ": Failed to initate connection to share target "
2043 << share_target.device_name;
2044 if (info->transfer_update_callback()) {
2045 info->transfer_update_callback()->OnTransferUpdate(
2046 share_target, TransferMetadataBuilder()
2047 .set_status(TransferMetadata::Status::kFailed)
2048 .build());
2049 }
2050 return;
2051 }
2052
2053 info->set_connection(connection);
2054
2055 connection->SetDisconnectionListener(base::BindOnce(
2056 &NearbySharingServiceImpl::OnOutgoingConnectionDisconnected,
2057 weak_ptr_factory_.GetWeakPtr(), share_target));
2058
2059 base::Optional<std::string> four_digit_token =
2060 ToFourDigitString(nearby_connections_manager_->GetRawAuthenticationToken(
2061 *info->endpoint_id()));
2062
2063 RunPairedKeyVerification(
2064 share_target, *info->endpoint_id(),
2065 base::BindOnce(
2066 &NearbySharingServiceImpl::OnOutgoingConnectionKeyVerificationDone,
2067 weak_ptr_factory_.GetWeakPtr(), share_target,
2068 std::move(four_digit_token)));
2069 }
2070
SendIntroduction(const ShareTarget & share_target,base::Optional<std::string> four_digit_token)2071 void NearbySharingServiceImpl::SendIntroduction(
2072 const ShareTarget& share_target,
2073 base::Optional<std::string> four_digit_token) {
2074 // We successfully connected! Now lets build up Payloads for all the files we
2075 // want to send them. We won't send any just yet, but we'll send the Payload
2076 // IDs in our our introduction frame so that they know what to expect if they
2077 // accept.
2078 NS_LOG(VERBOSE) << __func__ << ": Preparing to send introduction to "
2079 << share_target.device_name;
2080
2081 ShareTargetInfo* info = GetShareTargetInfo(share_target);
2082 if (!info || !info->connection()) {
2083 NS_LOG(WARNING) << __func__ << ": No NearbyConnection tied to "
2084 << share_target.device_name;
2085 return;
2086 }
2087 NearbyConnection* connection = info->connection();
2088
2089 if (!info->transfer_update_callback()) {
2090 connection->Close();
2091 NS_LOG(WARNING) << __func__
2092 << ": No transfer update callback, disconnecting.";
2093 return;
2094 }
2095
2096 if (!foreground_send_transfer_callbacks_.might_have_observers() &&
2097 !background_send_transfer_callbacks_.might_have_observers()) {
2098 connection->Close();
2099 NS_LOG(WARNING) << __func__ << ": No transfer callbacks, disconnecting.";
2100 return;
2101 }
2102
2103 // Build the introduction.
2104 auto introduction = std::make_unique<sharing::nearby::IntroductionFrame>();
2105 NS_LOG(VERBOSE) << __func__ << ": Sending attachments to "
2106 << share_target.device_name;
2107
2108 // Write introduction of file payloads.
2109 for (const auto& file : share_target.file_attachments) {
2110 base::Optional<int64_t> payload_id = GetAttachmentPayloadId(file.id());
2111 if (!payload_id) {
2112 NS_LOG(VERBOSE) << __func__ << ": Skipping unknown file attachment";
2113 continue;
2114 }
2115 auto* file_metadata = introduction->add_file_metadata();
2116 file_metadata->set_id(file.id());
2117 file_metadata->set_name(file.file_name());
2118 file_metadata->set_payload_id(*payload_id);
2119 file_metadata->set_type(sharing::ConvertFileMetadataType(file.type()));
2120 file_metadata->set_mime_type(file.mime_type());
2121 file_metadata->set_size(file.size());
2122 }
2123
2124 // Write introduction of text payloads.
2125 for (const auto& text : share_target.text_attachments) {
2126 base::Optional<int64_t> payload_id = GetAttachmentPayloadId(text.id());
2127 if (!payload_id) {
2128 NS_LOG(VERBOSE) << __func__ << ": Skipping unknown text attachment";
2129 continue;
2130 }
2131 auto* text_metadata = introduction->add_text_metadata();
2132 text_metadata->set_id(text.id());
2133 text_metadata->set_text_title(text.text_title());
2134 text_metadata->set_type(sharing::ConvertTextMetadataType(text.type()));
2135 text_metadata->set_size(text.size());
2136 text_metadata->set_payload_id(*payload_id);
2137 }
2138
2139 if (introduction->file_metadata_size() == 0 &&
2140 introduction->text_metadata_size() == 0) {
2141 NS_LOG(WARNING) << __func__
2142 << ": No payloads tied to transfer, disconnecting.";
2143 info->transfer_update_callback()->OnTransferUpdate(
2144 share_target, TransferMetadataBuilder()
2145 .set_status(TransferMetadata::Status::kFailed)
2146 .build());
2147 connection->Close();
2148 return;
2149 }
2150
2151 // Write the introduction to the remote device.
2152 sharing::nearby::Frame frame;
2153 frame.set_version(sharing::nearby::Frame::V1);
2154 sharing::nearby::V1Frame* v1_frame = frame.mutable_v1();
2155 v1_frame->set_type(sharing::nearby::V1Frame::INTRODUCTION);
2156 v1_frame->set_allocated_introduction(introduction.release());
2157
2158 std::vector<uint8_t> data(frame.ByteSize());
2159 frame.SerializeToArray(data.data(), frame.ByteSize());
2160 connection->Write(std::move(data));
2161
2162 // We've successfully written the introduction, so we now have to wait for the
2163 // remote side to accept.
2164 NS_LOG(VERBOSE) << __func__ << ": Successfully wrote the introduction frame";
2165
2166 mutual_acceptance_timeout_alarm_.Reset(base::BindOnce(
2167 &NearbySharingServiceImpl::OnOutgoingMutualAcceptanceTimeout,
2168 weak_ptr_factory_.GetWeakPtr(), share_target));
2169
2170 base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
2171 FROM_HERE, base::BindOnce(mutual_acceptance_timeout_alarm_.callback()),
2172 kReadResponseFrameTimeout);
2173
2174 info->transfer_update_callback()->OnTransferUpdate(
2175 share_target,
2176 TransferMetadataBuilder()
2177 .set_status(TransferMetadata::Status::kAwaitingLocalConfirmation)
2178 .set_token(four_digit_token)
2179 .build());
2180 }
2181
CreatePayloads(ShareTarget share_target,base::OnceCallback<void (ShareTarget,bool)> callback)2182 void NearbySharingServiceImpl::CreatePayloads(
2183 ShareTarget share_target,
2184 base::OnceCallback<void(ShareTarget, bool)> callback) {
2185 OutgoingShareTargetInfo* info = GetOutgoingShareTargetInfo(share_target);
2186 if (!info || !share_target.has_attachments()) {
2187 std::move(callback).Run(std::move(share_target), /*success=*/false);
2188 return;
2189 }
2190
2191 if (!info->file_payloads().empty() || !info->text_payloads().empty()) {
2192 // We may have already created the payloads in the case of retry, so we can
2193 // skip this step.
2194 std::move(callback).Run(std::move(share_target), /*success=*/false);
2195 return;
2196 }
2197
2198 info->set_text_payloads(CreateTextPayloads(share_target.text_attachments));
2199 if (share_target.file_attachments.empty()) {
2200 std::move(callback).Run(std::move(share_target), /*success=*/true);
2201 return;
2202 }
2203
2204 std::vector<base::FilePath> file_paths;
2205 for (const FileAttachment& attachment : share_target.file_attachments) {
2206 if (!attachment.file_path()) {
2207 NS_LOG(WARNING) << __func__ << ": Got file attachment without path";
2208 std::move(callback).Run(std::move(share_target), /*success=*/false);
2209 return;
2210 }
2211 file_paths.push_back(*attachment.file_path());
2212 }
2213
2214 file_handler_.OpenFiles(
2215 std::move(file_paths),
2216 base::BindOnce(&NearbySharingServiceImpl::OnOpenFiles,
2217 weak_ptr_factory_.GetWeakPtr(), std::move(share_target),
2218 std::move(callback)));
2219 }
2220
OnCreatePayloads(std::vector<uint8_t> endpoint_info,ShareTarget share_target,bool success)2221 void NearbySharingServiceImpl::OnCreatePayloads(
2222 std::vector<uint8_t> endpoint_info,
2223 ShareTarget share_target,
2224 bool success) {
2225 OutgoingShareTargetInfo* info = GetOutgoingShareTargetInfo(share_target);
2226 bool has_payloads = info && (!info->text_payloads().empty() ||
2227 !info->file_payloads().empty());
2228 if (!success || !has_payloads || !info->endpoint_id()) {
2229 NS_LOG(WARNING) << __func__
2230 << ": Failed to send file to remote ShareTarget. Failed to "
2231 "create payloads.";
2232 if (info && info->transfer_update_callback()) {
2233 info->transfer_update_callback()->OnTransferUpdate(
2234 share_target,
2235 TransferMetadataBuilder()
2236 .set_status(TransferMetadata::Status::kMediaUnavailable)
2237 .build());
2238 }
2239 return;
2240 }
2241
2242 base::Optional<std::vector<uint8_t>> bluetooth_mac_address =
2243 GetBluetoothMacAddress(share_target);
2244
2245 DataUsage adjusted_data_usage = CheckFileSizeForDataUsagePreference(
2246 settings_.GetDataUsage(), share_target);
2247
2248 // TODO(crbug.com/1111458): Add preferred transfer type.
2249 nearby_connections_manager_->Connect(
2250 std::move(endpoint_info), *info->endpoint_id(),
2251 std::move(bluetooth_mac_address), adjusted_data_usage,
2252 base::BindOnce(&NearbySharingServiceImpl::OnOutgoingConnection,
2253 weak_ptr_factory_.GetWeakPtr(), share_target));
2254 }
2255
OnOpenFiles(ShareTarget share_target,base::OnceCallback<void (ShareTarget,bool)> callback,std::vector<NearbyFileHandler::FileInfo> files)2256 void NearbySharingServiceImpl::OnOpenFiles(
2257 ShareTarget share_target,
2258 base::OnceCallback<void(ShareTarget, bool)> callback,
2259 std::vector<NearbyFileHandler::FileInfo> files) {
2260 OutgoingShareTargetInfo* info = GetOutgoingShareTargetInfo(share_target);
2261 if (!info || files.size() != share_target.file_attachments.size()) {
2262 std::move(callback).Run(std::move(share_target), /*success=*/false);
2263 return;
2264 }
2265
2266 std::vector<location::nearby::connections::mojom::PayloadPtr> payloads;
2267 payloads.reserve(files.size());
2268
2269 for (size_t i = 0; i < files.size(); ++i) {
2270 FileAttachment& attachment = share_target.file_attachments[i];
2271 attachment.set_size(files[i].size);
2272 base::File& file = files[i].file;
2273 int64_t payload_id = GeneratePayloadId();
2274 SetAttachmentPayloadId(attachment, payload_id);
2275 payloads.push_back(location::nearby::connections::mojom::Payload::New(
2276 payload_id,
2277 location::nearby::connections::mojom::PayloadContent::NewFile(
2278 location::nearby::connections::mojom::FilePayload::New(
2279 std::move(file)))));
2280 }
2281
2282 info->set_file_payloads(std::move(payloads));
2283 std::move(callback).Run(std::move(share_target), /*success=*/true);
2284 }
2285
2286 std::vector<location::nearby::connections::mojom::PayloadPtr>
CreateTextPayloads(const std::vector<TextAttachment> & attachments)2287 NearbySharingServiceImpl::CreateTextPayloads(
2288 const std::vector<TextAttachment>& attachments) {
2289 std::vector<location::nearby::connections::mojom::PayloadPtr> payloads;
2290 payloads.reserve(attachments.size());
2291 for (const TextAttachment& attachment : attachments) {
2292 const std::string& body = attachment.text_body();
2293 std::vector<uint8_t> bytes(body.begin(), body.end());
2294
2295 int64_t payload_id = GeneratePayloadId();
2296 SetAttachmentPayloadId(attachment, payload_id);
2297 payloads.push_back(location::nearby::connections::mojom::Payload::New(
2298 payload_id,
2299 location::nearby::connections::mojom::PayloadContent::NewBytes(
2300 location::nearby::connections::mojom::BytesPayload::New(
2301 std::move(bytes)))));
2302 }
2303 return payloads;
2304 }
2305
WriteResponse(NearbyConnection & connection,sharing::nearby::ConnectionResponseFrame::Status status)2306 void NearbySharingServiceImpl::WriteResponse(
2307 NearbyConnection& connection,
2308 sharing::nearby::ConnectionResponseFrame::Status status) {
2309 sharing::nearby::Frame frame;
2310 frame.set_version(sharing::nearby::Frame::V1);
2311 sharing::nearby::V1Frame* v1_frame = frame.mutable_v1();
2312 v1_frame->set_type(sharing::nearby::V1Frame::RESPONSE);
2313 v1_frame->mutable_connection_response()->set_status(status);
2314
2315 std::vector<uint8_t> data(frame.ByteSize());
2316 frame.SerializeToArray(data.data(), frame.ByteSize());
2317
2318 connection.Write(std::move(data));
2319 }
2320
WriteCancel(NearbyConnection & connection)2321 void NearbySharingServiceImpl::WriteCancel(NearbyConnection& connection) {
2322 NS_LOG(INFO) << __func__ << ": Writing cancel frame.";
2323
2324 sharing::nearby::Frame frame;
2325 frame.set_version(sharing::nearby::Frame::V1);
2326 sharing::nearby::V1Frame* v1_frame = frame.mutable_v1();
2327 v1_frame->set_type(sharing::nearby::V1Frame::CANCEL);
2328
2329 std::vector<uint8_t> data(frame.ByteSize());
2330 frame.SerializeToArray(data.data(), frame.ByteSize());
2331
2332 connection.Write(std::move(data));
2333 }
2334
Fail(const ShareTarget & share_target,TransferMetadata::Status status)2335 void NearbySharingServiceImpl::Fail(const ShareTarget& share_target,
2336 TransferMetadata::Status status) {
2337 ShareTargetInfo* info = GetShareTargetInfo(share_target);
2338 if (!info || !info->connection()) {
2339 NS_LOG(WARNING) << __func__ << ": Fail invoked for unknown share target.";
2340 return;
2341 }
2342 NearbyConnection* connection = info->connection();
2343
2344 base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
2345 FROM_HERE,
2346 base::BindOnce(&NearbySharingServiceImpl::CloseConnection,
2347 weak_ptr_factory_.GetWeakPtr(), share_target),
2348 kIncomingRejectionDelay);
2349
2350 connection->SetDisconnectionListener(
2351 base::BindOnce(&NearbySharingServiceImpl::UnregisterShareTarget,
2352 weak_ptr_factory_.GetWeakPtr(), share_target));
2353
2354 // Send response to remote device.
2355 sharing::nearby::ConnectionResponseFrame::Status response_status;
2356 switch (status) {
2357 case TransferMetadata::Status::kNotEnoughSpace:
2358 response_status =
2359 sharing::nearby::ConnectionResponseFrame::NOT_ENOUGH_SPACE;
2360 break;
2361
2362 case TransferMetadata::Status::kUnsupportedAttachmentType:
2363 response_status =
2364 sharing::nearby::ConnectionResponseFrame::UNSUPPORTED_ATTACHMENT_TYPE;
2365 break;
2366
2367 case TransferMetadata::Status::kTimedOut:
2368 response_status = sharing::nearby::ConnectionResponseFrame::TIMED_OUT;
2369 break;
2370
2371 default:
2372 response_status = sharing::nearby::ConnectionResponseFrame::UNKNOWN;
2373 break;
2374 }
2375
2376 WriteResponse(*connection, response_status);
2377
2378 if (info->transfer_update_callback()) {
2379 info->transfer_update_callback()->OnTransferUpdate(
2380 share_target, TransferMetadataBuilder().set_status(status).build());
2381 }
2382 }
2383
OnIncomingAdvertisementDecoded(const std::string & endpoint_id,ShareTarget placeholder_share_target,sharing::mojom::AdvertisementPtr advertisement)2384 void NearbySharingServiceImpl::OnIncomingAdvertisementDecoded(
2385 const std::string& endpoint_id,
2386 ShareTarget placeholder_share_target,
2387 sharing::mojom::AdvertisementPtr advertisement) {
2388 NearbyConnection* connection = GetConnection(placeholder_share_target);
2389 if (!connection) {
2390 NS_LOG(VERBOSE) << __func__ << ": Invalid connection for endoint id - "
2391 << endpoint_id;
2392 return;
2393 }
2394
2395 if (!advertisement) {
2396 NS_LOG(VERBOSE) << __func__
2397 << "Failed to parse incoming connection from endpoint - "
2398 << endpoint_id << ", disconnecting.";
2399 connection->Close();
2400 return;
2401 }
2402
2403 NearbyShareEncryptedMetadataKey encrypted_metadata_key(
2404 advertisement->salt, advertisement->encrypted_metadata_key);
2405 GetCertificateManager()->GetDecryptedPublicCertificate(
2406 std::move(encrypted_metadata_key),
2407 base::BindOnce(&NearbySharingServiceImpl::OnIncomingDecryptedCertificate,
2408 weak_ptr_factory_.GetWeakPtr(), endpoint_id,
2409 std::move(advertisement),
2410 std::move(placeholder_share_target)));
2411 }
2412
OnIncomingTransferUpdate(const ShareTarget & share_target,const TransferMetadata & metadata)2413 void NearbySharingServiceImpl::OnIncomingTransferUpdate(
2414 const ShareTarget& share_target,
2415 const TransferMetadata& metadata) {
2416 NS_LOG(VERBOSE) << __func__ << ": Nearby Share service: "
2417 << "Incoming transfer update for share target with ID "
2418 << share_target.id << ": "
2419 << TransferMetadata::StatusToString(metadata.status());
2420 if (metadata.status() != TransferMetadata::Status::kCancelled &&
2421 metadata.status() != TransferMetadata::Status::kRejected) {
2422 last_incoming_metadata_ =
2423 std::make_pair(share_target, TransferMetadataBuilder::Clone(metadata)
2424 .set_is_original(false)
2425 .build());
2426 } else {
2427 last_incoming_metadata_ = base::nullopt;
2428 }
2429
2430 if (metadata.is_final_status()) {
2431 RecordNearbyShareTransferCompletionStatusMetric(
2432 /*is_incoming=*/true, share_target.type, metadata.status());
2433 OnTransferComplete();
2434 if (metadata.status() != TransferMetadata::Status::kComplete) {
2435 // For any type of failure, lets make sure any pending files get cleaned
2436 // up.
2437 RemoveIncomingPayloads(share_target);
2438 }
2439 } else if (metadata.status() ==
2440 TransferMetadata::Status::kAwaitingLocalConfirmation) {
2441 OnTransferStarted(/*is_incoming=*/true);
2442 }
2443
2444 base::ObserverList<TransferUpdateCallback>& transfer_callbacks =
2445 foreground_receive_callbacks_.might_have_observers()
2446 ? foreground_receive_callbacks_
2447 : background_receive_callbacks_;
2448
2449 for (TransferUpdateCallback& callback : transfer_callbacks) {
2450 callback.OnTransferUpdate(share_target, metadata);
2451 }
2452 }
2453
OnOutgoingTransferUpdate(const ShareTarget & share_target,const TransferMetadata & metadata)2454 void NearbySharingServiceImpl::OnOutgoingTransferUpdate(
2455 const ShareTarget& share_target,
2456 const TransferMetadata& metadata) {
2457 NS_LOG(VERBOSE) << __func__ << ": Nearby Share service: "
2458 << "Outgoing transfer update for share target with ID "
2459 << share_target.id << ": "
2460 << TransferMetadata::StatusToString(metadata.status());
2461
2462 if (metadata.is_final_status()) {
2463 is_connecting_ = false;
2464 RecordNearbyShareTransferCompletionStatusMetric(
2465 /*is_incoming=*/false, share_target.type, metadata.status());
2466 OnTransferComplete();
2467 } else if (metadata.status() == TransferMetadata::Status::kMediaDownloading ||
2468 metadata.status() ==
2469 TransferMetadata::Status::kAwaitingLocalConfirmation) {
2470 is_connecting_ = false;
2471 OnTransferStarted(/*is_incoming=*/false);
2472 }
2473
2474 bool has_foreground_send_surface =
2475 foreground_send_transfer_callbacks_.might_have_observers();
2476 base::ObserverList<TransferUpdateCallback>& transfer_callbacks =
2477 has_foreground_send_surface ? foreground_send_transfer_callbacks_
2478 : background_send_transfer_callbacks_;
2479
2480 for (TransferUpdateCallback& callback : transfer_callbacks)
2481 callback.OnTransferUpdate(share_target, metadata);
2482
2483 if (has_foreground_send_surface && metadata.is_final_status()) {
2484 last_outgoing_metadata_ = base::nullopt;
2485 } else {
2486 last_outgoing_metadata_ =
2487 std::make_pair(share_target, TransferMetadataBuilder::Clone(metadata)
2488 .set_is_original(false)
2489 .build());
2490 }
2491 }
2492
CloseConnection(const ShareTarget & share_target)2493 void NearbySharingServiceImpl::CloseConnection(
2494 const ShareTarget& share_target) {
2495 NearbyConnection* connection = GetConnection(share_target);
2496 if (!connection) {
2497 NS_LOG(WARNING) << __func__ << ": Invalid connection for target - "
2498 << share_target.device_name;
2499 return;
2500 }
2501 connection->Close();
2502 }
2503
OnIncomingDecryptedCertificate(const std::string & endpoint_id,sharing::mojom::AdvertisementPtr advertisement,ShareTarget placeholder_share_target,base::Optional<NearbyShareDecryptedPublicCertificate> certificate)2504 void NearbySharingServiceImpl::OnIncomingDecryptedCertificate(
2505 const std::string& endpoint_id,
2506 sharing::mojom::AdvertisementPtr advertisement,
2507 ShareTarget placeholder_share_target,
2508 base::Optional<NearbyShareDecryptedPublicCertificate> certificate) {
2509 NearbyConnection* connection = GetConnection(placeholder_share_target);
2510 if (!connection) {
2511 NS_LOG(VERBOSE) << __func__ << ": Invalid connection for endpoint id - "
2512 << endpoint_id;
2513 return;
2514 }
2515
2516 // Remove placeholder share target since we are creating the actual share
2517 // target below.
2518 incoming_share_target_info_map_.erase(placeholder_share_target.id);
2519
2520 base::Optional<ShareTarget> share_target = CreateShareTarget(
2521 endpoint_id, advertisement, std::move(certificate), /*is_incoming=*/true);
2522
2523 if (!share_target) {
2524 NS_LOG(VERBOSE) << __func__
2525 << "Failed to convert advertisement to share target for "
2526 "incoming connection, disconnecting";
2527 connection->Close();
2528 return;
2529 }
2530
2531 NS_LOG(VERBOSE) << __func__ << "Received incoming connection from "
2532 << share_target->device_name;
2533
2534 ShareTargetInfo* share_target_info = GetShareTargetInfo(*share_target);
2535 DCHECK(share_target_info);
2536 share_target_info->set_connection(connection);
2537
2538 share_target_info->set_transfer_update_callback(
2539 std::make_unique<TransferUpdateDecorator>(base::BindRepeating(
2540 &NearbySharingServiceImpl::OnIncomingTransferUpdate,
2541 weak_ptr_factory_.GetWeakPtr())));
2542
2543 connection->SetDisconnectionListener(
2544 base::BindOnce(&NearbySharingServiceImpl::UnregisterShareTarget,
2545 weak_ptr_factory_.GetWeakPtr(), *share_target));
2546
2547 base::Optional<std::string> four_digit_token = ToFourDigitString(
2548 nearby_connections_manager_->GetRawAuthenticationToken(endpoint_id));
2549
2550 RunPairedKeyVerification(
2551 *share_target, endpoint_id,
2552 base::BindOnce(
2553 &NearbySharingServiceImpl::OnIncomingConnectionKeyVerificationDone,
2554 weak_ptr_factory_.GetWeakPtr(), *share_target,
2555 std::move(four_digit_token)));
2556 }
2557
RunPairedKeyVerification(const ShareTarget & share_target,const std::string & endpoint_id,base::OnceCallback<void (PairedKeyVerificationRunner::PairedKeyVerificationResult)> callback)2558 void NearbySharingServiceImpl::RunPairedKeyVerification(
2559 const ShareTarget& share_target,
2560 const std::string& endpoint_id,
2561 base::OnceCallback<void(
2562 PairedKeyVerificationRunner::PairedKeyVerificationResult)> callback) {
2563 DCHECK(profile_);
2564 base::Optional<std::vector<uint8_t>> token =
2565 nearby_connections_manager_->GetRawAuthenticationToken(endpoint_id);
2566 if (!token) {
2567 NS_LOG(VERBOSE) << __func__
2568 << ": Failed to read authentication token from endpoint - "
2569 << endpoint_id;
2570 std::move(callback).Run(
2571 PairedKeyVerificationRunner::PairedKeyVerificationResult::kFail);
2572 return;
2573 }
2574
2575 ShareTargetInfo* share_target_info = GetShareTargetInfo(share_target);
2576 DCHECK(share_target_info);
2577
2578 share_target_info->set_frames_reader(std::make_unique<IncomingFramesReader>(
2579 process_manager_, profile_, share_target_info->connection()));
2580
2581 bool restrict_to_contacts =
2582 share_target.is_incoming &&
2583 advertising_power_level_ != PowerLevel::kHighPower;
2584 share_target_info->set_key_verification_runner(
2585 std::make_unique<PairedKeyVerificationRunner>(
2586 share_target, endpoint_id, *token, share_target_info->connection(),
2587 share_target_info->certificate(), GetCertificateManager(),
2588 settings_.GetVisibility(), restrict_to_contacts,
2589 share_target_info->frames_reader(), kReadFramesTimeout));
2590 share_target_info->key_verification_runner()->Run(std::move(callback));
2591 }
2592
OnIncomingConnectionKeyVerificationDone(ShareTarget share_target,base::Optional<std::string> four_digit_token,PairedKeyVerificationRunner::PairedKeyVerificationResult result)2593 void NearbySharingServiceImpl::OnIncomingConnectionKeyVerificationDone(
2594 ShareTarget share_target,
2595 base::Optional<std::string> four_digit_token,
2596 PairedKeyVerificationRunner::PairedKeyVerificationResult result) {
2597 ShareTargetInfo* info = GetShareTargetInfo(share_target);
2598 if (!info || !info->connection() || !info->endpoint_id()) {
2599 NS_LOG(VERBOSE) << __func__ << ": Invalid connection or endpoint id";
2600 return;
2601 }
2602
2603 switch (result) {
2604 case PairedKeyVerificationRunner::PairedKeyVerificationResult::kFail:
2605 NS_LOG(VERBOSE) << __func__ << ": Paired key handshake failed for target "
2606 << share_target.device_name << ". Disconnecting.";
2607 info->connection()->Close();
2608 return;
2609
2610 case PairedKeyVerificationRunner::PairedKeyVerificationResult::kSuccess:
2611 NS_LOG(VERBOSE) << __func__
2612 << ": Paired key handshake succeeded for target - "
2613 << share_target.device_name;
2614 nearby_connections_manager_->UpgradeBandwidth(*info->endpoint_id());
2615 ReceiveIntroduction(share_target, /*four_digit_token=*/base::nullopt);
2616 break;
2617
2618 case PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnable:
2619 NS_LOG(VERBOSE) << __func__
2620 << ": Unable to verify paired key encryption when "
2621 "receiving connection from target - "
2622 << share_target.device_name;
2623 if (advertising_power_level_ == PowerLevel::kHighPower)
2624 nearby_connections_manager_->UpgradeBandwidth(*info->endpoint_id());
2625
2626 if (four_digit_token)
2627 info->set_token(*four_digit_token);
2628
2629 ReceiveIntroduction(share_target, std::move(four_digit_token));
2630 break;
2631
2632 case PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnknown:
2633 NS_LOG(VERBOSE) << __func__
2634 << ": Unknown PairedKeyVerificationResult for target "
2635 << share_target.device_name << ". Disconnecting.";
2636 info->connection()->Close();
2637 break;
2638 }
2639 }
2640
OnOutgoingConnectionKeyVerificationDone(const ShareTarget & share_target,base::Optional<std::string> four_digit_token,PairedKeyVerificationRunner::PairedKeyVerificationResult result)2641 void NearbySharingServiceImpl::OnOutgoingConnectionKeyVerificationDone(
2642 const ShareTarget& share_target,
2643 base::Optional<std::string> four_digit_token,
2644 PairedKeyVerificationRunner::PairedKeyVerificationResult result) {
2645 ShareTargetInfo* info = GetShareTargetInfo(share_target);
2646 if (!info || !info->connection())
2647 return;
2648
2649 if (!info->transfer_update_callback()) {
2650 NS_LOG(VERBOSE) << __func__
2651 << ": No transfer update callback. Disconnecting.";
2652 info->connection()->Close();
2653 return;
2654 }
2655
2656 // TODO(crbug.com/1119279): Check if we need to set this to false for
2657 // Advanced Protection users.
2658 bool sender_skips_confirmation = true;
2659
2660 switch (result) {
2661 case PairedKeyVerificationRunner::PairedKeyVerificationResult::kFail:
2662 NS_LOG(VERBOSE) << __func__ << ": Paired key handshake failed for target "
2663 << share_target.device_name << ". Disconnecting.";
2664 info->transfer_update_callback()->OnTransferUpdate(
2665 share_target, TransferMetadataBuilder()
2666 .set_status(TransferMetadata::Status::kFailed)
2667 .build());
2668 info->connection()->Close();
2669 return;
2670
2671 case PairedKeyVerificationRunner::PairedKeyVerificationResult::kSuccess:
2672 NS_LOG(VERBOSE) << __func__
2673 << ": Paired key handshake succeeded for target - "
2674 << share_target.device_name;
2675 SendIntroduction(share_target, /*four_digit_token=*/base::nullopt);
2676 SendPayloads(share_target);
2677 return;
2678
2679 case PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnable:
2680 NS_LOG(VERBOSE) << __func__
2681 << ": Unable to verify paired key encryption when "
2682 "initating connection to target - "
2683 << share_target.device_name;
2684
2685 if (four_digit_token)
2686 info->set_token(*four_digit_token);
2687
2688 if (sender_skips_confirmation) {
2689 NS_LOG(VERBOSE) << __func__
2690 << ": Sender-side verification is disabled. Skipping "
2691 "token comparison with "
2692 << share_target.device_name;
2693 SendIntroduction(share_target, /*four_digit_token=*/base::nullopt);
2694 SendPayloads(share_target);
2695 } else {
2696 SendIntroduction(share_target, std::move(four_digit_token));
2697 }
2698 return;
2699
2700 case PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnknown:
2701 NS_LOG(VERBOSE) << __func__
2702 << ": Unknown PairedKeyVerificationResult for target "
2703 << share_target.device_name << ". Disconnecting.";
2704 info->connection()->Close();
2705 break;
2706 }
2707 }
2708
RefreshUIOnDisconnection(ShareTarget share_target)2709 void NearbySharingServiceImpl::RefreshUIOnDisconnection(
2710 ShareTarget share_target) {
2711 ShareTargetInfo* info = GetShareTargetInfo(share_target);
2712 if (info && info->transfer_update_callback()) {
2713 info->transfer_update_callback()->OnTransferUpdate(
2714 share_target,
2715 TransferMetadataBuilder()
2716 .set_status(
2717 TransferMetadata::Status::kAwaitingRemoteAcceptanceFailed)
2718 .build());
2719 }
2720
2721 UnregisterShareTarget(share_target);
2722 }
2723
ReceiveIntroduction(ShareTarget share_target,base::Optional<std::string> four_digit_token)2724 void NearbySharingServiceImpl::ReceiveIntroduction(
2725 ShareTarget share_target,
2726 base::Optional<std::string> four_digit_token) {
2727 NS_LOG(INFO) << __func__ << ": Receiving introduction from "
2728 << share_target.device_name;
2729 ShareTargetInfo* info = GetShareTargetInfo(share_target);
2730 DCHECK(info && info->connection());
2731
2732 info->frames_reader()->ReadFrame(
2733 sharing::mojom::V1Frame::Tag::INTRODUCTION,
2734 base::BindOnce(&NearbySharingServiceImpl::OnReceivedIntroduction,
2735 weak_ptr_factory_.GetWeakPtr(), std::move(share_target),
2736 std::move(four_digit_token)),
2737 kReadFramesTimeout);
2738 }
2739
OnReceivedIntroduction(ShareTarget share_target,base::Optional<std::string> four_digit_token,base::Optional<sharing::mojom::V1FramePtr> frame)2740 void NearbySharingServiceImpl::OnReceivedIntroduction(
2741 ShareTarget share_target,
2742 base::Optional<std::string> four_digit_token,
2743 base::Optional<sharing::mojom::V1FramePtr> frame) {
2744 ShareTargetInfo* info = GetShareTargetInfo(share_target);
2745 if (!info || !info->connection()) {
2746 NS_LOG(WARNING)
2747 << __func__
2748 << ": Ignore received introduction, due to no connection established.";
2749 return;
2750 }
2751 NearbyConnection* connection = info->connection();
2752 DCHECK(profile_);
2753
2754 if (!frame) {
2755 connection->Close();
2756 NS_LOG(WARNING) << __func__ << ": Invalid introduction frame";
2757 return;
2758 }
2759
2760 NS_LOG(INFO) << __func__ << ": Successfully read the introduction frame.";
2761
2762 base::CheckedNumeric<int64_t> file_size_sum(0);
2763
2764 sharing::mojom::IntroductionFramePtr introduction_frame =
2765 std::move((*frame)->get_introduction());
2766 for (const auto& file : introduction_frame->file_metadata) {
2767 if (file->size <= 0) {
2768 Fail(share_target, TransferMetadata::Status::kUnsupportedAttachmentType);
2769 NS_LOG(WARNING)
2770 << __func__
2771 << ": Ignore introduction, due to invalid attachment size";
2772 return;
2773 }
2774
2775 NS_LOG(VERBOSE) << __func__ << "Found file attachment " << file->name
2776 << " of type " << file->type << " with mimeType "
2777 << file->mime_type;
2778 FileAttachment attachment(file->id, file->size, file->name, file->mime_type,
2779 file->type);
2780 SetAttachmentPayloadId(attachment, file->payload_id);
2781 share_target.file_attachments.push_back(std::move(attachment));
2782
2783 file_size_sum += file->size;
2784 if (!file_size_sum.IsValid()) {
2785 Fail(share_target, TransferMetadata::Status::kNotEnoughSpace);
2786 NS_LOG(WARNING) << __func__
2787 << ": Ignoring introduction, total file size overflowed "
2788 "64 bit integer.";
2789 return;
2790 }
2791 }
2792
2793 for (const auto& text : introduction_frame->text_metadata) {
2794 if (text->size <= 0) {
2795 Fail(share_target, TransferMetadata::Status::kUnsupportedAttachmentType);
2796 NS_LOG(WARNING)
2797 << __func__
2798 << ": Ignore introduction, due to invalid attachment size";
2799 return;
2800 }
2801
2802 NS_LOG(VERBOSE) << __func__ << "Found text attachment " << text->text_title
2803 << " of type " << text->type;
2804 TextAttachment attachment(text->id, text->type, text->text_title,
2805 text->size);
2806 SetAttachmentPayloadId(attachment, text->payload_id);
2807 share_target.text_attachments.push_back(std::move(attachment));
2808 }
2809
2810 if (!share_target.has_attachments()) {
2811 NS_LOG(WARNING) << __func__
2812 << ": No attachment is found for this share target. It can "
2813 "be result of unrecognizable attachment type";
2814 Fail(share_target, TransferMetadata::Status::kUnsupportedAttachmentType);
2815
2816 NS_LOG(VERBOSE) << __func__
2817 << ": We don't support the attachments sent by the sender. "
2818 "We have informed "
2819 << share_target.device_name;
2820 return;
2821 }
2822
2823 if (file_size_sum.ValueOrDie() == 0) {
2824 OnStorageCheckCompleted(std::move(share_target),
2825 std::move(four_digit_token),
2826 /*is_out_of_storage=*/false);
2827 return;
2828 }
2829
2830 base::FilePath download_path =
2831 DownloadPrefs::FromDownloadManager(
2832 content::BrowserContext::GetDownloadManager(profile_))
2833 ->DownloadPath();
2834
2835 base::ThreadPool::PostTaskAndReplyWithResult(
2836 FROM_HERE, {base::MayBlock()},
2837 base::BindOnce(&IsOutOfStorage, std::move(download_path),
2838 file_size_sum.ValueOrDie(), free_disk_space_for_testing_),
2839 base::BindOnce(&NearbySharingServiceImpl::OnStorageCheckCompleted,
2840 weak_ptr_factory_.GetWeakPtr(), std::move(share_target),
2841 std::move(four_digit_token)));
2842 }
2843
ReceiveConnectionResponse(ShareTarget share_target)2844 void NearbySharingServiceImpl::ReceiveConnectionResponse(
2845 ShareTarget share_target) {
2846 NS_LOG(VERBOSE) << __func__ << ": Receiving response frame from "
2847 << share_target.device_name;
2848 ShareTargetInfo* info = GetShareTargetInfo(share_target);
2849 DCHECK(info && info->connection());
2850
2851 info->frames_reader()->ReadFrame(
2852 sharing::mojom::V1Frame::Tag::CONNECTION_RESPONSE,
2853 base::BindOnce(&NearbySharingServiceImpl::OnReceiveConnectionResponse,
2854 weak_ptr_factory_.GetWeakPtr(), std::move(share_target)),
2855 kReadResponseFrameTimeout);
2856 }
2857
OnReceiveConnectionResponse(ShareTarget share_target,base::Optional<sharing::mojom::V1FramePtr> frame)2858 void NearbySharingServiceImpl::OnReceiveConnectionResponse(
2859 ShareTarget share_target,
2860 base::Optional<sharing::mojom::V1FramePtr> frame) {
2861 OutgoingShareTargetInfo* info = GetOutgoingShareTargetInfo(share_target);
2862 if (!info || !info->connection()) {
2863 NS_LOG(WARNING) << __func__
2864 << ": Ignore received connection response, due to no "
2865 "connection established.";
2866 return;
2867 }
2868 NearbyConnection* connection = info->connection();
2869
2870 if (!info->transfer_update_callback()) {
2871 NS_LOG(WARNING) << __func__
2872 << ": No transfer update callback. Disconnecting.";
2873 connection->Close();
2874 return;
2875 }
2876
2877 if (!frame) {
2878 NS_LOG(WARNING)
2879 << __func__
2880 << ": Failed to read a response from the remote device. Disconnecting.";
2881 info->transfer_update_callback()->OnTransferUpdate(
2882 share_target, TransferMetadataBuilder()
2883 .set_status(TransferMetadata::Status::kFailed)
2884 .build());
2885 connection->Close();
2886 return;
2887 }
2888
2889 mutual_acceptance_timeout_alarm_.Cancel();
2890
2891 NS_LOG(VERBOSE) << __func__
2892 << ": Successfully read the connection response frame.";
2893
2894 sharing::mojom::ConnectionResponseFramePtr response =
2895 std::move((*frame)->get_connection_response());
2896 switch (response->status) {
2897 case sharing::mojom::ConnectionResponseFrame::Status::kAccept: {
2898 info->frames_reader()->ReadFrame(
2899 base::BindOnce(&NearbySharingServiceImpl::OnFrameRead,
2900 weak_ptr_factory_.GetWeakPtr(), share_target));
2901
2902 info->transfer_update_callback()->OnTransferUpdate(
2903 share_target, TransferMetadataBuilder()
2904 .set_status(TransferMetadata::Status::kInProgress)
2905 .build());
2906
2907 info->set_payload_tracker(std::make_unique<PayloadTracker>(
2908 share_target, attachment_info_map_,
2909 base::BindRepeating(
2910 &NearbySharingServiceImpl::OnPayloadTransferUpdate,
2911 weak_ptr_factory_.GetWeakPtr())));
2912
2913 for (auto& payload : info->ExtractTextPayloads()) {
2914 nearby_connections_manager_->Send(
2915 *info->endpoint_id(), std::move(payload), info->payload_tracker());
2916 }
2917 for (auto& payload : info->ExtractFilePayloads()) {
2918 nearby_connections_manager_->Send(
2919 *info->endpoint_id(), std::move(payload), info->payload_tracker());
2920 }
2921 NS_LOG(VERBOSE)
2922 << __func__
2923 << ": The connection was accepted. Payloads are now being sent.";
2924 break;
2925 }
2926 case sharing::mojom::ConnectionResponseFrame::Status::kReject:
2927 info->transfer_update_callback()->OnTransferUpdate(
2928 share_target, TransferMetadataBuilder()
2929 .set_status(TransferMetadata::Status::kRejected)
2930 .build());
2931 connection->Close();
2932 NS_LOG(VERBOSE)
2933 << __func__
2934 << ": The connection was rejected. The connection has been closed.";
2935 break;
2936 case sharing::mojom::ConnectionResponseFrame::Status::kNotEnoughSpace:
2937 info->transfer_update_callback()->OnTransferUpdate(
2938 share_target,
2939 TransferMetadataBuilder()
2940 .set_status(TransferMetadata::Status::kNotEnoughSpace)
2941 .build());
2942 connection->Close();
2943 NS_LOG(VERBOSE)
2944 << __func__
2945 << ": The connection was rejected because the remote device "
2946 "does not have enough space for our attachments. The "
2947 "connection has been closed.";
2948 break;
2949 case sharing::mojom::ConnectionResponseFrame::Status::
2950 kUnsupportedAttachmentType:
2951 info->transfer_update_callback()->OnTransferUpdate(
2952 share_target,
2953 TransferMetadataBuilder()
2954 .set_status(TransferMetadata::Status::kUnsupportedAttachmentType)
2955 .build());
2956 connection->Close();
2957 NS_LOG(VERBOSE)
2958 << __func__
2959 << ": The connection was rejected because the remote device "
2960 "does not support the attachments we were sending. The "
2961 "connection has been closed.";
2962 break;
2963 case sharing::mojom::ConnectionResponseFrame::Status::kTimedOut:
2964 info->transfer_update_callback()->OnTransferUpdate(
2965 share_target, TransferMetadataBuilder()
2966 .set_status(TransferMetadata::Status::kTimedOut)
2967 .build());
2968 connection->Close();
2969 NS_LOG(VERBOSE)
2970 << __func__
2971 << ": The connection was rejected because the remote device "
2972 "timed out. The connection has been closed.";
2973 break;
2974 default:
2975 info->transfer_update_callback()->OnTransferUpdate(
2976 share_target, TransferMetadataBuilder()
2977 .set_status(TransferMetadata::Status::kFailed)
2978 .build());
2979 connection->Close();
2980 NS_LOG(VERBOSE)
2981 << __func__
2982 << ": The connection failed. The connection has been closed.";
2983 break;
2984 }
2985 }
2986
OnStorageCheckCompleted(ShareTarget share_target,base::Optional<std::string> four_digit_token,bool is_out_of_storage)2987 void NearbySharingServiceImpl::OnStorageCheckCompleted(
2988 ShareTarget share_target,
2989 base::Optional<std::string> four_digit_token,
2990 bool is_out_of_storage) {
2991 if (is_out_of_storage) {
2992 Fail(share_target, TransferMetadata::Status::kNotEnoughSpace);
2993 NS_LOG(WARNING) << __func__
2994 << ": Not enough space on the receiver. We have informed "
2995 << share_target.device_name;
2996 return;
2997 }
2998
2999 ShareTargetInfo* info = GetShareTargetInfo(share_target);
3000 if (!info || !info->connection()) {
3001 NS_LOG(WARNING) << __func__ << ": Invalid connection for share target - "
3002 << share_target.device_name;
3003 return;
3004 }
3005 NearbyConnection* connection = info->connection();
3006
3007 if (!info->transfer_update_callback()) {
3008 connection->Close();
3009 NS_LOG(VERBOSE) << __func__
3010 << ": No transfer update callback. Disconnecting.";
3011 return;
3012 }
3013
3014 mutual_acceptance_timeout_alarm_.Reset(base::BindOnce(
3015 &NearbySharingServiceImpl::OnIncomingMutualAcceptanceTimeout,
3016 weak_ptr_factory_.GetWeakPtr(), share_target));
3017
3018 base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
3019 FROM_HERE, base::BindOnce(mutual_acceptance_timeout_alarm_.callback()),
3020 kReadResponseFrameTimeout);
3021
3022 info->transfer_update_callback()->OnTransferUpdate(
3023 share_target,
3024 TransferMetadataBuilder()
3025 .set_status(TransferMetadata::Status::kAwaitingLocalConfirmation)
3026 .set_token(std::move(four_digit_token))
3027 .build());
3028
3029 if (!incoming_share_target_info_map_.count(share_target.id)) {
3030 connection->Close();
3031 NS_LOG(VERBOSE) << __func__
3032 << ": IncomingShareTarget not found, disconnecting "
3033 << share_target.device_name;
3034 return;
3035 }
3036
3037 connection->SetDisconnectionListener(base::BindOnce(
3038 &NearbySharingServiceImpl::OnIncomingConnectionDisconnected,
3039 weak_ptr_factory_.GetWeakPtr(), share_target));
3040
3041 auto* frames_reader = info->frames_reader();
3042 if (!frames_reader) {
3043 NS_LOG(WARNING) << __func__
3044 << ": Stopped reading further frames, due to no connection "
3045 "established.";
3046 return;
3047 }
3048
3049 frames_reader->ReadFrame(
3050 base::BindOnce(&NearbySharingServiceImpl::OnFrameRead,
3051 weak_ptr_factory_.GetWeakPtr(), std::move(share_target)));
3052 }
3053
OnFrameRead(ShareTarget share_target,base::Optional<sharing::mojom::V1FramePtr> frame)3054 void NearbySharingServiceImpl::OnFrameRead(
3055 ShareTarget share_target,
3056 base::Optional<sharing::mojom::V1FramePtr> frame) {
3057 if (!frame) {
3058 // This is the case when the connection has been closed since we wait
3059 // indefinitely for incoming frames.
3060 return;
3061 }
3062
3063 sharing::mojom::V1FramePtr v1_frame = std::move(*frame);
3064 switch (v1_frame->which()) {
3065 case sharing::mojom::V1Frame::Tag::CANCEL_FRAME:
3066 NS_LOG(INFO) << __func__ << ": Read the cancel frame, closing connection";
3067 DoCancel(share_target, base::DoNothing(), /*write_cancel_frame=*/false);
3068 break;
3069
3070 case sharing::mojom::V1Frame::Tag::CERTIFICATE_INFO:
3071 HandleCertificateInfoFrame(v1_frame->get_certificate_info());
3072 break;
3073
3074 default:
3075 NS_LOG(VERBOSE) << __func__ << ": Discarding unknown frame of type";
3076 break;
3077 }
3078
3079 ShareTargetInfo* info = GetShareTargetInfo(share_target);
3080 if (!info || !info->frames_reader()) {
3081 NS_LOG(WARNING) << __func__
3082 << ": Stopped reading further frames, due to no connection "
3083 "established.";
3084 return;
3085 }
3086
3087 info->frames_reader()->ReadFrame(
3088 base::BindOnce(&NearbySharingServiceImpl::OnFrameRead,
3089 weak_ptr_factory_.GetWeakPtr(), std::move(share_target)));
3090 }
3091
HandleCertificateInfoFrame(const sharing::mojom::CertificateInfoFramePtr & certificate_frame)3092 void NearbySharingServiceImpl::HandleCertificateInfoFrame(
3093 const sharing::mojom::CertificateInfoFramePtr& certificate_frame) {
3094 DCHECK(certificate_frame);
3095
3096 // TODO(crbug.com/1113858): Allow saving certificates from remote devices.
3097 }
3098
OnIncomingConnectionDisconnected(const ShareTarget & share_target)3099 void NearbySharingServiceImpl::OnIncomingConnectionDisconnected(
3100 const ShareTarget& share_target) {
3101 ShareTargetInfo* info = GetShareTargetInfo(share_target);
3102 if (info && info->transfer_update_callback()) {
3103 info->transfer_update_callback()->OnTransferUpdate(
3104 share_target, TransferMetadataBuilder()
3105 .set_status(TransferMetadata::Status::kFailed)
3106 .build());
3107 }
3108 UnregisterShareTarget(share_target);
3109 }
3110
OnOutgoingConnectionDisconnected(const ShareTarget & share_target)3111 void NearbySharingServiceImpl::OnOutgoingConnectionDisconnected(
3112 const ShareTarget& share_target) {
3113 ShareTargetInfo* info = GetShareTargetInfo(share_target);
3114 if (info && info->transfer_update_callback()) {
3115 info->transfer_update_callback()->OnTransferUpdate(
3116 share_target,
3117 TransferMetadataBuilder()
3118 .set_status(
3119 TransferMetadata::Status::kAwaitingRemoteAcceptanceFailed)
3120 .build());
3121 }
3122 UnregisterShareTarget(share_target);
3123 }
3124
OnIncomingMutualAcceptanceTimeout(const ShareTarget & share_target)3125 void NearbySharingServiceImpl::OnIncomingMutualAcceptanceTimeout(
3126 const ShareTarget& share_target) {
3127 DCHECK(share_target.is_incoming);
3128
3129 NS_LOG(VERBOSE)
3130 << __func__
3131 << ": Incoming mutual acceptance timed out, closing connection for "
3132 << share_target.device_name;
3133
3134 Fail(share_target, TransferMetadata::Status::kTimedOut);
3135 }
3136
OnOutgoingMutualAcceptanceTimeout(const ShareTarget & share_target)3137 void NearbySharingServiceImpl::OnOutgoingMutualAcceptanceTimeout(
3138 const ShareTarget& share_target) {
3139 DCHECK(!share_target.is_incoming);
3140
3141 NS_LOG(VERBOSE)
3142 << __func__
3143 << ": Outgoing mutual acceptance timed out, closing connection for "
3144 << share_target.device_name;
3145
3146 ShareTargetInfo* info = GetShareTargetInfo(share_target);
3147 if (!info)
3148 return;
3149
3150 if (info->transfer_update_callback()) {
3151 info->transfer_update_callback()->OnTransferUpdate(
3152 share_target, TransferMetadataBuilder()
3153 .set_status(TransferMetadata::Status::kTimedOut)
3154 .build());
3155 }
3156
3157 if (info->connection())
3158 info->connection()->Close();
3159 }
3160
CreateShareTarget(const std::string & endpoint_id,const sharing::mojom::AdvertisementPtr & advertisement,base::Optional<NearbyShareDecryptedPublicCertificate> certificate,bool is_incoming)3161 base::Optional<ShareTarget> NearbySharingServiceImpl::CreateShareTarget(
3162 const std::string& endpoint_id,
3163 const sharing::mojom::AdvertisementPtr& advertisement,
3164 base::Optional<NearbyShareDecryptedPublicCertificate> certificate,
3165 bool is_incoming) {
3166 DCHECK(advertisement);
3167
3168 if (!advertisement->device_name && !certificate) {
3169 NS_LOG(VERBOSE) << __func__
3170 << ": Failed to retrieve public certificate for contact "
3171 "only advertisement.";
3172 return base::nullopt;
3173 }
3174
3175 base::Optional<std::string> device_name =
3176 GetDeviceName(advertisement, certificate);
3177 if (!device_name) {
3178 NS_LOG(VERBOSE) << __func__
3179 << ": Failed to retrieve device name for advertisement.";
3180 return base::nullopt;
3181 }
3182
3183 ShareTarget target;
3184 target.type = advertisement->device_type;
3185 target.device_name = std::move(*device_name);
3186 target.is_incoming = is_incoming;
3187 target.device_id = GetDeviceId(endpoint_id, certificate);
3188
3189 ShareTargetInfo& info = GetOrCreateShareTargetInfo(target, endpoint_id);
3190
3191 if (certificate) {
3192 if (certificate->unencrypted_metadata().has_full_name())
3193 target.full_name = certificate->unencrypted_metadata().full_name();
3194
3195 if (certificate->unencrypted_metadata().has_icon_url())
3196 target.image_url = GURL(certificate->unencrypted_metadata().icon_url());
3197
3198 target.is_known = true;
3199 info.set_certificate(std::move(*certificate));
3200 }
3201
3202 return target;
3203 }
3204
OnPayloadTransferUpdate(ShareTarget share_target,TransferMetadata metadata)3205 void NearbySharingServiceImpl::OnPayloadTransferUpdate(
3206 ShareTarget share_target,
3207 TransferMetadata metadata) {
3208 NS_LOG(VERBOSE) << __func__ << ": Nearby Share service: "
3209 << "Payload transfer update for share target with ID "
3210 << share_target.id << ": "
3211 << TransferMetadata::StatusToString(metadata.status());
3212
3213 if (metadata.status() == TransferMetadata::Status::kComplete &&
3214 share_target.is_incoming && !OnIncomingPayloadsComplete(share_target)) {
3215 metadata = TransferMetadataBuilder()
3216 .set_status(TransferMetadata::Status::kFailed)
3217 .build();
3218
3219 // Reset file paths for file attachments.
3220 for (auto& file : share_target.file_attachments)
3221 file.set_file_path(base::nullopt);
3222
3223 // Reset body of text attachments.
3224 for (auto& text : share_target.text_attachments)
3225 text.set_text_body(std::string());
3226 }
3227
3228 // Make sure to call this before calling Disconnect or we risk loosing some
3229 // transfer updates in the receive case due to the Disconnect call cleaning up
3230 // share targets.
3231 ShareTargetInfo* info = GetShareTargetInfo(share_target);
3232 if (info && info->transfer_update_callback())
3233 info->transfer_update_callback()->OnTransferUpdate(share_target, metadata);
3234
3235 // Cancellation has its own disconnection strategy, possibly adding a delay
3236 // before disconnection to provide the other party time to process the
3237 // cancellation.
3238 if (TransferMetadata::IsFinalStatus(metadata.status()) &&
3239 metadata.status() != TransferMetadata::Status::kCancelled) {
3240 Disconnect(share_target, metadata);
3241 }
3242 }
3243
OnIncomingPayloadsComplete(ShareTarget & share_target)3244 bool NearbySharingServiceImpl::OnIncomingPayloadsComplete(
3245 ShareTarget& share_target) {
3246 DCHECK(share_target.is_incoming);
3247
3248 ShareTargetInfo* info = GetShareTargetInfo(share_target);
3249 if (!info || !info->connection()) {
3250 NS_LOG(VERBOSE) << __func__ << ": Connection not found for target - "
3251 << share_target.device_name;
3252
3253 return false;
3254 }
3255 NearbyConnection* connection = info->connection();
3256
3257 connection->SetDisconnectionListener(
3258 base::BindOnce(&NearbySharingServiceImpl::UnregisterShareTarget,
3259 weak_ptr_factory_.GetWeakPtr(), share_target));
3260
3261 for (auto& file : share_target.file_attachments) {
3262 AttachmentInfo& attachment_info = attachment_info_map_[file.id()];
3263 base::Optional<int64_t> payload_id = attachment_info.payload_id;
3264 if (!payload_id) {
3265 NS_LOG(WARNING) << __func__ << ": No payload id found for file - "
3266 << file.id();
3267 return false;
3268 }
3269
3270 location::nearby::connections::mojom::Payload* incoming_payload =
3271 nearby_connections_manager_->GetIncomingPayload(*payload_id);
3272 if (!incoming_payload || !incoming_payload->content ||
3273 !incoming_payload->content->is_file()) {
3274 NS_LOG(WARNING) << __func__ << ": No payload found for file - "
3275 << file.id();
3276 return false;
3277 }
3278
3279 file.set_file_path(attachment_info.file_path);
3280 }
3281
3282 for (auto& text : share_target.text_attachments) {
3283 AttachmentInfo& attachment_info = attachment_info_map_[text.id()];
3284 base::Optional<int64_t> payload_id = attachment_info.payload_id;
3285 if (!payload_id) {
3286 NS_LOG(WARNING) << __func__ << ": No payload id found for text - "
3287 << text.id();
3288 return false;
3289 }
3290
3291 location::nearby::connections::mojom::Payload* incoming_payload =
3292 nearby_connections_manager_->GetIncomingPayload(*payload_id);
3293 if (!incoming_payload || !incoming_payload->content ||
3294 !incoming_payload->content->is_bytes()) {
3295 NS_LOG(WARNING) << __func__ << ": No payload found for text - "
3296 << text.id();
3297 return false;
3298 }
3299
3300 std::vector<uint8_t>& bytes = incoming_payload->content->get_bytes()->bytes;
3301 if (bytes.empty()) {
3302 NS_LOG(WARNING)
3303 << __func__
3304 << ": Incoming bytes is empty for text payload with payload_id - "
3305 << *payload_id;
3306 return false;
3307 }
3308
3309 std::string text_body(bytes.begin(), bytes.end());
3310 text.set_text_body(text_body);
3311
3312 attachment_info.text_body = std::move(text_body);
3313 }
3314 return true;
3315 }
3316
RemoveIncomingPayloads(ShareTarget share_target)3317 void NearbySharingServiceImpl::RemoveIncomingPayloads(
3318 ShareTarget share_target) {
3319 if (!share_target.is_incoming)
3320 return;
3321
3322 NS_LOG(INFO) << __func__ << ": Cleaning up payloads due to transfer failure";
3323
3324 nearby_connections_manager_->ClearIncomingPayloads();
3325 std::vector<base::FilePath> files_for_deletion;
3326 for (const auto& file : share_target.file_attachments) {
3327 auto it = attachment_info_map_.find(file.id());
3328 if (it == attachment_info_map_.end())
3329 continue;
3330
3331 files_for_deletion.push_back(it->second.file_path);
3332 }
3333
3334 file_handler_.DeleteFilesFromDisk(std::move(files_for_deletion));
3335 }
3336
Disconnect(const ShareTarget & share_target,TransferMetadata metadata)3337 void NearbySharingServiceImpl::Disconnect(const ShareTarget& share_target,
3338 TransferMetadata metadata) {
3339 ShareTargetInfo* share_target_info = GetShareTargetInfo(share_target);
3340 if (!share_target_info) {
3341 NS_LOG(WARNING)
3342 << __func__
3343 << ": Failed to disconnect. No share target info found for target - "
3344 << share_target.device_name;
3345 return;
3346 }
3347
3348 base::Optional<std::string> endpoint_id = share_target_info->endpoint_id();
3349 if (!endpoint_id) {
3350 NS_LOG(WARNING)
3351 << __func__
3352 << ": Failed to disconnect. No endpoint id found for share target - "
3353 << share_target.device_name;
3354 return;
3355 }
3356
3357 // Failed to send or receive. No point in continuing, so disconnect
3358 // immediately.
3359 if (metadata.status() != TransferMetadata::Status::kComplete) {
3360 if (share_target_info->connection()) {
3361 share_target_info->connection()->Close();
3362 } else {
3363 nearby_connections_manager_->Disconnect(*endpoint_id);
3364 }
3365 return;
3366 }
3367
3368 // Files received successfully. Receivers can immediately cancel.
3369 if (share_target.is_incoming) {
3370 if (share_target_info->connection()) {
3371 share_target_info->connection()->Close();
3372 } else {
3373 nearby_connections_manager_->Disconnect(*endpoint_id);
3374 }
3375 return;
3376 }
3377
3378 // Disconnect after a timeout to make sure any pending payloads are sent.
3379 auto timer = std::make_unique<base::CancelableOnceClosure>(base::BindOnce(
3380 &NearbySharingServiceImpl::OnDisconnectingConnectionTimeout,
3381 weak_ptr_factory_.GetWeakPtr(), *endpoint_id));
3382 base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
3383 FROM_HERE, timer->callback(), kOutgoingDisconnectionDelay);
3384 disconnection_timeout_alarms_[*endpoint_id] = std::move(timer);
3385
3386 // Stop the disconnection timeout if the connection has been closed already.
3387 if (share_target_info->connection()) {
3388 share_target_info->connection()->SetDisconnectionListener(base::BindOnce(
3389 &NearbySharingServiceImpl::OnDisconnectingConnectionDisconnected,
3390 weak_ptr_factory_.GetWeakPtr(), share_target, *endpoint_id));
3391 }
3392 }
3393
OnDisconnectingConnectionTimeout(const std::string & endpoint_id)3394 void NearbySharingServiceImpl::OnDisconnectingConnectionTimeout(
3395 const std::string& endpoint_id) {
3396 disconnection_timeout_alarms_.erase(endpoint_id);
3397 nearby_connections_manager_->Disconnect(endpoint_id);
3398 }
3399
OnDisconnectingConnectionDisconnected(const ShareTarget & share_target,const std::string & endpoint_id)3400 void NearbySharingServiceImpl::OnDisconnectingConnectionDisconnected(
3401 const ShareTarget& share_target,
3402 const std::string& endpoint_id) {
3403 disconnection_timeout_alarms_.erase(endpoint_id);
3404 UnregisterShareTarget(share_target);
3405 }
3406
GetOrCreateShareTargetInfo(const ShareTarget & share_target,const std::string & endpoint_id)3407 ShareTargetInfo& NearbySharingServiceImpl::GetOrCreateShareTargetInfo(
3408 const ShareTarget& share_target,
3409 const std::string& endpoint_id) {
3410 if (share_target.is_incoming) {
3411 auto& info = incoming_share_target_info_map_[share_target.id];
3412 info.set_endpoint_id(endpoint_id);
3413 return info;
3414 } else {
3415 // We need to explicitly remove any previous share target for
3416 // |endpoint_id| if one exists, notifying observers that a share target is
3417 // lost.
3418 const auto it = outgoing_share_target_map_.find(endpoint_id);
3419 if (it != outgoing_share_target_map_.end() &&
3420 it->second.id != share_target.id) {
3421 RemoveOutgoingShareTargetWithEndpointId(endpoint_id);
3422 }
3423
3424 NS_LOG(VERBOSE) << __func__ << ": Adding (endpoint_id=" << endpoint_id
3425 << ", share_target_id=" << share_target.id
3426 << ") to outgoing share target map";
3427 outgoing_share_target_map_.insert_or_assign(endpoint_id, share_target);
3428 auto& info = outgoing_share_target_info_map_[share_target.id];
3429 info.set_endpoint_id(endpoint_id);
3430 return info;
3431 }
3432 }
3433
GetShareTargetInfo(const ShareTarget & share_target)3434 ShareTargetInfo* NearbySharingServiceImpl::GetShareTargetInfo(
3435 const ShareTarget& share_target) {
3436 if (share_target.is_incoming)
3437 return GetIncomingShareTargetInfo(share_target);
3438 else
3439 return GetOutgoingShareTargetInfo(share_target);
3440 }
3441
GetIncomingShareTargetInfo(const ShareTarget & share_target)3442 IncomingShareTargetInfo* NearbySharingServiceImpl::GetIncomingShareTargetInfo(
3443 const ShareTarget& share_target) {
3444 auto it = incoming_share_target_info_map_.find(share_target.id);
3445 if (it == incoming_share_target_info_map_.end())
3446 return nullptr;
3447
3448 return &it->second;
3449 }
3450
GetOutgoingShareTargetInfo(const ShareTarget & share_target)3451 OutgoingShareTargetInfo* NearbySharingServiceImpl::GetOutgoingShareTargetInfo(
3452 const ShareTarget& share_target) {
3453 auto it = outgoing_share_target_info_map_.find(share_target.id);
3454 if (it == outgoing_share_target_info_map_.end())
3455 return nullptr;
3456
3457 return &it->second;
3458 }
3459
GetConnection(const ShareTarget & share_target)3460 NearbyConnection* NearbySharingServiceImpl::GetConnection(
3461 const ShareTarget& share_target) {
3462 ShareTargetInfo* share_target_info = GetShareTargetInfo(share_target);
3463 return share_target_info ? share_target_info->connection() : nullptr;
3464 }
3465
3466 base::Optional<std::vector<uint8_t>>
GetBluetoothMacAddress(const ShareTarget & share_target)3467 NearbySharingServiceImpl::GetBluetoothMacAddress(
3468 const ShareTarget& share_target) {
3469 ShareTargetInfo* info = GetShareTargetInfo(share_target);
3470 if (!info)
3471 return base::nullopt;
3472
3473 const base::Optional<NearbyShareDecryptedPublicCertificate>& certificate =
3474 info->certificate();
3475 if (!certificate ||
3476 !certificate->unencrypted_metadata().has_bluetooth_mac_address()) {
3477 return base::nullopt;
3478 }
3479
3480 std::string mac_address =
3481 certificate->unencrypted_metadata().bluetooth_mac_address();
3482 if (mac_address.size() != 6)
3483 return base::nullopt;
3484
3485 return std::vector<uint8_t>(mac_address.begin(), mac_address.end());
3486 }
3487
ClearOutgoingShareTargetInfoMap()3488 void NearbySharingServiceImpl::ClearOutgoingShareTargetInfoMap() {
3489 NS_LOG(VERBOSE) << __func__ << ": Clearing outgoing share target map.";
3490 while (!outgoing_share_target_map_.empty()) {
3491 RemoveOutgoingShareTargetWithEndpointId(
3492 /*endpoint_id=*/outgoing_share_target_map_.begin()->first);
3493 }
3494 DCHECK(outgoing_share_target_map_.empty());
3495 DCHECK(outgoing_share_target_info_map_.empty());
3496 }
3497
SetAttachmentPayloadId(const Attachment & attachment,int64_t payload_id)3498 void NearbySharingServiceImpl::SetAttachmentPayloadId(
3499 const Attachment& attachment,
3500 int64_t payload_id) {
3501 attachment_info_map_[attachment.id()].payload_id = payload_id;
3502 }
3503
GetAttachmentPayloadId(int64_t attachment_id)3504 base::Optional<int64_t> NearbySharingServiceImpl::GetAttachmentPayloadId(
3505 int64_t attachment_id) {
3506 auto it = attachment_info_map_.find(attachment_id);
3507 if (it == attachment_info_map_.end())
3508 return base::nullopt;
3509
3510 return it->second.payload_id;
3511 }
3512
UnregisterShareTarget(const ShareTarget & share_target)3513 void NearbySharingServiceImpl::UnregisterShareTarget(
3514 const ShareTarget& share_target) {
3515 NS_LOG(VERBOSE) << __func__ << ": Unregistering share target - "
3516 << share_target.device_name;
3517
3518 if (share_target.is_incoming) {
3519 if (last_incoming_metadata_ &&
3520 last_incoming_metadata_->first.id == share_target.id) {
3521 last_incoming_metadata_.reset();
3522 }
3523
3524 // Clear legacy incoming payloads to release resource.
3525 nearby_connections_manager_->ClearIncomingPayloads();
3526 incoming_share_target_info_map_.erase(share_target.id);
3527 } else {
3528 if (last_outgoing_metadata_ &&
3529 last_outgoing_metadata_->first.id == share_target.id) {
3530 last_outgoing_metadata_.reset();
3531 }
3532 // Find the endpoint id that matches the given share target.
3533 base::Optional<std::string> endpoint_id;
3534 auto it = outgoing_share_target_info_map_.find(share_target.id);
3535 if (it != outgoing_share_target_info_map_.end())
3536 endpoint_id = it->second.endpoint_id();
3537
3538 // TODO(crbug/1108348): Support caching manager by keeping track of the
3539 // share_target/endpoint_id for next time.
3540 ClearOutgoingShareTargetInfoMap();
3541
3542 NS_LOG(VERBOSE) << __func__ << ": Unregister share target: "
3543 << share_target.device_name;
3544 }
3545 mutual_acceptance_timeout_alarm_.Cancel();
3546 }
3547
OnStartAdvertisingResult(bool used_device_name,NearbyConnectionsManager::ConnectionsStatus status)3548 void NearbySharingServiceImpl::OnStartAdvertisingResult(
3549 bool used_device_name,
3550 NearbyConnectionsManager::ConnectionsStatus status) {
3551 RecordNearbyShareStartAdvertisingResultMetric(
3552 /*is_high_visibility=*/used_device_name, status);
3553
3554 if (status == NearbyConnectionsManager::ConnectionsStatus::kSuccess) {
3555 NS_LOG(VERBOSE)
3556 << "StartAdvertising over Nearby Connections was successful.";
3557 SetInHighVisibility(used_device_name);
3558 } else {
3559 NS_LOG(ERROR) << "StartAdvertising over Nearby Connections failed: "
3560 << NearbyConnectionsManager::ConnectionsStatusToString(
3561 status);
3562 SetInHighVisibility(false);
3563 }
3564 }
3565
SetInHighVisibility(bool new_in_high_visibility)3566 void NearbySharingServiceImpl::SetInHighVisibility(
3567 bool new_in_high_visibility) {
3568 if (in_high_visibility == new_in_high_visibility)
3569 return;
3570
3571 in_high_visibility = new_in_high_visibility;
3572 for (auto& observer : observers_) {
3573 observer.OnHighVisibilityChanged(in_high_visibility);
3574 }
3575 }
3576