developer_private_api.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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/saved_files_service.h"
10#include "apps/shell_window.h"
11#include "base/base64.h"
12#include "base/command_line.h"
13#include "base/file_util.h"
14#include "base/files/file_enumerator.h"
15#include "base/i18n/file_util_icu.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/developer_private_api_factory.h"
21#include "chrome/browser/extensions/api/developer_private/entry_picker.h"
22#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
23#include "chrome/browser/extensions/event_names.h"
24#include "chrome/browser/extensions/extension_disabled_ui.h"
25#include "chrome/browser/extensions/extension_error_reporter.h"
26#include "chrome/browser/extensions/extension_service.h"
27#include "chrome/browser/extensions/extension_system.h"
28#include "chrome/browser/extensions/management_policy.h"
29#include "chrome/browser/extensions/shell_window_registry.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/drive_file_sync_service.h"
35#include "chrome/browser/ui/chrome_select_file_policy.h"
36#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
37#include "chrome/common/chrome_notification_types.h"
38#include "chrome/common/chrome_switches.h"
39#include "chrome/common/extensions/api/developer_private.h"
40#include "chrome/common/extensions/background_info.h"
41#include "chrome/common/extensions/incognito_handler.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_handlers/offline_enabled_info.h"
45#include "chrome/common/extensions/manifest_url_handler.h"
46#include "chrome/common/url_constants.h"
47#include "content/public/browser/browser_thread.h"
48#include "content/public/browser/notification_service.h"
49#include "content/public/browser/render_process_host.h"
50#include "content/public/browser/render_view_host.h"
51#include "content/public/browser/site_instance.h"
52#include "content/public/browser/storage_partition.h"
53#include "content/public/browser/web_contents.h"
54#include "extensions/browser/view_type_utils.h"
55#include "extensions/common/constants.h"
56#include "extensions/common/extension_resource.h"
57#include "grit/chromium_strings.h"
58#include "grit/generated_resources.h"
59#include "net/base/net_util.h"
60#include "ui/base/l10n/l10n_util.h"
61#include "ui/webui/web_ui_util.h"
62#include "webkit/browser/fileapi/file_system_context.h"
63#include "webkit/browser/fileapi/file_system_operation_runner.h"
64#include "webkit/browser/fileapi/local_file_system_operation.h"
65#include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
66#include "webkit/common/blob/shareable_file_reference.h"
67
68using apps::ShellWindow;
69using content::RenderViewHost;
70
71namespace extensions {
72
73namespace events = event_names;
74
75namespace {
76
77const base::FilePath::CharType kUnpackedAppsFolder[]
78    = FILE_PATH_LITERAL("apps_target");
79
80ExtensionUpdater* GetExtensionUpdater(Profile* profile) {
81    return profile->GetExtensionService()->updater();
82}
83
84std::vector<base::FilePath> ListFolder(const base::FilePath path) {
85  base::FileEnumerator files(path, false,
86      base::FileEnumerator::DIRECTORIES | base::FileEnumerator::FILES);
87  std::vector<base::FilePath> paths;
88
89  for (base::FilePath current_path = files.Next(); !current_path.empty();
90       current_path = files.Next()) {
91    paths.push_back(current_path);
92  }
93  return paths;
94}
95
96bool ValidateFolderName(const base::FilePath::StringType& name) {
97  base::FilePath::StringType name_sanitized(name);
98  file_util::ReplaceIllegalCharactersInPath(&name_sanitized, '_');
99  return name == name_sanitized;
100}
101
102const Extension* GetExtensionByPath(const ExtensionSet* extensions,
103                                    const base::FilePath& path) {
104  base::FilePath extension_path = base::MakeAbsoluteFilePath(path);
105  for (ExtensionSet::const_iterator iter = extensions->begin();
106       iter != extensions->end(); ++iter) {
107    if ((*iter)->path() == extension_path)
108      return iter->get();
109  }
110  return NULL;
111}
112
113std::string GetExtensionID(const RenderViewHost* render_view_host) {
114  if (!render_view_host->GetSiteInstance())
115    return std::string();
116
117  return render_view_host->GetSiteInstance()->GetSiteURL().host();
118}
119
120}  // namespace
121
122namespace AllowFileAccess = api::developer_private::AllowFileAccess;
123namespace AllowIncognito = api::developer_private::AllowIncognito;
124namespace ChoosePath = api::developer_private::ChoosePath;
125namespace Enable = api::developer_private::Enable;
126namespace GetItemsInfo = api::developer_private::GetItemsInfo;
127namespace Inspect = api::developer_private::Inspect;
128namespace PackDirectory = api::developer_private::PackDirectory;
129namespace Reload = api::developer_private::Reload;
130namespace Restart = api::developer_private::Restart;
131
132DeveloperPrivateAPI* DeveloperPrivateAPI::Get(Profile* profile) {
133  return DeveloperPrivateAPIFactory::GetForProfile(profile);
134}
135
136DeveloperPrivateAPI::DeveloperPrivateAPI(Profile* profile) : profile_(profile) {
137  RegisterNotifications();
138}
139
140DeveloperPrivateEventRouter::DeveloperPrivateEventRouter(Profile* profile)
141: profile_(profile) {
142  int types[] = {
143    chrome::NOTIFICATION_EXTENSION_INSTALLED,
144    chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
145    chrome::NOTIFICATION_EXTENSION_LOADED,
146    chrome::NOTIFICATION_EXTENSION_UNLOADED,
147    chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED,
148    chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED
149  };
150
151  CHECK(registrar_.IsEmpty());
152  for (size_t i = 0; i < arraysize(types); ++i) {
153    registrar_.Add(this,
154                   types[i],
155                   content::Source<Profile>(profile_));
156  }
157}
158
159
160DeveloperPrivateEventRouter::~DeveloperPrivateEventRouter() {}
161
162void DeveloperPrivateEventRouter::Observe(
163    int type,
164    const content::NotificationSource& source,
165    const content::NotificationDetails& details) {
166  const char* event_name = NULL;
167  Profile* profile = content::Source<Profile>(source).ptr();
168  CHECK(profile);
169  CHECK(profile_->IsSameProfile(profile));
170  developer::EventData event_data;
171  std::string extension_id;
172  const Extension* extension = NULL;
173
174  switch (type) {
175    case chrome::NOTIFICATION_EXTENSION_INSTALLED:
176      event_data.event_type = developer::EVENT_TYPE_INSTALLED;
177      extension =
178          content::Details<const InstalledExtensionInfo>(details)->extension;
179      break;
180    case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
181      event_data.event_type = developer::EVENT_TYPE_UNINSTALLED;
182      extension = content::Details<const Extension>(details).ptr();
183      break;
184    case chrome::NOTIFICATION_EXTENSION_LOADED:
185      event_data.event_type = developer::EVENT_TYPE_LOADED;
186      extension = content::Details<const Extension>(details).ptr();
187      break;
188    case chrome::NOTIFICATION_EXTENSION_UNLOADED:
189      event_data.event_type = developer::EVENT_TYPE_UNLOADED;
190      extension =
191          content::Details<const UnloadedExtensionInfo>(details)->extension;
192      break;
193    case chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED:
194      event_data.event_type = developer::EVENT_TYPE_VIEW_UNREGISTERED;
195      event_data.item_id = GetExtensionID(
196          content::Details<const RenderViewHost>(details).ptr());
197      break;
198    case chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED:
199      event_data.event_type = developer::EVENT_TYPE_VIEW_REGISTERED;
200      event_data.item_id = GetExtensionID(
201          content::Details<const RenderViewHost>(details).ptr());
202      break;
203    default:
204      NOTREACHED();
205      return;
206  }
207
208  if (extension)
209    event_data.item_id = extension->id();
210
211  scoped_ptr<ListValue> args(new ListValue());
212  args->Append(event_data.ToValue().release());
213
214  event_name = events::kDeveloperPrivateOnItemStateChanged;
215  scoped_ptr<Event> event(new Event(event_name, args.Pass()));
216  ExtensionSystem::Get(profile)->event_router()->BroadcastEvent(event.Pass());
217}
218
219void DeveloperPrivateAPI::SetLastUnpackedDirectory(const base::FilePath& path) {
220  last_unpacked_directory_ = path;
221}
222
223void DeveloperPrivateAPI::RegisterNotifications() {
224  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
225      this, events::kDeveloperPrivateOnItemStateChanged);
226}
227
228DeveloperPrivateAPI::~DeveloperPrivateAPI() {}
229
230void DeveloperPrivateAPI::Shutdown() {}
231
232void DeveloperPrivateAPI::OnListenerAdded(
233    const EventListenerInfo& details) {
234  if (!developer_private_event_router_)
235    developer_private_event_router_.reset(
236        new DeveloperPrivateEventRouter(profile_));
237}
238
239void DeveloperPrivateAPI::OnListenerRemoved(
240    const EventListenerInfo& details) {
241  if (!ExtensionSystem::Get(profile_)->event_router()->HasEventListener(
242          event_names::kDeveloperPrivateOnItemStateChanged))
243    developer_private_event_router_.reset(NULL);
244}
245
246namespace api {
247
248bool DeveloperPrivateAutoUpdateFunction::RunImpl() {
249  ExtensionUpdater* updater = GetExtensionUpdater(profile());
250  if (updater)
251    updater->CheckNow(ExtensionUpdater::CheckParams());
252  SetResult(Value::CreateBooleanValue(true));
253  return true;
254}
255
256DeveloperPrivateAutoUpdateFunction::~DeveloperPrivateAutoUpdateFunction() {}
257
258scoped_ptr<developer::ItemInfo>
259  DeveloperPrivateGetItemsInfoFunction::CreateItemInfo(
260      const Extension& item,
261      bool item_is_enabled) {
262  scoped_ptr<developer::ItemInfo> info(new developer::ItemInfo());
263
264  ExtensionSystem* system = ExtensionSystem::Get(profile());
265  ExtensionService* service = profile()->GetExtensionService();
266
267  info->id = item.id();
268  info->name = item.name();
269  info->enabled = service->IsExtensionEnabled(info->id);
270  info->offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&item);
271  info->version = item.VersionString();
272  info->description = item.description();
273
274  GURL url =
275      ExtensionIconSource::GetIconURL(&item,
276                                      extension_misc::EXTENSION_ICON_MEDIUM,
277                                      ExtensionIconSet::MATCH_BIGGER,
278                                      false,
279                                      NULL);
280  info->icon_url = url.spec();
281
282  if (item.is_app()) {
283    if (item.is_legacy_packaged_app())
284      info->type = developer::ITEM_TYPE_LEGACY_PACKAGED_APP;
285    else if (item.is_hosted_app())
286      info->type = developer::ITEM_TYPE_HOSTED_APP;
287    else if (item.is_platform_app())
288      info->type = developer::ITEM_TYPE_PACKAGED_APP;
289    else
290      NOTREACHED();
291  } else if (item.is_theme()) {
292    info->type = developer::ITEM_TYPE_THEME;
293  } else if (item.is_extension()) {
294    info->type = developer::ITEM_TYPE_EXTENSION;
295  } else {
296    NOTREACHED();
297  }
298
299  if (Manifest::IsUnpackedLocation(item.location())) {
300    info->path.reset(
301        new std::string(UTF16ToUTF8(item.path().LossyDisplayName())));
302  }
303
304  info->incognito_enabled = service->IsIncognitoEnabled(item.id());
305  info->wants_file_access = item.wants_file_access();
306  info->allow_file_access = service->AllowFileAccess(&item);
307  info->allow_reload = Manifest::IsUnpackedLocation(item.location());
308  info->is_unpacked = Manifest::IsUnpackedLocation(item.location());
309  info->terminated = service->terminated_extensions()->Contains(item.id());
310  info->allow_incognito = item.can_be_incognito_enabled();
311
312  info->homepage_url.reset(new std::string(
313      ManifestURL::GetHomepageURL(&item).spec()));
314  if (!ManifestURL::GetOptionsPage(&item).is_empty()) {
315    info->options_url.reset(
316        new std::string(ManifestURL::GetOptionsPage(&item).spec()));
317  }
318
319  if (!ManifestURL::GetUpdateURL(&item).is_empty()) {
320    info->update_url.reset(
321        new std::string(ManifestURL::GetUpdateURL(&item).spec()));
322  }
323
324  if (item.is_app()) {
325    info->app_launch_url.reset(new std::string(
326        extensions::AppLaunchInfo::GetFullLaunchURL(&item).spec()));
327  }
328
329  info->may_disable = system->management_policy()->
330      UserMayModifySettings(&item, NULL);
331  info->is_app = item.is_app();
332  info->views = GetInspectablePagesForExtension(&item, item_is_enabled);
333
334  return info.Pass();
335}
336
337void DeveloperPrivateGetItemsInfoFunction::
338    GetInspectablePagesForExtensionProcess(
339        const std::set<content::RenderViewHost*>& views,
340        ItemInspectViewList* result) {
341  for (std::set<content::RenderViewHost*>::const_iterator iter = views.begin();
342       iter != views.end(); ++iter) {
343    content::RenderViewHost* host = *iter;
344    content::WebContents* web_contents =
345        content::WebContents::FromRenderViewHost(host);
346    ViewType host_type = GetViewType(web_contents);
347    if (VIEW_TYPE_EXTENSION_POPUP == host_type ||
348        VIEW_TYPE_EXTENSION_DIALOG == host_type)
349      continue;
350
351    content::RenderProcessHost* process = host->GetProcess();
352    result->push_back(
353        constructInspectView(web_contents->GetURL(),
354                             process->GetID(),
355                             host->GetRoutingID(),
356                             process->GetBrowserContext()->IsOffTheRecord()));
357  }
358}
359
360void DeveloperPrivateGetItemsInfoFunction::
361    GetShellWindowPagesForExtensionProfile(
362        const Extension* extension,
363        ItemInspectViewList* result) {
364  ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile());
365  if (!registry) return;
366
367  const ShellWindowRegistry::ShellWindowList windows =
368      registry->GetShellWindowsForApp(extension->id());
369
370  for (ShellWindowRegistry::const_iterator it = windows.begin();
371       it != windows.end(); ++it) {
372    content::WebContents* web_contents = (*it)->web_contents();
373    RenderViewHost* host = web_contents->GetRenderViewHost();
374    content::RenderProcessHost* process = host->GetProcess();
375    result->push_back(
376        constructInspectView(web_contents->GetURL(),
377                             process->GetID(),
378                             host->GetRoutingID(),
379                             process->GetBrowserContext()->IsOffTheRecord()));
380  }
381}
382
383linked_ptr<developer::ItemInspectView> DeveloperPrivateGetItemsInfoFunction::
384    constructInspectView(
385        const GURL& url,
386        int render_process_id,
387        int render_view_id,
388        bool incognito) {
389  linked_ptr<developer::ItemInspectView> view(new developer::ItemInspectView());
390
391  if (url.scheme() == kExtensionScheme) {
392    // No leading slash.
393    view->path = url.path().substr(1);
394  } else {
395    // For live pages, use the full URL.
396    view->path = url.spec();
397  }
398
399  view->render_process_id = render_process_id;
400  view->render_view_id = render_view_id;
401  view->incognito = incognito;
402  return view;
403}
404
405ItemInspectViewList DeveloperPrivateGetItemsInfoFunction::
406    GetInspectablePagesForExtension(
407        const Extension* extension,
408        bool extension_is_enabled) {
409
410  ItemInspectViewList result;
411  // Get the extension process's active views.
412  ExtensionProcessManager* process_manager =
413      ExtensionSystem::Get(profile())->process_manager();
414  GetInspectablePagesForExtensionProcess(
415      process_manager->GetRenderViewHostsForExtension(extension->id()),
416      &result);
417
418  // Get shell window views
419  GetShellWindowPagesForExtensionProfile(extension, &result);
420
421  // Include a link to start the lazy background page, if applicable.
422  if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
423      extension_is_enabled &&
424      !process_manager->GetBackgroundHostForExtension(extension->id())) {
425    result.push_back(constructInspectView(
426        BackgroundInfo::GetBackgroundURL(extension), -1, -1, false));
427  }
428
429  ExtensionService* service = profile()->GetExtensionService();
430  // Repeat for the incognito process, if applicable. Don't try to get
431  // shell windows for incognito process.
432  if (service->profile()->HasOffTheRecordProfile() &&
433      IncognitoInfo::IsSplitMode(extension)) {
434    process_manager = ExtensionSystem::Get(
435        service->profile()->GetOffTheRecordProfile())->process_manager();
436    GetInspectablePagesForExtensionProcess(
437        process_manager->GetRenderViewHostsForExtension(extension->id()),
438        &result);
439
440    if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
441        extension_is_enabled &&
442        !process_manager->GetBackgroundHostForExtension(extension->id())) {
443    result.push_back(constructInspectView(
444        BackgroundInfo::GetBackgroundURL(extension), -1, -1, false));
445    }
446  }
447
448  return result;
449}
450
451bool DeveloperPrivateGetItemsInfoFunction::RunImpl() {
452  scoped_ptr<developer::GetItemsInfo::Params> params(
453      developer::GetItemsInfo::Params::Create(*args_));
454  EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
455
456  bool include_disabled = params->include_disabled;
457  bool include_terminated = params->include_terminated;
458
459  ExtensionSet items;
460
461  ExtensionService* service = profile()->GetExtensionService();
462
463  items.InsertAll(*service->extensions());
464
465  if (include_disabled) {
466    items.InsertAll(*service->disabled_extensions());
467  }
468
469  if (include_terminated) {
470    items.InsertAll(*service->terminated_extensions());
471  }
472
473  ItemInfoList item_list;
474
475  for (ExtensionSet::const_iterator iter = items.begin();
476       iter != items.end(); ++iter) {
477    const Extension& item = *iter->get();
478
479    // Don't show component extensions because they are only extensions as an
480    // implementation detail of Chrome.
481    if (item.location() == Manifest::COMPONENT &&
482        !CommandLine::ForCurrentProcess()->HasSwitch(
483          switches::kShowComponentExtensionOptions)) {
484      continue;
485    }
486
487    // Don't show apps that aren't visible in either launcher or ntp.
488    if (item.is_app() && !item.ShouldDisplayInAppLauncher() &&
489        !item.ShouldDisplayInNewTabPage() &&
490        !Manifest::IsUnpackedLocation(item.location())) {
491      continue;
492    }
493
494    item_list.push_back(make_linked_ptr<developer::ItemInfo>(
495        CreateItemInfo(
496            item, service->IsExtensionEnabled(item.id())).release()));
497  }
498
499  results_ = developer::GetItemsInfo::Results::Create(item_list);
500  SendResponse(true);
501
502  return true;
503}
504
505DeveloperPrivateGetItemsInfoFunction::~DeveloperPrivateGetItemsInfoFunction() {}
506
507bool DeveloperPrivateAllowFileAccessFunction::RunImpl() {
508  scoped_ptr<AllowFileAccess::Params> params(
509      AllowFileAccess::Params::Create(*args_));
510  EXTENSION_FUNCTION_VALIDATE(params.get());
511
512  EXTENSION_FUNCTION_VALIDATE(user_gesture_);
513
514  ExtensionSystem* system = ExtensionSystem::Get(profile());
515  ManagementPolicy* management_policy = system->management_policy();
516  ExtensionService* service = profile()->GetExtensionService();
517  const Extension* extension = service->GetInstalledExtension(params->item_id);
518  bool result = true;
519
520  if (!extension) {
521    result = false;
522  } else if (!management_policy->UserMayModifySettings(extension, NULL)) {
523    LOG(ERROR) << "Attempt to change allow file access of an extension that "
524               << "non-usermanagable was made. Extension id : "
525               << extension->id();
526    result = false;
527  } else {
528    service->SetAllowFileAccess(extension, params->allow);
529    result = true;
530  }
531
532  return result;
533}
534
535DeveloperPrivateAllowFileAccessFunction::
536    ~DeveloperPrivateAllowFileAccessFunction() {}
537
538bool DeveloperPrivateAllowIncognitoFunction::RunImpl() {
539  scoped_ptr<AllowIncognito::Params> params(
540      AllowIncognito::Params::Create(*args_));
541  EXTENSION_FUNCTION_VALIDATE(params.get());
542
543  ExtensionService* service = profile()->GetExtensionService();
544  const Extension* extension = service->GetInstalledExtension(params->item_id);
545  bool result = true;
546
547  if (!extension)
548    result = false;
549  else
550    service->SetIsIncognitoEnabled(extension->id(), params->allow);
551
552  return result;
553}
554
555DeveloperPrivateAllowIncognitoFunction::
556    ~DeveloperPrivateAllowIncognitoFunction() {}
557
558
559bool DeveloperPrivateReloadFunction::RunImpl() {
560  scoped_ptr<Reload::Params> params(Reload::Params::Create(*args_));
561  EXTENSION_FUNCTION_VALIDATE(params.get());
562
563  ExtensionService* service = profile()->GetExtensionService();
564  CHECK(!params->item_id.empty());
565  service->ReloadExtension(params->item_id);
566  return true;
567}
568
569bool DeveloperPrivateShowPermissionsDialogFunction::RunImpl() {
570  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id_));
571  ExtensionService* service = profile()->GetExtensionService();
572  CHECK(!extension_id_.empty());
573  ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile());
574  DCHECK(registry);
575  ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost(
576      render_view_host());
577  prompt_.reset(new ExtensionInstallPrompt(shell_window->web_contents()));
578  const Extension* extension = service->GetInstalledExtension(extension_id_);
579
580  if (!extension)
581    return false;
582
583  // Released by InstallUIAbort or InstallUIProceed.
584  AddRef();
585  std::vector<base::FilePath> retained_file_paths;
586  if (extension->HasAPIPermission(extensions::APIPermission::kFileSystem)) {
587    std::vector<apps::SavedFileEntry> retained_file_entries =
588        apps::SavedFilesService::Get(profile())->GetAllFileEntries(
589            extension_id_);
590    for (size_t i = 0; i < retained_file_entries.size(); i++) {
591      retained_file_paths.push_back(retained_file_entries[i].path);
592    }
593  }
594  prompt_->ReviewPermissions(this, extension, retained_file_paths);
595  return true;
596}
597
598DeveloperPrivateReloadFunction::~DeveloperPrivateReloadFunction() {}
599
600// This is called when the user clicks "Revoke File Access."
601void DeveloperPrivateShowPermissionsDialogFunction::InstallUIProceed() {
602  apps::SavedFilesService::Get(profile())->ClearQueue(
603      profile()->GetExtensionService()->GetExtensionById(extension_id_, true));
604  if (apps::AppRestoreService::Get(profile())->IsAppRestorable(extension_id_))
605    apps::AppLoadService::Get(profile())->RestartApplication(extension_id_);
606  SendResponse(true);
607  Release();
608}
609
610void DeveloperPrivateShowPermissionsDialogFunction::InstallUIAbort(
611    bool user_initiated) {
612  SendResponse(true);
613  Release();
614}
615
616DeveloperPrivateShowPermissionsDialogFunction::
617    DeveloperPrivateShowPermissionsDialogFunction() {}
618
619DeveloperPrivateShowPermissionsDialogFunction::
620    ~DeveloperPrivateShowPermissionsDialogFunction() {}
621
622bool DeveloperPrivateRestartFunction::RunImpl() {
623  scoped_ptr<Restart::Params> params(Restart::Params::Create(*args_));
624  EXTENSION_FUNCTION_VALIDATE(params.get());
625
626  apps::AppLoadService* service = apps::AppLoadService::Get(profile());
627  EXTENSION_FUNCTION_VALIDATE(!params->item_id.empty());
628  ExtensionService* extension_service = profile()->GetExtensionService();
629  // Don't restart disabled applications.
630  if (!extension_service->IsExtensionEnabled(params->item_id))
631    return false;
632
633  service->RestartApplication(params->item_id);
634  return true;
635}
636
637DeveloperPrivateRestartFunction::~DeveloperPrivateRestartFunction() {}
638
639DeveloperPrivateEnableFunction::DeveloperPrivateEnableFunction() {}
640
641bool DeveloperPrivateEnableFunction::RunImpl() {
642  scoped_ptr<Enable::Params> params(Enable::Params::Create(*args_));
643  EXTENSION_FUNCTION_VALIDATE(params.get());
644
645  std::string extension_id = params->item_id;
646
647  ExtensionSystem* system = ExtensionSystem::Get(profile());
648  ManagementPolicy* management_policy = system->management_policy();
649  ExtensionService* service = profile()->GetExtensionService();
650
651  const Extension* extension = service->GetInstalledExtension(extension_id);
652  if (!extension ||
653      !management_policy->UserMayModifySettings(extension, NULL)) {
654    LOG(ERROR) << "Attempt to enable an extension that is non-usermanagable "
655               "was made. Extension id: " << extension->id();
656    return false;
657  }
658
659  if (params->enable) {
660    ExtensionPrefs* prefs = service->extension_prefs();
661    if (prefs->DidExtensionEscalatePermissions(extension_id)) {
662      ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile());
663      CHECK(registry);
664      ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost(
665          render_view_host());
666      if (!shell_window) {
667        return false;
668      }
669
670      ShowExtensionDisabledDialog(
671          service, shell_window->web_contents(), extension);
672    } else if ((prefs->GetDisableReasons(extension_id) &
673                  Extension::DISABLE_UNSUPPORTED_REQUIREMENT) &&
674               !requirements_checker_.get()) {
675      // Recheck the requirements.
676      scoped_refptr<const Extension> extension =
677          service->GetExtensionById(extension_id,
678                                     true );// include_disabled
679      requirements_checker_.reset(new RequirementsChecker);
680      // Released by OnRequirementsChecked.
681      AddRef();
682      requirements_checker_->Check(
683          extension,
684          base::Bind(&DeveloperPrivateEnableFunction::OnRequirementsChecked,
685                     this, extension_id));
686    } else {
687      service->EnableExtension(extension_id);
688
689      // Make sure any browser action contained within it is not hidden.
690      ExtensionActionAPI::SetBrowserActionVisibility(
691          prefs, extension->id(), true);
692    }
693  } else {
694    service->DisableExtension(extension_id, Extension::DISABLE_USER_ACTION);
695  }
696  return true;
697}
698
699void DeveloperPrivateEnableFunction::OnRequirementsChecked(
700    std::string extension_id,
701    std::vector<std::string> requirements_errors) {
702  if (requirements_errors.empty()) {
703    ExtensionService* service = profile()->GetExtensionService();
704    service->EnableExtension(extension_id);
705  } else {
706    ExtensionErrorReporter::GetInstance()->ReportError(
707        UTF8ToUTF16(JoinString(requirements_errors, ' ')),
708        true /* be noisy */);
709  }
710  Release();
711}
712
713DeveloperPrivateEnableFunction::~DeveloperPrivateEnableFunction() {}
714
715bool DeveloperPrivateInspectFunction::RunImpl() {
716  scoped_ptr<developer::Inspect::Params> params(
717      developer::Inspect::Params::Create(*args_));
718  EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
719  const developer::InspectOptions& options = params->options;
720
721  int render_process_id;
722  base::StringToInt(options.render_process_id, &render_process_id);
723
724  if (render_process_id == -1) {
725    // This is a lazy background page. Identify if it is a normal
726    // or incognito background page.
727    ExtensionService* service = profile()->GetExtensionService();
728    if (options.incognito)
729      service = ExtensionSystem::Get(
730          service->profile()->GetOffTheRecordProfile())->extension_service();
731    const Extension* extension = service->extensions()->GetByID(
732        options.extension_id);
733    DCHECK(extension);
734    // Wakes up the background page and  opens the inspect window.
735    service->InspectBackgroundPage(extension);
736    return false;
737  }
738
739  int render_view_id;
740  base::StringToInt(options.render_view_id, &render_view_id);
741  content::RenderViewHost* host = content::RenderViewHost::FromID(
742      render_process_id, render_view_id);
743
744  if (!host) {
745    // This can happen if the host has gone away since the page was displayed.
746    return false;
747  }
748
749  DevToolsWindow::OpenDevToolsWindow(host);
750  return true;
751}
752
753DeveloperPrivateInspectFunction::~DeveloperPrivateInspectFunction() {}
754
755bool DeveloperPrivateLoadUnpackedFunction::RunImpl() {
756  string16 select_title =
757      l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY);
758
759  // Balanced in FileSelected / FileSelectionCanceled.
760  AddRef();
761  bool result = ShowPicker(
762      ui::SelectFileDialog::SELECT_FOLDER,
763      DeveloperPrivateAPI::Get(profile())->GetLastUnpackedDirectory(),
764      select_title,
765      ui::SelectFileDialog::FileTypeInfo(),
766      0);
767  return result;
768}
769
770void DeveloperPrivateLoadUnpackedFunction::FileSelected(
771    const base::FilePath& path) {
772  ExtensionService* service = profile()->GetExtensionService();
773  UnpackedInstaller::Create(service)->Load(path);
774  DeveloperPrivateAPI::Get(profile())->SetLastUnpackedDirectory(path);
775  SendResponse(true);
776  Release();
777}
778
779void DeveloperPrivateLoadUnpackedFunction::FileSelectionCanceled() {
780  SendResponse(false);
781  Release();
782}
783
784bool DeveloperPrivateChooseEntryFunction::ShowPicker(
785    ui::SelectFileDialog::Type picker_type,
786    const base::FilePath& last_directory,
787    const string16& select_title,
788    const ui::SelectFileDialog::FileTypeInfo& info,
789    int file_type_index) {
790  ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile());
791  DCHECK(registry);
792  ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost(
793      render_view_host());
794  if (!shell_window) {
795    return false;
796  }
797
798  // The entry picker will hold a reference to this function instance,
799  // and subsequent sending of the function response) until the user has
800  // selected a file or cancelled the picker. At that point, the picker will
801  // delete itself.
802  new EntryPicker(this, shell_window->web_contents(), picker_type,
803  last_directory, select_title, info, file_type_index);
804  return true;
805}
806
807bool DeveloperPrivateChooseEntryFunction::RunImpl() { return false; }
808
809DeveloperPrivateChooseEntryFunction::~DeveloperPrivateChooseEntryFunction() {}
810
811void DeveloperPrivatePackDirectoryFunction::OnPackSuccess(
812    const base::FilePath& crx_file,
813    const base::FilePath& pem_file) {
814  developer::PackDirectoryResponse response;
815  response.message =
816      UTF16ToUTF8(PackExtensionJob::StandardSuccessMessage(crx_file, pem_file));
817  response.status = developer::PACK_STATUS_SUCCESS;
818  results_ = developer::PackDirectory::Results::Create(response);
819  SendResponse(true);
820  Release();
821}
822
823void DeveloperPrivatePackDirectoryFunction::OnPackFailure(
824    const std::string& error,
825    ExtensionCreator::ErrorType error_type) {
826  developer::PackDirectoryResponse response;
827  response.message = error;
828  if (error_type == ExtensionCreator::kCRXExists) {
829    response.item_path = item_path_str_;
830    response.pem_path = key_path_str_;
831    response.override_flags = ExtensionCreator::kOverwriteCRX;
832    response.status = developer::PACK_STATUS_WARNING;
833  } else {
834    response.status = developer::PACK_STATUS_ERROR;
835  }
836  results_ = developer::PackDirectory::Results::Create(response);
837  SendResponse(true);
838  Release();
839}
840
841bool DeveloperPrivatePackDirectoryFunction::RunImpl() {
842  scoped_ptr<PackDirectory::Params> params(
843      PackDirectory::Params::Create(*args_));
844  EXTENSION_FUNCTION_VALIDATE(params.get());
845
846  int flags = params->flags;
847  item_path_str_ = params->path;
848  key_path_str_ = params->private_key_path;
849
850  base::FilePath root_directory =
851      base::FilePath::FromWStringHack(UTF8ToWide(item_path_str_));
852
853  base::FilePath key_file =
854      base::FilePath::FromWStringHack(UTF8ToWide(key_path_str_));
855
856  developer::PackDirectoryResponse response;
857  if (root_directory.empty()) {
858    if (item_path_str_.empty())
859      response.message = l10n_util::GetStringUTF8(
860          IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED);
861    else
862      response.message = l10n_util::GetStringUTF8(
863          IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID);
864
865    response.status = developer::PACK_STATUS_ERROR;
866    results_ = developer::PackDirectory::Results::Create(response);
867    SendResponse(true);
868    return true;
869  }
870
871  if (!key_path_str_.empty() && key_file.empty()) {
872    response.message = l10n_util::GetStringUTF8(
873        IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID);
874    response.status = developer::PACK_STATUS_ERROR;
875    results_ = developer::PackDirectory::Results::Create(response);
876    SendResponse(true);
877    return true;
878  }
879
880  // Balanced in OnPackSuccess / OnPackFailure.
881  AddRef();
882
883  pack_job_ = new PackExtensionJob(this, root_directory, key_file, flags);
884  pack_job_->Start();
885  return true;
886}
887
888DeveloperPrivatePackDirectoryFunction::DeveloperPrivatePackDirectoryFunction()
889{}
890
891DeveloperPrivatePackDirectoryFunction::~DeveloperPrivatePackDirectoryFunction()
892{}
893
894DeveloperPrivateLoadUnpackedFunction::~DeveloperPrivateLoadUnpackedFunction() {}
895
896bool DeveloperPrivateExportSyncfsFolderToLocalfsFunction::RunImpl() {
897  // TODO(grv) : add unittests.
898  base::FilePath::StringType project_name;
899  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &project_name));
900  if (!ValidateFolderName(project_name)) {
901    DLOG(INFO) << "Invalid project_name : [" << project_name << "]";
902    return false;
903  }
904
905  context_ = content::BrowserContext::GetStoragePartition(profile(),
906      render_view_host()->GetSiteInstance())->GetFileSystemContext();
907
908  base::FilePath project_path(profile()->GetPath());
909  project_path = project_path.Append(kUnpackedAppsFolder);
910  project_path = project_path.Append(project_name);
911
912  content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
913      base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
914                     ClearPrexistingDirectoryContent,
915                 this,
916                 project_path));
917
918  return true;
919}
920
921void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
922    ClearPrexistingDirectoryContent(const base::FilePath& project_path) {
923  if (!base::Delete(project_path, true/*recursive*/)) {
924    SetError("Error in copying files from sync filesystem.");
925    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
926        base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
927                       SendResponse,
928                   this,
929                   false));
930    return;
931  }
932
933  pendingCopyOperationsCount_ = 1;
934
935  content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
936      base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
937                 ReadSyncFileSystemDirectory,
938                 this, project_path, project_path.BaseName()));
939}
940
941void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
942    ReadSyncFileSystemDirectory(const base::FilePath& project_path,
943                                const base::FilePath& destination_path) {
944  std::string origin_url(
945      Extension::GetBaseURLFromExtensionId(extension_id()).spec());
946  fileapi::FileSystemURL url(sync_file_system::CreateSyncableFileSystemURL(
947      GURL(origin_url),
948      destination_path));
949
950  context_->operation_runner()->ReadDirectory(
951      url, base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
952                      ReadSyncFileSystemDirectoryCb,
953                      this, project_path, destination_path));
954}
955
956void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
957    ReadSyncFileSystemDirectoryCb(
958    const base::FilePath& project_path,
959    const base::FilePath& destination_path,
960    base::PlatformFileError status,
961    const fileapi::FileSystemOperation::FileEntryList& file_list,
962    bool has_more) {
963
964  if (status != base::PLATFORM_FILE_OK) {
965    DLOG(ERROR) << "Error in copying files from sync filesystem.";
966    return;
967  }
968
969  // We add 1 to the pending copy operations for both files and directories. We
970  // release the directory copy operation once all the files under the directory
971  // are added for copying. We do that to ensure that pendingCopyOperationsCount
972  // does not become zero before all copy operations are finished.
973  // In case the directory happens to be executing the last copy operation it
974  // will call SendResponse to send the response to the API. The pending copy
975  // operations of files are released by the CopyFile function.
976  pendingCopyOperationsCount_ += file_list.size();
977
978  for (size_t i = 0; i < file_list.size(); ++i) {
979    if (file_list[i].is_directory) {
980      ReadSyncFileSystemDirectory(project_path.Append(file_list[i].name),
981                                  destination_path.Append(file_list[i].name));
982      continue;
983    }
984
985    std::string origin_url(
986        Extension::GetBaseURLFromExtensionId(extension_id()).spec());
987    fileapi::FileSystemURL url(sync_file_system::CreateSyncableFileSystemURL(
988        GURL(origin_url),
989        destination_path.Append(file_list[i].name)));
990    base::FilePath target_path = project_path;
991    target_path = target_path.Append(file_list[i].name);
992
993    context_->operation_runner()->CreateSnapshotFile(
994        url,
995        base::Bind(
996            &DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
997                SnapshotFileCallback,
998            this,
999            target_path));
1000
1001  }
1002
1003  // Directory copy operation released here.
1004  pendingCopyOperationsCount_--;
1005
1006  if (!pendingCopyOperationsCount_) {
1007    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
1008        base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
1009                       SendResponse,
1010                   this,
1011                   success_));
1012  }
1013}
1014
1015void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::SnapshotFileCallback(
1016    const base::FilePath& target_path,
1017    base::PlatformFileError result,
1018    const base::PlatformFileInfo& file_info,
1019    const base::FilePath& src_path,
1020    const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) {
1021  if (result != base::PLATFORM_FILE_OK) {
1022    SetError("Error in copying files from sync filesystem.");
1023    success_ = false;
1024    return;
1025  }
1026
1027  content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
1028      base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::CopyFile,
1029                 this,
1030                 src_path,
1031                 target_path));
1032}
1033
1034void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::CopyFile(
1035    const base::FilePath& src_path,
1036    const base::FilePath& target_path) {
1037  if (!file_util::CreateDirectory(target_path.DirName())) {
1038    SetError("Error in copying files from sync filesystem.");
1039    success_ = false;
1040  }
1041
1042  if (success_)
1043    file_util::CopyFile(src_path, target_path);
1044
1045  CHECK(pendingCopyOperationsCount_ > 0);
1046  pendingCopyOperationsCount_--;
1047
1048  if (!pendingCopyOperationsCount_) {
1049    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
1050        base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
1051                       SendResponse,
1052                   this,
1053                   success_));
1054  }
1055}
1056
1057DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
1058    DeveloperPrivateExportSyncfsFolderToLocalfsFunction()
1059    : pendingCopyOperationsCount_(0), success_(true) {}
1060
1061DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
1062    ~DeveloperPrivateExportSyncfsFolderToLocalfsFunction() {}
1063
1064bool DeveloperPrivateLoadProjectFunction::RunImpl() {
1065  // TODO(grv) : add unit tests.
1066  base::FilePath::StringType project_name;
1067  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &project_name));
1068  if (!ValidateFolderName(project_name)) {
1069    DLOG(INFO) << "Invalid project_name : [" << project_name << "]";
1070    return false;
1071  }
1072
1073  base::FilePath path(profile()->GetPath());
1074  path = path.Append(kUnpackedAppsFolder);
1075  // TODO(grv) : Sanitize / check project_name.
1076  path = path.Append(project_name);
1077  ExtensionService* service = profile()->GetExtensionService();
1078  UnpackedInstaller::Create(service)->Load(path);
1079
1080  const ExtensionSet* extensions = service->extensions();
1081  // Released by GetUnpackedExtension.
1082  AddRef();
1083  content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
1084      base::Bind(&DeveloperPrivateLoadProjectFunction::GetUnpackedExtension,
1085                 this, path, extensions));
1086  return true;
1087}
1088
1089void DeveloperPrivateLoadProjectFunction::GetUnpackedExtension(
1090    const base::FilePath& path,
1091    const ExtensionSet* extensions) {
1092  const Extension* extension = GetExtensionByPath(extensions, path);
1093  bool success = true;
1094  if (extension) {
1095    SetResult(base::Value::CreateStringValue(extension->id()));
1096  } else {
1097    SetError("unable to load the project");
1098    success = false;
1099  }
1100  content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
1101      base::Bind(&DeveloperPrivateLoadProjectFunction::SendResponse,
1102                 this,
1103                 success));
1104  Release();
1105}
1106
1107DeveloperPrivateLoadProjectFunction::DeveloperPrivateLoadProjectFunction() {}
1108
1109DeveloperPrivateLoadProjectFunction::~DeveloperPrivateLoadProjectFunction() {}
1110
1111bool DeveloperPrivateChoosePathFunction::RunImpl() {
1112
1113  scoped_ptr<developer::ChoosePath::Params> params(
1114      developer::ChoosePath::Params::Create(*args_));
1115  EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
1116
1117  ui::SelectFileDialog::Type type = ui::SelectFileDialog::SELECT_FOLDER;
1118  ui::SelectFileDialog::FileTypeInfo info;
1119  if (params->select_type == developer::SELECT_TYPE_FILE) {
1120    type = ui::SelectFileDialog::SELECT_OPEN_FILE;
1121  }
1122  string16 select_title;
1123
1124  int file_type_index = 0;
1125  if (params->file_type == developer::FILE_TYPE_LOAD)
1126    select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY);
1127  else if (params->file_type== developer::FILE_TYPE_PEM) {
1128    select_title = l10n_util::GetStringUTF16(
1129        IDS_EXTENSION_PACK_DIALOG_SELECT_KEY);
1130    info.extensions.push_back(std::vector<base::FilePath::StringType>());
1131    info.extensions.front().push_back(FILE_PATH_LITERAL("pem"));
1132    info.extension_description_overrides.push_back(
1133        l10n_util::GetStringUTF16(
1134            IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION));
1135    info.include_all_files = true;
1136    file_type_index = 1;
1137  } else {
1138    NOTREACHED();
1139  }
1140
1141  // Balanced by FileSelected / FileSelectionCanceled.
1142  AddRef();
1143  bool result = ShowPicker(
1144      type,
1145      DeveloperPrivateAPI::Get(profile())->GetLastUnpackedDirectory(),
1146      select_title,
1147      info,
1148      file_type_index);
1149  return result;
1150}
1151
1152void DeveloperPrivateChoosePathFunction::FileSelected(
1153    const base::FilePath& path) {
1154  SetResult(base::Value::CreateStringValue(
1155      UTF16ToUTF8(path.LossyDisplayName())));
1156  SendResponse(true);
1157  Release();
1158}
1159
1160void DeveloperPrivateChoosePathFunction::FileSelectionCanceled() {
1161  SendResponse(false);
1162  Release();
1163}
1164
1165DeveloperPrivateChoosePathFunction::~DeveloperPrivateChoosePathFunction() {}
1166
1167bool DeveloperPrivateGetStringsFunction::RunImpl() {
1168  base::DictionaryValue* dict = new base::DictionaryValue();
1169  SetResult(dict);
1170
1171  webui::SetFontAndTextDirection(dict);
1172
1173  #define   SET_STRING(id, idr) \
1174    dict->SetString(id, l10n_util::GetStringUTF16(idr))
1175  SET_STRING("extensionSettings", IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE);
1176
1177  SET_STRING("appsDevtoolSearch", IDS_APPS_DEVTOOL_SEARCH);
1178  SET_STRING("appsDevtoolNoApps", IDS_APPS_DEVTOOL_NO_APPS_INSTALLED);
1179  SET_STRING("appsDevtoolApps", IDS_APPS_DEVTOOL_APPS_INSTALLED);
1180  SET_STRING("appsDevtoolExtensions", IDS_APPS_DEVTOOL_EXTENSIONS_INSTALLED);
1181  SET_STRING("appsDevtoolNoExtensions", IDS_EXTENSIONS_NONE_INSTALLED);
1182  SET_STRING("appsDevtoolUnpacked", IDS_APPS_DEVTOOL_UNPACKED_INSTALLED);
1183  SET_STRING("appsDevtoolNoUnpacked", IDS_APPS_DEVTOOL_NO_UNPACKED_INSTALLED);
1184  SET_STRING("appsDevtoolTitle", IDS_APPS_DEVTOOL_TITLE);
1185  SET_STRING("extensionSettingsGetMoreExtensions", IDS_GET_MORE_EXTENSIONS);
1186  SET_STRING("extensionSettingsExtensionId", IDS_EXTENSIONS_ID);
1187  SET_STRING("extensionSettingsExtensionPath", IDS_EXTENSIONS_PATH);
1188  SET_STRING("extensionSettingsInspectViews", IDS_EXTENSIONS_INSPECT_VIEWS);
1189  SET_STRING("extensionSettingsInstallWarnings",
1190             IDS_EXTENSIONS_INSTALL_WARNINGS);
1191  SET_STRING("viewIncognito", IDS_EXTENSIONS_VIEW_INCOGNITO);
1192  SET_STRING("viewInactive", IDS_EXTENSIONS_VIEW_INACTIVE);
1193  SET_STRING("extensionSettingsEnable", IDS_EXTENSIONS_ENABLE);
1194  SET_STRING("extensionSettingsEnabled", IDS_EXTENSIONS_ENABLED);
1195  SET_STRING("extensionSettingsRemove", IDS_EXTENSIONS_REMOVE);
1196  SET_STRING("extensionSettingsEnableIncognito",
1197             IDS_EXTENSIONS_ENABLE_INCOGNITO);
1198  SET_STRING("extensionSettingsAllowFileAccess",
1199             IDS_EXTENSIONS_ALLOW_FILE_ACCESS);
1200  SET_STRING("extensionSettingsReloadTerminated",
1201             IDS_EXTENSIONS_RELOAD_TERMINATED);
1202  SET_STRING("extensionSettingsReloadUnpacked", IDS_EXTENSIONS_RELOAD_UNPACKED);
1203  SET_STRING("extensionSettingsLaunch", IDS_EXTENSIONS_LAUNCH);
1204  SET_STRING("extensionSettingsRestart", IDS_EXTENSIONS_RESTART);
1205  SET_STRING("extensionSettingsOptions", IDS_EXTENSIONS_OPTIONS_LINK);
1206  SET_STRING("extensionSettingsPermissions", IDS_EXTENSIONS_PERMISSIONS_LINK);
1207  SET_STRING("extensionSettingsVisitWebsite", IDS_EXTENSIONS_VISIT_WEBSITE);
1208  SET_STRING("extensionSettingsVisitWebStore", IDS_EXTENSIONS_VISIT_WEBSTORE);
1209  SET_STRING("extensionSettingsPolicyControlled",
1210             IDS_EXTENSIONS_POLICY_CONTROLLED);
1211  SET_STRING("extensionSettingsManagedMode",
1212             IDS_EXTENSIONS_LOCKED_MANAGED_USER);
1213  SET_STRING("extensionSettingsShowButton", IDS_EXTENSIONS_SHOW_BUTTON);
1214  SET_STRING("appsDevtoolLoadUnpackedButton",
1215             IDS_APPS_DEVTOOL_LOAD_UNPACKED_BUTTON);
1216  SET_STRING("appsDevtoolPackButton", IDS_APPS_DEVTOOL_PACK_BUTTON);
1217  SET_STRING("extensionSettingsCommandsLink",
1218             IDS_EXTENSIONS_COMMANDS_CONFIGURE);
1219  SET_STRING("appsDevtoolUpdateButton", IDS_APPS_DEVTOOL_UPDATE_BUTTON);
1220  SET_STRING("extensionSettingsWarningsTitle", IDS_EXTENSION_WARNINGS_TITLE);
1221  SET_STRING("extensionSettingsShowDetails", IDS_EXTENSIONS_SHOW_DETAILS);
1222  SET_STRING("extensionSettingsHideDetails", IDS_EXTENSIONS_HIDE_DETAILS);
1223  SET_STRING("extensionUninstall", IDS_EXTENSIONS_UNINSTALL);
1224  SET_STRING("extensionsPermissionsHeading",
1225             IDS_EXTENSIONS_PERMISSIONS_HEADING);
1226  SET_STRING("extensionsPermissionsClose", IDS_EXTENSIONS_PERMISSIONS_CLOSE);
1227  SET_STRING("extensionDisabled", IDS_EXTENSIONS_DISABLED);
1228  SET_STRING("extensionSettingsShowLogsButton", IDS_EXTENSIONS_SHOW_LOGS);
1229  SET_STRING("extensionSettingsMoreDetailsButton", IDS_EXTENSIONS_MORE_DETAILS);
1230  SET_STRING("extensionSettingsVersion", IDS_EXTENSIONS_VERSION);
1231  SET_STRING("extensionSettingsDelete", IDS_EXTENSIONS_DELETE);
1232  SET_STRING("extensionSettingsPack", IDS_EXTENSIONS_PACK);
1233
1234// Pack Extension strings
1235  SET_STRING("packExtensionOverlay", IDS_EXTENSION_PACK_DIALOG_TITLE);
1236  SET_STRING("packExtensionHeading", IDS_EXTENSION_ADT_PACK_DIALOG_HEADING);
1237  SET_STRING("packExtensionCommit", IDS_EXTENSION_PACK_BUTTON);
1238  SET_STRING("ok",IDS_OK);
1239  SET_STRING("cancel",IDS_CANCEL);
1240  SET_STRING("packExtensionRootDir",
1241     IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL);
1242  SET_STRING("packExtensionPrivateKey",
1243     IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL);
1244  SET_STRING("packExtensionBrowseButton", IDS_EXTENSION_PACK_DIALOG_BROWSE);
1245  SET_STRING("packExtensionProceedAnyway", IDS_EXTENSION_PROCEED_ANYWAY);
1246  SET_STRING("packExtensionWarningTitle", IDS_EXTENSION_PACK_WARNING_TITLE);
1247  SET_STRING("packExtensionErrorTitle", IDS_EXTENSION_PACK_ERROR_TITLE);
1248
1249  #undef   SET_STRING
1250  return true;
1251}
1252
1253DeveloperPrivateGetStringsFunction::~DeveloperPrivateGetStringsFunction() {}
1254
1255} // namespace api
1256
1257} // namespace extensions
1258