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