| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/crosapi/image_writer_ash.h" |
| |
| #include "base/containers/contains.h" |
| #include "base/functional/bind.h" |
| #include "base/unguessable_token.h" |
| #include "chrome/browser/extensions/api/image_writer_private/operation_manager.h" |
| #include "chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chrome/common/extensions/api/image_writer_private.h" |
| #include "content/public/browser/browser_context.h" |
| #include "extensions/browser/api/extensions_api_client.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "url/gurl.h" |
| |
| namespace crosapi { |
| |
| namespace { |
| |
| crosapi::mojom::RemovableStorageDevicePtr ToMojo( |
| const extensions::api::image_writer_private::RemovableStorageDevice& |
| device) { |
| auto mojo_device = crosapi::mojom::RemovableStorageDevice::New(); |
| mojo_device->storage_unit_id = device.storage_unit_id; |
| mojo_device->capacity = device.capacity; |
| mojo_device->vendor = device.vendor; |
| mojo_device->model = device.model; |
| mojo_device->removable = device.removable; |
| return mojo_device; |
| } |
| |
| content::BrowserContext* GetActiveUserBrowserContext() { |
| return ProfileManager::GetActiveUserProfile(); |
| } |
| |
| } // namespace |
| |
| ImageWriterAsh::ImageWriterAsh() = default; |
| |
| ImageWriterAsh::~ImageWriterAsh() = default; |
| |
| void ImageWriterAsh::BindReceiver( |
| mojo::PendingReceiver<mojom::ImageWriter> pending_receiver) { |
| receivers_.Add(this, std::move(pending_receiver)); |
| } |
| |
| void ImageWriterAsh::ListRemovableStorageDevices( |
| ListRemovableStorageDevicesCallback callback) { |
| extensions::RemovableStorageProvider::GetAllDevices( |
| base::BindOnce(&ImageWriterAsh::OnDeviceListReady, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void ImageWriterAsh::DestroyPartitions( |
| const std::string& storage_unit_id, |
| mojo::PendingRemote<mojom::ImageWriterClient> remote_client, |
| DestroyPartitionsCallback callback) { |
| mojo::Remote<mojom::ImageWriterClient> remote(std::move(remote_client)); |
| base::UnguessableToken remote_client_token = base::UnguessableToken::Create(); |
| remote.set_disconnect_handler( |
| base::BindOnce(&ImageWriterAsh::OnImageWriterClientDisconnected, |
| weak_ptr_factory_.GetWeakPtr(), remote_client_token)); |
| remote_image_writer_clients_.emplace(remote_client_token.ToString(), |
| std::move(remote)); |
| |
| // Pass the string of |remote_client_token| to OperationManager, which will |
| // be used to dispatch writing progress events back. |
| extensions::image_writer::OperationManager::Get(GetActiveUserBrowserContext()) |
| ->DestroyPartitions( |
| /*extension_id=*/remote_client_token.ToString(), storage_unit_id, |
| base::BindOnce(&ImageWriterAsh::OnOperationCompleted, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void ImageWriterAsh::WriteFromUrl( |
| const std::string& storage_unit_id, |
| const GURL& image_url, |
| const absl::optional<std::string>& image_hash, |
| mojo::PendingRemote<mojom::ImageWriterClient> remote_client, |
| WriteFromUrlCallback callback) { |
| mojo::Remote<mojom::ImageWriterClient> remote(std::move(remote_client)); |
| base::UnguessableToken remote_client_token = base::UnguessableToken::Create(); |
| remote.set_disconnect_handler( |
| base::BindOnce(&ImageWriterAsh::OnImageWriterClientDisconnected, |
| weak_ptr_factory_.GetWeakPtr(), remote_client_token)); |
| remote_image_writer_clients_.emplace(remote_client_token.ToString(), |
| std::move(remote)); |
| |
| extensions::image_writer::OperationManager::Get(GetActiveUserBrowserContext()) |
| ->StartWriteFromUrl( |
| /*extension_id=*/remote_client_token.ToString(), image_url, |
| image_hash ? image_hash.value() : "", storage_unit_id, |
| base::BindOnce(&ImageWriterAsh::OnOperationCompleted, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void ImageWriterAsh::WriteFromFile( |
| const std::string& storage_unit_id, |
| const base::FilePath& image_path, |
| mojo::PendingRemote<mojom::ImageWriterClient> remote_client, |
| WriteFromFileCallback callback) { |
| mojo::Remote<mojom::ImageWriterClient> remote(std::move(remote_client)); |
| base::UnguessableToken remote_client_token = base::UnguessableToken::Create(); |
| remote.set_disconnect_handler( |
| base::BindOnce(&ImageWriterAsh::OnImageWriterClientDisconnected, |
| weak_ptr_factory_.GetWeakPtr(), remote_client_token)); |
| remote_image_writer_clients_.emplace(remote_client_token.ToString(), |
| std::move(remote)); |
| |
| extensions::image_writer::OperationManager::Get(GetActiveUserBrowserContext()) |
| ->StartWriteFromFile( |
| /*extension_id=*/remote_client_token.ToString(), image_path, |
| storage_unit_id, |
| base::BindOnce(&ImageWriterAsh::OnOperationCompleted, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void ImageWriterAsh::DispatchOnWriteProgressEvent( |
| const std::string& client_token_string, |
| crosapi::mojom::Stage stage, |
| uint32_t percent_complete) { |
| auto it = remote_image_writer_clients_.find(client_token_string); |
| if (it != remote_image_writer_clients_.end()) |
| it->second->DispatchOnWriteProgressEvent(stage, percent_complete); |
| } |
| |
| void ImageWriterAsh::DispatchOnWriteCompleteEvent( |
| const std::string& client_token_string) { |
| auto it = remote_image_writer_clients_.find(client_token_string); |
| if (it != remote_image_writer_clients_.end()) { |
| it->second->DispatchOnWriteCompleteEvent(); |
| // Clean up the remote client after the writing operation completes. |
| remote_image_writer_clients_.erase(it); |
| } |
| } |
| |
| void ImageWriterAsh::DispatchOnWriteErrorEvent( |
| const std::string& client_token_string, |
| crosapi::mojom::Stage stage, |
| uint32_t percent_complete, |
| const std::string& error) { |
| auto it = remote_image_writer_clients_.find(client_token_string); |
| if (it != remote_image_writer_clients_.end()) { |
| it->second->DispatchOnWriteErrorEvent(stage, percent_complete, error); |
| // Clean up the remote client after the writing operation fails. |
| remote_image_writer_clients_.erase(it); |
| } |
| } |
| |
| bool ImageWriterAsh::IsRemoteClientToken(const std::string& id) const { |
| return base::Contains(remote_image_writer_clients_, id); |
| } |
| |
| void ImageWriterAsh::OnImageWriterClientDisconnected( |
| const base::UnguessableToken& remote_client_token) { |
| auto it = remote_image_writer_clients_.find(remote_client_token.ToString()); |
| if (it != remote_image_writer_clients_.end()) { |
| // Cancel the write operation if there is any pending. |
| extensions::image_writer::OperationManager::Get( |
| GetActiveUserBrowserContext()) |
| ->CancelWrite(/*extension_id=*/remote_client_token.ToString(), |
| base::BindOnce(&ImageWriterAsh::OnCancelWriteDone, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| remote_image_writer_clients_.erase(it); |
| } |
| } |
| |
| void ImageWriterAsh::OnDeviceListReady( |
| ListRemovableStorageDevicesCallback callback, |
| scoped_refptr<StorageDeviceList> device_list) { |
| if (!device_list) { |
| std::move(callback).Run(absl::nullopt); |
| return; |
| } |
| |
| std::vector<crosapi::mojom::RemovableStorageDevicePtr> mojo_devices; |
| for (const auto& device : device_list->data) { |
| mojo_devices.push_back(ToMojo(device)); |
| } |
| |
| std::move(callback).Run(std::move(mojo_devices)); |
| } |
| |
| void ImageWriterAsh::OnOperationCompleted(OperationCallback callback, |
| bool success, |
| const std::string& error) { |
| std::move(callback).Run(success ? absl::nullopt : absl::make_optional(error)); |
| } |
| |
| void ImageWriterAsh::OnCancelWriteDone(bool success, const std::string& error) { |
| if (!success) |
| DLOG(WARNING) << "Failed to cancel write for remote client: " << error; |
| } |
| |
| } // namespace crosapi |