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 {
// https://crbug.com/896917
class Host {
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|
// object owns the lifetime of the app shim process.
virtual void OnBootstrapConnected(
......
......@@ -71,6 +71,17 @@ void AppShimHost::ChannelError(uint32_t custom_reason,
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() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Note that we must call GetAppShimHandler here and not in the destructor
......@@ -88,6 +99,10 @@ apps::AppShimHandler* AppShimHost::GetAppShimHandler() const {
////////////////////////////////////////////////////////////////////////////////
// AppShimHost, chrome::mojom::AppShimHost
bool AppShimHost::HasBootstrapConnected() const {
return bootstrap_ != nullptr;
}
void AppShimHost::OnBootstrapConnected(
std::unique_ptr<AppShimHostBootstrap> bootstrap) {
DCHECK(!bootstrap_);
......@@ -97,6 +112,11 @@ void AppShimHost::OnBootstrapConnected(
host_binding_.Bind(bootstrap_->GetLaunchAppShimHostRequest());
host_binding_.set_connection_error_with_reason_handler(
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,
......@@ -126,12 +146,9 @@ void AppShimHost::QuitApp() {
void AppShimHost::OnAppLaunchComplete(apps::AppShimLaunchResult result) {
DCHECK(!has_sent_on_launch_complete_);
DCHECK(bootstrap_);
if (result == apps::APP_SHIM_LAUNCH_SUCCESS)
bootstrap_->OnLaunchAppSucceeded(std::move(app_shim_request_));
else
bootstrap_->OnLaunchAppFailed(result);
has_sent_on_launch_complete_ = true;
launch_result_.emplace(result);
if (bootstrap_)
SendLaunchResult();
}
void AppShimHost::OnAppClosed() {
......
......@@ -10,6 +10,7 @@
#include <vector>
#include "base/files/file_path.h"
#include "base/optional.h"
#include "base/threading/thread_checker.h"
#include "chrome/browser/apps/app_shim/app_shim_handler_mac.h"
#include "chrome/common/mac/app_shim.mojom.h"
......@@ -35,6 +36,7 @@ class AppShimHost : public chrome::mojom::AppShimHost,
AppShimHost(const std::string& app_id, const base::FilePath& profile_path);
// apps::AppShimHandler::Host overrides:
bool HasBootstrapConnected() const override;
void OnBootstrapConnected(
std::unique_ptr<AppShimHostBootstrap> bootstrap) override;
void OnAppLaunchComplete(apps::AppShimLaunchResult result) override;
......@@ -51,6 +53,7 @@ class AppShimHost : public chrome::mojom::AppShimHost,
// channel error and OnAppClosed).
~AppShimHost() override;
void ChannelError(uint32_t custom_reason, const std::string& description);
void SendLaunchResult();
// Closes the channel and destroys the AppShimHost.
void Close();
......@@ -75,6 +78,10 @@ class AppShimHost : public chrome::mojom::AppShimHost,
std::string app_id_;
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;
THREAD_CHECKER(thread_checker_);
......
......@@ -151,21 +151,25 @@ class EnableViaPrompt : public ExtensionEnableFlowDelegate {
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(
const base::FilePath& path) {
const base::FilePath& full_path) {
ProfileManager* profile_manager = g_browser_process->profile_manager();
// Check for the profile name in the profile info cache to ensure that we
// never access any directory that isn't a known profile.
base::FilePath full_path = profile_manager->user_data_dir().Append(path);
ProfileAttributesEntry* entry;
return profile_manager->GetProfileAttributesStorage().
GetProfileAttributesWithPath(full_path, &entry);
}
Profile* ExtensionAppShimHandler::Delegate::ProfileForPath(
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);
Profile* profile = profile_manager->GetProfileByPath(full_path);
// Use IsValidProfile to check if the profile has been created.
......@@ -173,17 +177,14 @@ Profile* ExtensionAppShimHandler::Delegate::ProfileForPath(
}
void ExtensionAppShimHandler::Delegate::LoadProfileAsync(
const base::FilePath& path,
const base::FilePath& full_path,
base::OnceCallback<void(Profile*)> callback) {
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));
}
bool ExtensionAppShimHandler::Delegate::IsProfileLockedForPath(
const base::FilePath& path) {
ProfileManager* profile_manager = g_browser_process->profile_manager();
base::FilePath full_path = profile_manager->user_data_dir().Append(path);
const base::FilePath& full_path) {
return profiles::IsProfileLocked(full_path);
}
......@@ -277,13 +278,26 @@ AppShimHandler::Host* ExtensionAppShimHandler::FindHost(
return it == hosts_.end() ? NULL : it->second;
}
AppShimHandler::Host* ExtensionAppShimHandler::FindHostForBrowser(
Browser* browser) {
AppShimHandler::Host* ExtensionAppShimHandler::FindOrCreateHost(
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 =
apps::ExtensionAppShimHandler::MaybeGetAppForBrowser(browser);
if (extension) {
return FindHost(Profile::FromBrowserContext(browser->profile()),
extension->id());
if (extension && extension->is_hosted_app()) {
Host* host = FindOrCreateHost(
Profile::FromBrowserContext(browser->profile()), extension->id());
return host->GetViewsBridgeFactoryHost();
}
return nullptr;
}
......@@ -417,8 +431,10 @@ void ExtensionAppShimHandler::OnShimLaunch(
AppShimLaunchType launch_type = bootstrap->GetLaunchType();
DCHECK(crx_file::id_util::IdIsValid(app_id));
const base::FilePath& profile_path = bootstrap->GetProfilePath();
DCHECK(!profile_path.empty());
const base::FilePath& relative_profile_path = bootstrap->GetProfilePath();
DCHECK(!relative_profile_path.empty());
base::FilePath profile_path =
delegate_->GetFullProfilePath(relative_profile_path);
if (!delegate_->ProfileExistsForPath(profile_path)) {
// User may have deleted the profile this shim was originally created for.
......@@ -499,12 +515,11 @@ void ExtensionAppShimHandler::OnProfileLoaded(
AppShimLaunchType launch_type = bootstrap->GetLaunchType();
const std::vector<base::FilePath>& files = bootstrap->GetLaunchFiles();
// The first host to claim this (profile, app_id) becomes the main host.
// For any others, focus or relaunch the app.
Host*& host = hosts_[make_pair(profile, app_id)];
if (!host) {
host = delegate_->CreateHost(app_id, bootstrap->GetProfilePath());
} else {
Host* host = FindOrCreateHost(profile, app_id);
if (host->HasBootstrapConnected()) {
// If another app shim process has already connected to this (profile,
// app_id) pair, then focus the windows for the existing process, and
// close the new process.
OnShimFocus(host,
launch_type == APP_SHIM_LAUNCH_NORMAL ?
APP_SHIM_FOCUS_REOPEN : APP_SHIM_FOCUS_NORMAL,
......@@ -713,13 +728,15 @@ void ExtensionAppShimHandler::OnAppActivated(content::BrowserContext* context,
Profile* profile = static_cast<Profile*>(context);
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);
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,
......
......@@ -26,16 +26,20 @@ class Profile;
namespace base {
class FilePath;
}
} // namespace base
namespace content {
class BrowserContext;
}
} // namespace content
namespace extensions {
class AppWindow;
class Extension;
}
} // namespace extensions
namespace views {
class BridgeFactoryHost;
} // namespace views
namespace apps {
......@@ -50,6 +54,8 @@ class ExtensionAppShimHandler : public AppShimHandler,
public:
virtual ~Delegate() {}
virtual base::FilePath GetFullProfilePath(
const base::FilePath& relative_path);
virtual bool ProfileExistsForPath(const base::FilePath& path);
virtual Profile* ProfileForPath(const base::FilePath& path);
virtual void LoadProfileAsync(const base::FilePath& path,
......@@ -90,9 +96,15 @@ class ExtensionAppShimHandler : public AppShimHandler,
virtual AppShimHandler::Host* FindHost(Profile* profile,
const std::string& app_id);
// Get the host corresponding to a browser instance, or nullptr if none
// exists.
AppShimHandler::Host* FindHostForBrowser(Browser* browser);
// Return the host corresponding to |profile| and |app_id|, or create one if
// needed.
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,
const std::string& app_id,
......
......@@ -36,6 +36,9 @@ class MockDelegate : public ExtensionAppShimHandler::Delegate {
public:
virtual ~MockDelegate() {}
base::FilePath GetFullProfilePath(const base::FilePath& relative_path) {
return relative_path;
}
MOCK_METHOD1(ProfileExistsForPath, bool(const base::FilePath&));
MOCK_METHOD1(ProfileForPath, Profile*(const base::FilePath&));
void LoadProfileAsync(const base::FilePath& path,
......@@ -66,6 +69,7 @@ class MockDelegate : public ExtensionAppShimHandler::Delegate {
AppShimHandler::Host* CreateHost(
const std::string& app_id,
const base::FilePath& profile_path) override {
DCHECK(host_for_create_);
auto* result = host_for_create_;
host_for_create_ = nullptr;
return result;
......@@ -124,13 +128,47 @@ class TestingExtensionAppShimHandler : public ExtensionAppShimHandler {
class TestingAppShimHostBootstrap : public AppShimHostBootstrap {
public:
TestingAppShimHostBootstrap(apps::AppShimHandler* handler)
: handler_(handler) {}
using AppShimHostBootstrap::LaunchApp;
TestingAppShimHostBootstrap(
const base::FilePath& profile_path,
const std::string& app_id,
base::Optional<apps::AppShimLaunchResult>* launch_result,
apps::AppShimHandler* handler)
: profile_path_(profile_path),
app_id_(app_id),
launch_result_(launch_result),
handler_(handler),
weak_factory_(this) {}
apps::AppShimHandler* GetHandler() override { return handler_; }
void DoTestLaunch(apps::AppShimLaunchType launch_type,
const std::vector<base::FilePath>& files) {
chrome::mojom::AppShimHostPtr host_ptr;
LaunchApp(mojo::MakeRequest(&host_ptr), profile_path_, app_id_, launch_type,
files,
base::BindOnce(&TestingAppShimHostBootstrap::DoTestLaunchDone,
launch_result_));
}
static void DoTestLaunchDone(
base::Optional<apps::AppShimLaunchResult>* launch_result,
apps::AppShimLaunchResult result,
chrome::mojom::AppShimRequest app_shim_request) {
if (launch_result)
launch_result->emplace(result);
}
base::WeakPtr<TestingAppShimHostBootstrap> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
private:
base::FilePath profile_path_;
std::string app_id_;
// Note that |launch_result_| is optional so that we can track whether or not
// the callback to set it has arrived.
base::Optional<apps::AppShimLaunchResult>* launch_result_;
apps::AppShimHandler* const handler_;
base::WeakPtrFactory<TestingAppShimHostBootstrap> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(TestingAppShimHostBootstrap);
};
......@@ -141,30 +179,30 @@ class TestHost : public AppShimHost {
public:
TestHost(const base::FilePath& profile_path,
const std::string& app_id,
base::Optional<apps::AppShimLaunchResult>* launch_result,
TestingExtensionAppShimHandler* handler)
: AppShimHost(app_id, profile_path),
launch_result_(launch_result),
handler_(handler),
weak_factory_(this) {}
// Override the GetAppShimHandler for testing.
apps::AppShimHandler* GetAppShimHandler() const override { return handler_; }
void SetLaunchResult(apps::AppShimLaunchResult result) {
launch_result_->emplace(result);
// Save the result of OnAppLaunchComplete for testing.
void OnAppLaunchComplete(apps::AppShimLaunchResult result) override {
app_launch_result.emplace(result);
AppShimHost::OnAppLaunchComplete(result);
}
apps::AppShimLaunchResult GetLaunchResult() {
DCHECK(*launch_result_);
return *(*launch_result_);
base::Optional<apps::AppShimLaunchResult> app_launch_result;
apps::AppShimLaunchResult GetAppLaunchResult() {
DCHECK(app_launch_result);
return *app_launch_result;
}
base::WeakPtr<TestHost> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
private:
~TestHost() override {}
// Note that |launch_result_| is optional so that we can track whether or not
// the callback to set it has arrived.
base::Optional<apps::AppShimLaunchResult>* launch_result_;
TestingExtensionAppShimHandler* handler_;
base::WeakPtrFactory<TestHost> weak_factory_;
......@@ -178,18 +216,32 @@ class ExtensionAppShimHandlerTest : public testing::Test {
handler_(new TestingExtensionAppShimHandler(delegate_)),
profile_path_a_("Profile A"),
profile_path_b_("Profile B") {
host_aa_ = (new TestHost(profile_path_a_, kTestAppIdA,
&host_aa_launch_result_, handler_.get()))
bootstrap_aa_ =
(new TestingAppShimHostBootstrap(profile_path_a_, kTestAppIdA,
&bootstrap_aa_result_, handler_.get()))
->GetWeakPtr();
bootstrap_ab_ =
(new TestingAppShimHostBootstrap(profile_path_a_, kTestAppIdB,
&bootstrap_ab_result_, handler_.get()))
->GetWeakPtr();
bootstrap_bb_ =
(new TestingAppShimHostBootstrap(profile_path_b_, kTestAppIdB,
&bootstrap_bb_result_, handler_.get()))
->GetWeakPtr();
bootstrap_aa_duplicate_ =
(new TestingAppShimHostBootstrap(profile_path_a_, kTestAppIdA,
&bootstrap_aa_duplicate_result_,
handler_.get()))
->GetWeakPtr();
host_aa_ = (new TestHost(profile_path_a_, kTestAppIdA, handler_.get()))
->GetWeakPtr();
host_ab_ = (new TestHost(profile_path_a_, kTestAppIdB,
&host_ab_launch_result_, handler_.get()))
host_ab_ = (new TestHost(profile_path_a_, kTestAppIdB, handler_.get()))
->GetWeakPtr();
host_bb_ = (new TestHost(profile_path_b_, kTestAppIdB,
&host_bb_launch_result_, handler_.get()))
host_bb_ = (new TestHost(profile_path_b_, kTestAppIdB, handler_.get()))
->GetWeakPtr();
host_aa_duplicate_ =
(new TestHost(profile_path_a_, kTestAppIdA,
&host_aa_duplicate_launch_result_, handler_.get()))
(new TestHost(profile_path_a_, kTestAppIdA, handler_.get()))
->GetWeakPtr();
base::FilePath extension_path("/fake/path");
......@@ -241,43 +293,43 @@ class ExtensionAppShimHandlerTest : public testing::Test {
host_bb_->OnAppClosed();
if (host_aa_duplicate_)
host_aa_duplicate_->OnAppClosed();
delete bootstrap_aa_.get();
delete bootstrap_ab_.get();
delete bootstrap_bb_.get();
delete bootstrap_aa_duplicate_.get();
}
void DoShimLaunch(TestHost* host,
void DoShimLaunch(base::WeakPtr<TestingAppShimHostBootstrap> bootstrap,
base::WeakPtr<TestHost> host,
apps::AppShimLaunchType launch_type,
const std::vector<base::FilePath>& files) {
delegate_->SetHostForCreate(host);
chrome::mojom::AppShimHostPtr host_ptr;
(new TestingAppShimHostBootstrap(handler_.get()))
->LaunchApp(
mojo::MakeRequest(&host_ptr), host->GetProfilePath(),
host->GetAppId(), launch_type, files,
base::BindOnce(&ExtensionAppShimHandlerTest::DoShimLaunchDone,
base::Unretained(this), host));
if (host)
delegate_->SetHostForCreate(host.get());
bootstrap->DoTestLaunch(launch_type, files);
}
void DoShimLaunchDone(TestHost* host,
apps::AppShimLaunchResult result,
chrome::mojom::AppShimRequest app_shim_request) {
host->SetLaunchResult(result);
}
void NormalLaunch(TestHost* host) {
DoShimLaunch(host, APP_SHIM_LAUNCH_NORMAL, std::vector<base::FilePath>());
void NormalLaunch(base::WeakPtr<TestingAppShimHostBootstrap> bootstrap,
base::WeakPtr<TestHost> host) {
DoShimLaunch(bootstrap, host, APP_SHIM_LAUNCH_NORMAL,
std::vector<base::FilePath>());
}
void RegisterOnlyLaunch(TestHost* host) {
DoShimLaunch(host, APP_SHIM_LAUNCH_REGISTER_ONLY,
void RegisterOnlyLaunch(base::WeakPtr<TestingAppShimHostBootstrap> bootstrap,
base::WeakPtr<TestHost> host) {
DoShimLaunch(bootstrap, host, APP_SHIM_LAUNCH_REGISTER_ONLY,
std::vector<base::FilePath>());
}
// Completely launch a shim host and leave it running.
void LaunchAndActivate(TestHost* host, Profile* profile) {
NormalLaunch(host);
EXPECT_EQ(host, handler_->FindHost(profile, host->GetAppId()));
EXPECT_CALL(*handler_, OnShimFocus(host, APP_SHIM_FOCUS_NORMAL, _));
void LaunchAndActivate(base::WeakPtr<TestingAppShimHostBootstrap> bootstrap,
base::WeakPtr<TestHost> host,
Profile* profile) {
NormalLaunch(bootstrap, host);
EXPECT_EQ(host.get(), handler_->FindHost(profile, host->GetAppId()));
EXPECT_CALL(*handler_, OnShimFocus(host.get(), APP_SHIM_FOCUS_NORMAL, _));
handler_->OnAppActivated(profile, host->GetAppId());
EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, host->GetLaunchResult());
EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, host->GetAppLaunchResult());
}
// Simulates a focus request coming from a running app shim.
......@@ -302,14 +354,22 @@ class ExtensionAppShimHandlerTest : public testing::Test {
base::FilePath profile_path_b_;
TestingProfile profile_a_;
TestingProfile profile_b_;
base::Optional<apps::AppShimLaunchResult> host_aa_launch_result_;
base::Optional<apps::AppShimLaunchResult> host_ab_launch_result_;
base::Optional<apps::AppShimLaunchResult> host_bb_launch_result_;
base::Optional<apps::AppShimLaunchResult> host_aa_duplicate_launch_result_;
base::WeakPtr<TestingAppShimHostBootstrap> bootstrap_aa_;
base::WeakPtr<TestingAppShimHostBootstrap> bootstrap_ab_;
base::WeakPtr<TestingAppShimHostBootstrap> bootstrap_bb_;
base::WeakPtr<TestingAppShimHostBootstrap> bootstrap_aa_duplicate_;
base::Optional<apps::AppShimLaunchResult> bootstrap_aa_result_;
base::Optional<apps::AppShimLaunchResult> bootstrap_ab_result_;
base::Optional<apps::AppShimLaunchResult> bootstrap_bb_result_;
base::Optional<apps::AppShimLaunchResult> bootstrap_aa_duplicate_result_;
base::WeakPtr<TestHost> host_aa_;
base::WeakPtr<TestHost> host_ab_;
base::WeakPtr<TestHost> host_bb_;
base::WeakPtr<TestHost> host_aa_duplicate_;
scoped_refptr<const Extension> extension_a_;
scoped_refptr<const Extension> extension_b_;
......@@ -322,8 +382,8 @@ TEST_F(ExtensionAppShimHandlerTest, LaunchProfileNotFound) {
EXPECT_CALL(*delegate_, ProfileExistsForPath(profile_path_a_))
.WillOnce(Return(false))
.WillRepeatedly(Return(true));
NormalLaunch(host_aa_.get());
EXPECT_EQ(APP_SHIM_LAUNCH_PROFILE_NOT_FOUND, *host_aa_launch_result_);
NormalLaunch(bootstrap_aa_, nullptr);
EXPECT_EQ(APP_SHIM_LAUNCH_PROFILE_NOT_FOUND, *bootstrap_aa_result_);
}
TEST_F(ExtensionAppShimHandlerTest, LaunchProfileIsLocked) {
......@@ -331,8 +391,8 @@ TEST_F(ExtensionAppShimHandlerTest, LaunchProfileIsLocked) {
EXPECT_CALL(*delegate_, IsProfileLockedForPath(profile_path_a_))
.WillOnce(Return(true));
EXPECT_CALL(*delegate_, LaunchUserManager());
NormalLaunch(host_aa_.get());
EXPECT_EQ(APP_SHIM_LAUNCH_PROFILE_LOCKED, *host_aa_launch_result_);
NormalLaunch(bootstrap_aa_, nullptr);
EXPECT_EQ(APP_SHIM_LAUNCH_PROFILE_LOCKED, *bootstrap_aa_result_);
}
TEST_F(ExtensionAppShimHandlerTest, LaunchAppNotFound) {
......@@ -341,8 +401,8 @@ TEST_F(ExtensionAppShimHandlerTest, LaunchAppNotFound) {
.WillRepeatedly(Return(static_cast<const Extension*>(NULL)));
EXPECT_CALL(*delegate_, EnableExtension(&profile_a_, kTestAppIdA, _))
.WillOnce(WithArgs<2>(Invoke(delegate_, &MockDelegate::RunCallback)));
NormalLaunch(host_aa_.get());
EXPECT_EQ(APP_SHIM_LAUNCH_APP_NOT_FOUND, *host_aa_launch_result_);
NormalLaunch(bootstrap_aa_, host_aa_);
EXPECT_EQ(APP_SHIM_LAUNCH_APP_NOT_FOUND, *bootstrap_aa_result_);
}
TEST_F(ExtensionAppShimHandlerTest, LaunchAppNotEnabled) {
......@@ -352,36 +412,37 @@ TEST_F(ExtensionAppShimHandlerTest, LaunchAppNotEnabled) {
.WillRepeatedly(Return(extension_a_.get()));
EXPECT_CALL(*delegate_, EnableExtension(&profile_a_, kTestAppIdA, _))
.WillOnce(WithArgs<2>(Invoke(delegate_, &MockDelegate::RunCallback)));
NormalLaunch(host_aa_.get());
NormalLaunch(bootstrap_aa_, host_aa_);
}
TEST_F(ExtensionAppShimHandlerTest, LaunchAndCloseShim) {
// Normal startup.
NormalLaunch(host_aa_.get());
NormalLaunch(bootstrap_aa_, host_aa_);
EXPECT_EQ(host_aa_.get(), handler_->FindHost(&profile_a_, kTestAppIdA));
NormalLaunch(host_ab_.get());
NormalLaunch(bootstrap_ab_, host_ab_);
EXPECT_EQ(host_ab_.get(), handler_->FindHost(&profile_a_, kTestAppIdB));
std::vector<base::FilePath> some_file(1, base::FilePath("some_file"));
EXPECT_CALL(*delegate_,
LaunchApp(&profile_b_, extension_b_.get(), some_file));
DoShimLaunch(host_bb_.get(), APP_SHIM_LAUNCH_NORMAL, some_file);
DoShimLaunch(bootstrap_bb_, host_bb_, APP_SHIM_LAUNCH_NORMAL, some_file);
EXPECT_EQ(host_bb_.get(), handler_->FindHost(&profile_b_, kTestAppIdB));
// Activation when there is a registered shim finishes launch with success and
// focuses the app.
EXPECT_CALL(*handler_, OnShimFocus(host_aa_.get(), APP_SHIM_FOCUS_NORMAL, _));
handler_->OnAppActivated(&profile_a_, kTestAppIdA);
EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, *host_aa_launch_result_);
EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, *bootstrap_aa_result_);
// Starting and closing a second host just focuses the original host of the
// app.
EXPECT_CALL(*handler_,
OnShimFocus(host_aa_.get(), APP_SHIM_FOCUS_REOPEN, some_file));
DoShimLaunch(host_aa_duplicate_.get(), APP_SHIM_LAUNCH_NORMAL, some_file);
EXPECT_EQ(APP_SHIM_LAUNCH_DUPLICATE_HOST, *host_aa_duplicate_launch_result_);
DoShimLaunch(bootstrap_aa_duplicate_, host_aa_duplicate_,
APP_SHIM_LAUNCH_NORMAL, some_file);
EXPECT_EQ(APP_SHIM_LAUNCH_DUPLICATE_HOST, *bootstrap_aa_duplicate_result_);
EXPECT_EQ(host_aa_.get(), handler_->FindHost(&profile_a_, kTestAppIdA));
handler_->OnShimClose(host_aa_duplicate_.get());
......@@ -406,8 +467,8 @@ TEST_F(ExtensionAppShimHandlerTest, AppLifetime) {
EXPECT_CALL(*delegate_,
LaunchApp(&profile_a_, extension_a_.get(), _))
.Times(0);
RegisterOnlyLaunch(host_aa_.get());
EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, *host_aa_launch_result_);
RegisterOnlyLaunch(bootstrap_aa_, host_aa_);
EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, *bootstrap_aa_result_);
EXPECT_EQ(host_aa_.get(), handler_->FindHost(&profile_a_, kTestAppIdA));
// Return no app windows for OnShimFocus and OnShimQuit.
......@@ -446,12 +507,12 @@ TEST_F(ExtensionAppShimHandlerTest, AppLifetime) {
TEST_F(ExtensionAppShimHandlerTest, MaybeTerminate) {
// Launch shims, adding entries in the map.
RegisterOnlyLaunch(host_aa_.get());
EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, *host_aa_launch_result_);
RegisterOnlyLaunch(bootstrap_aa_, host_aa_);
EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, *bootstrap_aa_result_);
EXPECT_EQ(host_aa_.get(), handler_->FindHost(&profile_a_, kTestAppIdA));
RegisterOnlyLaunch(host_ab_.get());
EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, *host_ab_launch_result_);
RegisterOnlyLaunch(bootstrap_ab_, host_ab_);
EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, *bootstrap_ab_result_);
EXPECT_EQ(host_ab_.get(), handler_->FindHost(&profile_a_, kTestAppIdB));
// Return empty window list.
......@@ -473,8 +534,8 @@ TEST_F(ExtensionAppShimHandlerTest, RegisterOnly) {
// For an APP_SHIM_LAUNCH_REGISTER_ONLY, don't launch the app.
EXPECT_CALL(*delegate_, LaunchApp(_, _, _))
.Times(0);
RegisterOnlyLaunch(host_aa_.get());
EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, *host_aa_launch_result_);
RegisterOnlyLaunch(bootstrap_aa_, host_aa_);
EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, *bootstrap_aa_result_);
EXPECT_TRUE(handler_->FindHost(&profile_a_, kTestAppIdA));
// Close the shim, removing the entry in the map.
......@@ -489,7 +550,7 @@ TEST_F(ExtensionAppShimHandlerTest, LoadProfile) {
EXPECT_CALL(*delegate_, ProfileForPath(profile_path_a_))
.WillOnce(Return(static_cast<Profile*>(NULL)))
.WillRepeatedly(Return(&profile_a_));
NormalLaunch(host_aa_.get());
NormalLaunch(bootstrap_aa_, host_aa_);
EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
delegate_->RunLoadProfileCallback(profile_path_a_, &profile_a_);
EXPECT_TRUE(handler_->FindHost(&profile_a_, kTestAppIdA));
......@@ -498,7 +559,7 @@ TEST_F(ExtensionAppShimHandlerTest, LoadProfile) {
// Tests that calls to OnShimFocus, OnShimHide correctly handle a null extension
// being provided by the extension system.
TEST_F(ExtensionAppShimHandlerTest, ExtensionUninstalled) {
LaunchAndActivate(host_aa_.get(), &profile_a_);
LaunchAndActivate(bootstrap_aa_, host_aa_, &profile_a_);
// Have GetWindows() return an empty window list for focus (otherwise, it
// will contain a single nullptr, which can't be focused). Expect 1 call only.
......@@ -518,7 +579,7 @@ TEST_F(ExtensionAppShimHandlerTest, ExtensionUninstalled) {
EXPECT_EQ(nullptr, host_aa_.get());
// Do the same for SetHidden on host_bb.
LaunchAndActivate(host_bb_.get(), &profile_b_);
LaunchAndActivate(bootstrap_bb_, host_bb_, &profile_b_);
ShimSetHidden(host_bb_.get(), true);
EXPECT_NE(nullptr, host_bb_.get());
......@@ -528,4 +589,34 @@ TEST_F(ExtensionAppShimHandlerTest, ExtensionUninstalled) {
EXPECT_EQ(nullptr, host_bb_.get());
}
TEST_F(ExtensionAppShimHandlerTest, PreExistingHost) {
// Create a host for our profile.
delegate_->SetHostForCreate(host_aa_.get());
EXPECT_EQ(nullptr, handler_->FindHost(&profile_a_, kTestAppIdA));
EXPECT_EQ(host_aa_.get(),
handler_->FindOrCreateHost(&profile_a_, kTestAppIdA));
EXPECT_FALSE(bool(host_aa_->app_launch_result));
// Launch the app for this host. It should find the pre-existing host, and the
// pre-existing host's launch result should be set.
EXPECT_CALL(*handler_, OnShimFocus(host_aa_.get(), APP_SHIM_FOCUS_NORMAL, _))
.Times(1);
EXPECT_CALL(*delegate_, LaunchApp(&profile_a_, extension_a_.get(), _))
.Times(0);
EXPECT_FALSE(bool(host_aa_->app_launch_result));
DoShimLaunch(bootstrap_aa_, nullptr, APP_SHIM_LAUNCH_REGISTER_ONLY,
std::vector<base::FilePath>());
EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, host_aa_->app_launch_result);
EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, *bootstrap_aa_result_);
EXPECT_EQ(host_aa_.get(), handler_->FindHost(&profile_a_, kTestAppIdA));
// Try to launch the app again. It should fail to launch, and the previous
// profile should remain.
DoShimLaunch(bootstrap_aa_duplicate_, nullptr, APP_SHIM_LAUNCH_REGISTER_ONLY,
std::vector<base::FilePath>());
EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, host_aa_->app_launch_result);
EXPECT_EQ(APP_SHIM_LAUNCH_DUPLICATE_HOST, *bootstrap_aa_duplicate_result_);
EXPECT_EQ(host_aa_.get(), handler_->FindHost(&profile_a_, kTestAppIdA));
}
} // namespace apps
......@@ -190,13 +190,10 @@ NativeWidgetMacNSWindow* BrowserFrameMac::CreateNSWindow(
views::BridgeFactoryHost* BrowserFrameMac::GetBridgeFactoryHost() {
auto* shim_handler = apps::ExtensionAppShimHandler::Get();
if (shim_handler) {
apps::AppShimHandler::Host* host =
shim_handler->FindHostForBrowser(browser_view_->browser());
if (host)
return host->GetViewsBridgeFactoryHost();
}
return nullptr;
if (!shim_handler)
return nullptr;
return shim_handler->GetViewsBridgeFactoryHostForBrowser(
browser_view_->browser());
}
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