[Extensions] Make chrome://extensions use developerPrivate for unpacked loading
[chromium-blink-merge.git] / chrome / browser / extensions / api / developer_private / developer_private_api.cc
blob9470e7821be80f10b1f9df841071588ddfea849e
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/api/developer_private/developer_private_api.h"
7 #include "apps/app_load_service.h"
8 #include "apps/saved_files_service.h"
9 #include "base/base64.h"
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/files/file_enumerator.h"
13 #include "base/files/file_util.h"
14 #include "base/i18n/file_util_icu.h"
15 #include "base/lazy_instance.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/values.h"
19 #include "chrome/browser/devtools/devtools_window.h"
20 #include "chrome/browser/extensions/api/developer_private/entry_picker.h"
21 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
22 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
23 #include "chrome/browser/extensions/chrome_requirements_checker.h"
24 #include "chrome/browser/extensions/devtools_util.h"
25 #include "chrome/browser/extensions/extension_disabled_ui.h"
26 #include "chrome/browser/extensions/extension_error_reporter.h"
27 #include "chrome/browser/extensions/extension_service.h"
28 #include "chrome/browser/extensions/extension_ui_util.h"
29 #include "chrome/browser/extensions/extension_util.h"
30 #include "chrome/browser/extensions/unpacked_installer.h"
31 #include "chrome/browser/extensions/updater/extension_updater.h"
32 #include "chrome/browser/platform_util.h"
33 #include "chrome/browser/profiles/profile.h"
34 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
35 #include "chrome/browser/ui/chrome_select_file_policy.h"
36 #include "chrome/browser/ui/webui/extensions/extension_error_ui_util.h"
37 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
38 #include "chrome/common/extensions/api/developer_private.h"
39 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
40 #include "chrome/common/url_constants.h"
41 #include "chrome/grit/generated_resources.h"
42 #include "content/public/browser/browser_thread.h"
43 #include "content/public/browser/notification_service.h"
44 #include "content/public/browser/render_process_host.h"
45 #include "content/public/browser/render_view_host.h"
46 #include "content/public/browser/site_instance.h"
47 #include "content/public/browser/storage_partition.h"
48 #include "content/public/browser/web_contents.h"
49 #include "extensions/browser/api/device_permissions_manager.h"
50 #include "extensions/browser/app_window/app_window.h"
51 #include "extensions/browser/app_window/app_window_registry.h"
52 #include "extensions/browser/extension_error.h"
53 #include "extensions/browser/extension_prefs.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/notification_types.h"
58 #include "extensions/browser/view_type_utils.h"
59 #include "extensions/common/constants.h"
60 #include "extensions/common/extension_resource.h"
61 #include "extensions/common/extension_set.h"
62 #include "extensions/common/install_warning.h"
63 #include "extensions/common/manifest.h"
64 #include "extensions/common/manifest_handlers/background_info.h"
65 #include "extensions/common/manifest_handlers/icons_handler.h"
66 #include "extensions/common/manifest_handlers/incognito_info.h"
67 #include "extensions/common/manifest_handlers/offline_enabled_info.h"
68 #include "extensions/common/manifest_handlers/options_page_info.h"
69 #include "extensions/common/manifest_url_handlers.h"
70 #include "extensions/common/permissions/permissions_data.h"
71 #include "extensions/common/switches.h"
72 #include "extensions/grit/extensions_browser_resources.h"
73 #include "net/base/net_util.h"
74 #include "storage/browser/blob/shareable_file_reference.h"
75 #include "storage/browser/fileapi/external_mount_points.h"
76 #include "storage/browser/fileapi/file_system_context.h"
77 #include "storage/browser/fileapi/file_system_operation.h"
78 #include "storage/browser/fileapi/file_system_operation_runner.h"
79 #include "storage/browser/fileapi/isolated_context.h"
80 #include "ui/base/l10n/l10n_util.h"
81 #include "ui/base/resource/resource_bundle.h"
82 #include "ui/base/webui/web_ui_util.h"
84 using content::RenderViewHost;
86 namespace extensions {
88 namespace developer_private = api::developer_private;
90 namespace {
92 const char kNoSuchExtensionError[] = "No such extension.";
93 const char kSupervisedUserError[] =
94 "Supervised users cannot modify extension settings.";
95 const char kCannotModifyPolicyExtensionError[] =
96 "Cannot modify the extension by policy.";
97 const char kRequiresUserGestureError[] =
98 "This action requires a user gesture.";
99 const char kCouldNotShowSelectFileDialogError[] =
100 "Could not show a file chooser.";
101 const char kFileSelectionCanceled[] =
102 "File selection was canceled.";
104 const char kUnpackedAppsFolder[] = "apps_target";
106 ExtensionService* GetExtensionService(content::BrowserContext* context) {
107 return ExtensionSystem::Get(context)->extension_service();
110 ExtensionUpdater* GetExtensionUpdater(Profile* profile) {
111 return GetExtensionService(profile)->updater();
114 GURL GetImageURLFromData(const std::string& contents) {
115 std::string contents_base64;
116 base::Base64Encode(contents, &contents_base64);
118 // TODO(dvh): make use of content::kDataScheme. Filed as crbug/297301.
119 const char kDataURLPrefix[] = "data:;base64,";
120 return GURL(kDataURLPrefix + contents_base64);
123 GURL GetDefaultImageURL(developer_private::ItemType type) {
124 int icon_resource_id;
125 switch (type) {
126 case developer::ITEM_TYPE_LEGACY_PACKAGED_APP:
127 case developer::ITEM_TYPE_HOSTED_APP:
128 case developer::ITEM_TYPE_PACKAGED_APP:
129 icon_resource_id = IDR_APP_DEFAULT_ICON;
130 break;
131 default:
132 icon_resource_id = IDR_EXTENSION_DEFAULT_ICON;
133 break;
136 return GetImageURLFromData(
137 ResourceBundle::GetSharedInstance().GetRawDataResourceForScale(
138 icon_resource_id, ui::SCALE_FACTOR_100P).as_string());
141 // TODO(dvh): This code should be refactored and moved to
142 // extensions::ImageLoader. Also a resize should be performed to avoid
143 // potential huge URLs: crbug/297298.
144 GURL ToDataURL(const base::FilePath& path, developer_private::ItemType type) {
145 std::string contents;
146 if (path.empty() || !base::ReadFileToString(path, &contents))
147 return GetDefaultImageURL(type);
149 return GetImageURLFromData(contents);
152 std::string GetExtensionID(const RenderViewHost* render_view_host) {
153 if (!render_view_host->GetSiteInstance())
154 return std::string();
156 return render_view_host->GetSiteInstance()->GetSiteURL().host();
159 void BroadcastItemStateChanged(content::BrowserContext* browser_context,
160 developer::EventType event_type,
161 const std::string& item_id) {
162 developer::EventData event_data;
163 event_data.event_type = event_type;
164 event_data.item_id = item_id;
166 scoped_ptr<base::ListValue> args(new base::ListValue());
167 args->Append(event_data.ToValue().release());
168 scoped_ptr<Event> event(new Event(
169 developer_private::OnItemStateChanged::kEventName, args.Pass()));
170 EventRouter::Get(browser_context)->BroadcastEvent(event.Pass());
173 } // namespace
175 namespace AllowFileAccess = api::developer_private::AllowFileAccess;
176 namespace AllowIncognito = api::developer_private::AllowIncognito;
177 namespace ChoosePath = api::developer_private::ChoosePath;
178 namespace GetItemsInfo = api::developer_private::GetItemsInfo;
179 namespace Inspect = api::developer_private::Inspect;
180 namespace PackDirectory = api::developer_private::PackDirectory;
181 namespace Reload = api::developer_private::Reload;
183 static base::LazyInstance<BrowserContextKeyedAPIFactory<DeveloperPrivateAPI> >
184 g_factory = LAZY_INSTANCE_INITIALIZER;
186 // static
187 BrowserContextKeyedAPIFactory<DeveloperPrivateAPI>*
188 DeveloperPrivateAPI::GetFactoryInstance() {
189 return g_factory.Pointer();
192 // static
193 DeveloperPrivateAPI* DeveloperPrivateAPI::Get(
194 content::BrowserContext* context) {
195 return GetFactoryInstance()->Get(context);
198 DeveloperPrivateAPI::DeveloperPrivateAPI(content::BrowserContext* context)
199 : profile_(Profile::FromBrowserContext(context)) {
200 RegisterNotifications();
203 DeveloperPrivateEventRouter::DeveloperPrivateEventRouter(Profile* profile)
204 : extension_registry_observer_(this), profile_(profile) {
205 registrar_.Add(this,
206 extensions::NOTIFICATION_EXTENSION_VIEW_REGISTERED,
207 content::Source<Profile>(profile_));
208 registrar_.Add(this,
209 extensions::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED,
210 content::Source<Profile>(profile_));
212 // TODO(limasdf): Use scoped_observer instead.
213 ErrorConsole::Get(profile)->AddObserver(this);
215 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
218 DeveloperPrivateEventRouter::~DeveloperPrivateEventRouter() {
219 ErrorConsole::Get(profile_)->RemoveObserver(this);
222 void DeveloperPrivateEventRouter::AddExtensionId(
223 const std::string& extension_id) {
224 extension_ids_.insert(extension_id);
227 void DeveloperPrivateEventRouter::RemoveExtensionId(
228 const std::string& extension_id) {
229 extension_ids_.erase(extension_id);
232 void DeveloperPrivateEventRouter::Observe(
233 int type,
234 const content::NotificationSource& source,
235 const content::NotificationDetails& details) {
236 Profile* profile = content::Source<Profile>(source).ptr();
237 CHECK(profile);
238 CHECK(profile_->IsSameProfile(profile));
239 developer::EventData event_data;
241 switch (type) {
242 case extensions::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED: {
243 event_data.event_type = developer::EVENT_TYPE_VIEW_UNREGISTERED;
244 event_data.item_id = GetExtensionID(
245 content::Details<const RenderViewHost>(details).ptr());
246 break;
248 case extensions::NOTIFICATION_EXTENSION_VIEW_REGISTERED: {
249 event_data.event_type = developer::EVENT_TYPE_VIEW_REGISTERED;
250 event_data.item_id = GetExtensionID(
251 content::Details<const RenderViewHost>(details).ptr());
252 break;
254 default:
255 NOTREACHED();
256 return;
259 BroadcastItemStateChanged(profile, event_data.event_type, event_data.item_id);
262 void DeveloperPrivateEventRouter::OnExtensionLoaded(
263 content::BrowserContext* browser_context,
264 const Extension* extension) {
265 DCHECK(profile_->IsSameProfile(Profile::FromBrowserContext(browser_context)));
266 BroadcastItemStateChanged(
267 browser_context, developer::EVENT_TYPE_LOADED, extension->id());
270 void DeveloperPrivateEventRouter::OnExtensionUnloaded(
271 content::BrowserContext* browser_context,
272 const Extension* extension,
273 UnloadedExtensionInfo::Reason reason) {
274 DCHECK(profile_->IsSameProfile(Profile::FromBrowserContext(browser_context)));
275 BroadcastItemStateChanged(
276 browser_context, developer::EVENT_TYPE_UNLOADED, extension->id());
279 void DeveloperPrivateEventRouter::OnExtensionWillBeInstalled(
280 content::BrowserContext* browser_context,
281 const Extension* extension,
282 bool is_update,
283 bool from_ephemeral,
284 const std::string& old_name) {
285 DCHECK(profile_->IsSameProfile(Profile::FromBrowserContext(browser_context)));
286 BroadcastItemStateChanged(
287 browser_context, developer::EVENT_TYPE_INSTALLED, extension->id());
290 void DeveloperPrivateEventRouter::OnExtensionUninstalled(
291 content::BrowserContext* browser_context,
292 const Extension* extension,
293 extensions::UninstallReason reason) {
294 DCHECK(profile_->IsSameProfile(Profile::FromBrowserContext(browser_context)));
295 BroadcastItemStateChanged(
296 browser_context, developer::EVENT_TYPE_UNINSTALLED, extension->id());
299 void DeveloperPrivateEventRouter::OnErrorAdded(const ExtensionError* error) {
300 // We don't want to handle errors thrown by extensions subscribed to these
301 // events (currently only the Apps Developer Tool), because doing so risks
302 // entering a loop.
303 if (extension_ids_.find(error->extension_id()) != extension_ids_.end())
304 return;
306 BroadcastItemStateChanged(
307 profile_, developer::EVENT_TYPE_ERROR_ADDED, error->extension_id());
310 void DeveloperPrivateAPI::SetLastUnpackedDirectory(const base::FilePath& path) {
311 last_unpacked_directory_ = path;
314 void DeveloperPrivateAPI::RegisterNotifications() {
315 EventRouter::Get(profile_)->RegisterObserver(
316 this, developer_private::OnItemStateChanged::kEventName);
319 DeveloperPrivateAPI::~DeveloperPrivateAPI() {}
321 void DeveloperPrivateAPI::Shutdown() {}
323 void DeveloperPrivateAPI::OnListenerAdded(
324 const EventListenerInfo& details) {
325 if (!developer_private_event_router_) {
326 developer_private_event_router_.reset(
327 new DeveloperPrivateEventRouter(profile_));
330 developer_private_event_router_->AddExtensionId(details.extension_id);
333 void DeveloperPrivateAPI::OnListenerRemoved(
334 const EventListenerInfo& details) {
335 if (!EventRouter::Get(profile_)->HasEventListener(
336 developer_private::OnItemStateChanged::kEventName)) {
337 developer_private_event_router_.reset(NULL);
338 } else {
339 developer_private_event_router_->RemoveExtensionId(details.extension_id);
343 namespace api {
345 DeveloperPrivateAPIFunction::~DeveloperPrivateAPIFunction() {
348 const Extension* DeveloperPrivateAPIFunction::GetExtensionById(
349 const std::string& id) {
350 return ExtensionRegistry::Get(browser_context())->GetExtensionById(
351 id, ExtensionRegistry::EVERYTHING);
354 bool DeveloperPrivateAutoUpdateFunction::RunSync() {
355 ExtensionUpdater* updater = GetExtensionUpdater(GetProfile());
356 if (updater)
357 updater->CheckNow(ExtensionUpdater::CheckParams());
358 SetResult(new base::FundamentalValue(true));
359 return true;
362 DeveloperPrivateAutoUpdateFunction::~DeveloperPrivateAutoUpdateFunction() {}
364 scoped_ptr<developer::ItemInfo>
365 DeveloperPrivateGetItemsInfoFunction::CreateItemInfo(const Extension& item,
366 bool item_is_enabled) {
367 scoped_ptr<developer::ItemInfo> info(new developer::ItemInfo());
369 ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
370 ExtensionService* service = system->extension_service();
371 ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile());
373 info->id = item.id();
374 info->name = item.name();
375 info->enabled = service->IsExtensionEnabled(info->id);
376 info->offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&item);
377 info->version = item.VersionString();
378 info->description = item.description();
380 if (item.is_app()) {
381 if (item.is_legacy_packaged_app())
382 info->type = developer::ITEM_TYPE_LEGACY_PACKAGED_APP;
383 else if (item.is_hosted_app())
384 info->type = developer::ITEM_TYPE_HOSTED_APP;
385 else if (item.is_platform_app())
386 info->type = developer::ITEM_TYPE_PACKAGED_APP;
387 else
388 NOTREACHED();
389 } else if (item.is_theme()) {
390 info->type = developer::ITEM_TYPE_THEME;
391 } else if (item.is_extension()) {
392 info->type = developer::ITEM_TYPE_EXTENSION;
393 } else {
394 NOTREACHED();
397 if (Manifest::IsUnpackedLocation(item.location())) {
398 info->path.reset(
399 new std::string(base::UTF16ToUTF8(item.path().LossyDisplayName())));
400 // If the ErrorConsole is enabled and the extension is unpacked, use the
401 // more detailed errors from the ErrorConsole. Otherwise, use the install
402 // warnings (using both is redundant).
403 ErrorConsole* error_console = ErrorConsole::Get(GetProfile());
404 if (error_console->IsEnabledForAppsDeveloperTools() &&
405 item.location() == Manifest::UNPACKED) {
406 const ErrorList& errors = error_console->GetErrorsForExtension(item.id());
407 if (!errors.empty()) {
408 for (ErrorList::const_iterator iter = errors.begin();
409 iter != errors.end();
410 ++iter) {
411 switch ((*iter)->type()) {
412 case ExtensionError::MANIFEST_ERROR:
413 info->manifest_errors.push_back(
414 make_linked_ptr((*iter)->ToValue().release()));
415 break;
416 case ExtensionError::RUNTIME_ERROR: {
417 const RuntimeError* error =
418 static_cast<const RuntimeError*>(*iter);
419 scoped_ptr<base::DictionaryValue> value = error->ToValue();
420 bool can_inspect = content::RenderViewHost::FromID(
421 error->render_process_id(),
422 error->render_view_id()) != NULL;
423 value->SetBoolean("canInspect", can_inspect);
424 info->runtime_errors.push_back(make_linked_ptr(value.release()));
425 break;
427 case ExtensionError::NUM_ERROR_TYPES:
428 NOTREACHED();
429 break;
433 } else {
434 for (std::vector<InstallWarning>::const_iterator it =
435 item.install_warnings().begin();
436 it != item.install_warnings().end();
437 ++it) {
438 scoped_ptr<developer::InstallWarning> warning(
439 new developer::InstallWarning);
440 warning->message = it->message;
441 info->install_warnings.push_back(make_linked_ptr(warning.release()));
446 info->incognito_enabled = util::IsIncognitoEnabled(item.id(), GetProfile());
447 info->wants_file_access = item.wants_file_access();
448 info->allow_file_access = util::AllowFileAccess(item.id(), GetProfile());
449 info->allow_reload = Manifest::IsUnpackedLocation(item.location());
450 info->is_unpacked = Manifest::IsUnpackedLocation(item.location());
451 info->terminated = registry->terminated_extensions().Contains(item.id());
452 info->allow_incognito = item.can_be_incognito_enabled();
454 info->homepage_url.reset(new std::string(
455 ManifestURL::GetHomepageURL(&item).spec()));
456 if (!OptionsPageInfo::GetOptionsPage(&item).is_empty()) {
457 info->options_url.reset(
458 new std::string(OptionsPageInfo::GetOptionsPage(&item).spec()));
461 if (!ManifestURL::GetUpdateURL(&item).is_empty()) {
462 info->update_url.reset(
463 new std::string(ManifestURL::GetUpdateURL(&item).spec()));
466 if (item.is_app()) {
467 info->app_launch_url.reset(
468 new std::string(AppLaunchInfo::GetFullLaunchURL(&item).spec()));
471 info->may_disable = system->management_policy()->
472 UserMayModifySettings(&item, NULL);
473 info->is_app = item.is_app();
474 info->views = GetInspectablePagesForExtension(&item, item_is_enabled);
476 return info.Pass();
479 void DeveloperPrivateGetItemsInfoFunction::GetIconsOnFileThread(
480 ItemInfoList item_list,
481 const std::map<std::string, ExtensionResource> idToIcon) {
482 for (ItemInfoList::iterator iter = item_list.begin();
483 iter != item_list.end(); ++iter) {
484 developer_private::ItemInfo* info = iter->get();
485 std::map<std::string, ExtensionResource>::const_iterator resource_ptr
486 = idToIcon.find(info->id);
487 if (resource_ptr != idToIcon.end()) {
488 info->icon_url =
489 ToDataURL(resource_ptr->second.GetFilePath(), info->type).spec();
493 results_ = developer::GetItemsInfo::Results::Create(item_list);
494 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
495 base::Bind(&DeveloperPrivateGetItemsInfoFunction::SendResponse,
496 this,
497 true));
500 void DeveloperPrivateGetItemsInfoFunction::
501 GetInspectablePagesForExtensionProcess(
502 const Extension* extension,
503 const std::set<content::RenderViewHost*>& views,
504 ItemInspectViewList* result) {
505 bool has_generated_background_page =
506 BackgroundInfo::HasGeneratedBackgroundPage(extension);
507 for (std::set<content::RenderViewHost*>::const_iterator iter = views.begin();
508 iter != views.end(); ++iter) {
509 content::RenderViewHost* host = *iter;
510 content::WebContents* web_contents =
511 content::WebContents::FromRenderViewHost(host);
512 ViewType host_type = GetViewType(web_contents);
513 if (VIEW_TYPE_EXTENSION_POPUP == host_type ||
514 VIEW_TYPE_EXTENSION_DIALOG == host_type)
515 continue;
517 content::RenderProcessHost* process = host->GetProcess();
518 bool is_background_page =
519 (web_contents->GetURL() == BackgroundInfo::GetBackgroundURL(extension));
520 result->push_back(constructInspectView(
521 web_contents->GetURL(),
522 process->GetID(),
523 host->GetRoutingID(),
524 process->GetBrowserContext()->IsOffTheRecord(),
525 is_background_page && has_generated_background_page));
529 void DeveloperPrivateGetItemsInfoFunction::GetAppWindowPagesForExtensionProfile(
530 const Extension* extension,
531 ItemInspectViewList* result) {
532 AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile());
533 if (!registry) return;
535 const AppWindowRegistry::AppWindowList windows =
536 registry->GetAppWindowsForApp(extension->id());
538 bool has_generated_background_page =
539 BackgroundInfo::HasGeneratedBackgroundPage(extension);
540 for (AppWindowRegistry::const_iterator it = windows.begin();
541 it != windows.end();
542 ++it) {
543 content::WebContents* web_contents = (*it)->web_contents();
544 RenderViewHost* host = web_contents->GetRenderViewHost();
545 content::RenderProcessHost* process = host->GetProcess();
546 bool is_background_page =
547 (web_contents->GetURL() == BackgroundInfo::GetBackgroundURL(extension));
548 result->push_back(constructInspectView(
549 web_contents->GetURL(),
550 process->GetID(),
551 host->GetRoutingID(),
552 process->GetBrowserContext()->IsOffTheRecord(),
553 is_background_page && has_generated_background_page));
557 linked_ptr<developer::ItemInspectView> DeveloperPrivateGetItemsInfoFunction::
558 constructInspectView(
559 const GURL& url,
560 int render_process_id,
561 int render_view_id,
562 bool incognito,
563 bool generated_background_page) {
564 linked_ptr<developer::ItemInspectView> view(new developer::ItemInspectView());
566 if (url.scheme() == kExtensionScheme) {
567 // No leading slash.
568 view->path = url.path().substr(1);
569 } else {
570 // For live pages, use the full URL.
571 view->path = url.spec();
574 view->render_process_id = render_process_id;
575 view->render_view_id = render_view_id;
576 view->incognito = incognito;
577 view->generated_background_page = generated_background_page;
578 return view;
581 ItemInspectViewList DeveloperPrivateGetItemsInfoFunction::
582 GetInspectablePagesForExtension(
583 const Extension* extension,
584 bool extension_is_enabled) {
585 ItemInspectViewList result;
586 // Get the extension process's active views.
587 ProcessManager* process_manager = ProcessManager::Get(GetProfile());
588 GetInspectablePagesForExtensionProcess(
589 extension,
590 process_manager->GetRenderViewHostsForExtension(extension->id()),
591 &result);
593 // Get app window views.
594 GetAppWindowPagesForExtensionProfile(extension, &result);
596 // Include a link to start the lazy background page, if applicable.
597 if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
598 extension_is_enabled &&
599 !process_manager->GetBackgroundHostForExtension(extension->id())) {
600 result.push_back(constructInspectView(
601 BackgroundInfo::GetBackgroundURL(extension),
604 false,
605 BackgroundInfo::HasGeneratedBackgroundPage(extension)));
608 ExtensionService* service = GetExtensionService(GetProfile());
609 // Repeat for the incognito process, if applicable. Don't try to get
610 // app windows for incognito process.
611 if (service->profile()->HasOffTheRecordProfile() &&
612 IncognitoInfo::IsSplitMode(extension)) {
613 process_manager =
614 ProcessManager::Get(service->profile()->GetOffTheRecordProfile());
615 GetInspectablePagesForExtensionProcess(
616 extension,
617 process_manager->GetRenderViewHostsForExtension(extension->id()),
618 &result);
620 if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
621 extension_is_enabled &&
622 !process_manager->GetBackgroundHostForExtension(extension->id())) {
623 result.push_back(constructInspectView(
624 BackgroundInfo::GetBackgroundURL(extension),
627 false,
628 BackgroundInfo::HasGeneratedBackgroundPage(extension)));
632 return result;
635 bool DeveloperPrivateGetItemsInfoFunction::RunAsync() {
636 scoped_ptr<developer::GetItemsInfo::Params> params(
637 developer::GetItemsInfo::Params::Create(*args_));
638 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
640 bool include_disabled = params->include_disabled;
641 bool include_terminated = params->include_terminated;
643 ExtensionSet items;
645 ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile());
647 items.InsertAll(registry->enabled_extensions());
649 if (include_disabled) {
650 items.InsertAll(registry->disabled_extensions());
653 if (include_terminated) {
654 items.InsertAll(registry->terminated_extensions());
657 ExtensionService* service =
658 ExtensionSystem::Get(GetProfile())->extension_service();
659 std::map<std::string, ExtensionResource> id_to_icon;
660 ItemInfoList item_list;
662 for (ExtensionSet::const_iterator iter = items.begin(); iter != items.end();
663 ++iter) {
664 const Extension& item = *iter->get();
666 ExtensionResource item_resource =
667 IconsInfo::GetIconResource(&item,
668 extension_misc::EXTENSION_ICON_MEDIUM,
669 ExtensionIconSet::MATCH_BIGGER);
670 id_to_icon[item.id()] = item_resource;
672 // Don't show component extensions and invisible apps.
673 if (ui_util::ShouldNotBeVisible(&item, GetProfile()))
674 continue;
676 item_list.push_back(make_linked_ptr<developer::ItemInfo>(
677 CreateItemInfo(
678 item, service->IsExtensionEnabled(item.id())).release()));
681 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
682 base::Bind(&DeveloperPrivateGetItemsInfoFunction::GetIconsOnFileThread,
683 this,
684 item_list,
685 id_to_icon));
687 return true;
690 DeveloperPrivateGetItemsInfoFunction::~DeveloperPrivateGetItemsInfoFunction() {}
692 ExtensionFunction::ResponseAction
693 DeveloperPrivateAllowFileAccessFunction::Run() {
694 scoped_ptr<AllowFileAccess::Params> params(
695 AllowFileAccess::Params::Create(*args_));
696 EXTENSION_FUNCTION_VALIDATE(params.get());
698 const Extension* extension = GetExtensionById(params->extension_id);
700 if (!extension)
701 return RespondNow(Error(kNoSuchExtensionError));
703 if (!user_gesture())
704 return RespondNow(Error(kRequiresUserGestureError));
706 if (util::IsExtensionSupervised(
707 extension, Profile::FromBrowserContext(browser_context()))) {
708 return RespondNow(Error(kSupervisedUserError));
711 ManagementPolicy* management_policy =
712 ExtensionSystem::Get(browser_context())->management_policy();
713 if (!management_policy->UserMayModifySettings(extension, nullptr)) {
714 LOG(ERROR) << "Attempt to change allow file access of an extension that "
715 << "non-usermanagable was made. Extension id : "
716 << extension->id();
717 return RespondNow(Error(kCannotModifyPolicyExtensionError));
720 util::SetAllowFileAccess(extension->id(), browser_context(), params->allow);
721 return RespondNow(NoArguments());
724 DeveloperPrivateAllowFileAccessFunction::
725 ~DeveloperPrivateAllowFileAccessFunction() {}
727 ExtensionFunction::ResponseAction
728 DeveloperPrivateAllowIncognitoFunction::Run() {
729 scoped_ptr<AllowIncognito::Params> params(
730 AllowIncognito::Params::Create(*args_));
731 EXTENSION_FUNCTION_VALIDATE(params.get());
733 const Extension* extension = GetExtensionById(params->extension_id);
735 if (!extension)
736 return RespondNow(Error(kNoSuchExtensionError));
738 if (!user_gesture())
739 return RespondNow(Error(kRequiresUserGestureError));
741 // Should this take into account policy settings?
742 util::SetIsIncognitoEnabled(
743 extension->id(), browser_context(), params->allow);
745 return RespondNow(NoArguments());
748 DeveloperPrivateAllowIncognitoFunction::
749 ~DeveloperPrivateAllowIncognitoFunction() {}
751 ExtensionFunction::ResponseAction DeveloperPrivateReloadFunction::Run() {
752 scoped_ptr<Reload::Params> params(Reload::Params::Create(*args_));
753 EXTENSION_FUNCTION_VALIDATE(params.get());
755 const Extension* extension = GetExtensionById(params->extension_id);
756 if (!extension)
757 return RespondNow(Error(kNoSuchExtensionError));
759 bool fail_quietly = params->options &&
760 params->options->fail_quietly &&
761 *params->options->fail_quietly;
763 ExtensionService* service = GetExtensionService(browser_context());
764 if (fail_quietly)
765 service->ReloadExtensionWithQuietFailure(params->extension_id);
766 else
767 service->ReloadExtension(params->extension_id);
769 // TODO(devlin): We shouldn't return until the extension has finished trying
770 // to reload (and then we could also return the error).
771 return RespondNow(NoArguments());
774 bool DeveloperPrivateShowPermissionsDialogFunction::RunSync() {
775 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id_));
776 CHECK(!extension_id_.empty());
777 AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile());
778 DCHECK(registry);
779 AppWindow* app_window =
780 registry->GetAppWindowForRenderViewHost(render_view_host());
781 prompt_.reset(new ExtensionInstallPrompt(app_window->web_contents()));
782 const Extension* extension =
783 ExtensionRegistry::Get(GetProfile())
784 ->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
786 if (!extension)
787 return false;
789 // Released by InstallUIAbort or InstallUIProceed.
790 AddRef();
791 std::vector<base::FilePath> retained_file_paths;
792 if (extension->permissions_data()->HasAPIPermission(
793 APIPermission::kFileSystem)) {
794 std::vector<apps::SavedFileEntry> retained_file_entries =
795 apps::SavedFilesService::Get(GetProfile())
796 ->GetAllFileEntries(extension_id_);
797 for (size_t i = 0; i < retained_file_entries.size(); i++) {
798 retained_file_paths.push_back(retained_file_entries[i].path);
801 std::vector<base::string16> retained_device_messages;
802 if (extension->permissions_data()->HasAPIPermission(APIPermission::kUsb)) {
803 retained_device_messages =
804 extensions::DevicePermissionsManager::Get(GetProfile())
805 ->GetPermissionMessageStrings(extension_id_);
807 prompt_->ReviewPermissions(
808 this, extension, retained_file_paths, retained_device_messages);
809 return true;
812 DeveloperPrivateReloadFunction::~DeveloperPrivateReloadFunction() {}
814 // This is called when the user clicks "Revoke File Access."
815 void DeveloperPrivateShowPermissionsDialogFunction::InstallUIProceed() {
816 Profile* profile = GetProfile();
817 extensions::DevicePermissionsManager::Get(profile)->Clear(extension_id_);
818 const Extension* extension = ExtensionRegistry::Get(
819 profile)->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
820 apps::SavedFilesService::Get(profile)->ClearQueue(extension);
821 apps::AppLoadService::Get(profile)
822 ->RestartApplicationIfRunning(extension_id_);
823 SendResponse(true);
824 Release();
827 void DeveloperPrivateShowPermissionsDialogFunction::InstallUIAbort(
828 bool user_initiated) {
829 SendResponse(true);
830 Release();
833 DeveloperPrivateShowPermissionsDialogFunction::
834 DeveloperPrivateShowPermissionsDialogFunction() {}
836 DeveloperPrivateShowPermissionsDialogFunction::
837 ~DeveloperPrivateShowPermissionsDialogFunction() {}
839 bool DeveloperPrivateInspectFunction::RunSync() {
840 scoped_ptr<developer::Inspect::Params> params(
841 developer::Inspect::Params::Create(*args_));
842 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
843 const developer::InspectOptions& options = params->options;
845 int render_process_id;
846 base::StringToInt(options.render_process_id, &render_process_id);
848 if (render_process_id == -1) {
849 // This is a lazy background page. Identify if it is a normal
850 // or incognito background page.
851 const Extension* extension = ExtensionRegistry::Get(
852 GetProfile())->enabled_extensions().GetByID(options.extension_id);
853 DCHECK(extension);
854 // Wakes up the background page and opens the inspect window.
855 devtools_util::InspectBackgroundPage(extension, GetProfile());
856 return false;
859 int render_view_id;
860 base::StringToInt(options.render_view_id, &render_view_id);
861 content::RenderViewHost* host = content::RenderViewHost::FromID(
862 render_process_id, render_view_id);
864 if (!host || !content::WebContents::FromRenderViewHost(host)) {
865 // This can happen if the host has gone away since the page was displayed.
866 return false;
869 DevToolsWindow::OpenDevToolsWindow(
870 content::WebContents::FromRenderViewHost(host));
871 return true;
874 DeveloperPrivateInspectFunction::~DeveloperPrivateInspectFunction() {}
876 DeveloperPrivateLoadUnpackedFunction::DeveloperPrivateLoadUnpackedFunction()
877 : fail_quietly_(false) {
880 ExtensionFunction::ResponseAction DeveloperPrivateLoadUnpackedFunction::Run() {
881 scoped_ptr<developer_private::LoadUnpacked::Params> params(
882 developer_private::LoadUnpacked::Params::Create(*args_));
883 EXTENSION_FUNCTION_VALIDATE(params);
885 if (!ShowPicker(
886 ui::SelectFileDialog::SELECT_FOLDER,
887 l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY),
888 ui::SelectFileDialog::FileTypeInfo(),
889 0 /* file_type_index */)) {
890 return RespondNow(Error(kCouldNotShowSelectFileDialogError));
893 fail_quietly_ = params->options &&
894 params->options->fail_quietly &&
895 *params->options->fail_quietly;
897 AddRef(); // Balanced in FileSelected / FileSelectionCanceled.
898 return RespondLater();
901 void DeveloperPrivateLoadUnpackedFunction::FileSelected(
902 const base::FilePath& path) {
903 scoped_refptr<UnpackedInstaller> installer(
904 UnpackedInstaller::Create(GetExtensionService(browser_context())));
905 installer->set_be_noisy_on_failure(!fail_quietly_);
906 installer->set_completion_callback(
907 base::Bind(&DeveloperPrivateLoadUnpackedFunction::OnLoadComplete, this));
908 installer->Load(path);
910 DeveloperPrivateAPI::Get(browser_context())->SetLastUnpackedDirectory(path);
912 Release(); // Balanced in Run().
915 void DeveloperPrivateLoadUnpackedFunction::FileSelectionCanceled() {
916 // This isn't really an error, but we should keep it like this for
917 // backward compatability.
918 Respond(Error(kFileSelectionCanceled));
919 Release(); // Balanced in Run().
922 void DeveloperPrivateLoadUnpackedFunction::OnLoadComplete(
923 const Extension* extension,
924 const base::FilePath& file_path,
925 const std::string& error) {
926 Respond(extension ? NoArguments() : Error(error));
929 bool DeveloperPrivateChooseEntryFunction::ShowPicker(
930 ui::SelectFileDialog::Type picker_type,
931 const base::string16& select_title,
932 const ui::SelectFileDialog::FileTypeInfo& info,
933 int file_type_index) {
934 content::WebContents* web_contents = GetSenderWebContents();
935 if (!web_contents)
936 return false;
938 // The entry picker will hold a reference to this function instance,
939 // and subsequent sending of the function response) until the user has
940 // selected a file or cancelled the picker. At that point, the picker will
941 // delete itself.
942 new EntryPicker(this,
943 web_contents,
944 picker_type,
945 DeveloperPrivateAPI::Get(browser_context())->
946 GetLastUnpackedDirectory(),
947 select_title,
948 info,
949 file_type_index);
950 return true;
953 DeveloperPrivateChooseEntryFunction::~DeveloperPrivateChooseEntryFunction() {}
955 void DeveloperPrivatePackDirectoryFunction::OnPackSuccess(
956 const base::FilePath& crx_file,
957 const base::FilePath& pem_file) {
958 developer::PackDirectoryResponse response;
959 response.message = base::UTF16ToUTF8(
960 PackExtensionJob::StandardSuccessMessage(crx_file, pem_file));
961 response.status = developer::PACK_STATUS_SUCCESS;
962 Respond(OneArgument(response.ToValue().release()));
963 Release(); // Balanced in Run().
966 void DeveloperPrivatePackDirectoryFunction::OnPackFailure(
967 const std::string& error,
968 ExtensionCreator::ErrorType error_type) {
969 developer::PackDirectoryResponse response;
970 response.message = error;
971 if (error_type == ExtensionCreator::kCRXExists) {
972 response.item_path = item_path_str_;
973 response.pem_path = key_path_str_;
974 response.override_flags = ExtensionCreator::kOverwriteCRX;
975 response.status = developer::PACK_STATUS_WARNING;
976 } else {
977 response.status = developer::PACK_STATUS_ERROR;
979 Respond(OneArgument(response.ToValue().release()));
980 Release(); // Balanced in Run().
983 ExtensionFunction::ResponseAction DeveloperPrivatePackDirectoryFunction::Run() {
984 scoped_ptr<PackDirectory::Params> params(
985 PackDirectory::Params::Create(*args_));
986 EXTENSION_FUNCTION_VALIDATE(params);
988 int flags = params->flags ? *params->flags : 0;
989 item_path_str_ = params->path;
990 if (params->private_key_path)
991 key_path_str_ = *params->private_key_path;
993 base::FilePath root_directory =
994 base::FilePath::FromUTF8Unsafe(item_path_str_);
995 base::FilePath key_file = base::FilePath::FromUTF8Unsafe(key_path_str_);
997 developer::PackDirectoryResponse response;
998 if (root_directory.empty()) {
999 if (item_path_str_.empty())
1000 response.message = l10n_util::GetStringUTF8(
1001 IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED);
1002 else
1003 response.message = l10n_util::GetStringUTF8(
1004 IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID);
1006 response.status = developer::PACK_STATUS_ERROR;
1007 return RespondNow(OneArgument(response.ToValue().release()));
1010 if (!key_path_str_.empty() && key_file.empty()) {
1011 response.message = l10n_util::GetStringUTF8(
1012 IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID);
1013 response.status = developer::PACK_STATUS_ERROR;
1014 return RespondNow(OneArgument(response.ToValue().release()));
1017 AddRef(); // Balanced in OnPackSuccess / OnPackFailure.
1019 // TODO(devlin): Why is PackExtensionJob ref-counted?
1020 pack_job_ = new PackExtensionJob(this, root_directory, key_file, flags);
1021 pack_job_->Start();
1022 return RespondLater();
1025 DeveloperPrivatePackDirectoryFunction::DeveloperPrivatePackDirectoryFunction() {
1028 DeveloperPrivatePackDirectoryFunction::
1029 ~DeveloperPrivatePackDirectoryFunction() {}
1031 DeveloperPrivateLoadUnpackedFunction::~DeveloperPrivateLoadUnpackedFunction() {}
1033 bool DeveloperPrivateLoadDirectoryFunction::RunAsync() {
1034 // TODO(grv) : add unittests.
1035 std::string directory_url_str;
1036 std::string filesystem_name;
1037 std::string filesystem_path;
1039 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name));
1040 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path));
1041 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &directory_url_str));
1043 context_ = content::BrowserContext::GetStoragePartition(
1044 GetProfile(), render_view_host()->GetSiteInstance())
1045 ->GetFileSystemContext();
1047 // Directory url is non empty only for syncfilesystem.
1048 if (!directory_url_str.empty()) {
1049 storage::FileSystemURL directory_url =
1050 context_->CrackURL(GURL(directory_url_str));
1051 if (!directory_url.is_valid() ||
1052 directory_url.type() != storage::kFileSystemTypeSyncable) {
1053 SetError("DirectoryEntry of unsupported filesystem.");
1054 return false;
1056 return LoadByFileSystemAPI(directory_url);
1057 } else {
1058 // Check if the DirecotryEntry is the instance of chrome filesystem.
1059 if (!app_file_handler_util::ValidateFileEntryAndGetPath(filesystem_name,
1060 filesystem_path,
1061 render_view_host_,
1062 &project_base_path_,
1063 &error_)) {
1064 SetError("DirectoryEntry of unsupported filesystem.");
1065 return false;
1068 // Try to load using the FileSystem API backend, in case the filesystem
1069 // points to a non-native local directory.
1070 std::string filesystem_id;
1071 bool cracked =
1072 storage::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id);
1073 CHECK(cracked);
1074 base::FilePath virtual_path =
1075 storage::IsolatedContext::GetInstance()
1076 ->CreateVirtualRootPath(filesystem_id)
1077 .Append(base::FilePath::FromUTF8Unsafe(filesystem_path));
1078 storage::FileSystemURL directory_url = context_->CreateCrackedFileSystemURL(
1079 extensions::Extension::GetBaseURLFromExtensionId(extension_id()),
1080 storage::kFileSystemTypeIsolated,
1081 virtual_path);
1083 if (directory_url.is_valid() &&
1084 directory_url.type() != storage::kFileSystemTypeNativeLocal &&
1085 directory_url.type() != storage::kFileSystemTypeRestrictedNativeLocal &&
1086 directory_url.type() != storage::kFileSystemTypeDragged) {
1087 return LoadByFileSystemAPI(directory_url);
1090 Load();
1093 return true;
1096 bool DeveloperPrivateLoadDirectoryFunction::LoadByFileSystemAPI(
1097 const storage::FileSystemURL& directory_url) {
1098 std::string directory_url_str = directory_url.ToGURL().spec();
1100 size_t pos = 0;
1101 // Parse the project directory name from the project url. The project url is
1102 // expected to have project name as the suffix.
1103 if ((pos = directory_url_str.rfind("/")) == std::string::npos) {
1104 SetError("Invalid Directory entry.");
1105 return false;
1108 std::string project_name;
1109 project_name = directory_url_str.substr(pos + 1);
1110 project_base_url_ = directory_url_str.substr(0, pos + 1);
1112 base::FilePath project_path(GetProfile()->GetPath());
1113 project_path = project_path.AppendASCII(kUnpackedAppsFolder);
1114 project_path = project_path.Append(
1115 base::FilePath::FromUTF8Unsafe(project_name));
1117 project_base_path_ = project_path;
1119 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
1120 base::Bind(&DeveloperPrivateLoadDirectoryFunction::
1121 ClearExistingDirectoryContent,
1122 this,
1123 project_base_path_));
1124 return true;
1127 void DeveloperPrivateLoadDirectoryFunction::Load() {
1128 ExtensionService* service = GetExtensionService(GetProfile());
1129 UnpackedInstaller::Create(service)->Load(project_base_path_);
1131 // TODO(grv) : The unpacked installer should fire an event when complete
1132 // and return the extension_id.
1133 SetResult(new base::StringValue("-1"));
1134 SendResponse(true);
1137 void DeveloperPrivateLoadDirectoryFunction::ClearExistingDirectoryContent(
1138 const base::FilePath& project_path) {
1140 // Clear the project directory before copying new files.
1141 base::DeleteFile(project_path, true /*recursive*/);
1143 pending_copy_operations_count_ = 1;
1145 content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
1146 base::Bind(&DeveloperPrivateLoadDirectoryFunction::
1147 ReadDirectoryByFileSystemAPI,
1148 this, project_path, project_path.BaseName()));
1151 void DeveloperPrivateLoadDirectoryFunction::ReadDirectoryByFileSystemAPI(
1152 const base::FilePath& project_path,
1153 const base::FilePath& destination_path) {
1154 GURL project_url = GURL(project_base_url_ + destination_path.AsUTF8Unsafe());
1155 storage::FileSystemURL url = context_->CrackURL(project_url);
1157 context_->operation_runner()->ReadDirectory(
1158 url, base::Bind(&DeveloperPrivateLoadDirectoryFunction::
1159 ReadDirectoryByFileSystemAPICb,
1160 this, project_path, destination_path));
1163 void DeveloperPrivateLoadDirectoryFunction::ReadDirectoryByFileSystemAPICb(
1164 const base::FilePath& project_path,
1165 const base::FilePath& destination_path,
1166 base::File::Error status,
1167 const storage::FileSystemOperation::FileEntryList& file_list,
1168 bool has_more) {
1169 if (status != base::File::FILE_OK) {
1170 DLOG(ERROR) << "Error in copying files from sync filesystem.";
1171 return;
1174 // We add 1 to the pending copy operations for both files and directories. We
1175 // release the directory copy operation once all the files under the directory
1176 // are added for copying. We do that to ensure that pendingCopyOperationsCount
1177 // does not become zero before all copy operations are finished.
1178 // In case the directory happens to be executing the last copy operation it
1179 // will call SendResponse to send the response to the API. The pending copy
1180 // operations of files are released by the CopyFile function.
1181 pending_copy_operations_count_ += file_list.size();
1183 for (size_t i = 0; i < file_list.size(); ++i) {
1184 if (file_list[i].is_directory) {
1185 ReadDirectoryByFileSystemAPI(project_path.Append(file_list[i].name),
1186 destination_path.Append(file_list[i].name));
1187 continue;
1190 GURL project_url = GURL(project_base_url_ +
1191 destination_path.Append(file_list[i].name).AsUTF8Unsafe());
1192 storage::FileSystemURL url = context_->CrackURL(project_url);
1194 base::FilePath target_path = project_path;
1195 target_path = target_path.Append(file_list[i].name);
1197 context_->operation_runner()->CreateSnapshotFile(
1198 url,
1199 base::Bind(&DeveloperPrivateLoadDirectoryFunction::SnapshotFileCallback,
1200 this,
1201 target_path));
1204 if (!has_more) {
1205 // Directory copy operation released here.
1206 pending_copy_operations_count_--;
1208 if (!pending_copy_operations_count_) {
1209 content::BrowserThread::PostTask(
1210 content::BrowserThread::UI, FROM_HERE,
1211 base::Bind(&DeveloperPrivateLoadDirectoryFunction::SendResponse,
1212 this,
1213 success_));
1218 void DeveloperPrivateLoadDirectoryFunction::SnapshotFileCallback(
1219 const base::FilePath& target_path,
1220 base::File::Error result,
1221 const base::File::Info& file_info,
1222 const base::FilePath& src_path,
1223 const scoped_refptr<storage::ShareableFileReference>& file_ref) {
1224 if (result != base::File::FILE_OK) {
1225 SetError("Error in copying files from sync filesystem.");
1226 success_ = false;
1227 return;
1230 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
1231 base::Bind(&DeveloperPrivateLoadDirectoryFunction::CopyFile,
1232 this,
1233 src_path,
1234 target_path));
1237 void DeveloperPrivateLoadDirectoryFunction::CopyFile(
1238 const base::FilePath& src_path,
1239 const base::FilePath& target_path) {
1240 if (!base::CreateDirectory(target_path.DirName())) {
1241 SetError("Error in copying files from sync filesystem.");
1242 success_ = false;
1245 if (success_)
1246 base::CopyFile(src_path, target_path);
1248 CHECK(pending_copy_operations_count_ > 0);
1249 pending_copy_operations_count_--;
1251 if (!pending_copy_operations_count_) {
1252 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
1253 base::Bind(&DeveloperPrivateLoadDirectoryFunction::Load,
1254 this));
1258 DeveloperPrivateLoadDirectoryFunction::DeveloperPrivateLoadDirectoryFunction()
1259 : pending_copy_operations_count_(0), success_(true) {}
1261 DeveloperPrivateLoadDirectoryFunction::~DeveloperPrivateLoadDirectoryFunction()
1264 ExtensionFunction::ResponseAction DeveloperPrivateChoosePathFunction::Run() {
1265 scoped_ptr<developer::ChoosePath::Params> params(
1266 developer::ChoosePath::Params::Create(*args_));
1267 EXTENSION_FUNCTION_VALIDATE(params);
1269 ui::SelectFileDialog::Type type = ui::SelectFileDialog::SELECT_FOLDER;
1270 ui::SelectFileDialog::FileTypeInfo info;
1272 if (params->select_type == developer::SELECT_TYPE_FILE)
1273 type = ui::SelectFileDialog::SELECT_OPEN_FILE;
1274 base::string16 select_title;
1276 int file_type_index = 0;
1277 if (params->file_type == developer::FILE_TYPE_LOAD) {
1278 select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY);
1279 } else if (params->file_type == developer::FILE_TYPE_PEM) {
1280 select_title = l10n_util::GetStringUTF16(
1281 IDS_EXTENSION_PACK_DIALOG_SELECT_KEY);
1282 info.extensions.push_back(std::vector<base::FilePath::StringType>(
1283 1, FILE_PATH_LITERAL("pem")));
1284 info.extension_description_overrides.push_back(
1285 l10n_util::GetStringUTF16(
1286 IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION));
1287 info.include_all_files = true;
1288 file_type_index = 1;
1289 } else {
1290 NOTREACHED();
1293 if (!ShowPicker(
1294 type,
1295 select_title,
1296 info,
1297 file_type_index)) {
1298 return RespondNow(Error(kCouldNotShowSelectFileDialogError));
1301 AddRef(); // Balanced by FileSelected / FileSelectionCanceled.
1302 return RespondLater();
1305 void DeveloperPrivateChoosePathFunction::FileSelected(
1306 const base::FilePath& path) {
1307 Respond(OneArgument(new base::StringValue(path.LossyDisplayName())));
1308 Release();
1311 void DeveloperPrivateChoosePathFunction::FileSelectionCanceled() {
1312 // This isn't really an error, but we should keep it like this for
1313 // backward compatability.
1314 Respond(Error(kFileSelectionCanceled));
1315 Release();
1318 DeveloperPrivateChoosePathFunction::~DeveloperPrivateChoosePathFunction() {}
1320 bool DeveloperPrivateIsProfileManagedFunction::RunSync() {
1321 SetResult(new base::FundamentalValue(GetProfile()->IsSupervised()));
1322 return true;
1325 DeveloperPrivateIsProfileManagedFunction::
1326 ~DeveloperPrivateIsProfileManagedFunction() {
1329 DeveloperPrivateRequestFileSourceFunction::
1330 DeveloperPrivateRequestFileSourceFunction() {}
1332 DeveloperPrivateRequestFileSourceFunction::
1333 ~DeveloperPrivateRequestFileSourceFunction() {}
1335 bool DeveloperPrivateRequestFileSourceFunction::RunAsync() {
1336 scoped_ptr<developer::RequestFileSource::Params> params(
1337 developer::RequestFileSource::Params::Create(*args_));
1338 EXTENSION_FUNCTION_VALIDATE(params);
1340 base::DictionaryValue* dict = nullptr;
1341 // TODO(devlin): Use generated |params|.
1342 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0u, &dict));
1344 AddRef(); // Balanced in LaunchCallback().
1345 error_ui_util::HandleRequestFileSource(
1346 dict,
1347 GetProfile(),
1348 base::Bind(&DeveloperPrivateRequestFileSourceFunction::LaunchCallback,
1349 base::Unretained(this)));
1350 return true;
1353 void DeveloperPrivateRequestFileSourceFunction::LaunchCallback(
1354 const base::DictionaryValue& results) {
1355 SetResult(results.DeepCopy());
1356 SendResponse(true);
1357 Release(); // Balanced in RunAsync().
1360 DeveloperPrivateOpenDevToolsFunction::DeveloperPrivateOpenDevToolsFunction() {}
1361 DeveloperPrivateOpenDevToolsFunction::~DeveloperPrivateOpenDevToolsFunction() {}
1363 bool DeveloperPrivateOpenDevToolsFunction::RunAsync() {
1364 scoped_ptr<developer::OpenDevTools::Params> params(
1365 developer::OpenDevTools::Params::Create(*args_));
1366 EXTENSION_FUNCTION_VALIDATE(params);
1368 base::DictionaryValue* dict = nullptr;
1369 // TODO(devlin): Use generated |params|.
1370 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0u, &dict));
1372 error_ui_util::HandleOpenDevTools(dict);
1374 return true;
1377 } // namespace api
1379 } // namespace extensions