Prevent chrome://net-internals/#export from flickering
[chromium-blink-merge.git] / chrome / browser / extensions / startup_helper.cc
blob07c868bdc75eb0586861b95f604ab1d1fde4568b
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/startup_helper.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/extensions/extension_service.h"
17 #include "chrome/browser/extensions/webstore_startup_installer.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/common/extensions/chrome_extensions_client.h"
21 #include "components/crx_file/id_util.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/web_contents.h"
24 #include "extensions/browser/sandboxed_unpacker.h"
25 #include "extensions/common/extension.h"
26 #include "ipc/ipc_message.h"
28 #if defined(OS_WIN)
29 #include "extensions/browser/app_window/app_window.h"
30 #include "extensions/browser/app_window/app_window_registry.h"
31 #include "extensions/browser/extension_registry.h"
32 #include "extensions/browser/extension_util.h"
33 #endif
35 using content::BrowserThread;
37 namespace extensions {
39 namespace {
41 void PrintPackExtensionMessage(const std::string& message) {
42 VLOG(1) << message;
45 // On Windows, the jumplist action for installing an ephemeral app has to use
46 // the --install-ephemeral-app-from-webstore command line arg to initiate an
47 // install.
48 scoped_refptr<WebstoreStandaloneInstaller> CreateEphemeralAppInstaller(
49 Profile* profile,
50 const std::string& app_id,
51 WebstoreStandaloneInstaller::Callback callback) {
52 scoped_refptr<WebstoreStandaloneInstaller> installer;
54 #if defined(OS_WIN)
55 ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
56 DCHECK(registry);
57 if (!registry->GetExtensionById(app_id, ExtensionRegistry::EVERYTHING) ||
58 !util::IsEphemeralApp(app_id, profile)) {
59 return installer;
62 AppWindowRegistry* app_window_registry = AppWindowRegistry::Get(profile);
63 DCHECK(app_window_registry);
64 AppWindow* app_window =
65 app_window_registry->GetCurrentAppWindowForApp(app_id);
66 if (!app_window)
67 return installer;
69 installer = new WebstoreInstallWithPrompt(
70 app_id, profile, app_window->GetNativeWindow(), callback);
71 #endif
73 return installer;
76 } // namespace
78 StartupHelper::StartupHelper() : pack_job_succeeded_(false) {
79 ExtensionsClient::Set(ChromeExtensionsClient::GetInstance());
82 void StartupHelper::OnPackSuccess(
83 const base::FilePath& crx_path,
84 const base::FilePath& output_private_key_path) {
85 pack_job_succeeded_ = true;
86 PrintPackExtensionMessage(
87 base::UTF16ToUTF8(
88 PackExtensionJob::StandardSuccessMessage(crx_path,
89 output_private_key_path)));
92 void StartupHelper::OnPackFailure(const std::string& error_message,
93 ExtensionCreator::ErrorType type) {
94 PrintPackExtensionMessage(error_message);
97 bool StartupHelper::PackExtension(const base::CommandLine& cmd_line) {
98 if (!cmd_line.HasSwitch(switches::kPackExtension))
99 return false;
101 // Input Paths.
102 base::FilePath src_dir =
103 cmd_line.GetSwitchValuePath(switches::kPackExtension);
104 base::FilePath private_key_path;
105 if (cmd_line.HasSwitch(switches::kPackExtensionKey)) {
106 private_key_path = cmd_line.GetSwitchValuePath(switches::kPackExtensionKey);
109 // Launch a job to perform the packing on the file thread. Ignore warnings
110 // from the packing process. (e.g. Overwrite any existing crx file.)
111 pack_job_ = new PackExtensionJob(this, src_dir, private_key_path,
112 ExtensionCreator::kOverwriteCRX);
113 pack_job_->set_asynchronous(false);
114 pack_job_->Start();
116 return pack_job_succeeded_;
119 namespace {
121 class ValidateCrxHelper : public SandboxedUnpackerClient {
122 public:
123 ValidateCrxHelper(const CRXFileInfo& file,
124 const base::FilePath& temp_dir,
125 base::RunLoop* run_loop)
126 : crx_file_(file),
127 temp_dir_(temp_dir),
128 run_loop_(run_loop),
129 finished_(false),
130 success_(false) {}
132 bool finished() { return finished_; }
133 bool success() { return success_; }
134 const base::string16& error() { return error_; }
136 void Start() {
137 BrowserThread::PostTask(BrowserThread::FILE,
138 FROM_HERE,
139 base::Bind(&ValidateCrxHelper::StartOnFileThread,
140 this));
143 protected:
144 ~ValidateCrxHelper() override {}
146 void OnUnpackSuccess(const base::FilePath& temp_dir,
147 const base::FilePath& extension_root,
148 const base::DictionaryValue* original_manifest,
149 const Extension* extension,
150 const SkBitmap& install_icon) override {
151 finished_ = true;
152 success_ = true;
153 BrowserThread::PostTask(BrowserThread::UI,
154 FROM_HERE,
155 base::Bind(&ValidateCrxHelper::FinishOnUIThread,
156 this));
159 void OnUnpackFailure(const CrxInstallError& error) override {
160 finished_ = true;
161 success_ = false;
162 error_ = error.message();
163 BrowserThread::PostTask(BrowserThread::UI,
164 FROM_HERE,
165 base::Bind(&ValidateCrxHelper::FinishOnUIThread,
166 this));
169 void FinishOnUIThread() {
170 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
171 if (run_loop_->running())
172 run_loop_->Quit();
175 void StartOnFileThread() {
176 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
177 scoped_refptr<base::MessageLoopProxy> file_thread_proxy =
178 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE);
180 scoped_refptr<SandboxedUnpacker> unpacker(
181 new SandboxedUnpacker(crx_file_,
182 Manifest::INTERNAL,
183 0, /* no special creation flags */
184 temp_dir_,
185 file_thread_proxy.get(),
186 this));
187 unpacker->Start();
190 // The file being validated.
191 const CRXFileInfo& crx_file_;
193 // The temporary directory where the sandboxed unpacker will do work.
194 const base::FilePath& temp_dir_;
196 // Unowned pointer to a runloop, so our consumer can wait for us to finish.
197 base::RunLoop* run_loop_;
199 // Whether we're finished unpacking;
200 bool finished_;
202 // Whether the unpacking was successful.
203 bool success_;
205 // If the unpacking wasn't successful, this contains an error message.
206 base::string16 error_;
209 } // namespace
211 bool StartupHelper::ValidateCrx(const base::CommandLine& cmd_line,
212 std::string* error) {
213 CHECK(error);
214 base::FilePath path = cmd_line.GetSwitchValuePath(switches::kValidateCrx);
215 if (path.empty()) {
216 *error = base::StringPrintf("Empty path passed for %s",
217 switches::kValidateCrx);
218 return false;
220 base::ScopedTempDir temp_dir;
222 if (!temp_dir.CreateUniqueTempDir()) {
223 *error = std::string("Failed to create temp dir");
224 return false;
227 base::RunLoop run_loop;
228 CRXFileInfo file(path);
229 scoped_refptr<ValidateCrxHelper> helper(
230 new ValidateCrxHelper(file, temp_dir.path(), &run_loop));
231 helper->Start();
232 if (!helper->finished())
233 run_loop.Run();
235 bool success = helper->success();
236 if (!success)
237 *error = base::UTF16ToUTF8(helper->error());
238 return success;
241 namespace {
243 class AppInstallHelper {
244 public:
245 // A callback for when the install process is done.
246 typedef base::Callback<void()> DoneCallback;
248 AppInstallHelper();
249 virtual ~AppInstallHelper();
250 bool success() { return success_; }
251 const std::string& error() { return error_; }
252 void BeginInstall(Profile* profile,
253 const std::string& id,
254 bool show_prompt,
255 DoneCallback callback);
257 private:
258 WebstoreStandaloneInstaller::Callback Callback();
259 void OnAppInstallComplete(bool success,
260 const std::string& error,
261 webstore_install::Result result);
263 DoneCallback done_callback_;
265 // These hold on to the result of the app install when it is complete.
266 bool success_;
267 std::string error_;
269 scoped_refptr<WebstoreStandaloneInstaller> installer_;
272 AppInstallHelper::AppInstallHelper() : success_(false) {}
274 AppInstallHelper::~AppInstallHelper() {}
276 WebstoreStandaloneInstaller::Callback AppInstallHelper::Callback() {
277 return base::Bind(&AppInstallHelper::OnAppInstallComplete,
278 base::Unretained(this));
281 void AppInstallHelper::BeginInstall(
282 Profile* profile,
283 const std::string& id,
284 bool show_prompt,
285 DoneCallback done_callback) {
286 done_callback_ = done_callback;
288 WebstoreStandaloneInstaller::Callback callback =
289 base::Bind(&AppInstallHelper::OnAppInstallComplete,
290 base::Unretained(this));
292 installer_ = CreateEphemeralAppInstaller(profile, id, callback);
293 if (installer_.get()) {
294 installer_->BeginInstall();
295 } else {
296 error_ = "Not a supported ephemeral app installation.";
297 done_callback_.Run();
301 void AppInstallHelper::OnAppInstallComplete(bool success,
302 const std::string& error,
303 webstore_install::Result result) {
304 success_ = success;
305 error_ = error;
306 done_callback_.Run();
309 } // namespace
311 bool StartupHelper::InstallEphemeralApp(const base::CommandLine& cmd_line,
312 Profile* profile) {
313 std::string id =
314 cmd_line.GetSwitchValueASCII(switches::kInstallEphemeralAppFromWebstore);
315 if (!crx_file::id_util::IdIsValid(id)) {
316 LOG(ERROR) << "Invalid id for "
317 << switches::kInstallEphemeralAppFromWebstore << " : '" << id << "'";
318 return false;
321 AppInstallHelper helper;
322 base::RunLoop run_loop;
323 helper.BeginInstall(profile, id, true, run_loop.QuitClosure());
324 run_loop.Run();
326 if (!helper.success())
327 LOG(ERROR) << "InstallFromWebstore failed with error: " << helper.error();
328 return helper.success();
331 StartupHelper::~StartupHelper() {
332 if (pack_job_.get())
333 pack_job_->ClearClient();
336 } // namespace extensions