Commit ae0e8508 authored by Christopher Cameron's avatar Christopher Cameron Committed by Commit Bot

MacPWAs: Allow creating of AppShimHost before process exists

Allow for an AppShimHost to be created before the corresponding
AppShimHostBootstrap. Update OnAppLaunchComplete to save the launch
result and send it only once an AppShimHostBootstrap is attached.

Change ExtensionAppShimHandler profile paths to use the full path
(as is reported by the Profile object, as opposed to the shim's
message).

Change the method GetHostForBrowser to instead be
GetViewsBridgeFactoryHostForBrowser, because the ViewsBridgeFactory is
what all callers are after. Make this call trigger creation of an
AppShimHost if needed to provide a ViewsBridgeFactory. Keep this
guarded behind a flag for now.

Add tests for this functionality. In the tests, further decouple
the AppShimHostBootstrap from its AppShimHost.

Bug: 896917
Change-Id: Ib9e4ad6535ca87cd0e01303fbfc772b8892aec12
Reviewed-on: https://chromium-review.googlesource.com/c/1309307Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Reviewed-by: default avatarccameron <ccameron@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Commit-Queue: ccameron <ccameron@chromium.org>
Cr-Commit-Position: refs/heads/master@{#604440}
parent a1361929
...@@ -29,6 +29,9 @@ class AppShimHandler { ...@@ -29,6 +29,9 @@ class AppShimHandler {
// https://crbug.com/896917 // https://crbug.com/896917
class Host { class Host {
public: public:
// Returns true if an AppShimHostBootstrap has already connected to this
// host.
virtual bool HasBootstrapConnected() const = 0;
// Invoked when the app shim process has finished launching. The |bootstrap| // Invoked when the app shim process has finished launching. The |bootstrap|
// object owns the lifetime of the app shim process. // object owns the lifetime of the app shim process.
virtual void OnBootstrapConnected( virtual void OnBootstrapConnected(
......
...@@ -71,6 +71,17 @@ void AppShimHost::ChannelError(uint32_t custom_reason, ...@@ -71,6 +71,17 @@ void AppShimHost::ChannelError(uint32_t custom_reason,
Close(); Close();
} }
void AppShimHost::SendLaunchResult() {
DCHECK(!has_sent_on_launch_complete_);
DCHECK(bootstrap_);
DCHECK(launch_result_);
if (*launch_result_ == apps::APP_SHIM_LAUNCH_SUCCESS)
bootstrap_->OnLaunchAppSucceeded(std::move(app_shim_request_));
else
bootstrap_->OnLaunchAppFailed(*launch_result_);
has_sent_on_launch_complete_ = true;
}
void AppShimHost::Close() { void AppShimHost::Close() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Note that we must call GetAppShimHandler here and not in the destructor // Note that we must call GetAppShimHandler here and not in the destructor
...@@ -88,6 +99,10 @@ apps::AppShimHandler* AppShimHost::GetAppShimHandler() const { ...@@ -88,6 +99,10 @@ apps::AppShimHandler* AppShimHost::GetAppShimHandler() const {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// AppShimHost, chrome::mojom::AppShimHost // AppShimHost, chrome::mojom::AppShimHost
bool AppShimHost::HasBootstrapConnected() const {
return bootstrap_ != nullptr;
}
void AppShimHost::OnBootstrapConnected( void AppShimHost::OnBootstrapConnected(
std::unique_ptr<AppShimHostBootstrap> bootstrap) { std::unique_ptr<AppShimHostBootstrap> bootstrap) {
DCHECK(!bootstrap_); DCHECK(!bootstrap_);
...@@ -97,6 +112,11 @@ void AppShimHost::OnBootstrapConnected( ...@@ -97,6 +112,11 @@ void AppShimHost::OnBootstrapConnected(
host_binding_.Bind(bootstrap_->GetLaunchAppShimHostRequest()); host_binding_.Bind(bootstrap_->GetLaunchAppShimHostRequest());
host_binding_.set_connection_error_with_reason_handler( host_binding_.set_connection_error_with_reason_handler(
base::BindOnce(&AppShimHost::ChannelError, base::Unretained(this))); base::BindOnce(&AppShimHost::ChannelError, base::Unretained(this)));
// If we already have a launch result ready (e.g, because we launched the app
// from Chrome), send the result immediately.
if (launch_result_)
SendLaunchResult();
} }
void AppShimHost::FocusApp(apps::AppShimFocusType focus_type, void AppShimHost::FocusApp(apps::AppShimFocusType focus_type,
...@@ -126,12 +146,9 @@ void AppShimHost::QuitApp() { ...@@ -126,12 +146,9 @@ void AppShimHost::QuitApp() {
void AppShimHost::OnAppLaunchComplete(apps::AppShimLaunchResult result) { void AppShimHost::OnAppLaunchComplete(apps::AppShimLaunchResult result) {
DCHECK(!has_sent_on_launch_complete_); DCHECK(!has_sent_on_launch_complete_);
DCHECK(bootstrap_); launch_result_.emplace(result);
if (result == apps::APP_SHIM_LAUNCH_SUCCESS) if (bootstrap_)
bootstrap_->OnLaunchAppSucceeded(std::move(app_shim_request_)); SendLaunchResult();
else
bootstrap_->OnLaunchAppFailed(result);
has_sent_on_launch_complete_ = true;
} }
void AppShimHost::OnAppClosed() { void AppShimHost::OnAppClosed() {
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <vector> #include <vector>
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/optional.h"
#include "base/threading/thread_checker.h" #include "base/threading/thread_checker.h"
#include "chrome/browser/apps/app_shim/app_shim_handler_mac.h" #include "chrome/browser/apps/app_shim/app_shim_handler_mac.h"
#include "chrome/common/mac/app_shim.mojom.h" #include "chrome/common/mac/app_shim.mojom.h"
...@@ -35,6 +36,7 @@ class AppShimHost : public chrome::mojom::AppShimHost, ...@@ -35,6 +36,7 @@ class AppShimHost : public chrome::mojom::AppShimHost,
AppShimHost(const std::string& app_id, const base::FilePath& profile_path); AppShimHost(const std::string& app_id, const base::FilePath& profile_path);
// apps::AppShimHandler::Host overrides: // apps::AppShimHandler::Host overrides:
bool HasBootstrapConnected() const override;
void OnBootstrapConnected( void OnBootstrapConnected(
std::unique_ptr<AppShimHostBootstrap> bootstrap) override; std::unique_ptr<AppShimHostBootstrap> bootstrap) override;
void OnAppLaunchComplete(apps::AppShimLaunchResult result) override; void OnAppLaunchComplete(apps::AppShimLaunchResult result) override;
...@@ -51,6 +53,7 @@ class AppShimHost : public chrome::mojom::AppShimHost, ...@@ -51,6 +53,7 @@ class AppShimHost : public chrome::mojom::AppShimHost,
// channel error and OnAppClosed). // channel error and OnAppClosed).
~AppShimHost() override; ~AppShimHost() override;
void ChannelError(uint32_t custom_reason, const std::string& description); void ChannelError(uint32_t custom_reason, const std::string& description);
void SendLaunchResult();
// Closes the channel and destroys the AppShimHost. // Closes the channel and destroys the AppShimHost.
void Close(); void Close();
...@@ -75,6 +78,10 @@ class AppShimHost : public chrome::mojom::AppShimHost, ...@@ -75,6 +78,10 @@ class AppShimHost : public chrome::mojom::AppShimHost,
std::string app_id_; std::string app_id_;
base::FilePath profile_path_; base::FilePath profile_path_;
// The result passed to OnAppLaunchComplete, not set until OnAppLaunchComplete
// is called.
base::Optional<apps::AppShimLaunchResult> launch_result_;
bool has_sent_on_launch_complete_ = false; bool has_sent_on_launch_complete_ = false;
THREAD_CHECKER(thread_checker_); THREAD_CHECKER(thread_checker_);
......
...@@ -151,21 +151,25 @@ class EnableViaPrompt : public ExtensionEnableFlowDelegate { ...@@ -151,21 +151,25 @@ class EnableViaPrompt : public ExtensionEnableFlowDelegate {
namespace apps { namespace apps {
base::FilePath ExtensionAppShimHandler::Delegate::GetFullProfilePath(
const base::FilePath& relative_profile_path) {
ProfileManager* profile_manager = g_browser_process->profile_manager();
return profile_manager->user_data_dir().Append(relative_profile_path);
}
bool ExtensionAppShimHandler::Delegate::ProfileExistsForPath( bool ExtensionAppShimHandler::Delegate::ProfileExistsForPath(
const base::FilePath& path) { const base::FilePath& full_path) {
ProfileManager* profile_manager = g_browser_process->profile_manager(); ProfileManager* profile_manager = g_browser_process->profile_manager();
// Check for the profile name in the profile info cache to ensure that we // Check for the profile name in the profile info cache to ensure that we
// never access any directory that isn't a known profile. // never access any directory that isn't a known profile.
base::FilePath full_path = profile_manager->user_data_dir().Append(path);
ProfileAttributesEntry* entry; ProfileAttributesEntry* entry;
return profile_manager->GetProfileAttributesStorage(). return profile_manager->GetProfileAttributesStorage().
GetProfileAttributesWithPath(full_path, &entry); GetProfileAttributesWithPath(full_path, &entry);
} }
Profile* ExtensionAppShimHandler::Delegate::ProfileForPath( Profile* ExtensionAppShimHandler::Delegate::ProfileForPath(
const base::FilePath& path) { const base::FilePath& full_path) {
ProfileManager* profile_manager = g_browser_process->profile_manager(); ProfileManager* profile_manager = g_browser_process->profile_manager();
base::FilePath full_path = profile_manager->user_data_dir().Append(path);
Profile* profile = profile_manager->GetProfileByPath(full_path); Profile* profile = profile_manager->GetProfileByPath(full_path);
// Use IsValidProfile to check if the profile has been created. // Use IsValidProfile to check if the profile has been created.
...@@ -173,17 +177,14 @@ Profile* ExtensionAppShimHandler::Delegate::ProfileForPath( ...@@ -173,17 +177,14 @@ Profile* ExtensionAppShimHandler::Delegate::ProfileForPath(
} }
void ExtensionAppShimHandler::Delegate::LoadProfileAsync( void ExtensionAppShimHandler::Delegate::LoadProfileAsync(
const base::FilePath& path, const base::FilePath& full_path,
base::OnceCallback<void(Profile*)> callback) { base::OnceCallback<void(Profile*)> callback) {
ProfileManager* profile_manager = g_browser_process->profile_manager(); ProfileManager* profile_manager = g_browser_process->profile_manager();
base::FilePath full_path = profile_manager->user_data_dir().Append(path);
profile_manager->LoadProfileByPath(full_path, false, std::move(callback)); profile_manager->LoadProfileByPath(full_path, false, std::move(callback));
} }
bool ExtensionAppShimHandler::Delegate::IsProfileLockedForPath( bool ExtensionAppShimHandler::Delegate::IsProfileLockedForPath(
const base::FilePath& path) { const base::FilePath& full_path) {
ProfileManager* profile_manager = g_browser_process->profile_manager();
base::FilePath full_path = profile_manager->user_data_dir().Append(path);
return profiles::IsProfileLocked(full_path); return profiles::IsProfileLocked(full_path);
} }
...@@ -277,13 +278,26 @@ AppShimHandler::Host* ExtensionAppShimHandler::FindHost( ...@@ -277,13 +278,26 @@ AppShimHandler::Host* ExtensionAppShimHandler::FindHost(
return it == hosts_.end() ? NULL : it->second; return it == hosts_.end() ? NULL : it->second;
} }
AppShimHandler::Host* ExtensionAppShimHandler::FindHostForBrowser( AppShimHandler::Host* ExtensionAppShimHandler::FindOrCreateHost(
Browser* browser) { Profile* profile,
const std::string& app_id) {
Host*& host = hosts_[make_pair(profile, app_id)];
if (!host)
host = delegate_->CreateHost(app_id, profile->GetPath());
return host;
}
views::BridgeFactoryHost*
ExtensionAppShimHandler::GetViewsBridgeFactoryHostForBrowser(Browser* browser) {
if (!features::HostWindowsInAppShimProcess())
return nullptr;
const Extension* extension = const Extension* extension =
apps::ExtensionAppShimHandler::MaybeGetAppForBrowser(browser); apps::ExtensionAppShimHandler::MaybeGetAppForBrowser(browser);
if (extension) { if (extension && extension->is_hosted_app()) {
return FindHost(Profile::FromBrowserContext(browser->profile()), Host* host = FindOrCreateHost(
extension->id()); Profile::FromBrowserContext(browser->profile()), extension->id());
return host->GetViewsBridgeFactoryHost();
} }
return nullptr; return nullptr;
} }
...@@ -417,8 +431,10 @@ void ExtensionAppShimHandler::OnShimLaunch( ...@@ -417,8 +431,10 @@ void ExtensionAppShimHandler::OnShimLaunch(
AppShimLaunchType launch_type = bootstrap->GetLaunchType(); AppShimLaunchType launch_type = bootstrap->GetLaunchType();
DCHECK(crx_file::id_util::IdIsValid(app_id)); DCHECK(crx_file::id_util::IdIsValid(app_id));
const base::FilePath& profile_path = bootstrap->GetProfilePath(); const base::FilePath& relative_profile_path = bootstrap->GetProfilePath();
DCHECK(!profile_path.empty()); DCHECK(!relative_profile_path.empty());
base::FilePath profile_path =
delegate_->GetFullProfilePath(relative_profile_path);
if (!delegate_->ProfileExistsForPath(profile_path)) { if (!delegate_->ProfileExistsForPath(profile_path)) {
// User may have deleted the profile this shim was originally created for. // User may have deleted the profile this shim was originally created for.
...@@ -499,12 +515,11 @@ void ExtensionAppShimHandler::OnProfileLoaded( ...@@ -499,12 +515,11 @@ void ExtensionAppShimHandler::OnProfileLoaded(
AppShimLaunchType launch_type = bootstrap->GetLaunchType(); AppShimLaunchType launch_type = bootstrap->GetLaunchType();
const std::vector<base::FilePath>& files = bootstrap->GetLaunchFiles(); const std::vector<base::FilePath>& files = bootstrap->GetLaunchFiles();
// The first host to claim this (profile, app_id) becomes the main host. Host* host = FindOrCreateHost(profile, app_id);
// For any others, focus or relaunch the app. if (host->HasBootstrapConnected()) {
Host*& host = hosts_[make_pair(profile, app_id)]; // If another app shim process has already connected to this (profile,
if (!host) { // app_id) pair, then focus the windows for the existing process, and
host = delegate_->CreateHost(app_id, bootstrap->GetProfilePath()); // close the new process.
} else {
OnShimFocus(host, OnShimFocus(host,
launch_type == APP_SHIM_LAUNCH_NORMAL ? launch_type == APP_SHIM_LAUNCH_NORMAL ?
APP_SHIM_FOCUS_REOPEN : APP_SHIM_FOCUS_NORMAL, APP_SHIM_FOCUS_REOPEN : APP_SHIM_FOCUS_NORMAL,
...@@ -713,13 +728,15 @@ void ExtensionAppShimHandler::OnAppActivated(content::BrowserContext* context, ...@@ -713,13 +728,15 @@ void ExtensionAppShimHandler::OnAppActivated(content::BrowserContext* context,
Profile* profile = static_cast<Profile*>(context); Profile* profile = static_cast<Profile*>(context);
Host* host = FindHost(profile, app_id); Host* host = FindHost(profile, app_id);
if (host) { if (host && host->HasBootstrapConnected()) {
// If there is a connected app shim process, notify it of success and focus
// the app windows.
host->OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS); host->OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS);
OnShimFocus(host, APP_SHIM_FOCUS_NORMAL, std::vector<base::FilePath>()); OnShimFocus(host, APP_SHIM_FOCUS_NORMAL, std::vector<base::FilePath>());
return; } else {
} // Otherwise, launch an app shim.
delegate_->LaunchShim(profile, extension); delegate_->LaunchShim(profile, extension);
}
} }
void ExtensionAppShimHandler::OnAppDeactivated(content::BrowserContext* context, void ExtensionAppShimHandler::OnAppDeactivated(content::BrowserContext* context,
......
...@@ -26,16 +26,20 @@ class Profile; ...@@ -26,16 +26,20 @@ class Profile;
namespace base { namespace base {
class FilePath; class FilePath;
} } // namespace base
namespace content { namespace content {
class BrowserContext; class BrowserContext;
} } // namespace content
namespace extensions { namespace extensions {
class AppWindow; class AppWindow;
class Extension; class Extension;
} } // namespace extensions
namespace views {
class BridgeFactoryHost;
} // namespace views
namespace apps { namespace apps {
...@@ -50,6 +54,8 @@ class ExtensionAppShimHandler : public AppShimHandler, ...@@ -50,6 +54,8 @@ class ExtensionAppShimHandler : public AppShimHandler,
public: public:
virtual ~Delegate() {} virtual ~Delegate() {}
virtual base::FilePath GetFullProfilePath(
const base::FilePath& relative_path);
virtual bool ProfileExistsForPath(const base::FilePath& path); virtual bool ProfileExistsForPath(const base::FilePath& path);
virtual Profile* ProfileForPath(const base::FilePath& path); virtual Profile* ProfileForPath(const base::FilePath& path);
virtual void LoadProfileAsync(const base::FilePath& path, virtual void LoadProfileAsync(const base::FilePath& path,
...@@ -90,9 +96,15 @@ class ExtensionAppShimHandler : public AppShimHandler, ...@@ -90,9 +96,15 @@ class ExtensionAppShimHandler : public AppShimHandler,
virtual AppShimHandler::Host* FindHost(Profile* profile, virtual AppShimHandler::Host* FindHost(Profile* profile,
const std::string& app_id); const std::string& app_id);
// Get the host corresponding to a browser instance, or nullptr if none // Return the host corresponding to |profile| and |app_id|, or create one if
// exists. // needed.
AppShimHandler::Host* FindHostForBrowser(Browser* browser); AppShimHandler::Host* FindOrCreateHost(Profile* profile,
const std::string& app_id);
// Get the ViewBridgeFactoryHost, which may be used to create remote
// NSWindows, corresponding to a browser instance (or nullptr if none exists).
views::BridgeFactoryHost* GetViewsBridgeFactoryHostForBrowser(
Browser* browser);
void SetHostedAppHidden(Profile* profile, void SetHostedAppHidden(Profile* profile,
const std::string& app_id, const std::string& app_id,
......
...@@ -190,13 +190,10 @@ NativeWidgetMacNSWindow* BrowserFrameMac::CreateNSWindow( ...@@ -190,13 +190,10 @@ NativeWidgetMacNSWindow* BrowserFrameMac::CreateNSWindow(
views::BridgeFactoryHost* BrowserFrameMac::GetBridgeFactoryHost() { views::BridgeFactoryHost* BrowserFrameMac::GetBridgeFactoryHost() {
auto* shim_handler = apps::ExtensionAppShimHandler::Get(); auto* shim_handler = apps::ExtensionAppShimHandler::Get();
if (shim_handler) { if (!shim_handler)
apps::AppShimHandler::Host* host =
shim_handler->FindHostForBrowser(browser_view_->browser());
if (host)
return host->GetViewsBridgeFactoryHost();
}
return nullptr; return nullptr;
return shim_handler->GetViewsBridgeFactoryHostForBrowser(
browser_view_->browser());
} }
void BrowserFrameMac::OnWindowDestroying(gfx::NativeWindow native_window) { void BrowserFrameMac::OnWindowDestroying(gfx::NativeWindow native_window) {
......
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