Commit 9c7b3096 authored by tmdiep@chromium.org's avatar tmdiep@chromium.org

Update the EphemeralAppLauncher for use by the webstorePrivate API

- The WebstoreStandaloneInstaller now supports error codes to allow
translation to API error codes.
- The EphemeralAppLauncher now also returns error codes and performs
more checks before installing an ephemeral app or enabling an
installed app.
- Introduces the ExtensionInstallChecker, which checks blacklist
state, requirement errors and management policies for a given
extension.

BUG=380980
TEST=browser_tests (EphemeralAppLauncherTest.*)
unit_tests (ExtensionInstallCheckerTest.*)

Review URL: https://codereview.chromium.org/339103002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278890 0039d316-1c4b-4281-b951-d872f2087c98
parent 6964f564
...@@ -6,8 +6,10 @@ ...@@ -6,8 +6,10 @@
#define CHROME_BROWSER_APPS_EPHEMERAL_APP_LAUNCHER_H_ #define CHROME_BROWSER_APPS_EPHEMERAL_APP_LAUNCHER_H_
#include <string> #include <string>
#include <vector>
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/callback.h"
#include "base/scoped_observer.h" #include "base/scoped_observer.h"
#include "chrome/browser/extensions/webstore_standalone_installer.h" #include "chrome/browser/extensions/webstore_standalone_installer.h"
#include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h" #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
...@@ -22,6 +24,7 @@ class WebContents; ...@@ -22,6 +24,7 @@ class WebContents;
namespace extensions { namespace extensions {
class Extension; class Extension;
class ExtensionInstallChecker;
class ExtensionRegistry; class ExtensionRegistry;
} }
...@@ -32,38 +35,74 @@ class EphemeralAppLauncher : public extensions::WebstoreStandaloneInstaller, ...@@ -32,38 +35,74 @@ class EphemeralAppLauncher : public extensions::WebstoreStandaloneInstaller,
public content::WebContentsObserver, public content::WebContentsObserver,
public ExtensionEnableFlowDelegate { public ExtensionEnableFlowDelegate {
public: public:
typedef WebstoreStandaloneInstaller::Callback Callback; typedef base::Callback<void(extensions::webstore_install::Result result,
const std::string& error)> LaunchCallback;
// Returns true if launching ephemeral apps is enabled.
static bool IsFeatureEnabled();
// Create for the app launcher. // Create for the app launcher.
static scoped_refptr<EphemeralAppLauncher> CreateForLauncher( static scoped_refptr<EphemeralAppLauncher> CreateForLauncher(
const std::string& webstore_item_id, const std::string& webstore_item_id,
Profile* profile, Profile* profile,
gfx::NativeWindow parent_window, gfx::NativeWindow parent_window,
const Callback& callback); const LaunchCallback& callback);
// Create for a link within a browser tab. // Create for a web contents.
static scoped_refptr<EphemeralAppLauncher> CreateForLink( static scoped_refptr<EphemeralAppLauncher> CreateForWebContents(
const std::string& webstore_item_id, const std::string& webstore_item_id,
content::WebContents* web_contents); content::WebContents* web_contents,
const LaunchCallback& callback);
// Initiate app launch. // Initiate app launch.
void Start(); void Start();
private: protected:
friend class base::RefCountedThreadSafe<EphemeralAppLauncher>;
EphemeralAppLauncher(const std::string& webstore_item_id, EphemeralAppLauncher(const std::string& webstore_item_id,
Profile* profile, Profile* profile,
gfx::NativeWindow parent_window, gfx::NativeWindow parent_window,
const Callback& callback); const LaunchCallback& callback);
EphemeralAppLauncher(const std::string& webstore_item_id, EphemeralAppLauncher(const std::string& webstore_item_id,
content::WebContents* web_contents, content::WebContents* web_contents,
const Callback& callback); const LaunchCallback& callback);
virtual ~EphemeralAppLauncher(); virtual ~EphemeralAppLauncher();
// Returns true if an app that is already installed in extension system can
// be launched.
bool CanLaunchInstalledApp(const extensions::Extension* extension,
extensions::webstore_install::Result* reason,
std::string* error);
// Initiates the enable flow for an app before it can be launched.
void EnableInstalledApp(const extensions::Extension* extension);
// After the ephemeral installation or enable flow are complete, attempts to
// launch the app and notify the client of the outcome.
void MaybeLaunchApp();
// Launches an app. At this point, it is assumed that the app is enabled and
// can be launched.
void LaunchApp(const extensions::Extension* extension) const; void LaunchApp(const extensions::Extension* extension) const;
// Notifies the client of the launch outcome.
void InvokeCallback(extensions::webstore_install::Result result,
const std::string& error);
// Aborts the ephemeral install and notifies the client of the outcome.
void AbortLaunch(extensions::webstore_install::Result result,
const std::string& error);
// Creates an install checker. Allows tests to mock the install checker.
virtual scoped_ptr<extensions::ExtensionInstallChecker>
CreateInstallChecker();
// Determines whether the app can be installed ephemerally.
void CheckEphemeralInstallPermitted();
// Install checker callback.
void OnInstallChecked(int check_failures);
// WebstoreStandaloneInstaller implementation. // WebstoreStandaloneInstaller implementation.
virtual bool CheckRequestorAlive() const OVERRIDE; virtual bool CheckRequestorAlive() const OVERRIDE;
virtual const GURL& GetRequestorURL() const OVERRIDE; virtual const GURL& GetRequestorURL() const OVERRIDE;
...@@ -78,13 +117,12 @@ class EphemeralAppLauncher : public extensions::WebstoreStandaloneInstaller, ...@@ -78,13 +117,12 @@ class EphemeralAppLauncher : public extensions::WebstoreStandaloneInstaller,
virtual bool CheckRequestorPermitted( virtual bool CheckRequestorPermitted(
const base::DictionaryValue& webstore_data, const base::DictionaryValue& webstore_data,
std::string* error) const OVERRIDE; std::string* error) const OVERRIDE;
virtual bool CheckInstallValid( virtual void OnManifestParsed() OVERRIDE;
const base::DictionaryValue& manifest,
std::string* error) OVERRIDE;
virtual scoped_ptr<ExtensionInstallPrompt> CreateInstallUI() OVERRIDE; virtual scoped_ptr<ExtensionInstallPrompt> CreateInstallUI() OVERRIDE;
virtual scoped_ptr<extensions::WebstoreInstaller::Approval> virtual scoped_ptr<extensions::WebstoreInstaller::Approval>
CreateApproval() const OVERRIDE; CreateApproval() const OVERRIDE;
virtual void CompleteInstall(const std::string& error) OVERRIDE; virtual void CompleteInstall(extensions::webstore_install::Result result,
const std::string& error) OVERRIDE;
// content::WebContentsObserver implementation. // content::WebContentsObserver implementation.
virtual void WebContentsDestroyed() OVERRIDE; virtual void WebContentsDestroyed() OVERRIDE;
...@@ -93,14 +131,19 @@ class EphemeralAppLauncher : public extensions::WebstoreStandaloneInstaller, ...@@ -93,14 +131,19 @@ class EphemeralAppLauncher : public extensions::WebstoreStandaloneInstaller,
virtual void ExtensionEnableFlowFinished() OVERRIDE; virtual void ExtensionEnableFlowFinished() OVERRIDE;
virtual void ExtensionEnableFlowAborted(bool user_initiated) OVERRIDE; virtual void ExtensionEnableFlowAborted(bool user_initiated) OVERRIDE;
private:
friend class base::RefCountedThreadSafe<EphemeralAppLauncher>;
friend class EphemeralAppLauncherTest;
LaunchCallback launch_callback_;
gfx::NativeWindow parent_window_; gfx::NativeWindow parent_window_;
scoped_ptr<content::WebContents> dummy_web_contents_; scoped_ptr<content::WebContents> dummy_web_contents_;
// Created in CheckInstallValid().
scoped_refptr<extensions::Extension> extension_;
scoped_ptr<ExtensionEnableFlow> extension_enable_flow_; scoped_ptr<ExtensionEnableFlow> extension_enable_flow_;
scoped_ptr<extensions::ExtensionInstallChecker> install_checker_;
DISALLOW_COPY_AND_ASSIGN(EphemeralAppLauncher); DISALLOW_COPY_AND_ASSIGN(EphemeralAppLauncher);
}; };
......
This diff is collapsed.
...@@ -52,7 +52,8 @@ bool LaunchEphemeralApp( ...@@ -52,7 +52,8 @@ bool LaunchEphemeralApp(
// The EphemeralAppLauncher will handle launching of an existing app or // The EphemeralAppLauncher will handle launching of an existing app or
// installing and launching a new ephemeral app. // installing and launching a new ephemeral app.
scoped_refptr<EphemeralAppLauncher> installer = scoped_refptr<EphemeralAppLauncher> installer =
EphemeralAppLauncher::CreateForLink(app_id, source); EphemeralAppLauncher::CreateForWebContents(
app_id, source, EphemeralAppLauncher::LaunchCallback());
installer->Start(); installer->Start();
return true; return true;
} }
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/extension_install_checker.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/blacklist.h"
#include "chrome/browser/extensions/requirements_checker.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/management_policy.h"
namespace extensions {
ExtensionInstallChecker::ExtensionInstallChecker(Profile* profile)
: profile_(profile),
blacklist_state_(NOT_BLACKLISTED),
policy_allows_load_(true),
current_sequence_number_(0),
running_checks_(0),
fail_fast_(false),
weak_ptr_factory_(this) {
}
ExtensionInstallChecker::~ExtensionInstallChecker() {
}
void ExtensionInstallChecker::Start(int enabled_checks,
bool fail_fast,
const Callback& callback) {
// Profile is null in tests.
if (profile_) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!extension_.get()) {
NOTREACHED();
return;
}
}
if (is_running() || !enabled_checks || callback.is_null()) {
NOTREACHED();
return;
}
running_checks_ = enabled_checks;
fail_fast_ = fail_fast;
callback_ = callback;
ResetResults();
// Execute the management policy check first as it is synchronous.
if (enabled_checks & CHECK_MANAGEMENT_POLICY) {
CheckManagementPolicy();
if (!is_running())
return;
}
if (enabled_checks & CHECK_REQUIREMENTS) {
CheckRequirements();
if (!is_running())
return;
}
if (enabled_checks & CHECK_BLACKLIST)
CheckBlacklistState();
}
void ExtensionInstallChecker::CheckManagementPolicy() {
DCHECK(extension_.get());
base::string16 error;
bool allow = ExtensionSystem::Get(profile_)->management_policy()->UserMayLoad(
extension_.get(), &error);
OnManagementPolicyCheckDone(allow, base::UTF16ToUTF8(error));
}
void ExtensionInstallChecker::OnManagementPolicyCheckDone(
bool allows_load,
const std::string& error) {
policy_allows_load_ = allows_load;
policy_error_ = error;
DCHECK(policy_allows_load_ || !policy_error_.empty());
running_checks_ &= ~CHECK_MANAGEMENT_POLICY;
MaybeInvokeCallback();
}
void ExtensionInstallChecker::CheckRequirements() {
DCHECK(extension_.get());
if (!requirements_checker_.get())
requirements_checker_.reset(new RequirementsChecker());
requirements_checker_->Check(
extension_,
base::Bind(&ExtensionInstallChecker::OnRequirementsCheckDone,
weak_ptr_factory_.GetWeakPtr(),
current_sequence_number_));
}
void ExtensionInstallChecker::OnRequirementsCheckDone(
int sequence_number,
std::vector<std::string> errors) {
// Some pending results may arrive after fail fast.
if (sequence_number != current_sequence_number_)
return;
requirement_errors_ = errors;
running_checks_ &= ~CHECK_REQUIREMENTS;
MaybeInvokeCallback();
}
void ExtensionInstallChecker::CheckBlacklistState() {
DCHECK(extension_.get());
extensions::Blacklist* blacklist =
ExtensionSystem::Get(profile_)->blacklist();
blacklist->IsBlacklisted(
extension_->id(),
base::Bind(&ExtensionInstallChecker::OnBlacklistStateCheckDone,
weak_ptr_factory_.GetWeakPtr(),
current_sequence_number_));
}
void ExtensionInstallChecker::OnBlacklistStateCheckDone(int sequence_number,
BlacklistState state) {
// Some pending results may arrive after fail fast.
if (sequence_number != current_sequence_number_)
return;
blacklist_state_ = state;
running_checks_ &= ~CHECK_BLACKLIST;
MaybeInvokeCallback();
}
void ExtensionInstallChecker::ResetResults() {
requirement_errors_.clear();
blacklist_state_ = NOT_BLACKLISTED;
policy_allows_load_ = true;
policy_error_.clear();
}
void ExtensionInstallChecker::MaybeInvokeCallback() {
if (callback_.is_null())
return;
// Set bits for failed checks.
int failed_mask = 0;
if (blacklist_state_ == BLACKLISTED_MALWARE)
failed_mask |= CHECK_BLACKLIST;
if (!requirement_errors_.empty())
failed_mask |= CHECK_REQUIREMENTS;
if (!policy_allows_load_)
failed_mask |= CHECK_MANAGEMENT_POLICY;
// Invoke callback if all checks are complete or there was at least one
// failure and |fail_fast_| is true.
if (!is_running() || (failed_mask && fail_fast_)) {
// If we are failing fast, discard any pending results.
weak_ptr_factory_.InvalidateWeakPtrs();
running_checks_ = 0;
++current_sequence_number_;
callback_.Run(failed_mask);
callback_.Reset();
}
}
} // namespace extensions
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_CHECKER_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_CHECKER_H_
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "extensions/browser/blacklist_state.h"
#include "extensions/common/extension.h"
class Profile;
namespace extensions {
class RequirementsChecker;
// Performs common checks for an extension. Extensions that violate these checks
// would be disabled or not even installed.
class ExtensionInstallChecker {
public:
// Called when checks are complete. The returned value is a bitmask of
// failed checks.
typedef base::Callback<void(int)> Callback;
enum CheckType {
// Check the blacklist state of the extension.
CHECK_BLACKLIST = 1 << 0,
// Check whether the extension has requirement errors.
CHECK_REQUIREMENTS = 1 << 1,
// Check whether the extension can be installed and loaded, according to
// management policies.
CHECK_MANAGEMENT_POLICY = 1 << 2,
// Perform all checks.
CHECK_ALL = (1 << 3) - 1
};
explicit ExtensionInstallChecker(Profile* profile);
virtual ~ExtensionInstallChecker();
// Start a set of checks. |enabled_checks| is a bitmask of CheckTypes to run.
// If |fail_fast| is true, the callback will be invoked once any check fails.
// Otherwise it will be invoked when all checks have completed. |callback|
// will only be called once.
// This function must be called on the UI thread. The callback also occurs on
// the UI thread. Checks may run asynchronously in parallel.
// If checks are currently running, the caller must wait for the callback to
// be invoked before starting another set of checks.
void Start(int enabled_checks, bool fail_fast, const Callback& callback);
Profile* profile() const { return profile_; }
scoped_refptr<const Extension> extension() { return extension_; }
void set_extension(const Extension* extension) { extension_ = extension; }
// Returns true if any checks are currently running.
bool is_running() const { return running_checks_ != 0; }
// Returns the requirement violations. A non-empty list is considered to be
// a check failure.
const std::vector<std::string>& requirement_errors() const {
return requirement_errors_;
}
// Returns the blacklist state of the extension. A blacklist state of
// BLACKLISTED_MALWARE is considered to be a check failure.
BlacklistState blacklist_state() const { return blacklist_state_; }
// Returns whether management policy permits installation of the extension.
bool policy_allows_load() const { return policy_allows_load_; }
const std::string& policy_error() const { return policy_error_; }
protected:
virtual void CheckManagementPolicy();
void OnManagementPolicyCheckDone(bool allows_load, const std::string& error);
virtual void CheckRequirements();
void OnRequirementsCheckDone(int sequence_number,
std::vector<std::string> errors);
virtual void CheckBlacklistState();
void OnBlacklistStateCheckDone(int sequence_number, BlacklistState state);
virtual void ResetResults();
int current_sequence_number() const { return current_sequence_number_; }
private:
void MaybeInvokeCallback();
scoped_ptr<RequirementsChecker> requirements_checker_;
// The Profile where the extension is being installed in.
Profile* profile_;
// The extension to run checks for.
scoped_refptr<const Extension> extension_;
// Requirement violations.
std::vector<std::string> requirement_errors_;
// Result of the blacklist state check.
BlacklistState blacklist_state_;
// Whether the extension can be installed, according to management policies.
bool policy_allows_load_;
std::string policy_error_;
// The sequence number of the currently running checks.
int current_sequence_number_;
// Bitmask of currently running checks.
int running_checks_;
// If true, the callback is invoked when the first check fails.
bool fail_fast_;
// The callback to invoke when checks are complete.
Callback callback_;
base::WeakPtrFactory<ExtensionInstallChecker> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ExtensionInstallChecker);
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_CHECKER_H_
...@@ -24,6 +24,11 @@ namespace extensions { ...@@ -24,6 +24,11 @@ namespace extensions {
// Holds common methods and data of extension installers. // Holds common methods and data of extension installers.
//
// NOTE: This class is deprecated and has been replaced by
// ExtensionInstallChecker.
// TODO(tmdiep): CrxInstaller and UnpackedInstaller should be refactored to use
// this class (crbug.com/386404).
class ExtensionInstaller { class ExtensionInstaller {
public: public:
typedef base::Callback<void(std::vector<std::string>)> RequirementsCallback; typedef base::Callback<void(std::vector<std::string>)> RequirementsCallback;
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALL_RESULT_H_
#define CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALL_RESULT_H_
namespace extensions {
namespace webstore_install {
// Result codes returned by WebstoreStandaloneInstaller and its subclasses.
enum Result {
// Successful operation.
SUCCESS,
// Unknown error.
UNKNOWN_ERROR,
// The operation was aborted as the requestor is no longer alive.
ABORTED,
// The installation is not permitted.
NOT_PERMITTED,
// Invalid Chrome Web Store item ID.
INVALID_ID,
// Failed to retrieve extension metadata from the Web Store.
WEBSTORE_REQUEST_ERROR,
// The extension metadata retrieved from the Web Store was invalid.
INVALID_WEBSTORE_RESPONSE,
// An error occurred while parsing the extension manifest retrieved from the
// Web Store.
INVALID_MANIFEST,
// Failed to retrieve the extension's icon from the Web Store, or the icon
// was invalid.
ICON_ERROR,
// The user cancelled the operation.
USER_CANCELLED,
// The extension is blacklisted.
BLACKLISTED,
// Unsatisfied dependencies, such as shared modules.
MISSING_DEPENDENCIES,
// Unsatisfied requirements, such as webgl.
REQUIREMENT_VIOLATIONS,
// The extension is blocked by management policies.
BLOCKED_BY_POLICY,
// The launch feature is not available.
LAUNCH_FEATURE_DISABLED,
// The launch feature is not supported for the extension type.
LAUNCH_UNSUPPORTED_EXTENSION_TYPE
};
} // namespace webstore_install
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALL_RESULT_H_
...@@ -52,6 +52,7 @@ WebstoreInstallerTest::WebstoreInstallerTest( ...@@ -52,6 +52,7 @@ WebstoreInstallerTest::WebstoreInstallerTest(
WebstoreInstallerTest::~WebstoreInstallerTest() {} WebstoreInstallerTest::~WebstoreInstallerTest() {}
void WebstoreInstallerTest::SetUpCommandLine(CommandLine* command_line) { void WebstoreInstallerTest::SetUpCommandLine(CommandLine* command_line) {
ExtensionBrowserTest::SetUpCommandLine(command_line);
// We start the test server now instead of in // We start the test server now instead of in
// SetUpInProcessBrowserTestFixture so that we can get its port number. // SetUpInProcessBrowserTestFixture so that we can get its port number.
ASSERT_TRUE(test_server()->Start()); ASSERT_TRUE(test_server()->Start());
...@@ -79,7 +80,7 @@ void WebstoreInstallerTest::SetUpInProcessBrowserTestFixture() { ...@@ -79,7 +80,7 @@ void WebstoreInstallerTest::SetUpInProcessBrowserTestFixture() {
} }
void WebstoreInstallerTest::SetUpOnMainThread() { void WebstoreInstallerTest::SetUpOnMainThread() {
InProcessBrowserTest::SetUpOnMainThread(); ExtensionBrowserTest::SetUpOnMainThread();
ASSERT_TRUE(download_directory_.CreateUniqueTempDir()); ASSERT_TRUE(download_directory_.CreateUniqueTempDir());
DownloadPrefs* download_prefs = DownloadPrefs::FromBrowserContext( DownloadPrefs* download_prefs = DownloadPrefs::FromBrowserContext(
browser()->profile()); browser()->profile());
...@@ -132,3 +133,15 @@ void WebstoreInstallerTest::RunTestAsync( ...@@ -132,3 +133,15 @@ void WebstoreInstallerTest::RunTestAsync(
browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame()-> browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame()->
ExecuteJavaScript(base::UTF8ToUTF16(script)); ExecuteJavaScript(base::UTF8ToUTF16(script));
} }
void WebstoreInstallerTest::AutoAcceptInstall() {
// TODO(tmdiep): Refactor and remove the use of the command line flag.
// See crbug.com/357774.
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kAppsGalleryInstallAutoConfirmForTests, "accept");
}
void WebstoreInstallerTest::AutoCancelInstall() {
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kAppsGalleryInstallAutoConfirmForTests, "cancel");
}
...@@ -8,14 +8,14 @@ ...@@ -8,14 +8,14 @@
#include <string> #include <string>
#include "base/files/scoped_temp_dir.h" #include "base/files/scoped_temp_dir.h"
#include "chrome/test/base/in_process_browser_test.h" #include "chrome/browser/extensions/extension_browsertest.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace base { namespace base {
class CommandLine; class CommandLine;
} // namespace base } // namespace base
class WebstoreInstallerTest : public InProcessBrowserTest { class WebstoreInstallerTest : public ExtensionBrowserTest {
public: public:
WebstoreInstallerTest(const std::string& webstore_domain, WebstoreInstallerTest(const std::string& webstore_domain,
const std::string& test_data_path, const std::string& test_data_path,
...@@ -45,6 +45,14 @@ class WebstoreInstallerTest : public InProcessBrowserTest { ...@@ -45,6 +45,14 @@ class WebstoreInstallerTest : public InProcessBrowserTest {
// Runs a test without waiting for any results from the renderer. // Runs a test without waiting for any results from the renderer.
void RunTestAsync(const std::string& test_function_name); void RunTestAsync(const std::string& test_function_name);
// Configures command line switches to simulate a user accepting the install
// prompt.
void AutoAcceptInstall();
// Configures command line switches to simulate a user cancelling the install
// prompt.
void AutoCancelInstall();
std::string webstore_domain_; std::string webstore_domain_;
std::string test_data_path_; std::string test_data_path_;
std::string crx_filename_; std::string crx_filename_;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "chrome/browser/extensions/extension_install_prompt.h" #include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/webstore_data_fetcher_delegate.h" #include "chrome/browser/extensions/webstore_data_fetcher_delegate.h"
#include "chrome/browser/extensions/webstore_install_helper.h" #include "chrome/browser/extensions/webstore_install_helper.h"
#include "chrome/browser/extensions/webstore_install_result.h"
#include "chrome/browser/extensions/webstore_installer.h" #include "chrome/browser/extensions/webstore_installer.h"
#include "net/url_request/url_fetcher_delegate.h" #include "net/url_request/url_fetcher_delegate.h"
#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkBitmap.h"
...@@ -60,9 +61,20 @@ class WebstoreStandaloneInstaller ...@@ -60,9 +61,20 @@ class WebstoreStandaloneInstaller
protected: protected:
virtual ~WebstoreStandaloneInstaller(); virtual ~WebstoreStandaloneInstaller();
// Called when the install should be aborted. The callback is cleared.
void AbortInstall(); void AbortInstall();
void InvokeCallback(const std::string& error);
virtual void CompleteInstall(const std::string& error); // Called when the install is complete.
virtual void CompleteInstall(webstore_install::Result result,
const std::string& error);
// Called when the installer should proceed to prompt the user.
void ProceedWithInstallPrompt();
// Lazily creates a dummy extension for display from the parsed manifest. This
// is safe to call from OnManifestParsed() onwards. The manifest may be
// invalid, thus the caller must check that the return value is not NULL.
scoped_refptr<const Extension> GetLocalizedExtensionForDisplay();
// Template Method's hooks to be implemented by subclasses. // Template Method's hooks to be implemented by subclasses.
...@@ -108,11 +120,12 @@ class WebstoreStandaloneInstaller ...@@ -108,11 +120,12 @@ class WebstoreStandaloneInstaller
const base::DictionaryValue& webstore_data, const base::DictionaryValue& webstore_data,
std::string* error) const = 0; std::string* error) const = 0;
// Perform all necessary checks after the manifest has been parsed to make // Will be called after the extension's manifest has been successfully parsed.
// sure that the install should still proceed. // Subclasses can perform asynchronous checks at this point and call
virtual bool CheckInstallValid( // ProceedWithInstallPrompt() to proceed with the install or otherwise call
const base::DictionaryValue& manifest, // CompleteInstall() with an error code. The default implementation calls
std::string* error); // ProceedWithInstallPrompt().
virtual void OnManifestParsed();
// Returns an install UI to be shown. By default, this returns an install UI // Returns an install UI to be shown. By default, this returns an install UI
// that is a transient child of the host window for GetWebContents(). // that is a transient child of the host window for GetWebContents().
...@@ -137,6 +150,9 @@ class WebstoreStandaloneInstaller ...@@ -137,6 +150,9 @@ class WebstoreStandaloneInstaller
Profile* profile() const { return profile_; } Profile* profile() const { return profile_; }
const std::string& id() const { return id_; } const std::string& id() const { return id_; }
const base::DictionaryValue* manifest() const { return manifest_.get(); } const base::DictionaryValue* manifest() const { return manifest_.get(); }
const Extension* localized_extension_for_display() const {
return localized_extension_for_display_.get();
}
private: private:
friend class base::RefCountedThreadSafe<WebstoreStandaloneInstaller>; friend class base::RefCountedThreadSafe<WebstoreStandaloneInstaller>;
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include <vector> #include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/command_line.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/browser/apps/ephemeral_app_launcher.h" #include "chrome/browser/apps/ephemeral_app_launcher.h"
...@@ -20,7 +19,6 @@ ...@@ -20,7 +19,6 @@
#include "chrome/browser/ui/app_list/search/webstore/webstore_installer.h" #include "chrome/browser/ui/app_list/search/webstore/webstore_installer.h"
#include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/extensions/application_launch.h"
#include "chrome/common/chrome_switches.h"
#include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h" #include "extensions/browser/extension_system.h"
#include "extensions/browser/extension_util.h" #include "extensions/browser/extension_util.h"
...@@ -134,8 +132,7 @@ void WebstoreResult::UpdateActions() { ...@@ -134,8 +132,7 @@ void WebstoreResult::UpdateActions() {
extensions::util::IsExtensionInstalledPermanently(app_id_, profile_); extensions::util::IsExtensionInstalledPermanently(app_id_, profile_);
if (!is_otr && !is_installed && !is_installing()) { if (!is_otr && !is_installed && !is_installing()) {
if (CommandLine::ForCurrentProcess()->HasSwitch( if (EphemeralAppLauncher::IsFeatureEnabled()) {
switches::kEnableEphemeralApps)) {
actions.push_back(Action( actions.push_back(Action(
l10n_util::GetStringUTF16(IDS_WEBSTORE_RESULT_INSTALL), l10n_util::GetStringUTF16(IDS_WEBSTORE_RESULT_INSTALL),
l10n_util::GetStringUTF16( l10n_util::GetStringUTF16(
...@@ -186,7 +183,7 @@ void WebstoreResult::StartInstall(bool launch_ephemeral_app) { ...@@ -186,7 +183,7 @@ void WebstoreResult::StartInstall(bool launch_ephemeral_app) {
app_id_, app_id_,
profile_, profile_,
controller_->GetAppListWindow(), controller_->GetAppListWindow(),
base::Bind(&WebstoreResult::InstallCallback, base::Bind(&WebstoreResult::LaunchCallback,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
installer->Start(); installer->Start();
return; return;
...@@ -209,10 +206,18 @@ void WebstoreResult::InstallCallback(bool success, const std::string& error) { ...@@ -209,10 +206,18 @@ void WebstoreResult::InstallCallback(bool success, const std::string& error) {
return; return;
} }
// Success handling is continued in OnExtensionInstalled. // Success handling is continued in OnExtensionWillBeInstalled.
SetPercentDownloaded(100); SetPercentDownloaded(100);
} }
void WebstoreResult::LaunchCallback(extensions::webstore_install::Result result,
const std::string& error) {
if (result != extensions::webstore_install::SUCCESS)
LOG(ERROR) << "Failed to launch app, error=" << error;
SetIsInstalling(false);
}
void WebstoreResult::StartObserving() { void WebstoreResult::StartObserving() {
DCHECK(!install_tracker_ && !extension_registry_); DCHECK(!install_tracker_ && !extension_registry_);
...@@ -253,8 +258,12 @@ void WebstoreResult::OnExtensionWillBeInstalled( ...@@ -253,8 +258,12 @@ void WebstoreResult::OnExtensionWillBeInstalled(
return; return;
SetIsInstalling(false); SetIsInstalling(false);
UpdateActions();
NotifyItemInstalled(); if (extensions::util::IsExtensionInstalledPermanently(extension->id(),
profile_)) {
UpdateActions();
NotifyItemInstalled();
}
} }
void WebstoreResult::OnShutdown() { void WebstoreResult::OnShutdown() {
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "chrome/browser/extensions/install_observer.h" #include "chrome/browser/extensions/install_observer.h"
#include "chrome/browser/extensions/webstore_install_result.h"
#include "chrome/browser/ui/app_list/search/chrome_search_result.h" #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
#include "extensions/browser/extension_registry_observer.h" #include "extensions/browser/extension_registry_observer.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -48,6 +49,8 @@ class WebstoreResult : public ChromeSearchResult, ...@@ -48,6 +49,8 @@ class WebstoreResult : public ChromeSearchResult,
void StartInstall(bool launch_ephemeral_app); void StartInstall(bool launch_ephemeral_app);
void InstallCallback(bool success, const std::string& error); void InstallCallback(bool success, const std::string& error);
void LaunchCallback(extensions::webstore_install::Result result,
const std::string& error);
// Start observing both InstallObserver and ExtensionRegistryObserver. // Start observing both InstallObserver and ExtensionRegistryObserver.
void StartObserving(); void StartObserving();
......
...@@ -746,6 +746,8 @@ ...@@ -746,6 +746,8 @@
'browser/extensions/extension_icon_manager.h', 'browser/extensions/extension_icon_manager.h',
'browser/extensions/extension_infobar_delegate.cc', 'browser/extensions/extension_infobar_delegate.cc',
'browser/extensions/extension_infobar_delegate.h', 'browser/extensions/extension_infobar_delegate.h',
'browser/extensions/extension_install_checker.cc',
'browser/extensions/extension_install_checker.h',
'browser/extensions/extension_install_prompt.cc', 'browser/extensions/extension_install_prompt.cc',
'browser/extensions/extension_install_prompt.h', 'browser/extensions/extension_install_prompt.h',
'browser/extensions/extension_install_prompt_experiment.cc', 'browser/extensions/extension_install_prompt_experiment.cc',
...@@ -941,6 +943,7 @@ ...@@ -941,6 +943,7 @@
'browser/extensions/webstore_inline_installer_factory.h', 'browser/extensions/webstore_inline_installer_factory.h',
'browser/extensions/webstore_install_helper.cc', 'browser/extensions/webstore_install_helper.cc',
'browser/extensions/webstore_install_helper.h', 'browser/extensions/webstore_install_helper.h',
'browser/extensions/webstore_install_result.h',
'browser/extensions/webstore_install_with_prompt.cc', 'browser/extensions/webstore_install_with_prompt.cc',
'browser/extensions/webstore_install_with_prompt.h', 'browser/extensions/webstore_install_with_prompt.h',
'browser/extensions/webstore_installer.cc', 'browser/extensions/webstore_installer.cc',
......
...@@ -884,6 +884,7 @@ ...@@ -884,6 +884,7 @@
'browser/apps/drive/drive_app_provider_browsertest.cc', 'browser/apps/drive/drive_app_provider_browsertest.cc',
'browser/apps/ephemeral_app_browsertest.cc', 'browser/apps/ephemeral_app_browsertest.cc',
'browser/apps/ephemeral_app_browsertest.h', 'browser/apps/ephemeral_app_browsertest.h',
'browser/apps/ephemeral_app_launcher_browsertest.cc',
'browser/apps/ephemeral_app_service_browsertest.cc', 'browser/apps/ephemeral_app_service_browsertest.cc',
'browser/apps/event_page_browsertest.cc', 'browser/apps/event_page_browsertest.cc',
'browser/apps/speech_recognition_browsertest.cc', 'browser/apps/speech_recognition_browsertest.cc',
......
...@@ -966,6 +966,7 @@ ...@@ -966,6 +966,7 @@
'browser/extensions/extension_garbage_collector_chromeos_unittest.cc', 'browser/extensions/extension_garbage_collector_chromeos_unittest.cc',
'browser/extensions/extension_gcm_app_handler_unittest.cc', 'browser/extensions/extension_gcm_app_handler_unittest.cc',
'browser/extensions/extension_icon_manager_unittest.cc', 'browser/extensions/extension_icon_manager_unittest.cc',
'browser/extensions/extension_install_checker_unittest.cc',
'browser/extensions/extension_message_bubble_controller_unittest.cc', 'browser/extensions/extension_message_bubble_controller_unittest.cc',
'browser/extensions/extension_prefs_unittest.cc', 'browser/extensions/extension_prefs_unittest.cc',
'browser/extensions/extension_prefs_unittest.h', 'browser/extensions/extension_prefs_unittest.h',
......
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDBUe9m01dbRMdT
irq/xyQojlugvSchBty8H/qWVs471yggJjkuN1A70Fmnk/oQCHkPhF5O6hV3ud0g
u89dDG0NPDSWl2qX0No4jqyeQ2VFOV31ZHPVrtGO21xNjIebAQZ/svNrce9Q8bVy
A3wUQXGvV+sOt7BhFU8AfYIqeQ5VldFeLM1zaLC8CsO8Eq12wsB/+h15EEKQtcDN
c+y/BnKd1tq89Vl+CcUe5d5mZS11E9SsxdNxzY3JTh/0OSNF71edKYFchnNbe0/3
Z85CfwktoQcIY7LovESm5o8Xf+3T1XBbc6Ifa4bfNjULGZuLXaNmksIz6nOw2GYt
jKJHNoDVAgMBAAECggEBAIpD6N75PxyG9603ptOtQZ5EGyK+xrKnbs6abKaEFWLV
QtyjmfgFFbyCCu2BN7Op67P+b1kvsQT9iTt1OB2L2p9BtTcTuug0Ny+GU82p1E+L
dTkijHqDW1w6Zi0M2pwxQo2o1tK9HXYeOjD+bwspt366eeL/3AXDsMpf+e4YwPjS
PT9ZFUr58pJH3e9p9oWa1i7LQssEqtgvHQjsLch05kj2V/pyJnydgwffcRQNguYE
uVfxSUnrmE2w438pJbOXWOMiGNnWeI01gTs7hhjOETX6uGmQyoPCo/wMm9fd3vCc
mjtJojsExxXHL1Mgbz4455SHPc33JCtI1My+RG4mSQ0CgYEA36XkTgYDVLnFBwfh
2MytmI0PlU5uZP78t0E6rnshbaseQPos5e+/tfn1/Vb64Qmk528+6fbTzM4e3vLo
d4KsvGf9SPs19ypm8OmAAu/3M6KjKOgG5YqoDsd6ED5qUjsTVB9LLjr9Xb5dPhte
0ErFG8dqS7IkIRwr/lLBRkM7ec8CgYEA3UjxICZk7i+7apOmutr6Y9vcRiVFoDhj
YHwZkr3CoRbwU0fPR1nm5qDXTAGDJ4S3iq7HsiSFByvzKizu4eIAyUz6028yKQ64
di98B79S+Lh7PykWx27nujVMWWw4du46kkr1qEVHvOu0exPMlfGgUEb8zSSDZrnk
31LDRRi22BsCgYEAkdMtJeKt0VS/r3HoROBQYKO5gXT+bkQEq8iQZqxKg6OLunpl
RBgrPJCbYHCSbKFJMM5Mi2kxeNz9LAneoe5GiyKS+D80VNEFBhh6K3AkEzr8f/Oq
a4kZQ2m1oVnRIYT7eWJeNuqnwbQaQCDAlbfrBc3k9S5WeHBSDyYOd63m3ekCgYEA
mAUHWf3mctep2nLrJQ1Q3Q9rCWmLpqF2bA91hiEFN6PJoH0BwlPZ0/EFV3rmflyn
tweRuylpll60I/JQfi/EOIbA/kYy4I/zW4YNoEjpGGOsj9yLgKEJYxxAgmJdfB73
cA89KsfFm90V1UPp1cz0RJIwFEKUXxswR9fUvIBZBKcCgYAngAbZkkaq1VWo0qYy
6tk7DyYob5kLvMY/FCDPx5+FZKz5NaJkIWkEvtytphidk2r4vqaCa9tp0VaTIe2Q
2BShVaBnkKyF0Qn0f1XXiTfVIa/zduQc580vqI1FTCoXaPO/3wYa345AjrQoRZls
nviXEgVqFDhTgBG0yzpSnHhhsg==
-----END PRIVATE KEY-----
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('index.html', {}, function(win) {
chrome.test.sendMessage('launched');
win.close();
});
});
{
"name": "Simple Test App",
"manifest_version": 2,
"version": "1",
"app": {
"background": {
"scripts": ["main.js"]
}
}
}
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC5ZOMEtT5hrz5k
Mh9cbalNWt8P81unURX+Q5sPx1PxOlCylF6EiciE+pQjcXSqFm2OsKQuNojqyEM6
93LMQnT1UKRxrV7tSNALqGiQ6Xh4JKKe0sLqW4rFscw9Hjrzop8KeOpwUygiFgdD
6t0NAVErSr85PNatureoC+nYEZxA7ESHI0X7SVnWoew7AFULfdWPYwQzmBbldFxx
UNeGklYlxviahey9HHiHC/kWomwQ0NvdN9jGAhI5W9nuFs5XY+fSiO/HPYSX37vP
0fkTyRPTkrRcncH9/YTh2vaEHDbHKsGZKuY8/nz2B32SX5zP+jjSQPJ8dfqjEFX6
He6d4C7tAgMBAAECggEAMm4J/sbacDH+M70aoMbHrd4RHUKiZNH+vIphTJp47/5f
4yPOzhi4rcuHrlh3VqkBJjZQgq2c8tiEyS50ULGnJO/Ju45gawVKalFmGD0Z4vx8
K93C3YMHLZ2eo+VsPce3oV6gzusf2J3LXiMt/BKmpLMRbx1ofBt1R8Xt1zN7IIFt
mR9gPF7EIzYRlD5M6Lj76j2e0dv/QZVdDOsNEcww1bys9If00BgLCPZmlAUz7rE5
uQytekLwrb5EM3jb3MTANHivNwWWMY1BR2hQTgRQ+QDKmK020GIRzth3B0Xa3fkJ
WpG26JbznF079IAFpb/+6b365mkTPs8TX3dyAa7iwQKBgQDpZYCh15bznP2jodfi
LpT40xuyxvhiKLvH1WlRxgcm3QewoZvKHfZXQ6HUCOcfirunlNdQviiByIr8za7A
qIXAsqg9W5BLCeLCMSAlRV4CnAF4457PShoFTaSN8Hu7MbpHSvM+NaDXm/lv5gNF
XSrH0wBP/PmtInn4mb6BzZFTcQKBgQDLWUgYPuF6sFcsD1ve2gKoj71jGEnuPdqP
5RF/ZIitS9sk+TP8KgsSycNFX1u/HrcuiOClVz3bZC39oKgqyEMiaUKYYBc+Tk71
ymJkAdGoLoJnaINXqTTRUZO8zaErhyNQxFut6X+ejgqLgGPV5Mc/HQXVr8eG0NA7
4W5Lo8OdPQKBgHu3PRcMw0xA1EXPfTK8hGTc6lq6k2DcvKTxn9Ejyhi0ouXi1ESv
2ytogzh0u6aBkHUFNZjsI2agGeRlVpNzAOsjCID1ryfHhrZu+d4nxexWK4WcCktQ
uThEbsx6Q+v3MQmnVgaMwMRpPjAtWWCEQTAIzaqYqvQ2STcYr934TGdRAoGAS997
Q/iqXwHO9NSiPctwdH51drUIWMlhdJFO7w6O5MJJ+Ui2ed8iFJeNsaO78tq+FLHj
yC1+Gg8ODfVU6emhCwTlYT9xTMEhOxqRjakUFkGMTJM1do7e8z8R9b9v5HLe3XL2
ljRqdrme+6AjIBrlsQneNHYK56WgHMenRLfM9C0CgYEA4SW4+QaO7AYJIJhWCZ8I
blFj6q95FUfsMEUBlEqJQJxKUSdn58AJ96RcwLD1KmXhyTNctD5BidkApFmi8IXa
qJcbbCOinEJn2NFT6/C8ZbF8w6cvJaG8c3iLZaUwDmmX+oKC2GbqSYhqN2K96HUp
tpcPgbZnwkbs/8pYq2jxTLk=
-----END PRIVATE KEY-----
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('index.html', {}, function(win) {
chrome.test.sendMessage('launched');
win.close();
});
});
{
"name": "Test App With Permissions",
"manifest_version": 2,
"version": "1",
"app": {
"background": {
"scripts": ["main.js"]
}
},
"permissions": ["audioCapture"]
}
{
"name": "Test Extension",
"version": "0.1",
"manifest_version": 2
}
{
"users": "371,674",
"average_rating": 4.36,
"rating_count": 788,
"manifest": "{\"name\":\"Test Extension\",\"version\":\"0.1\"}"
}
{
"users": "371,674",
"average_rating": 4.36,
"rating_count": 788,
"manifest": "{\"name\":\"Simple Test App\",\"manifest_version\":2,\"version\":\"1\",\"app\": {\"background\":{\"scripts\":[\"main.js\"]}}}"
}
{
"users": "371,674",
"average_rating": 4.36,
"rating_count": 788,
"manifest": "{\"name\":\"Test App With Permissions\",\"manifest_version\":2,\"version\":\"1\",\"app\":{\"background\":{\"scripts\":[\"main.js\"]}},\"permissions\":[\"audioCapture\"]}"
}
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