Commit 0758c369 authored by Joel Hockey's avatar Joel Hockey Committed by Commit Bot

Reland "Support Arc, crostini, and Plugin VM in drag drop FileHelper"

This reverts commit 8fd7b85d.

Reason for revert: relanding after creating fix for M88

Original change's description:
> Revert "Support Arc, crostini, and Plugin VM in drag drop FileHelper"
>
> This reverts commit 54e85384.
>
> Reason for revert: Reverting in order to create a patch for M88.
>
> Original change's description:
> > Support Arc, crostini, and Plugin VM in drag drop FileHelper
> >
> > The current code in FileHelper assumes all windows are Arc. We now
> > check the source and target aura::Window to detect and do the
> > appropriate path translations and share files when necessary with
> > crostini/pluginvm.
> >
> > For example, when crostini is the drag source, we will convert paths
> > such as:
> >
> >  <homedir>/file => /media/fuse/crostini_<hash>_termina_penguin/file
> >
> > And do the opposite translation when crostini is the drop target.
> >
> > We also convert paths and share files such as:
> >
> >  <cryptohome>/MyFiles/file => /mnt/chromeos/MyFiles/file
> >  /media/removable/MyUSB => /mnt/chromeos/removable/MyUSB
> >
> > For PluginVM, the translation is
> >
> >  <cryptohome>/MyFiles/file => //ChromeOS/MyFiles/file
> >  /media/removable/MyUSB => //ChromeOS/removable/MyUSB
> >
> > Bug: 1144138
> > Change-Id: I2bb38336537acf13c4797374d6dabe6e518d689e
> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2517346
> > Commit-Queue: Joel Hockey <joelhockey@chromium.org>
> > Reviewed-by: Jason Lin <lxj@google.com>
> > Reviewed-by: Mitsuru Oshima <oshima@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#827956}
>
> TBR=oshima@chromium.org,joelhockey@chromium.org,niwa@chromium.org,lxj@google.com
>
> # Not skipping CQ checks because original CL landed > 1 day ago.
>
> Bug: 1144138
> Change-Id: I212ae8759e9069e52837fd1bc324ea5f9046b6b5
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2547743
> Reviewed-by: Joel Hockey <joelhockey@chromium.org>
> Reviewed-by: Mitsuru Oshima <oshima@chromium.org>
> Commit-Queue: Joel Hockey <joelhockey@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#829031}

TBR=oshima@chromium.org,joelhockey@chromium.org,niwa@chromium.org,lxj@google.com

# Not skipping CQ checks because this is a reland.

Bug: 1144138
Change-Id: I0a735fb4e17679f735c11ecab427f7ba624db399
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2547844Reviewed-by: default avatarJoel Hockey <joelhockey@chromium.org>
Commit-Queue: Joel Hockey <joelhockey@chromium.org>
Cr-Commit-Position: refs/heads/master@{#829065}
parent 333f5ec1
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <utility> #include <utility>
#include "ash/public/cpp/app_types.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/callback_helpers.h" #include "base/callback_helpers.h"
...@@ -44,6 +45,7 @@ ...@@ -44,6 +45,7 @@
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/user_manager/user.h" #include "components/user_manager/user.h"
#include "google_apis/gaia/gaia_auth_util.h" #include "google_apis/gaia/gaia_auth_util.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/time_format.h" #include "ui/base/l10n/time_format.h"
...@@ -574,4 +576,10 @@ const ContainerId& DefaultContainerId() { ...@@ -574,4 +576,10 @@ const ContainerId& DefaultContainerId() {
kCrostiniDefaultVmName, kCrostiniDefaultContainerName); kCrostiniDefaultVmName, kCrostiniDefaultContainerName);
return *container_id; return *container_id;
} }
bool IsCrostiniWindow(aura::Window* window) {
return window->GetProperty(aura::client::kAppType) ==
static_cast<int>(ash::AppType::CROSTINI_APP);
}
} // namespace crostini } // namespace crostini
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
#include "storage/browser/file_system/file_system_url.h" #include "storage/browser/file_system/file_system_url.h"
#include "third_party/abseil-cpp/absl/types/variant.h" #include "third_party/abseil-cpp/absl/types/variant.h"
namespace aura {
class Window;
} // namespace aura
namespace base { namespace base {
class FilePath; class FilePath;
} // namespace base } // namespace base
...@@ -205,6 +209,8 @@ void UpdateContainerPref(Profile* profile, ...@@ -205,6 +209,8 @@ void UpdateContainerPref(Profile* profile,
const ContainerId& DefaultContainerId(); const ContainerId& DefaultContainerId();
bool IsCrostiniWindow(aura::Window* window);
} // namespace crostini } // namespace crostini
#endif // CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_UTIL_H_ #endif // CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_UTIL_H_
...@@ -22,21 +22,23 @@ ...@@ -22,21 +22,23 @@
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/chromeos/crostini/crostini_shelf_utils.h" #include "chrome/browser/chromeos/crostini/crostini_shelf_utils.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h" #include "chrome/browser/chromeos/crostini/crostini_util.h"
#include "chrome/browser/chromeos/file_manager/app_id.h" #include "chrome/browser/chromeos/file_manager/app_id.h"
#include "chrome/browser/chromeos/file_manager/fileapi_util.h" #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
#include "chrome/browser/chromeos/file_manager/path_util.h" #include "chrome/browser/chromeos/file_manager/path_util.h"
#include "chrome/browser/chromeos/guest_os/guest_os_share_path.h"
#include "chrome/browser/chromeos/plugin_vm/plugin_vm_files.h"
#include "chrome/browser/chromeos/plugin_vm/plugin_vm_util.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_switches.h"
#include "components/exo/file_helper.h" #include "components/exo/file_helper.h"
#include "components/exo/server/wayland_server_controller.h" #include "components/exo/server/wayland_server_controller.h"
#include "components/user_manager/user_manager.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/common/drop_data.h" #include "content/public/common/drop_data.h"
#include "net/base/filename_util.h" #include "net/base/filename_util.h"
#include "storage/browser/file_system/external_mount_points.h"
#include "storage/browser/file_system/file_system_context.h" #include "storage/browser/file_system/file_system_context.h"
#include "storage/browser/file_system/file_system_url.h" #include "storage/browser/file_system/file_system_url.h"
#include "storage/common/file_system/file_system_types.h" #include "storage/common/file_system/file_system_types.h"
...@@ -46,6 +48,7 @@ ...@@ -46,6 +48,7 @@
namespace { namespace {
constexpr char kMimeTypeArcUriList[] = "application/x-arc-uri-list"; constexpr char kMimeTypeArcUriList[] = "application/x-arc-uri-list";
constexpr char kMimeTypeTextUriList[] = "text/uri-list";
constexpr char kUriListSeparator[] = "\r\n"; constexpr char kUriListSeparator[] = "\r\n";
bool IsArcWindow(const aura::Window* window) { bool IsArcWindow(const aura::Window* window) {
...@@ -54,15 +57,7 @@ bool IsArcWindow(const aura::Window* window) { ...@@ -54,15 +57,7 @@ bool IsArcWindow(const aura::Window* window) {
} }
storage::FileSystemContext* GetFileSystemContext() { storage::FileSystemContext* GetFileSystemContext() {
// Obtains the primary profile. Profile* primary_profile = ProfileManager::GetPrimaryUserProfile();
if (!user_manager::UserManager::IsInitialized())
return nullptr;
const user_manager::User* primary_user =
user_manager::UserManager::Get()->GetPrimaryUser();
if (!primary_user)
return nullptr;
Profile* primary_profile =
chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user);
if (!primary_profile) if (!primary_profile)
return nullptr; return nullptr;
...@@ -104,6 +99,72 @@ void SendArcUrls(exo::FileHelper::SendDataCallback callback, ...@@ -104,6 +99,72 @@ void SendArcUrls(exo::FileHelper::SendDataCallback callback,
std::move(callback).Run(base::RefCountedString16::TakeString(&data)); std::move(callback).Run(base::RefCountedString16::TakeString(&data));
} }
void SendAfterShare(exo::FileHelper::SendDataCallback callback,
scoped_refptr<base::RefCountedMemory> data,
bool success,
const std::string& failure_reason) {
if (!success)
LOG(ERROR) << "Error sharing paths for drag and drop: " << failure_reason;
// Still send the data, even if sharing failed.
std::move(callback).Run(data);
}
struct FileInfo {
base::FilePath path;
storage::FileSystemURL url;
};
void ShareAndSend(aura::Window* target,
std::vector<FileInfo> files,
exo::FileHelper::SendDataCallback callback) {
Profile* primary_profile = ProfileManager::GetPrimaryUserProfile();
aura::Window* toplevel = target->GetToplevelWindow();
bool is_crostini = crostini::IsCrostiniWindow(toplevel);
bool is_plugin_vm = plugin_vm::IsPluginVmAppWindow(toplevel);
base::FilePath vm_mount;
std::string vm_name;
if (is_crostini) {
vm_mount = crostini::ContainerChromeOSBaseDirectory();
vm_name = crostini::kCrostiniDefaultVmName;
} else if (is_plugin_vm) {
vm_mount = plugin_vm::ChromeOSBaseDirectory();
vm_name = plugin_vm::kPluginVmName;
}
std::vector<std::string> lines_to_send;
auto* share_path = guest_os::GuestOsSharePath::GetForProfile(primary_profile);
std::vector<base::FilePath> paths_to_share;
for (auto& info : files) {
// Crostini and PluginVm converts to path inside VM. For other app types, or
// if we fail to convert, we just keep the original path.
base::FilePath path_to_send = info.path;
if ((is_crostini || is_plugin_vm) &&
file_manager::util::ConvertFileSystemURLToPathInsideVM(
primary_profile, info.url, vm_mount,
/*map_crostini_home=*/is_crostini, &path_to_send) &&
!share_path->IsPathShared(vm_name, info.path)) {
// Keep a record of any paths which are not yet shared.
paths_to_share.emplace_back(info.path);
}
lines_to_send.emplace_back(net::FilePathToFileURL(path_to_send).spec());
}
std::string joined = base::JoinString(lines_to_send, kUriListSeparator);
auto data = base::RefCountedString::TakeString(&joined);
if (!paths_to_share.empty()) {
share_path->SharePaths(
vm_name, std::move(paths_to_share),
/*persist=*/false,
base::BindOnce(&SendAfterShare, std::move(callback), std::move(data)));
} else {
std::move(callback).Run(std::move(data));
}
}
class ChromeFileHelper : public exo::FileHelper { class ChromeFileHelper : public exo::FileHelper {
public: public:
ChromeFileHelper() = default; ChromeFileHelper() = default;
...@@ -113,10 +174,10 @@ class ChromeFileHelper : public exo::FileHelper { ...@@ -113,10 +174,10 @@ class ChromeFileHelper : public exo::FileHelper {
std::vector<ui::FileInfo> GetFilenames( std::vector<ui::FileInfo> GetFilenames(
aura::Window* source, aura::Window* source,
const std::vector<uint8_t>& data) const override { const std::vector<uint8_t>& data) const override {
// TODO(crbug.com/1144138): We must translate the path if this was received Profile* primary_profile = ProfileManager::GetPrimaryUserProfile();
// from a VM. E.g. if this was from crostini as aura::Window* toplevel = source->GetToplevelWindow();
// file:///home/username/file.txt, we translate to bool is_crostini = crostini::IsCrostiniWindow(toplevel);
// file:///media/fuse/crostini_<hash>_termina_penguin/file.txt. bool is_plugin_vm = plugin_vm::IsPluginVmAppWindow(toplevel);
std::string lines(data.begin(), data.end()); std::string lines(data.begin(), data.end());
std::vector<ui::FileInfo> filenames; std::vector<ui::FileInfo> filenames;
// Until we have mapping for other VMs, only accept from arc. // Until we have mapping for other VMs, only accept from arc.
...@@ -129,29 +190,62 @@ class ChromeFileHelper : public exo::FileHelper { ...@@ -129,29 +190,62 @@ class ChromeFileHelper : public exo::FileHelper {
lines, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) { lines, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
if (!net::FileURLToFilePath(GURL(line), &path)) if (!net::FileURLToFilePath(GURL(line), &path))
continue; continue;
if (is_crostini &&
file_manager::util::ConvertPathInsideVMToFileSystemURL(
primary_profile, path, crostini::ContainerChromeOSBaseDirectory(),
/*map_crostini_home=*/true, &url)) {
path = url.path();
} else if (is_plugin_vm &&
file_manager::util::ConvertPathInsideVMToFileSystemURL(
primary_profile, path, plugin_vm::ChromeOSBaseDirectory(),
/*map_crostini_home=*/false, &url)) {
path = url.path();
}
filenames.emplace_back(ui::FileInfo(path, base::FilePath())); filenames.emplace_back(ui::FileInfo(path, base::FilePath()));
} }
return filenames; return filenames;
} }
std::string GetMimeTypeForUriList(aura::Window* target) const override { std::string GetMimeTypeForUriList(aura::Window* target) const override {
return kMimeTypeArcUriList; return IsArcWindow(target->GetToplevelWindow()) ? kMimeTypeArcUriList
: kMimeTypeTextUriList;
} }
void SendFileInfo(aura::Window* target, void SendFileInfo(aura::Window* target,
const std::vector<ui::FileInfo>& files, const std::vector<ui::FileInfo>& files,
exo::FileHelper::SendDataCallback callback) const override { exo::FileHelper::SendDataCallback callback) const override {
// TODO(crbug.com/1144138): Translate path and possibly share files with VM. // ARC converts to ArcUrl and uses utf-16.
std::vector<std::string> lines; if (IsArcWindow(target->GetToplevelWindow())) {
GURL url; std::vector<std::string> lines;
GURL url;
for (const auto& info : files) {
if (file_manager::util::ConvertPathToArcUrl(info.path, &url)) {
lines.emplace_back(url.spec());
}
}
base::string16 data =
base::UTF8ToUTF16(base::JoinString(lines, kUriListSeparator));
std::move(callback).Run(base::RefCountedString16::TakeString(&data));
return;
}
storage::ExternalMountPoints* mount_points =
storage::ExternalMountPoints::GetSystemInstance();
base::FilePath virtual_path;
std::vector<FileInfo> list;
for (const auto& info : files) { for (const auto& info : files) {
if (file_manager::util::ConvertPathToArcUrl(info.path, &url)) { // Convert absolute host path to FileSystemURL if possible.
lines.emplace_back(url.spec()); storage::FileSystemURL url;
if (mount_points->GetVirtualPath(info.path, &virtual_path)) {
url = mount_points->CreateCrackedFileSystemURL(
url::Origin(), storage::kFileSystemTypeExternal, virtual_path);
} }
list.push_back({info.path, std::move(url)});
} }
base::string16 data =
base::UTF8ToUTF16(base::JoinString(lines, kUriListSeparator)); ShareAndSend(target, std::move(list), std::move(callback));
std::move(callback).Run(base::RefCountedString16::TakeString(&data));
} }
bool HasUrlsInPickle(const base::Pickle& pickle) const override { bool HasUrlsInPickle(const base::Pickle& pickle) const override {
...@@ -163,15 +257,25 @@ class ChromeFileHelper : public exo::FileHelper { ...@@ -163,15 +257,25 @@ class ChromeFileHelper : public exo::FileHelper {
void SendPickle(aura::Window* target, void SendPickle(aura::Window* target,
const base::Pickle& pickle, const base::Pickle& pickle,
exo::FileHelper::SendDataCallback callback) override { exo::FileHelper::SendDataCallback callback) override {
// TODO(crbug.com/1144138): Translate path and possibly share files with VM.
std::vector<storage::FileSystemURL> file_system_urls; std::vector<storage::FileSystemURL> file_system_urls;
GetFileSystemUrlsFromPickle(pickle, &file_system_urls); GetFileSystemUrlsFromPickle(pickle, &file_system_urls);
if (file_system_urls.empty()) {
std::move(callback).Run(nullptr); // ARC FileSystemURLs are converted to Content URLs.
if (IsArcWindow(target->GetToplevelWindow())) {
if (file_system_urls.empty()) {
std::move(callback).Run(nullptr);
return;
}
file_manager::util::ConvertToContentUrls(
file_system_urls, base::BindOnce(&SendArcUrls, std::move(callback)));
return; return;
} }
file_manager::util::ConvertToContentUrls(
file_system_urls, base::BindOnce(&SendArcUrls, std::move(callback))); std::vector<FileInfo> list;
for (const auto& url : file_system_urls)
list.push_back({url.path(), url});
ShareAndSend(target, std::move(list), std::move(callback));
} }
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment