Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / extensions / startup_helper.cc
blob3719251609a821ff07956f375971a1f5182ca66a
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 "content/public/browser/browser_thread.h"
23 #include "content/public/browser/web_contents.h"
24 #include "extensions/common/extension.h"
25 #include "ipc/ipc_message.h"
27 using content::BrowserThread;
29 namespace {
31 void PrintPackExtensionMessage(const std::string& message) {
32 printf("%s\n", message.c_str());
35 } // namespace
37 namespace extensions {
39 StartupHelper::StartupHelper() : pack_job_succeeded_(false) {
40 ExtensionsClient::Set(ChromeExtensionsClient::GetInstance());
43 void StartupHelper::OnPackSuccess(
44 const base::FilePath& crx_path,
45 const base::FilePath& output_private_key_path) {
46 pack_job_succeeded_ = true;
47 PrintPackExtensionMessage(
48 base::UTF16ToUTF8(
49 PackExtensionJob::StandardSuccessMessage(crx_path,
50 output_private_key_path)));
53 void StartupHelper::OnPackFailure(const std::string& error_message,
54 ExtensionCreator::ErrorType type) {
55 PrintPackExtensionMessage(error_message);
58 bool StartupHelper::PackExtension(const CommandLine& cmd_line) {
59 if (!cmd_line.HasSwitch(switches::kPackExtension))
60 return false;
62 // Input Paths.
63 base::FilePath src_dir =
64 cmd_line.GetSwitchValuePath(switches::kPackExtension);
65 base::FilePath private_key_path;
66 if (cmd_line.HasSwitch(switches::kPackExtensionKey)) {
67 private_key_path = cmd_line.GetSwitchValuePath(switches::kPackExtensionKey);
70 // Launch a job to perform the packing on the file thread. Ignore warnings
71 // from the packing process. (e.g. Overwrite any existing crx file.)
72 pack_job_ = new PackExtensionJob(this, src_dir, private_key_path,
73 ExtensionCreator::kOverwriteCRX);
74 pack_job_->set_asynchronous(false);
75 pack_job_->Start();
77 return pack_job_succeeded_;
80 namespace {
82 class ValidateCrxHelper : public SandboxedUnpackerClient {
83 public:
84 ValidateCrxHelper(const base::FilePath& crx_file,
85 const base::FilePath& temp_dir,
86 base::RunLoop* run_loop)
87 : crx_file_(crx_file), temp_dir_(temp_dir), run_loop_(run_loop),
88 finished_(false), success_(false) {}
90 bool finished() { return finished_; }
91 bool success() { return success_; }
92 const base::string16& error() { return error_; }
94 void Start() {
95 BrowserThread::PostTask(BrowserThread::FILE,
96 FROM_HERE,
97 base::Bind(&ValidateCrxHelper::StartOnFileThread,
98 this));
101 protected:
102 virtual ~ValidateCrxHelper() {}
104 virtual void OnUnpackSuccess(const base::FilePath& temp_dir,
105 const base::FilePath& extension_root,
106 const base::DictionaryValue* original_manifest,
107 const Extension* extension,
108 const SkBitmap& install_icon) OVERRIDE {
109 finished_ = true;
110 success_ = true;
111 BrowserThread::PostTask(BrowserThread::UI,
112 FROM_HERE,
113 base::Bind(&ValidateCrxHelper::FinishOnUIThread,
114 this));
117 virtual void OnUnpackFailure(const base::string16& error) OVERRIDE {
118 finished_ = true;
119 success_ = false;
120 error_ = error;
121 BrowserThread::PostTask(BrowserThread::UI,
122 FROM_HERE,
123 base::Bind(&ValidateCrxHelper::FinishOnUIThread,
124 this));
127 void FinishOnUIThread() {
128 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
129 if (run_loop_->running())
130 run_loop_->Quit();
133 void StartOnFileThread() {
134 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
135 scoped_refptr<base::MessageLoopProxy> file_thread_proxy =
136 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE);
138 scoped_refptr<SandboxedUnpacker> unpacker(
139 new SandboxedUnpacker(crx_file_,
140 Manifest::INTERNAL,
141 0, /* no special creation flags */
142 temp_dir_,
143 file_thread_proxy.get(),
144 this));
145 unpacker->Start();
148 // The file being validated.
149 const base::FilePath& crx_file_;
151 // The temporary directory where the sandboxed unpacker will do work.
152 const base::FilePath& temp_dir_;
154 // Unowned pointer to a runloop, so our consumer can wait for us to finish.
155 base::RunLoop* run_loop_;
157 // Whether we're finished unpacking;
158 bool finished_;
160 // Whether the unpacking was successful.
161 bool success_;
163 // If the unpacking wasn't successful, this contains an error message.
164 base::string16 error_;
167 } // namespace
169 bool StartupHelper::ValidateCrx(const CommandLine& cmd_line,
170 std::string* error) {
171 CHECK(error);
172 base::FilePath path = cmd_line.GetSwitchValuePath(switches::kValidateCrx);
173 if (path.empty()) {
174 *error = base::StringPrintf("Empty path passed for %s",
175 switches::kValidateCrx);
176 return false;
178 base::ScopedTempDir temp_dir;
180 if (!temp_dir.CreateUniqueTempDir()) {
181 *error = std::string("Failed to create temp dir");
182 return false;
185 base::RunLoop run_loop;
186 scoped_refptr<ValidateCrxHelper> helper(
187 new ValidateCrxHelper(path, temp_dir.path(), &run_loop));
188 helper->Start();
189 if (!helper->finished())
190 run_loop.Run();
192 bool success = helper->success();
193 if (!success)
194 *error = base::UTF16ToUTF8(helper->error());
195 return success;
198 bool StartupHelper::UninstallExtension(const CommandLine& cmd_line,
199 Profile* profile) {
200 DCHECK(profile);
202 if (!cmd_line.HasSwitch(switches::kUninstallExtension))
203 return false;
205 ExtensionService* extension_service = profile->GetExtensionService();
206 if (!extension_service)
207 return false;
209 std::string extension_id = cmd_line.GetSwitchValueASCII(
210 switches::kUninstallExtension);
211 return ExtensionService::UninstallExtensionHelper(extension_service,
212 extension_id);
215 namespace {
217 class AppInstallHelper {
218 public:
219 // A callback for when the install process is done.
220 typedef base::Callback<void()> DoneCallback;
222 AppInstallHelper();
223 virtual ~AppInstallHelper();
224 bool success() { return success_; }
225 const std::string& error() { return error_; }
226 void BeginInstall(Profile* profile,
227 const std::string& id,
228 bool show_prompt,
229 DoneCallback callback);
231 private:
232 WebstoreStandaloneInstaller::Callback Callback();
233 void OnAppInstallComplete(bool success, const std::string& error);
235 DoneCallback done_callback_;
237 // These hold on to the result of the app install when it is complete.
238 bool success_;
239 std::string error_;
241 scoped_refptr<WebstoreStandaloneInstaller> installer_;
244 AppInstallHelper::AppInstallHelper() : success_(false) {}
246 AppInstallHelper::~AppInstallHelper() {}
248 WebstoreStandaloneInstaller::Callback AppInstallHelper::Callback() {
249 return base::Bind(&AppInstallHelper::OnAppInstallComplete,
250 base::Unretained(this));
253 void AppInstallHelper::BeginInstall(
254 Profile* profile,
255 const std::string& id,
256 bool show_prompt,
257 DoneCallback done_callback) {
258 done_callback_ = done_callback;
260 WebstoreStandaloneInstaller::Callback callback =
261 base::Bind(&AppInstallHelper::OnAppInstallComplete,
262 base::Unretained(this));
263 installer_ = new WebstoreStartupInstaller(
265 profile,
266 show_prompt,
267 callback);
268 installer_->BeginInstall();
271 void AppInstallHelper::OnAppInstallComplete(bool success,
272 const std::string& error) {
273 success_ = success;
274 error_= error;
275 done_callback_.Run();
278 void DeleteHelperAndRunCallback(AppInstallHelper* helper,
279 base::Callback<void()> callback) {
280 delete helper;
281 callback.Run();
284 } // namespace
286 bool StartupHelper::InstallFromWebstore(const CommandLine& cmd_line,
287 Profile* profile) {
288 std::string id = cmd_line.GetSwitchValueASCII(switches::kInstallFromWebstore);
289 if (!Extension::IdIsValid(id)) {
290 LOG(ERROR) << "Invalid id for " << switches::kInstallFromWebstore
291 << " : '" << id << "'";
292 return false;
295 AppInstallHelper helper;
296 helper.BeginInstall(profile, id,
297 !cmd_line.HasSwitch(switches::kForceAppMode),
298 base::MessageLoop::QuitWhenIdleClosure());
300 base::MessageLoop::current()->Run();
301 if (!helper.success())
302 LOG(ERROR) << "InstallFromWebstore failed with error: " << helper.error();
303 return helper.success();
306 void StartupHelper::LimitedInstallFromWebstore(
307 const CommandLine& cmd_line,
308 Profile* profile,
309 base::Callback<void()> done_callback) {
310 std::string id = WebStoreIdFromLimitedInstallCmdLine(cmd_line);
311 if (!Extension::IdIsValid(id)) {
312 LOG(ERROR) << "Invalid index for " << switches::kLimitedInstallFromWebstore;
313 done_callback.Run();
314 return;
317 AppInstallHelper* helper = new AppInstallHelper();
318 helper->BeginInstall(profile, id, false /*show_prompt*/,
319 base::Bind(&DeleteHelperAndRunCallback,
320 helper, done_callback));
323 std::string StartupHelper::WebStoreIdFromLimitedInstallCmdLine(
324 const CommandLine& cmd_line) {
325 std::string index = cmd_line.GetSwitchValueASCII(
326 switches::kLimitedInstallFromWebstore);
327 std::string id;
328 if (index == "1") {
329 id = "nckgahadagoaajjgafhacjanaoiihapd";
330 } else if (index == "2") {
331 id = "ecglahbcnmdpdciemllbhojghbkagdje";
333 return id;
336 StartupHelper::~StartupHelper() {
337 if (pack_job_.get())
338 pack_job_->ClearClient();
341 } // namespace extensions