Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / developer_private / developer_private_api.cc
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.
4
5 #include "chrome/browser/extensions/api/developer_private/developer_private_api.h"
6
7 #include "apps/app_load_service.h"
8 #include "apps/app_restore_service.h"
9 #include "apps/app_window.h"
10 #include "apps/app_window_registry.h"
11 #include "apps/saved_files_service.h"
12 #include "base/base64.h"
13 #include "base/bind.h"
14 #include "base/command_line.h"
15 #include "base/file_util.h"
16 #include "base/files/file_enumerator.h"
17 #include "base/i18n/file_util_icu.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/values.h"
21 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/devtools/devtools_window.h"
23 #include "chrome/browser/extensions/api/developer_private/developer_private_api_factory.h"
24 #include "chrome/browser/extensions/api/developer_private/entry_picker.h"
25 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
26 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
27 #include "chrome/browser/extensions/devtools_util.h"
28 #include "chrome/browser/extensions/extension_disabled_ui.h"
29 #include "chrome/browser/extensions/extension_error_reporter.h"
30 #include "chrome/browser/extensions/extension_service.h"
31 #include "chrome/browser/extensions/extension_util.h"
32 #include "chrome/browser/extensions/unpacked_installer.h"
33 #include "chrome/browser/extensions/updater/extension_updater.h"
34 #include "chrome/browser/platform_util.h"
35 #include "chrome/browser/profiles/profile.h"
36 #include "chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.h"
37 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
38 #include "chrome/browser/ui/chrome_select_file_policy.h"
39 #include "chrome/browser/ui/webui/extensions/extension_error_ui_util.h"
40 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
41 #include "chrome/common/extensions/api/developer_private.h"
42 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
43 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
44 #include "chrome/common/extensions/manifest_url_handler.h"
45 #include "chrome/common/url_constants.h"
46 #include "content/public/browser/browser_thread.h"
47 #include "content/public/browser/notification_service.h"
48 #include "content/public/browser/render_process_host.h"
49 #include "content/public/browser/render_view_host.h"
50 #include "content/public/browser/site_instance.h"
51 #include "content/public/browser/storage_partition.h"
52 #include "content/public/browser/web_contents.h"
53 #include "extensions/browser/extension_error.h"
54 #include "extensions/browser/extension_registry.h"
55 #include "extensions/browser/extension_system.h"
56 #include "extensions/browser/management_policy.h"
57 #include "extensions/browser/view_type_utils.h"
58 #include "extensions/common/constants.h"
59 #include "extensions/common/extension_resource.h"
60 #include "extensions/common/extension_set.h"
61 #include "extensions/common/install_warning.h"
62 #include "extensions/common/manifest_handlers/background_info.h"
63 #include "extensions/common/manifest_handlers/incognito_info.h"
64 #include "extensions/common/manifest_handlers/offline_enabled_info.h"
65 #include "extensions/common/switches.h"
66 #include "grit/chromium_strings.h"
67 #include "grit/generated_resources.h"
68 #include "grit/theme_resources.h"
69 #include "net/base/net_util.h"
70 #include "ui/base/l10n/l10n_util.h"
71 #include "ui/base/resource/resource_bundle.h"
72 #include "ui/base/webui/web_ui_util.h"
73 #include "webkit/browser/fileapi/external_mount_points.h"
74 #include "webkit/browser/fileapi/file_system_context.h"
75 #include "webkit/browser/fileapi/file_system_operation.h"
76 #include "webkit/browser/fileapi/file_system_operation_runner.h"
77 #include "webkit/common/blob/shareable_file_reference.h"
78
79 using apps::AppWindow;
80 using apps::AppWindowRegistry;
81 using content::RenderViewHost;
82
83 namespace extensions {
84
85 namespace developer_private = api::developer_private;
86
87 namespace {
88
89 const base::FilePath::CharType kUnpackedAppsFolder[]
90     = FILE_PATH_LITERAL("apps_target");
91
92 ExtensionUpdater* GetExtensionUpdater(Profile* profile) {
93     return profile->GetExtensionService()->updater();
94 }
95
96 GURL GetImageURLFromData(std::string contents) {
97   std::string contents_base64;
98   base::Base64Encode(contents, &contents_base64);
99
100   // TODO(dvh): make use of content::kDataScheme. Filed as crbug/297301.
101   const char kDataURLPrefix[] = "data:image;base64,";
102   return GURL(kDataURLPrefix + contents_base64);
103 }
104
105 GURL GetDefaultImageURL(developer_private::ItemType type) {
106   int icon_resource_id;
107   switch (type) {
108     case developer::ITEM_TYPE_LEGACY_PACKAGED_APP:
109     case developer::ITEM_TYPE_HOSTED_APP:
110     case developer::ITEM_TYPE_PACKAGED_APP:
111       icon_resource_id = IDR_APP_DEFAULT_ICON;
112       break;
113     default:
114       icon_resource_id = IDR_EXTENSION_DEFAULT_ICON;
115       break;
116   }
117
118   return GetImageURLFromData(
119       ResourceBundle::GetSharedInstance().GetRawDataResourceForScale(
120           icon_resource_id, ui::SCALE_FACTOR_100P).as_string());
121 }
122
123 // TODO(dvh): This code should be refactored and moved to
124 // extensions::ImageLoader. Also a resize should be performed to avoid
125 // potential huge URLs: crbug/297298.
126 GURL ToDataURL(const base::FilePath& path, developer_private::ItemType type) {
127   std::string contents;
128   if (path.empty() || !base::ReadFileToString(path, &contents))
129     return GetDefaultImageURL(type);
130
131   return GetImageURLFromData(contents);
132 }
133
134 std::string GetExtensionID(const RenderViewHost* render_view_host) {
135   if (!render_view_host->GetSiteInstance())
136     return std::string();
137
138   return render_view_host->GetSiteInstance()->GetSiteURL().host();
139 }
140
141 }  // namespace
142
143 namespace AllowFileAccess = api::developer_private::AllowFileAccess;
144 namespace AllowIncognito = api::developer_private::AllowIncognito;
145 namespace ChoosePath = api::developer_private::ChoosePath;
146 namespace Enable = api::developer_private::Enable;
147 namespace GetItemsInfo = api::developer_private::GetItemsInfo;
148 namespace Inspect = api::developer_private::Inspect;
149 namespace PackDirectory = api::developer_private::PackDirectory;
150 namespace Reload = api::developer_private::Reload;
151
152 DeveloperPrivateAPI* DeveloperPrivateAPI::Get(Profile* profile) {
153   return DeveloperPrivateAPIFactory::GetForProfile(profile);
154 }
155
156 DeveloperPrivateAPI::DeveloperPrivateAPI(Profile* profile) : profile_(profile) {
157   RegisterNotifications();
158 }
159
160 DeveloperPrivateEventRouter::DeveloperPrivateEventRouter(Profile* profile)
161     : profile_(profile) {
162   int types[] = {
163     chrome::NOTIFICATION_EXTENSION_INSTALLED,
164     chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
165     chrome::NOTIFICATION_EXTENSION_LOADED,
166     chrome::NOTIFICATION_EXTENSION_UNLOADED,
167     chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED,
168     chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED
169   };
170
171   CHECK(registrar_.IsEmpty());
172   for (size_t i = 0; i < arraysize(types); ++i) {
173     registrar_.Add(this,
174                    types[i],
175                    content::Source<Profile>(profile_));
176   }
177
178   ErrorConsole::Get(profile)->AddObserver(this);
179 }
180
181 DeveloperPrivateEventRouter::~DeveloperPrivateEventRouter() {
182   ErrorConsole::Get(profile_)->RemoveObserver(this);
183 }
184
185 void DeveloperPrivateEventRouter::AddExtensionId(
186     const std::string& extension_id) {
187   extension_ids_.insert(extension_id);
188 }
189
190 void DeveloperPrivateEventRouter::RemoveExtensionId(
191     const std::string& extension_id) {
192   extension_ids_.erase(extension_id);
193 }
194
195 void DeveloperPrivateEventRouter::Observe(
196     int type,
197     const content::NotificationSource& source,
198     const content::NotificationDetails& details) {
199   const char* event_name = NULL;
200   Profile* profile = content::Source<Profile>(source).ptr();
201   CHECK(profile);
202   CHECK(profile_->IsSameProfile(profile));
203   developer::EventData event_data;
204   const Extension* extension = NULL;
205
206   switch (type) {
207     case chrome::NOTIFICATION_EXTENSION_INSTALLED:
208       event_data.event_type = developer::EVENT_TYPE_INSTALLED;
209       extension =
210           content::Details<const InstalledExtensionInfo>(details)->extension;
211       break;
212     case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
213       event_data.event_type = developer::EVENT_TYPE_UNINSTALLED;
214       extension = content::Details<const Extension>(details).ptr();
215       break;
216     case chrome::NOTIFICATION_EXTENSION_LOADED:
217       event_data.event_type = developer::EVENT_TYPE_LOADED;
218       extension = content::Details<const Extension>(details).ptr();
219       break;
220     case chrome::NOTIFICATION_EXTENSION_UNLOADED:
221       event_data.event_type = developer::EVENT_TYPE_UNLOADED;
222       extension =
223           content::Details<const UnloadedExtensionInfo>(details)->extension;
224       break;
225     case chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED:
226       event_data.event_type = developer::EVENT_TYPE_VIEW_UNREGISTERED;
227       event_data.item_id = GetExtensionID(
228           content::Details<const RenderViewHost>(details).ptr());
229       break;
230     case chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED:
231       event_data.event_type = developer::EVENT_TYPE_VIEW_REGISTERED;
232       event_data.item_id = GetExtensionID(
233           content::Details<const RenderViewHost>(details).ptr());
234       break;
235     default:
236       NOTREACHED();
237       return;
238   }
239
240   if (extension)
241     event_data.item_id = extension->id();
242
243   scoped_ptr<base::ListValue> args(new base::ListValue());
244   args->Append(event_data.ToValue().release());
245
246   event_name = developer_private::OnItemStateChanged::kEventName;
247   scoped_ptr<Event> event(new Event(event_name, args.Pass()));
248   ExtensionSystem::Get(profile)->event_router()->BroadcastEvent(event.Pass());
249 }
250
251 void DeveloperPrivateEventRouter::OnErrorAdded(const ExtensionError* error) {
252   // We don't want to handle errors thrown by extensions subscribed to these
253   // events (currently only the Apps Developer Tool), because doing so risks
254   // entering a loop.
255   if (extension_ids_.find(error->extension_id()) != extension_ids_.end())
256     return;
257
258   developer::EventData event_data;
259   event_data.event_type = developer::EVENT_TYPE_ERROR_ADDED;
260   event_data.item_id = error->extension_id();
261
262   scoped_ptr<base::ListValue> args(new base::ListValue);
263   args->Append(event_data.ToValue().release());
264
265   ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(
266       scoped_ptr<Event>(new Event(
267           developer_private::OnItemStateChanged::kEventName, args.Pass())));
268 }
269
270 void DeveloperPrivateAPI::SetLastUnpackedDirectory(const base::FilePath& path) {
271   last_unpacked_directory_ = path;
272 }
273
274 void DeveloperPrivateAPI::RegisterNotifications() {
275   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
276       this, developer_private::OnItemStateChanged::kEventName);
277 }
278
279 DeveloperPrivateAPI::~DeveloperPrivateAPI() {}
280
281 void DeveloperPrivateAPI::Shutdown() {}
282
283 void DeveloperPrivateAPI::OnListenerAdded(
284     const EventListenerInfo& details) {
285   if (!developer_private_event_router_) {
286     developer_private_event_router_.reset(
287         new DeveloperPrivateEventRouter(profile_));
288   }
289
290   developer_private_event_router_->AddExtensionId(details.extension_id);
291 }
292
293 void DeveloperPrivateAPI::OnListenerRemoved(
294     const EventListenerInfo& details) {
295   if (!ExtensionSystem::Get(profile_)->event_router()->HasEventListener(
296            developer_private::OnItemStateChanged::kEventName)) {
297     developer_private_event_router_.reset(NULL);
298   } else {
299     developer_private_event_router_->RemoveExtensionId(details.extension_id);
300   }
301 }
302
303 namespace api {
304
305 bool DeveloperPrivateAutoUpdateFunction::RunImpl() {
306   ExtensionUpdater* updater = GetExtensionUpdater(GetProfile());
307   if (updater)
308     updater->CheckNow(ExtensionUpdater::CheckParams());
309   SetResult(new base::FundamentalValue(true));
310   return true;
311 }
312
313 DeveloperPrivateAutoUpdateFunction::~DeveloperPrivateAutoUpdateFunction() {}
314
315 scoped_ptr<developer::ItemInfo>
316 DeveloperPrivateGetItemsInfoFunction::CreateItemInfo(const Extension& item,
317                                                      bool item_is_enabled) {
318   scoped_ptr<developer::ItemInfo> info(new developer::ItemInfo());
319
320   ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
321   ExtensionService* service = system->extension_service();
322   ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile());
323
324   info->id = item.id();
325   info->name = item.name();
326   info->enabled = service->IsExtensionEnabled(info->id);
327   info->offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&item);
328   info->version = item.VersionString();
329   info->description = item.description();
330
331   if (item.is_app()) {
332     if (item.is_legacy_packaged_app())
333       info->type = developer::ITEM_TYPE_LEGACY_PACKAGED_APP;
334     else if (item.is_hosted_app())
335       info->type = developer::ITEM_TYPE_HOSTED_APP;
336     else if (item.is_platform_app())
337       info->type = developer::ITEM_TYPE_PACKAGED_APP;
338     else
339       NOTREACHED();
340   } else if (item.is_theme()) {
341     info->type = developer::ITEM_TYPE_THEME;
342   } else if (item.is_extension()) {
343     info->type = developer::ITEM_TYPE_EXTENSION;
344   } else {
345     NOTREACHED();
346   }
347
348   if (Manifest::IsUnpackedLocation(item.location())) {
349     info->path.reset(
350         new std::string(base::UTF16ToUTF8(item.path().LossyDisplayName())));
351     // If the ErrorConsole is enabled, get the errors for the extension and add
352     // them to the list. Otherwise, use the install warnings (using both is
353     // redundant).
354     ErrorConsole* error_console = ErrorConsole::Get(GetProfile());
355     if (error_console->enabled()) {
356       const ErrorList& errors = error_console->GetErrorsForExtension(item.id());
357       if (!errors.empty()) {
358         for (ErrorList::const_iterator iter = errors.begin();
359              iter != errors.end();
360              ++iter) {
361           switch ((*iter)->type()) {
362             case ExtensionError::MANIFEST_ERROR:
363               info->manifest_errors.push_back(
364                   make_linked_ptr((*iter)->ToValue().release()));
365               break;
366             case ExtensionError::RUNTIME_ERROR: {
367               const RuntimeError* error =
368                   static_cast<const RuntimeError*>(*iter);
369               scoped_ptr<base::DictionaryValue> value = error->ToValue();
370               bool can_inspect = content::RenderViewHost::FromID(
371                                      error->render_process_id(),
372                                      error->render_view_id()) != NULL;
373               value->SetBoolean("canInspect", can_inspect);
374               info->runtime_errors.push_back(make_linked_ptr(value.release()));
375               break;
376             }
377           }
378         }
379       }
380     } else {
381       for (std::vector<extensions::InstallWarning>::const_iterator it =
382                item.install_warnings().begin();
383            it != item.install_warnings().end();
384            ++it) {
385         scoped_ptr<developer::InstallWarning> warning(
386             new developer::InstallWarning);
387         warning->message = it->message;
388         info->install_warnings.push_back(make_linked_ptr(warning.release()));
389       }
390     }
391   }
392
393   info->incognito_enabled = util::IsIncognitoEnabled(item.id(), GetProfile());
394   info->wants_file_access = item.wants_file_access();
395   info->allow_file_access = util::AllowFileAccess(item.id(), GetProfile());
396   info->allow_reload = Manifest::IsUnpackedLocation(item.location());
397   info->is_unpacked = Manifest::IsUnpackedLocation(item.location());
398   info->terminated = registry->terminated_extensions().Contains(item.id());
399   info->allow_incognito = item.can_be_incognito_enabled();
400
401   info->homepage_url.reset(new std::string(
402       ManifestURL::GetHomepageURL(&item).spec()));
403   if (!ManifestURL::GetOptionsPage(&item).is_empty()) {
404     info->options_url.reset(
405         new std::string(ManifestURL::GetOptionsPage(&item).spec()));
406   }
407
408   if (!ManifestURL::GetUpdateURL(&item).is_empty()) {
409     info->update_url.reset(
410         new std::string(ManifestURL::GetUpdateURL(&item).spec()));
411   }
412
413   if (item.is_app()) {
414     info->app_launch_url.reset(new std::string(
415         extensions::AppLaunchInfo::GetFullLaunchURL(&item).spec()));
416   }
417
418   info->may_disable = system->management_policy()->
419       UserMayModifySettings(&item, NULL);
420   info->is_app = item.is_app();
421   info->views = GetInspectablePagesForExtension(&item, item_is_enabled);
422
423   return info.Pass();
424 }
425
426 void DeveloperPrivateGetItemsInfoFunction::GetIconsOnFileThread(
427     ItemInfoList item_list,
428     const std::map<std::string, ExtensionResource> idToIcon) {
429   for (ItemInfoList::iterator iter = item_list.begin();
430        iter != item_list.end(); ++iter) {
431     developer_private::ItemInfo* info = iter->get();
432     std::map<std::string, ExtensionResource>::const_iterator resource_ptr
433         = idToIcon.find(info->id);
434     if (resource_ptr != idToIcon.end()) {
435       info->icon_url =
436           ToDataURL(resource_ptr->second.GetFilePath(), info->type).spec();
437     }
438   }
439
440   results_ = developer::GetItemsInfo::Results::Create(item_list);
441   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
442       base::Bind(&DeveloperPrivateGetItemsInfoFunction::SendResponse,
443                  this,
444                  true));
445 }
446
447 void DeveloperPrivateGetItemsInfoFunction::
448     GetInspectablePagesForExtensionProcess(
449         const Extension* extension,
450         const std::set<content::RenderViewHost*>& views,
451         ItemInspectViewList* result) {
452   bool has_generated_background_page =
453       BackgroundInfo::HasGeneratedBackgroundPage(extension);
454   for (std::set<content::RenderViewHost*>::const_iterator iter = views.begin();
455        iter != views.end(); ++iter) {
456     content::RenderViewHost* host = *iter;
457     content::WebContents* web_contents =
458         content::WebContents::FromRenderViewHost(host);
459     ViewType host_type = GetViewType(web_contents);
460     if (VIEW_TYPE_EXTENSION_POPUP == host_type ||
461         VIEW_TYPE_EXTENSION_DIALOG == host_type)
462       continue;
463
464     content::RenderProcessHost* process = host->GetProcess();
465     bool is_background_page =
466         (web_contents->GetURL() == BackgroundInfo::GetBackgroundURL(extension));
467     result->push_back(constructInspectView(
468         web_contents->GetURL(),
469         process->GetID(),
470         host->GetRoutingID(),
471         process->GetBrowserContext()->IsOffTheRecord(),
472         is_background_page && has_generated_background_page));
473   }
474 }
475
476 void DeveloperPrivateGetItemsInfoFunction::GetAppWindowPagesForExtensionProfile(
477     const Extension* extension,
478     ItemInspectViewList* result) {
479   AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile());
480   if (!registry) return;
481
482   const AppWindowRegistry::AppWindowList windows =
483       registry->GetAppWindowsForApp(extension->id());
484
485   bool has_generated_background_page =
486       BackgroundInfo::HasGeneratedBackgroundPage(extension);
487   for (AppWindowRegistry::const_iterator it = windows.begin();
488        it != windows.end();
489        ++it) {
490     content::WebContents* web_contents = (*it)->web_contents();
491     RenderViewHost* host = web_contents->GetRenderViewHost();
492     content::RenderProcessHost* process = host->GetProcess();
493     bool is_background_page =
494         (web_contents->GetURL() == BackgroundInfo::GetBackgroundURL(extension));
495     result->push_back(constructInspectView(
496         web_contents->GetURL(),
497         process->GetID(),
498         host->GetRoutingID(),
499         process->GetBrowserContext()->IsOffTheRecord(),
500         is_background_page && has_generated_background_page));
501   }
502 }
503
504 linked_ptr<developer::ItemInspectView> DeveloperPrivateGetItemsInfoFunction::
505     constructInspectView(
506         const GURL& url,
507         int render_process_id,
508         int render_view_id,
509         bool incognito,
510         bool generated_background_page) {
511   linked_ptr<developer::ItemInspectView> view(new developer::ItemInspectView());
512
513   if (url.scheme() == kExtensionScheme) {
514     // No leading slash.
515     view->path = url.path().substr(1);
516   } else {
517     // For live pages, use the full URL.
518     view->path = url.spec();
519   }
520
521   view->render_process_id = render_process_id;
522   view->render_view_id = render_view_id;
523   view->incognito = incognito;
524   view->generated_background_page = generated_background_page;
525   return view;
526 }
527
528 ItemInspectViewList DeveloperPrivateGetItemsInfoFunction::
529     GetInspectablePagesForExtension(
530         const Extension* extension,
531         bool extension_is_enabled) {
532
533   ItemInspectViewList result;
534   // Get the extension process's active views.
535   extensions::ProcessManager* process_manager =
536       ExtensionSystem::Get(GetProfile())->process_manager();
537   GetInspectablePagesForExtensionProcess(
538       extension,
539       process_manager->GetRenderViewHostsForExtension(extension->id()),
540       &result);
541
542   // Get app window views
543   GetAppWindowPagesForExtensionProfile(extension, &result);
544
545   // Include a link to start the lazy background page, if applicable.
546   if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
547       extension_is_enabled &&
548       !process_manager->GetBackgroundHostForExtension(extension->id())) {
549     result.push_back(constructInspectView(
550         BackgroundInfo::GetBackgroundURL(extension),
551         -1,
552         -1,
553         false,
554         BackgroundInfo::HasGeneratedBackgroundPage(extension)));
555   }
556
557   ExtensionService* service = GetProfile()->GetExtensionService();
558   // Repeat for the incognito process, if applicable. Don't try to get
559   // app windows for incognito process.
560   if (service->profile()->HasOffTheRecordProfile() &&
561       IncognitoInfo::IsSplitMode(extension)) {
562     process_manager = ExtensionSystem::Get(
563         service->profile()->GetOffTheRecordProfile())->process_manager();
564     GetInspectablePagesForExtensionProcess(
565         extension,
566         process_manager->GetRenderViewHostsForExtension(extension->id()),
567         &result);
568
569     if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
570         extension_is_enabled &&
571         !process_manager->GetBackgroundHostForExtension(extension->id())) {
572     result.push_back(constructInspectView(
573         BackgroundInfo::GetBackgroundURL(extension),
574         -1,
575         -1,
576         false,
577         BackgroundInfo::HasGeneratedBackgroundPage(extension)));
578     }
579   }
580
581   return result;
582 }
583
584 bool DeveloperPrivateGetItemsInfoFunction::RunImpl() {
585   scoped_ptr<developer::GetItemsInfo::Params> params(
586       developer::GetItemsInfo::Params::Create(*args_));
587   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
588
589   bool include_disabled = params->include_disabled;
590   bool include_terminated = params->include_terminated;
591
592   extensions::ExtensionSet items;
593
594   ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile());
595
596   items.InsertAll(registry->enabled_extensions());
597
598   if (include_disabled) {
599     items.InsertAll(registry->disabled_extensions());
600   }
601
602   if (include_terminated) {
603     items.InsertAll(registry->terminated_extensions());
604   }
605
606   ExtensionService* service =
607       ExtensionSystem::Get(GetProfile())->extension_service();
608   std::map<std::string, ExtensionResource> id_to_icon;
609   ItemInfoList item_list;
610
611   for (extensions::ExtensionSet::const_iterator iter = items.begin();
612        iter != items.end(); ++iter) {
613     const Extension& item = *iter->get();
614
615     ExtensionResource item_resource =
616         IconsInfo::GetIconResource(&item,
617                                    extension_misc::EXTENSION_ICON_MEDIUM,
618                                    ExtensionIconSet::MATCH_BIGGER);
619     id_to_icon[item.id()] = item_resource;
620
621     // Don't show component extensions and invisible apps.
622     if (item.ShouldNotBeVisible())
623       continue;
624
625     item_list.push_back(make_linked_ptr<developer::ItemInfo>(
626         CreateItemInfo(
627             item, service->IsExtensionEnabled(item.id())).release()));
628   }
629
630   content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
631       base::Bind(&DeveloperPrivateGetItemsInfoFunction::GetIconsOnFileThread,
632                  this,
633                  item_list,
634                  id_to_icon));
635
636   return true;
637 }
638
639 DeveloperPrivateGetItemsInfoFunction::~DeveloperPrivateGetItemsInfoFunction() {}
640
641 bool DeveloperPrivateAllowFileAccessFunction::RunImpl() {
642   scoped_ptr<AllowFileAccess::Params> params(
643       AllowFileAccess::Params::Create(*args_));
644   EXTENSION_FUNCTION_VALIDATE(params.get());
645
646   EXTENSION_FUNCTION_VALIDATE(user_gesture_);
647
648   ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
649   ManagementPolicy* management_policy = system->management_policy();
650   ExtensionService* service = GetProfile()->GetExtensionService();
651   const Extension* extension = service->GetInstalledExtension(params->item_id);
652   bool result = true;
653
654   if (!extension) {
655     result = false;
656   } else if (!management_policy->UserMayModifySettings(extension, NULL)) {
657     LOG(ERROR) << "Attempt to change allow file access of an extension that "
658                << "non-usermanagable was made. Extension id : "
659                << extension->id();
660     result = false;
661   } else {
662     util::SetAllowFileAccess(extension->id(), GetProfile(), params->allow);
663     result = true;
664   }
665
666   return result;
667 }
668
669 DeveloperPrivateAllowFileAccessFunction::
670     ~DeveloperPrivateAllowFileAccessFunction() {}
671
672 bool DeveloperPrivateAllowIncognitoFunction::RunImpl() {
673   scoped_ptr<AllowIncognito::Params> params(
674       AllowIncognito::Params::Create(*args_));
675   EXTENSION_FUNCTION_VALIDATE(params.get());
676
677   ExtensionService* service = GetProfile()->GetExtensionService();
678   const Extension* extension = service->GetInstalledExtension(params->item_id);
679   bool result = true;
680
681   if (!extension)
682     result = false;
683   else
684     util::SetIsIncognitoEnabled(extension->id(), GetProfile(), params->allow);
685
686   return result;
687 }
688
689 DeveloperPrivateAllowIncognitoFunction::
690     ~DeveloperPrivateAllowIncognitoFunction() {}
691
692
693 bool DeveloperPrivateReloadFunction::RunImpl() {
694   scoped_ptr<Reload::Params> params(Reload::Params::Create(*args_));
695   EXTENSION_FUNCTION_VALIDATE(params.get());
696
697   ExtensionService* service = GetProfile()->GetExtensionService();
698   CHECK(!params->item_id.empty());
699   service->ReloadExtension(params->item_id);
700   return true;
701 }
702
703 bool DeveloperPrivateShowPermissionsDialogFunction::RunImpl() {
704   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id_));
705   ExtensionService* service = GetProfile()->GetExtensionService();
706   CHECK(!extension_id_.empty());
707   AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile());
708   DCHECK(registry);
709   AppWindow* app_window =
710       registry->GetAppWindowForRenderViewHost(render_view_host());
711   prompt_.reset(new ExtensionInstallPrompt(app_window->web_contents()));
712   const Extension* extension = service->GetInstalledExtension(extension_id_);
713
714   if (!extension)
715     return false;
716
717   // Released by InstallUIAbort or InstallUIProceed.
718   AddRef();
719   std::vector<base::FilePath> retained_file_paths;
720   if (extension->HasAPIPermission(extensions::APIPermission::kFileSystem)) {
721     std::vector<apps::SavedFileEntry> retained_file_entries =
722         apps::SavedFilesService::Get(GetProfile())
723             ->GetAllFileEntries(extension_id_);
724     for (size_t i = 0; i < retained_file_entries.size(); i++) {
725       retained_file_paths.push_back(retained_file_entries[i].path);
726     }
727   }
728   prompt_->ReviewPermissions(this, extension, retained_file_paths);
729   return true;
730 }
731
732 DeveloperPrivateReloadFunction::~DeveloperPrivateReloadFunction() {}
733
734 // This is called when the user clicks "Revoke File Access."
735 void DeveloperPrivateShowPermissionsDialogFunction::InstallUIProceed() {
736   apps::SavedFilesService::Get(GetProfile())
737       ->ClearQueue(GetProfile()->GetExtensionService()->GetExtensionById(
738             extension_id_, true));
739   if (apps::AppRestoreService::Get(GetProfile())
740           ->IsAppRestorable(extension_id_))
741     apps::AppLoadService::Get(GetProfile())->RestartApplication(extension_id_);
742   SendResponse(true);
743   Release();
744 }
745
746 void DeveloperPrivateShowPermissionsDialogFunction::InstallUIAbort(
747     bool user_initiated) {
748   SendResponse(true);
749   Release();
750 }
751
752 DeveloperPrivateShowPermissionsDialogFunction::
753     DeveloperPrivateShowPermissionsDialogFunction() {}
754
755 DeveloperPrivateShowPermissionsDialogFunction::
756     ~DeveloperPrivateShowPermissionsDialogFunction() {}
757
758 DeveloperPrivateEnableFunction::DeveloperPrivateEnableFunction() {}
759
760 bool DeveloperPrivateEnableFunction::RunImpl() {
761   scoped_ptr<Enable::Params> params(Enable::Params::Create(*args_));
762   EXTENSION_FUNCTION_VALIDATE(params.get());
763
764   std::string extension_id = params->item_id;
765
766   ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
767   ManagementPolicy* policy = system->management_policy();
768   ExtensionService* service = GetProfile()->GetExtensionService();
769
770   const Extension* extension = service->GetInstalledExtension(extension_id);
771   if (!extension) {
772     LOG(ERROR) << "Did not find extension with id " << extension_id;
773     return false;
774   }
775   bool enable = params->enable;
776   if (!policy->UserMayModifySettings(extension, NULL) ||
777       (!enable && policy->MustRemainEnabled(extension, NULL)) ||
778       (enable && policy->MustRemainDisabled(extension, NULL, NULL))) {
779     LOG(ERROR) << "Attempt to change enable state denied by management policy. "
780                << "Extension id: " << extension_id.c_str();
781     return false;
782   }
783
784   if (enable) {
785     ExtensionPrefs* prefs = service->extension_prefs();
786     if (prefs->DidExtensionEscalatePermissions(extension_id)) {
787       AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile());
788       CHECK(registry);
789       AppWindow* app_window =
790           registry->GetAppWindowForRenderViewHost(render_view_host());
791       if (!app_window) {
792         return false;
793       }
794
795       ShowExtensionDisabledDialog(
796           service, app_window->web_contents(), extension);
797     } else if ((prefs->GetDisableReasons(extension_id) &
798                   Extension::DISABLE_UNSUPPORTED_REQUIREMENT) &&
799                !requirements_checker_.get()) {
800       // Recheck the requirements.
801       scoped_refptr<const Extension> extension =
802           service->GetExtensionById(extension_id,
803                                      true );// include_disabled
804       requirements_checker_.reset(new RequirementsChecker);
805       // Released by OnRequirementsChecked.
806       AddRef();
807       requirements_checker_->Check(
808           extension,
809           base::Bind(&DeveloperPrivateEnableFunction::OnRequirementsChecked,
810                      this, extension_id));
811     } else {
812       service->EnableExtension(extension_id);
813
814       // Make sure any browser action contained within it is not hidden.
815       ExtensionActionAPI::SetBrowserActionVisibility(
816           prefs, extension->id(), true);
817     }
818   } else {
819     service->DisableExtension(extension_id, Extension::DISABLE_USER_ACTION);
820   }
821   return true;
822 }
823
824 void DeveloperPrivateEnableFunction::OnRequirementsChecked(
825     std::string extension_id,
826     std::vector<std::string> requirements_errors) {
827   if (requirements_errors.empty()) {
828     ExtensionService* service = GetProfile()->GetExtensionService();
829     service->EnableExtension(extension_id);
830   } else {
831     ExtensionErrorReporter::GetInstance()->ReportError(
832         base::UTF8ToUTF16(JoinString(requirements_errors, ' ')),
833         true /* be noisy */);
834   }
835   Release();
836 }
837
838 DeveloperPrivateEnableFunction::~DeveloperPrivateEnableFunction() {}
839
840 bool DeveloperPrivateInspectFunction::RunImpl() {
841   scoped_ptr<developer::Inspect::Params> params(
842       developer::Inspect::Params::Create(*args_));
843   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
844   const developer::InspectOptions& options = params->options;
845
846   int render_process_id;
847   base::StringToInt(options.render_process_id, &render_process_id);
848
849   if (render_process_id == -1) {
850     // This is a lazy background page. Identify if it is a normal
851     // or incognito background page.
852     ExtensionService* service = GetProfile()->GetExtensionService();
853     if (options.incognito)
854       service = ExtensionSystem::Get(
855           service->profile()->GetOffTheRecordProfile())->extension_service();
856     const Extension* extension = service->extensions()->GetByID(
857         options.extension_id);
858     DCHECK(extension);
859     // Wakes up the background page and  opens the inspect window.
860     devtools_util::InspectBackgroundPage(extension, GetProfile());
861     return false;
862   }
863
864   int render_view_id;
865   base::StringToInt(options.render_view_id, &render_view_id);
866   content::RenderViewHost* host = content::RenderViewHost::FromID(
867       render_process_id, render_view_id);
868
869   if (!host) {
870     // This can happen if the host has gone away since the page was displayed.
871     return false;
872   }
873
874   DevToolsWindow::OpenDevToolsWindow(host);
875   return true;
876 }
877
878 DeveloperPrivateInspectFunction::~DeveloperPrivateInspectFunction() {}
879
880 bool DeveloperPrivateLoadUnpackedFunction::RunImpl() {
881   base::string16 select_title =
882       l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY);
883
884   // Balanced in FileSelected / FileSelectionCanceled.
885   AddRef();
886   bool result = ShowPicker(
887       ui::SelectFileDialog::SELECT_FOLDER,
888       DeveloperPrivateAPI::Get(GetProfile())->GetLastUnpackedDirectory(),
889       select_title,
890       ui::SelectFileDialog::FileTypeInfo(),
891       0);
892   return result;
893 }
894
895 void DeveloperPrivateLoadUnpackedFunction::FileSelected(
896     const base::FilePath& path) {
897   ExtensionService* service = GetProfile()->GetExtensionService();
898   UnpackedInstaller::Create(service)->Load(path);
899   DeveloperPrivateAPI::Get(GetProfile())->SetLastUnpackedDirectory(path);
900   SendResponse(true);
901   Release();
902 }
903
904 void DeveloperPrivateLoadUnpackedFunction::FileSelectionCanceled() {
905   SendResponse(false);
906   Release();
907 }
908
909 bool DeveloperPrivateChooseEntryFunction::ShowPicker(
910     ui::SelectFileDialog::Type picker_type,
911     const base::FilePath& last_directory,
912     const base::string16& select_title,
913     const ui::SelectFileDialog::FileTypeInfo& info,
914     int file_type_index) {
915   AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile());
916   DCHECK(registry);
917   AppWindow* app_window =
918       registry->GetAppWindowForRenderViewHost(render_view_host());
919   if (!app_window) {
920     return false;
921   }
922
923   // The entry picker will hold a reference to this function instance,
924   // and subsequent sending of the function response) until the user has
925   // selected a file or cancelled the picker. At that point, the picker will
926   // delete itself.
927   new EntryPicker(this,
928                   app_window->web_contents(),
929                   picker_type,
930                   last_directory,
931                   select_title,
932                   info,
933                   file_type_index);
934   return true;
935 }
936
937 bool DeveloperPrivateChooseEntryFunction::RunImpl() { return false; }
938
939 DeveloperPrivateChooseEntryFunction::~DeveloperPrivateChooseEntryFunction() {}
940
941 void DeveloperPrivatePackDirectoryFunction::OnPackSuccess(
942     const base::FilePath& crx_file,
943     const base::FilePath& pem_file) {
944   developer::PackDirectoryResponse response;
945   response.message = base::UTF16ToUTF8(
946       PackExtensionJob::StandardSuccessMessage(crx_file, pem_file));
947   response.status = developer::PACK_STATUS_SUCCESS;
948   results_ = developer::PackDirectory::Results::Create(response);
949   SendResponse(true);
950   Release();
951 }
952
953 void DeveloperPrivatePackDirectoryFunction::OnPackFailure(
954     const std::string& error,
955     ExtensionCreator::ErrorType error_type) {
956   developer::PackDirectoryResponse response;
957   response.message = error;
958   if (error_type == ExtensionCreator::kCRXExists) {
959     response.item_path = item_path_str_;
960     response.pem_path = key_path_str_;
961     response.override_flags = ExtensionCreator::kOverwriteCRX;
962     response.status = developer::PACK_STATUS_WARNING;
963   } else {
964     response.status = developer::PACK_STATUS_ERROR;
965   }
966   results_ = developer::PackDirectory::Results::Create(response);
967   SendResponse(true);
968   Release();
969 }
970
971 bool DeveloperPrivatePackDirectoryFunction::RunImpl() {
972   scoped_ptr<PackDirectory::Params> params(
973       PackDirectory::Params::Create(*args_));
974   EXTENSION_FUNCTION_VALIDATE(params.get());
975
976   int flags = params->flags;
977   item_path_str_ = params->path;
978   key_path_str_ = params->private_key_path;
979
980   base::FilePath root_directory =
981       base::FilePath::FromUTF8Unsafe(item_path_str_);
982
983   base::FilePath key_file = base::FilePath::FromUTF8Unsafe(key_path_str_);
984
985   developer::PackDirectoryResponse response;
986   if (root_directory.empty()) {
987     if (item_path_str_.empty())
988       response.message = l10n_util::GetStringUTF8(
989           IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED);
990     else
991       response.message = l10n_util::GetStringUTF8(
992           IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID);
993
994     response.status = developer::PACK_STATUS_ERROR;
995     results_ = developer::PackDirectory::Results::Create(response);
996     SendResponse(true);
997     return true;
998   }
999
1000   if (!key_path_str_.empty() && key_file.empty()) {
1001     response.message = l10n_util::GetStringUTF8(
1002         IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID);
1003     response.status = developer::PACK_STATUS_ERROR;
1004     results_ = developer::PackDirectory::Results::Create(response);
1005     SendResponse(true);
1006     return true;
1007   }
1008
1009   // Balanced in OnPackSuccess / OnPackFailure.
1010   AddRef();
1011
1012   pack_job_ = new PackExtensionJob(this, root_directory, key_file, flags);
1013   pack_job_->Start();
1014   return true;
1015 }
1016
1017 DeveloperPrivatePackDirectoryFunction::DeveloperPrivatePackDirectoryFunction()
1018 {}
1019
1020 DeveloperPrivatePackDirectoryFunction::~DeveloperPrivatePackDirectoryFunction()
1021 {}
1022
1023 DeveloperPrivateLoadUnpackedFunction::~DeveloperPrivateLoadUnpackedFunction() {}
1024
1025 bool DeveloperPrivateLoadDirectoryFunction::RunImpl() {
1026   // TODO(grv) : add unittests.
1027   std::string directory_url_str;
1028   std::string filesystem_name;
1029   std::string filesystem_path;
1030
1031   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name));
1032   EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path));
1033   EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &directory_url_str));
1034
1035   // Directory url is non empty only for syncfilesystem.
1036   if (directory_url_str != "") {
1037
1038     context_ = content::BrowserContext::GetStoragePartition(
1039         GetProfile(), render_view_host()->GetSiteInstance())
1040                    ->GetFileSystemContext();
1041
1042     fileapi::FileSystemURL directory_url =
1043         context_->CrackURL(GURL(directory_url_str));
1044
1045     if (!directory_url.is_valid() && directory_url.type() ==
1046         fileapi::kFileSystemTypeSyncable) {
1047       SetError("DirectoryEntry of unsupported filesystem.");
1048       return false;
1049     }
1050
1051     size_t pos = 0;
1052     // Parse the project directory name from the project url. The project url is
1053     // expected to have project name as the suffix.
1054     if ((pos = directory_url_str.rfind("/")) == std::string::npos) {
1055       SetError("Invalid Directory entry.");
1056       return false;
1057     }
1058
1059     std::string project_name;
1060     project_name = directory_url_str.substr(pos + 1);
1061     project_base_url_ = directory_url_str.substr(0, pos + 1);
1062
1063     base::FilePath project_path(GetProfile()->GetPath());
1064     project_path = project_path.Append(kUnpackedAppsFolder);
1065     project_path = project_path.Append(
1066         base::FilePath::FromUTF8Unsafe(project_name));
1067
1068     project_base_path_ = project_path;
1069
1070     content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
1071         base::Bind(&DeveloperPrivateLoadDirectoryFunction::
1072                        ClearExistingDirectoryContent,
1073                    this,
1074                    project_base_path_));
1075   } else {
1076
1077     // Check if the DirecotryEntry is the instace of chrome filesystem..
1078     if (!app_file_handler_util::ValidateFileEntryAndGetPath(filesystem_name,
1079                                                             filesystem_path,
1080                                                             render_view_host_,
1081                                                             &project_base_path_,
1082                                                             &error_))
1083     return false;
1084
1085     Load();
1086   }
1087
1088   return true;
1089 }
1090
1091 void DeveloperPrivateLoadDirectoryFunction::Load() {
1092
1093   ExtensionService* service = GetProfile()->GetExtensionService();
1094   UnpackedInstaller::Create(service)->Load(project_base_path_);
1095
1096   // TODO(grv) : The unpacked installer should fire an event when complete
1097   // and return the extension_id.
1098   SetResult(new base::StringValue("-1"));
1099   SendResponse(true);
1100 }
1101
1102 void DeveloperPrivateLoadDirectoryFunction::ClearExistingDirectoryContent(
1103     const base::FilePath& project_path) {
1104
1105   // Clear the project directory before copying new files.
1106   base::DeleteFile(project_path, true/*recursive*/);
1107
1108   pending_copy_operations_count_ = 1;
1109
1110   content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
1111       base::Bind(&DeveloperPrivateLoadDirectoryFunction::
1112                  ReadSyncFileSystemDirectory,
1113                  this, project_path, project_path.BaseName()));
1114 }
1115
1116 void DeveloperPrivateLoadDirectoryFunction::ReadSyncFileSystemDirectory(
1117     const base::FilePath& project_path,
1118     const base::FilePath& destination_path) {
1119
1120   current_path_ = context_->CrackURL(GURL(project_base_url_)).path();
1121
1122   GURL project_url = GURL(project_base_url_ + destination_path.MaybeAsASCII());
1123
1124   fileapi::FileSystemURL url = context_->CrackURL(project_url);
1125
1126   context_->operation_runner()->ReadDirectory(
1127       url, base::Bind(&DeveloperPrivateLoadDirectoryFunction::
1128                       ReadSyncFileSystemDirectoryCb,
1129                       this, project_path, destination_path));
1130 }
1131
1132 void DeveloperPrivateLoadDirectoryFunction::ReadSyncFileSystemDirectoryCb(
1133     const base::FilePath& project_path,
1134     const base::FilePath& destination_path,
1135     base::File::Error status,
1136     const fileapi::FileSystemOperation::FileEntryList& file_list,
1137     bool has_more) {
1138
1139   if (status != base::File::FILE_OK) {
1140     DLOG(ERROR) << "Error in copying files from sync filesystem.";
1141     return;
1142   }
1143
1144   // We add 1 to the pending copy operations for both files and directories. We
1145   // release the directory copy operation once all the files under the directory
1146   // are added for copying. We do that to ensure that pendingCopyOperationsCount
1147   // does not become zero before all copy operations are finished.
1148   // In case the directory happens to be executing the last copy operation it
1149   // will call SendResponse to send the response to the API. The pending copy
1150   // operations of files are released by the CopyFile function.
1151   pending_copy_operations_count_ += file_list.size();
1152
1153   for (size_t i = 0; i < file_list.size(); ++i) {
1154     if (file_list[i].is_directory) {
1155       ReadSyncFileSystemDirectory(project_path.Append(file_list[i].name),
1156                                   destination_path.Append(file_list[i].name));
1157       continue;
1158     }
1159
1160     std::string origin_url(
1161         Extension::GetBaseURLFromExtensionId(extension_id()).spec());
1162     fileapi::FileSystemURL url(sync_file_system::CreateSyncableFileSystemURL(
1163         GURL(origin_url),
1164         current_path_.Append(destination_path.Append(file_list[i].name))));
1165     base::FilePath target_path = project_path;
1166     target_path = target_path.Append(file_list[i].name);
1167
1168     context_->operation_runner()->CreateSnapshotFile(
1169         url,
1170         base::Bind(&DeveloperPrivateLoadDirectoryFunction::SnapshotFileCallback,
1171             this,
1172             target_path));
1173
1174   }
1175
1176   // Directory copy operation released here.
1177   pending_copy_operations_count_--;
1178
1179   if (!pending_copy_operations_count_) {
1180     content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
1181         base::Bind(&DeveloperPrivateLoadDirectoryFunction::SendResponse,
1182                    this,
1183                    success_));
1184   }
1185 }
1186
1187 void DeveloperPrivateLoadDirectoryFunction::SnapshotFileCallback(
1188     const base::FilePath& target_path,
1189     base::File::Error result,
1190     const base::File::Info& file_info,
1191     const base::FilePath& src_path,
1192     const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) {
1193   if (result != base::File::FILE_OK) {
1194     SetError("Error in copying files from sync filesystem.");
1195     success_ = false;
1196     return;
1197   }
1198
1199   content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
1200       base::Bind(&DeveloperPrivateLoadDirectoryFunction::CopyFile,
1201                  this,
1202                  src_path,
1203                  target_path));
1204 }
1205
1206 void DeveloperPrivateLoadDirectoryFunction::CopyFile(
1207     const base::FilePath& src_path,
1208     const base::FilePath& target_path) {
1209   if (!base::CreateDirectory(target_path.DirName())) {
1210     SetError("Error in copying files from sync filesystem.");
1211     success_ = false;
1212   }
1213
1214   if (success_)
1215     base::CopyFile(src_path, target_path);
1216
1217   CHECK(pending_copy_operations_count_ > 0);
1218   pending_copy_operations_count_--;
1219
1220   if (!pending_copy_operations_count_) {
1221     content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
1222         base::Bind(&DeveloperPrivateLoadDirectoryFunction::Load,
1223                    this));
1224   }
1225 }
1226
1227 DeveloperPrivateLoadDirectoryFunction::DeveloperPrivateLoadDirectoryFunction()
1228     : pending_copy_operations_count_(0), success_(true) {}
1229
1230 DeveloperPrivateLoadDirectoryFunction::~DeveloperPrivateLoadDirectoryFunction()
1231     {}
1232
1233 bool DeveloperPrivateChoosePathFunction::RunImpl() {
1234
1235   scoped_ptr<developer::ChoosePath::Params> params(
1236       developer::ChoosePath::Params::Create(*args_));
1237   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
1238
1239   ui::SelectFileDialog::Type type = ui::SelectFileDialog::SELECT_FOLDER;
1240   ui::SelectFileDialog::FileTypeInfo info;
1241   if (params->select_type == developer::SELECT_TYPE_FILE) {
1242     type = ui::SelectFileDialog::SELECT_OPEN_FILE;
1243   }
1244   base::string16 select_title;
1245
1246   int file_type_index = 0;
1247   if (params->file_type == developer::FILE_TYPE_LOAD)
1248     select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY);
1249   else if (params->file_type== developer::FILE_TYPE_PEM) {
1250     select_title = l10n_util::GetStringUTF16(
1251         IDS_EXTENSION_PACK_DIALOG_SELECT_KEY);
1252     info.extensions.push_back(std::vector<base::FilePath::StringType>());
1253     info.extensions.front().push_back(FILE_PATH_LITERAL("pem"));
1254     info.extension_description_overrides.push_back(
1255         l10n_util::GetStringUTF16(
1256             IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION));
1257     info.include_all_files = true;
1258     file_type_index = 1;
1259   } else {
1260     NOTREACHED();
1261   }
1262
1263   // Balanced by FileSelected / FileSelectionCanceled.
1264   AddRef();
1265   bool result = ShowPicker(
1266       type,
1267       DeveloperPrivateAPI::Get(GetProfile())->GetLastUnpackedDirectory(),
1268       select_title,
1269       info,
1270       file_type_index);
1271   return result;
1272 }
1273
1274 void DeveloperPrivateChoosePathFunction::FileSelected(
1275     const base::FilePath& path) {
1276   SetResult(new base::StringValue(base::UTF16ToUTF8(path.LossyDisplayName())));
1277   SendResponse(true);
1278   Release();
1279 }
1280
1281 void DeveloperPrivateChoosePathFunction::FileSelectionCanceled() {
1282   SendResponse(false);
1283   Release();
1284 }
1285
1286 DeveloperPrivateChoosePathFunction::~DeveloperPrivateChoosePathFunction() {}
1287
1288 bool DeveloperPrivateIsProfileManagedFunction::RunImpl() {
1289   SetResult(new base::FundamentalValue(GetProfile()->IsManaged()));
1290   return true;
1291 }
1292
1293 DeveloperPrivateIsProfileManagedFunction::
1294     ~DeveloperPrivateIsProfileManagedFunction() {
1295 }
1296
1297 DeveloperPrivateRequestFileSourceFunction::
1298     DeveloperPrivateRequestFileSourceFunction() {}
1299
1300 DeveloperPrivateRequestFileSourceFunction::
1301     ~DeveloperPrivateRequestFileSourceFunction() {}
1302
1303 bool DeveloperPrivateRequestFileSourceFunction::RunImpl() {
1304   scoped_ptr<developer::RequestFileSource::Params> params(
1305       developer::RequestFileSource::Params::Create(*args_));
1306   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
1307
1308   base::DictionaryValue* dict = NULL;
1309   if (!params->dict->GetAsDictionary(&dict)) {
1310     NOTREACHED();
1311     return false;
1312   }
1313
1314   AddRef();  // Balanced in LaunchCallback().
1315   error_ui_util::HandleRequestFileSource(
1316       dict,
1317       GetProfile(),
1318       base::Bind(&DeveloperPrivateRequestFileSourceFunction::LaunchCallback,
1319                  base::Unretained(this)));
1320   return true;
1321 }
1322
1323 void DeveloperPrivateRequestFileSourceFunction::LaunchCallback(
1324     const base::DictionaryValue& results) {
1325   SetResult(results.DeepCopy());
1326   SendResponse(true);
1327   Release();  // Balanced in RunImpl().
1328 }
1329
1330 DeveloperPrivateOpenDevToolsFunction::DeveloperPrivateOpenDevToolsFunction() {}
1331 DeveloperPrivateOpenDevToolsFunction::~DeveloperPrivateOpenDevToolsFunction() {}
1332
1333 bool DeveloperPrivateOpenDevToolsFunction::RunImpl() {
1334   scoped_ptr<developer::OpenDevTools::Params> params(
1335       developer::OpenDevTools::Params::Create(*args_));
1336   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
1337
1338   base::DictionaryValue* dict = NULL;
1339   if (!params->dict->GetAsDictionary(&dict)) {
1340     NOTREACHED();
1341     return false;
1342   }
1343
1344   error_ui_util::HandleOpenDevTools(dict);
1345
1346   return true;
1347 }
1348
1349 } // namespace api
1350
1351 } // namespace extensions