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