MacViews: Get c/b/ui/views/tabs to build on Mac
[chromium-blink-merge.git] / chrome / browser / extensions / startup_helper.cc
blobb90fed3cd9b87896a376fea0c4f63ce76ab8a954
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/sandboxed_unpacker.h"
18 #include "chrome/browser/extensions/webstore_startup_installer.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/extensions/chrome_extensions_client.h"
22 #include "components/crx_file/id_util.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/web_contents.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 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 base::FilePath& crx_file,
124 const base::FilePath& temp_dir,
125 base::RunLoop* run_loop)
126 : crx_file_(crx_file), temp_dir_(temp_dir), run_loop_(run_loop),
127 finished_(false), success_(false) {}
129 bool finished() { return finished_; }
130 bool success() { return success_; }
131 const base::string16& error() { return error_; }
133 void Start() {
134 BrowserThread::PostTask(BrowserThread::FILE,
135 FROM_HERE,
136 base::Bind(&ValidateCrxHelper::StartOnFileThread,
137 this));
140 protected:
141 ~ValidateCrxHelper() override {}
143 void OnUnpackSuccess(const base::FilePath& temp_dir,
144 const base::FilePath& extension_root,
145 const base::DictionaryValue* original_manifest,
146 const Extension* extension,
147 const SkBitmap& install_icon) override {
148 finished_ = true;
149 success_ = true;
150 BrowserThread::PostTask(BrowserThread::UI,
151 FROM_HERE,
152 base::Bind(&ValidateCrxHelper::FinishOnUIThread,
153 this));
156 void OnUnpackFailure(const base::string16& error) override {
157 finished_ = true;
158 success_ = false;
159 error_ = error;
160 BrowserThread::PostTask(BrowserThread::UI,
161 FROM_HERE,
162 base::Bind(&ValidateCrxHelper::FinishOnUIThread,
163 this));
166 void FinishOnUIThread() {
167 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
168 if (run_loop_->running())
169 run_loop_->Quit();
172 void StartOnFileThread() {
173 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
174 scoped_refptr<base::MessageLoopProxy> file_thread_proxy =
175 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE);
177 scoped_refptr<SandboxedUnpacker> unpacker(
178 new SandboxedUnpacker(crx_file_,
179 Manifest::INTERNAL,
180 0, /* no special creation flags */
181 temp_dir_,
182 file_thread_proxy.get(),
183 this));
184 unpacker->Start();
187 // The file being validated.
188 const base::FilePath& crx_file_;
190 // The temporary directory where the sandboxed unpacker will do work.
191 const base::FilePath& temp_dir_;
193 // Unowned pointer to a runloop, so our consumer can wait for us to finish.
194 base::RunLoop* run_loop_;
196 // Whether we're finished unpacking;
197 bool finished_;
199 // Whether the unpacking was successful.
200 bool success_;
202 // If the unpacking wasn't successful, this contains an error message.
203 base::string16 error_;
206 } // namespace
208 bool StartupHelper::ValidateCrx(const CommandLine& cmd_line,
209 std::string* error) {
210 CHECK(error);
211 base::FilePath path = cmd_line.GetSwitchValuePath(switches::kValidateCrx);
212 if (path.empty()) {
213 *error = base::StringPrintf("Empty path passed for %s",
214 switches::kValidateCrx);
215 return false;
217 base::ScopedTempDir temp_dir;
219 if (!temp_dir.CreateUniqueTempDir()) {
220 *error = std::string("Failed to create temp dir");
221 return false;
224 base::RunLoop run_loop;
225 scoped_refptr<ValidateCrxHelper> helper(
226 new ValidateCrxHelper(path, temp_dir.path(), &run_loop));
227 helper->Start();
228 if (!helper->finished())
229 run_loop.Run();
231 bool success = helper->success();
232 if (!success)
233 *error = base::UTF16ToUTF8(helper->error());
234 return success;
237 namespace {
239 class AppInstallHelper {
240 public:
241 // A callback for when the install process is done.
242 typedef base::Callback<void()> DoneCallback;
244 AppInstallHelper();
245 virtual ~AppInstallHelper();
246 bool success() { return success_; }
247 const std::string& error() { return error_; }
248 void BeginInstall(Profile* profile,
249 const std::string& id,
250 bool show_prompt,
251 DoneCallback callback);
253 private:
254 WebstoreStandaloneInstaller::Callback Callback();
255 void OnAppInstallComplete(bool success,
256 const std::string& error,
257 webstore_install::Result result);
259 DoneCallback done_callback_;
261 // These hold on to the result of the app install when it is complete.
262 bool success_;
263 std::string error_;
265 scoped_refptr<WebstoreStandaloneInstaller> installer_;
268 AppInstallHelper::AppInstallHelper() : success_(false) {}
270 AppInstallHelper::~AppInstallHelper() {}
272 WebstoreStandaloneInstaller::Callback AppInstallHelper::Callback() {
273 return base::Bind(&AppInstallHelper::OnAppInstallComplete,
274 base::Unretained(this));
277 void AppInstallHelper::BeginInstall(
278 Profile* profile,
279 const std::string& id,
280 bool show_prompt,
281 DoneCallback done_callback) {
282 done_callback_ = done_callback;
284 WebstoreStandaloneInstaller::Callback callback =
285 base::Bind(&AppInstallHelper::OnAppInstallComplete,
286 base::Unretained(this));
288 installer_ = CreateEphemeralAppInstaller(profile, id, callback);
289 if (installer_.get()) {
290 installer_->BeginInstall();
291 } else {
292 error_ = "Not a supported ephemeral app installation.";
293 done_callback_.Run();
297 void AppInstallHelper::OnAppInstallComplete(bool success,
298 const std::string& error,
299 webstore_install::Result result) {
300 success_ = success;
301 error_= error;
302 done_callback_.Run();
305 } // namespace
307 bool StartupHelper::InstallEphemeralApp(const CommandLine& cmd_line,
308 Profile* profile) {
309 std::string id =
310 cmd_line.GetSwitchValueASCII(switches::kInstallEphemeralAppFromWebstore);
311 if (!crx_file::id_util::IdIsValid(id)) {
312 LOG(ERROR) << "Invalid id for "
313 << switches::kInstallEphemeralAppFromWebstore << " : '" << id << "'";
314 return false;
317 AppInstallHelper helper;
318 base::RunLoop run_loop;
319 helper.BeginInstall(profile, id, true, run_loop.QuitClosure());
320 run_loop.Run();
322 if (!helper.success())
323 LOG(ERROR) << "InstallFromWebstore failed with error: " << helper.error();
324 return helper.success();
327 StartupHelper::~StartupHelper() {
328 if (pack_job_.get())
329 pack_job_->ClearClient();
332 } // namespace extensions