diff options
| author | grv@chromium.org <grv@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-18 01:34:34 +0000 | 
|---|---|---|
| committer | grv@chromium.org <grv@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-18 01:34:34 +0000 | 
| commit | ffcf2f9b4acd11504a770dbb4efd5810f6387c1c (patch) | |
| tree | 70e21e452d36413ed30852e81dec2d651dfdbc4a | |
| parent | ac18c22ad570f314ee565d12804ef8c752459601 (diff) | |
| download | chromium_src-ffcf2f9b4acd11504a770dbb4efd5810f6387c1c.zip chromium_src-ffcf2f9b4acd11504a770dbb4efd5810f6387c1c.tar.gz chromium_src-ffcf2f9b4acd11504a770dbb4efd5810f6387c1c.tar.bz2 | |
First few API implementation of AppsDebuggerPrivate.
This CL adds the skeleton for AppsDebuggerPrivate APIs with 
Implementation of getItemInfo, Inspect and AutoUpdate.
Will be adding apitest to the CL.
BUG=149036
TBR=estrade@chromium.org
TBR=sky@chromium.org
Review URL: https://chromiumcodereview.appspot.com/11428116
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@173612 0039d316-1c4b-4281-b951-d872f2087c98
27 files changed, 826 insertions, 1 deletions
| diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc new file mode 100644 index 0000000..5519ee8 --- /dev/null +++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc @@ -0,0 +1,296 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/developer_private/developer_private_api.h" + +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/debugger/devtools_window.h" +#include "chrome/browser/extensions/api/developer_private/developer_private_api_factory.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_system.h" +#include "chrome/browser/extensions/management_policy.h" +#include "chrome/browser/extensions/updater/extension_updater.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/extensions/extension_icon_source.h" +#include "chrome/browser/view_type_utils.h" +#include "chrome/common/extensions/api/developer_private.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" +#include "grit/generated_resources.h" + +using content::RenderViewHost; +using extensions::DeveloperPrivateAPI; +using extensions::Extension; +using extensions::ExtensionSystem; + +namespace { + +extensions::ExtensionUpdater* GetExtensionUpdater(Profile* profile) { +    return profile->GetExtensionService()->updater(); +} + +}  // namespace + +namespace extensions { + +DeveloperPrivateAPI* DeveloperPrivateAPI::Get(Profile* profile) { +  return DeveloperPrivateAPIFactory::GetForProfile(profile); +} + +DeveloperPrivateAPI::DeveloperPrivateAPI(Profile* profile) +  : profile_(profile), +    deleting_render_view_host_(NULL) { +      RegisterNotifications(); +} + +scoped_ptr<developer::ItemInfo> DeveloperPrivateAPI::CreateItemInfo( +    const Extension& item, +    ExtensionSystem* system, +    bool item_is_enabled) { +  scoped_ptr<developer::ItemInfo> info(new developer::ItemInfo()); +  ExtensionService* service = system->extension_service(); + +  info->id = item.id(); +  info->name = item.name(); +  info->enabled = service->IsExtensionEnabled(info->id); +  info->offline_enabled = item.offline_enabled(); +  info->version = item.VersionString(); +  info->description = item.description(); + +  if (item.is_app()) { +    if (item.is_legacy_packaged_app()) +      info->type = developer::DEVELOPER_PRIVATE_ITEM_TYPE_LEGACY_PACKAGED_APP; +    else if (item.is_hosted_app()) +      info->type = developer::DEVELOPER_PRIVATE_ITEM_TYPE_HOSTED_APP; +    else if (item.is_platform_app()) +      info->type = developer::DEVELOPER_PRIVATE_ITEM_TYPE_PACKAGED_APP; +    else +      NOTREACHED(); +  } else if (item.is_theme()) { +    info->type = developer::DEVELOPER_PRIVATE_ITEM_TYPE_THEME; +  } else if (item.is_extension()) { +    info->type = developer::DEVELOPER_PRIVATE_ITEM_TYPE_EXTENSION; +  } else { +    NOTREACHED(); +  } + +  if (item.location() == Extension::LOAD) { +    info->path.reset( +        new std::string(UTF16ToUTF8(item.path().LossyDisplayName()))); +  } + +  info->enabled_incognito = service->IsIncognitoEnabled(item.id()); +  info->wants_file_access = item.wants_file_access(); +  info->allow_file_access = service->AllowFileAccess(&item); +  info->allow_reload = (item.location() == Extension::LOAD); +  info->is_unpacked = (item.location() == Extension::LOAD); + +  GURL icon = +      ExtensionIconSource::GetIconURL(&item, +                                      extension_misc::EXTENSION_ICON_MEDIUM, +                                      ExtensionIconSet::MATCH_BIGGER, +                                      !info->enabled, +                                      NULL); +  info->icon = icon.spec(); + +  info->homepage_url.reset(new std::string(item.GetHomepageURL().spec())); +  if (!item.options_url().is_empty()) { +    info->options_url.reset(new std::string(item.options_url().spec())); +  } + +  if (!item.update_url().is_empty()) { +    info->update_url.reset(new std::string( +        item.update_url().spec())); +  } + +  if (item.is_app()) { +    info->app_launch_url.reset(new std::string( +        item.GetFullLaunchURL().spec())); +  } + +  info->may_disable = system->management_policy()-> +      UserMayModifySettings(&item, NULL); +  info->is_app = item.is_app(); +  info->views = GetInspectablePagesForExtension(&item, item_is_enabled); + +  return info.Pass(); +} + +void DeveloperPrivateAPI::AddItemsInfo(const ExtensionSet& items, +                                       ExtensionSystem* system, +                                       ItemInfoList* item_list) { + +  for (ExtensionSet::const_iterator iter = items.begin(); +       iter != items.end(); ++iter) { +    const Extension& item = **iter; +    if (item.location() == Extension::COMPONENT) +      continue; // Skip built-in extensions / apps; +    item_list->push_back(make_linked_ptr<developer::ItemInfo>( +        CreateItemInfo(item, system, false).release())); +  } +} + +void DeveloperPrivateAPI::GetInspectablePagesForExtensionProcess( +    const std::set<content::RenderViewHost*>& views, +    ItemInspectViewList* result) { +  for (std::set<content::RenderViewHost*>::const_iterator iter = views.begin(); +       iter != views.end(); ++iter) { +    content::RenderViewHost* host = *iter; +    content::WebContents* web_contents = +        content::WebContents::FromRenderViewHost(host); +    chrome::ViewType host_type = chrome::GetViewType(web_contents); +    if (host == deleting_render_view_host_ || +        chrome::VIEW_TYPE_EXTENSION_POPUP == host_type || +        chrome::VIEW_TYPE_EXTENSION_DIALOG == host_type) +      continue; + +    GURL url = web_contents->GetURL(); +    content::RenderProcessHost* process = host->GetProcess(); +    linked_ptr<developer::ItemInspectView> +        view(new developer::ItemInspectView()); +    view->path = url.path().substr(1); +    view->render_process_id = process->GetID(); +    view->render_view_id = host->GetRoutingID(); +    view->incognito = process->GetBrowserContext()->IsOffTheRecord(); + +    result->push_back(view); +  } +} + +ItemInspectViewList DeveloperPrivateAPI::GetInspectablePagesForExtension( +    const extensions::Extension* extension, +    bool extension_is_enabled) { + +  ItemInspectViewList result; +  // Get the extension process's active views. +  ExtensionProcessManager* process_manager = +      extensions::ExtensionSystem::Get(profile_)->process_manager(); +  GetInspectablePagesForExtensionProcess( +      process_manager->GetRenderViewHostsForExtension(extension->id()), +      &result); +  return result; +} + +void DeveloperPrivateAPI::Observe( +    int type, +    const content::NotificationSource& source, +    const content::NotificationDetails& details) { +  Profile* source_profile = NULL; +  switch (type) { +    // TODO(grv): Listen to other notifications. +    case content::NOTIFICATION_RENDER_VIEW_HOST_DELETED: +    case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED: +      deleting_render_view_host_ +          = content::Source<RenderViewHost>(source).ptr(); +      source_profile = content::Source<Profile>(source).ptr(); +      break; +    default: +      NOTREACHED(); +  } +} + +void DeveloperPrivateAPI::RegisterNotifications() { +  registrar_.Add(this, +                 content::NOTIFICATION_RENDER_VIEW_HOST_DELETED, +                 content::NotificationService::AllBrowserContextsAndSources()); +  registrar_.Add(this, +                 chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED, +                 content::NotificationService::AllBrowserContextsAndSources()); +} + +DeveloperPrivateAPI::~DeveloperPrivateAPI() {} + +void DeveloperPrivateAPI::Shutdown() {} + +namespace api { + +bool DeveloperPrivateAutoUpdateFunction::RunImpl() { +  extensions::ExtensionUpdater* updater = GetExtensionUpdater(profile()); +  if (updater) +    updater->CheckNow(extensions::ExtensionUpdater::CheckParams()); +  SetResult(Value::CreateBooleanValue(true)); +  return true; +} + +DeveloperPrivateAutoUpdateFunction::~DeveloperPrivateAutoUpdateFunction() {} + +bool DeveloperPrivateGetItemsInfoFunction::RunImpl() { +  ItemInfoList items; +  ExtensionSystem* system = ExtensionSystem::Get(profile()); +  scoped_ptr<developer::GetItemsInfo::Params> params( +      developer::GetItemsInfo::Params::Create(*args_)); +  EXTENSION_FUNCTION_VALIDATE(params.get() != NULL); + +  bool include_disabled = params->include_disabled; +  bool include_terminated = params->include_terminated; +  ExtensionSet extension_set; +  extension_set.InsertAll( +      *profile()->GetExtensionService()->extensions()); + +  if (include_disabled) { +    extension_set.InsertAll( +        *profile()->GetExtensionService()->disabled_extensions()); +  } + +  if (include_terminated) { +    extension_set.InsertAll( +        *profile()->GetExtensionService()->disabled_extensions()); +  } + +  DeveloperPrivateAPI::Get(profile())->AddItemsInfo( +      extension_set, system, &items); + +  results_ = developer::GetItemsInfo::Results::Create(items); +  return true; +} + +DeveloperPrivateGetItemsInfoFunction::~DeveloperPrivateGetItemsInfoFunction() {} + +bool DeveloperPrivateInspectFunction::RunImpl() { +  scoped_ptr<developer::Inspect::Params> params( +      developer::Inspect::Params::Create(*args_)); +  EXTENSION_FUNCTION_VALIDATE(params.get() != NULL); +  const developer::InspectOptions& options = params->options; + +  int render_process_id; +  base::StringToInt(options.render_process_id, &render_process_id); + +  if (render_process_id == -1) { +    // This is a lazy background page. Identify if it is a normal +    // or incognito background page. +    ExtensionService* service = profile()->GetExtensionService(); +    if (options.incognito) +      service = extensions::ExtensionSystem::Get( +          service->profile()->GetOffTheRecordProfile())->extension_service(); +    const Extension* extension = service->extensions()->GetByID( +        options.extension_id); +    DCHECK(extension); +    // Wakes up the background page and  opens the inspect window. +    service->InspectBackgroundPage(extension); +    return false; +  } + +  int render_view_id; +  base::StringToInt(options.render_view_id, &render_view_id); +  content::RenderViewHost* host = content::RenderViewHost::FromID( +      render_process_id, render_view_id); + +  if (!host) { +    // This can happen if the host has gone away since the page was displayed. +    return false; +  } + +  DevToolsWindow::OpenDevToolsWindow(host); +  return true; +} + +DeveloperPrivateInspectFunction::~DeveloperPrivateInspectFunction() {} + +}  // namespace api + +}  // namespace extensions diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.h b/chrome/browser/extensions/api/developer_private/developer_private_api.h new file mode 100644 index 0000000..f97cad8 --- /dev/null +++ b/chrome/browser/extensions/api/developer_private/developer_private_api.h @@ -0,0 +1,128 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_API_DEVELOPER_PRIVATE_DEVELOPER_PRIVATE_API_H_ +#define CHROME_BROWSER_EXTENSIONS_API_DEVELOPER_PRIVATE_DEVELOPER_PRIVATE_API_H_ + +#include "chrome/browser/extensions/extension_function.h" +#include "chrome/browser/extensions/extension_install_prompt.h" +#include "chrome/browser/profiles/profile_keyed_service.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" +#include "content/public/browser/render_view_host.h" + +namespace extensions { + +class ExtensionSystem; + +namespace api { + +namespace developer_private { +struct ItemInfo; +struct ItemInspectView; +} + +}  // namespace api + +}  // namespace extensions + +namespace developer = extensions::api::developer_private; + +typedef std::vector<linked_ptr<developer::ItemInfo> > ItemInfoList; +typedef std::vector<linked_ptr<developer::ItemInspectView> > +    ItemInspectViewList; + +namespace extensions { + +// The profile-keyed service that manages the DeveloperPrivate API. +class DeveloperPrivateAPI : public ProfileKeyedService, +                            public content::NotificationObserver { + public: +  // Convenience method to get the DeveloperPrivateAPI for a profile. +  static DeveloperPrivateAPI* Get(Profile* profile); + +  explicit DeveloperPrivateAPI(Profile* profile); +  virtual ~DeveloperPrivateAPI(); + +  void AddItemsInfo(const ExtensionSet& items, +                    ExtensionSystem* system, +                    ItemInfoList* item_list); + +  // ProfileKeyedService implementation +  virtual void Shutdown() OVERRIDE; + +  // content::NotificationObserver implementation. +  virtual void Observe(int type, +                       const content::NotificationSource& source, +                       const content::NotificationDetails& details) OVERRIDE; + + private: +  void RegisterNotifications(); + +  scoped_ptr<developer::ItemInfo> CreateItemInfo( +      const extensions::Extension& item, +      ExtensionSystem* system, +      bool item_is_enabled); + +  // Helper that lists the current inspectable html pages for the extension. +  void GetInspectablePagesForExtensionProcess( +      const std::set<content::RenderViewHost*>& views, +      ItemInspectViewList* result); + +  ItemInspectViewList GetInspectablePagesForExtension( +      const extensions::Extension* extension, +      bool extension_is_enabled); + +  Profile* profile_; + +  content::NotificationRegistrar registrar_; + +  // The page may be refreshed in response to a RENDER_VIEW_HOST_DELETED, +  // but the iteration over RenderViewHosts will include the host because the +  // notification is sent when it is in the process of being deleted (and before +  // it is removed from the process). Keep a pointer to it so we can exclude +  // it from the active views. +  content::RenderViewHost* deleting_render_view_host_; +}; + +namespace api { + +class DeveloperPrivateAutoUpdateFunction : public SyncExtensionFunction { + public: +  DECLARE_EXTENSION_FUNCTION_NAME("developerPrivate.autoUpdate"); + + protected: +  virtual ~DeveloperPrivateAutoUpdateFunction(); + +  // ExtensionFunction: +  virtual bool RunImpl() OVERRIDE; +}; + +class DeveloperPrivateGetItemsInfoFunction : public SyncExtensionFunction { + public: +  DECLARE_EXTENSION_FUNCTION_NAME("developerPrivate.getItemsInfo"); + + protected: +  virtual ~DeveloperPrivateGetItemsInfoFunction(); + +  // ExtensionFunction: +  virtual bool RunImpl() OVERRIDE; +}; + +class DeveloperPrivateInspectFunction : public SyncExtensionFunction { + public: +  DECLARE_EXTENSION_FUNCTION_NAME("developerPrivate.inspect"); + + protected: +  virtual ~DeveloperPrivateInspectFunction(); + +  // ExtensionFunction: +  virtual bool RunImpl() OVERRIDE; +}; + +}  // namespace api + +}  // namespace extensions + +#endif  // CHROME_BROWSER_EXTENSIONS_API_DEVELOPER_PRIVATE_DEVELOPER_PRIVATE_API_H_ diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_factory.cc b/chrome/browser/extensions/api/developer_private/developer_private_api_factory.cc new file mode 100644 index 0000000..f1ab5d6 --- /dev/null +++ b/chrome/browser/extensions/api/developer_private/developer_private_api_factory.cc @@ -0,0 +1,51 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/developer_private/developer_private_api_factory.h" + +#include "chrome/browser/extensions/api/developer_private/developer_private_api.h" +#include "chrome/browser/extensions/extension_system_factory.h" +#include "chrome/browser/profiles/profile_dependency_manager.h" + +namespace extensions { + +// static +DeveloperPrivateAPI* DeveloperPrivateAPIFactory::GetForProfile( +    Profile* profile) { +  return static_cast<DeveloperPrivateAPI*>( +      GetInstance()->GetServiceForProfile(profile, true)); +} + +// static +DeveloperPrivateAPIFactory* DeveloperPrivateAPIFactory::GetInstance() { +  return Singleton<DeveloperPrivateAPIFactory>::get(); +} + +DeveloperPrivateAPIFactory::DeveloperPrivateAPIFactory() +    : ProfileKeyedServiceFactory("DeveloperPrivateAPI", +                                 ProfileDependencyManager::GetInstance()) { +  DependsOn(ExtensionSystemFactory::GetInstance()); +} + +DeveloperPrivateAPIFactory::~DeveloperPrivateAPIFactory() { +} + +ProfileKeyedService* DeveloperPrivateAPIFactory::BuildServiceInstanceFor( +    Profile* profile) const { +  return new DeveloperPrivateAPI(profile); +} + +bool DeveloperPrivateAPIFactory::ServiceRedirectedInIncognito() const { +  return true; +} + +bool DeveloperPrivateAPIFactory::ServiceIsCreatedWithProfile() const { +  return true; +} + +bool DeveloperPrivateAPIFactory::ServiceIsNULLWhileTesting() const { +  return true; +} + +}  // namespace extensions diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_factory.h b/chrome/browser/extensions/api/developer_private/developer_private_api_factory.h new file mode 100644 index 0000000..c1ef9f6 --- /dev/null +++ b/chrome/browser/extensions/api/developer_private/developer_private_api_factory.h @@ -0,0 +1,39 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_API_DEVELOPER_PRIVATE_DEVELOPER_PRIVATE_API_FACTORY_H_ +#define CHROME_BROWSER_EXTENSIONS_API_DEVELOPER_PRIVATE_DEVELOPER_PRIVATE_API_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "chrome/browser/profiles/profile_keyed_service_factory.h" + +namespace extensions { + +class DeveloperPrivateAPI; + +// This is a singleton class which holds profileKeyed references to +// DeveloperPrivateAPI class. +class DeveloperPrivateAPIFactory : public ProfileKeyedServiceFactory { + public: +  static DeveloperPrivateAPI* GetForProfile(Profile* profile); + +  static DeveloperPrivateAPIFactory* GetInstance(); + + private: +  friend struct DefaultSingletonTraits<DeveloperPrivateAPIFactory>; + +  DeveloperPrivateAPIFactory(); +  virtual ~DeveloperPrivateAPIFactory(); + +  // ProfileKeyedServiceFactory implementation. +  virtual ProfileKeyedService* BuildServiceInstanceFor( +      Profile* profile) const OVERRIDE; +  virtual bool ServiceRedirectedInIncognito() const OVERRIDE; +  virtual bool ServiceIsCreatedWithProfile() const OVERRIDE; +  virtual bool ServiceIsNULLWhileTesting() const OVERRIDE; +}; + +}  // namespace extensions + +#endif  // CHROME_BROWSER_EXTENSIONS_API_DEVELOPER_PRIVATE_DEVELOPER_PRIVATE_API_FACTORY_H_ diff --git a/chrome/browser/extensions/api/developer_private/developer_private_apitest.cc b/chrome/browser/extensions/api/developer_private/developer_private_apitest.cc new file mode 100644 index 0000000..3864e7c --- /dev/null +++ b/chrome/browser/extensions/api/developer_private/developer_private_apitest.cc @@ -0,0 +1,55 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <map> + +#include "chrome/browser/extensions/extension_apitest.h" +#include "chrome/common/chrome_switches.h" + +using extensions::Extension; +using extensions::Manifest; + +class DeveloperPrivateApiTest : public ExtensionApiTest { + public: +  virtual void SetUpCommandLine(CommandLine* command_line) { +    ExtensionApiTest::SetUpCommandLine(command_line); +    command_line->AppendSwitch(switches::kAppsDebugger); +  } + +  virtual void LoadExtensions() { +    FilePath base_dir = test_data_dir_.AppendASCII("developer"); +    LoadNamedExtension(base_dir, "hosted_app"); +  } + + protected: +  void LoadNamedExtension(const FilePath& path, +                          const std::string& name) { +    const Extension* extension = LoadExtension(path.AppendASCII(name)); +    ASSERT_TRUE(extension); +    extension_name_to_ids_[name] = extension->id(); +  } + +  void InstallNamedExtension(const FilePath& path, +                             const std::string& name, +                             Extension::Location install_source) { +    const Extension* extension = InstallExtension(path.AppendASCII(name), 1, +                                                  install_source); +    ASSERT_TRUE(extension); +    extension_name_to_ids_[name] = extension->id(); +  } + +  std::map<std::string, std::string> extension_name_to_ids_; +}; + +IN_PROC_BROWSER_TEST_F(DeveloperPrivateApiTest, Basics) { +  LoadExtensions(); + +  FilePath basedir = test_data_dir_.AppendASCII("developer"); +  InstallNamedExtension(basedir, "packaged_app", Extension::INTERNAL); + +  InstallNamedExtension(basedir, "simple_extension", Extension::INTERNAL); + +  ASSERT_TRUE(RunExtensionSubtest( +      "developer/test", "basics.html", kFlagLoadAsComponent)); +} diff --git a/chrome/browser/resources/apps_debugger/manifest.json b/chrome/browser/resources/apps_debugger/manifest.json index b75268e..50a5c08 100644 --- a/chrome/browser/resources/apps_debugger/manifest.json +++ b/chrome/browser/resources/apps_debugger/manifest.json @@ -9,7 +9,7 @@        "scripts": ["background.js"]      }    }, -  "permissions": ["notifications"], +  "permissions": ["notifications", "developerPrivate"],    "icons": {      "16": "images/dev-icon-16.png",      "128": "images/dev-icon-128.png" diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index 84bba2c..2a7056e 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -161,6 +161,10 @@          'browser/extensions/api/declarative_webrequest/webrequest_rule.h',          'browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc',          'browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h', +        'browser/extensions/api/developer_private/developer_private_api.cc', +        'browser/extensions/api/developer_private/developer_private_api.h', +        'browser/extensions/api/developer_private/developer_private_api_factory.cc', +        'browser/extensions/api/developer_private/developer_private_api_factory.h',          'browser/extensions/api/dial/dial_api.cc',          'browser/extensions/api/dial/dial_api.h',          'browser/extensions/api/dial/dial_api_factory.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index b303a10..2ff96b0 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -943,6 +943,7 @@          'browser/extensions/api/cookies/cookies_apitest.cc',          'browser/extensions/api/debugger/debugger_apitest.cc',          'browser/extensions/api/declarative/declarative_apitest.cc', +        'browser/extensions/api/developer_private/developer_private_apitest.cc',          'browser/extensions/api/dial/dial_apitest.cc',          'browser/extensions/api/dns/dns_apitest.cc',          'browser/extensions/api/dns/mock_host_resolver_creator.cc', diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json index 44eb540..c21083a 100644 --- a/chrome/common/extensions/api/_permission_features.json +++ b/chrome/common/extensions/api/_permission_features.json @@ -21,6 +21,11 @@      "channel": "stable",      "extension_types": ["platform_app"]    }, +  "developerPrivate": { +    "channel": "dev", +    "extension_types": ["packaged_app"], +    "location": "component" +  },    "appNotifications": {      "channel": "stable",      "extension_types": ["packaged_app", "hosted_app"] diff --git a/chrome/common/extensions/api/api.gyp b/chrome/common/extensions/api/api.gyp index 9731a2a..95af0dc 100644 --- a/chrome/common/extensions/api/api.gyp +++ b/chrome/common/extensions/api/api.gyp @@ -47,6 +47,7 @@            'app_window.idl',            'autotest_private.idl',            'bluetooth.idl', +          'developer_private.idl',            'dial.idl',            'downloads.idl',            'experimental_discovery.idl', diff --git a/chrome/common/extensions/api/developer_private.idl b/chrome/common/extensions/api/developer_private.idl new file mode 100644 index 0000000..c66616d --- /dev/null +++ b/chrome/common/extensions/api/developer_private.idl @@ -0,0 +1,91 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// developerPrivate API. +// This is a private API exposing developing and debugging functionalities for +// apps and extensions. + +namespace developerPrivate { + +  enum ItemType { +    hosted_app, +    packaged_app, +    legacy_packaged_app, +    extension, +    theme +  }; + +  dictionary ItemInspectView { +    // path to the inspect page. +    DOMString path; + +    // For lazy background pages, the value is -1. +    long render_process_id; + +    long render_view_id; +    boolean incognito; +  }; + +  dictionary ItemInfo { +    DOMString id; +    DOMString name; +    DOMString version; +    DOMString description; +    boolean may_disable; +    boolean enabled; +    DOMString? disabled_reason; +    boolean isApp; +    ItemType type; +    boolean allow_activity; +    boolean allow_file_access; +    boolean wants_file_access; +    boolean enabled_incognito; +    boolean is_unpacked; +    boolean allow_reload; +    DOMString icon; + +    // Path of an unpacked extension. +    DOMString? path; + +    // Options settings page for the item. +    DOMString? options_url; +    DOMString? app_launch_url; +    DOMString? homepage_url; +    DOMString? update_url; +    boolean offline_enabled; + +    // All views of the current extension. +    ItemInspectView[] views; +  }; + +  dictionary InspectOptions { +    DOMString extension_id; +    DOMString render_process_id; +    DOMString render_view_id; +    boolean incognito; +  }; + +  callback BooleanCallback = void (boolean result); +  callback ItemsInfoCallback = void (ItemInfo[] result); + +  interface Functions { +    // Runs auto update for extensions and apps immediately. +    // |callback| : Called with the boolean result, true if autoUpdate is +    // successful. +    static void autoUpdate(BooleanCallback callback); + +    // Returns information of all the extensions and apps installed. +    // |include_disabled| : include disabled items. +    // |include_terminated| : include terminated items. +    // |callback| : Called with items info. +    static void getItemsInfo(boolean include_disabled, +                             boolean include_terminated, +                             ItemsInfoCallback callback); + +    // Opens an inspect window for given |options| +    static void inspect(InspectOptions options, +                        BooleanCallback callback); +  }; + +}; diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc index 5c1d114..cbe9a2d 100644 --- a/chrome/common/extensions/extension.cc +++ b/chrome/common/extensions/extension.cc @@ -1339,6 +1339,10 @@ bool Extension::is_legacy_packaged_app() const {    return manifest()->is_legacy_packaged_app();  } +bool Extension::is_extension() const { +  return manifest()->is_extension(); +} +  bool Extension::can_be_incognito_enabled() const {    return !is_platform_app();  } diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h index bfb989f4..d2fd450 100644 --- a/chrome/common/extensions/extension.h +++ b/chrome/common/extensions/extension.h @@ -795,6 +795,7 @@ class Extension : public base::RefCountedThreadSafe<Extension> {    bool is_platform_app() const;    bool is_hosted_app() const;    bool is_legacy_packaged_app() const; +  bool is_extension() const;    bool is_storage_isolated() const { return is_storage_isolated_; }    bool can_be_incognito_enabled() const;    const URLPatternSet& web_extent() const { return extent_; } diff --git a/chrome/common/extensions/manifest.h b/chrome/common/extensions/manifest.h index da5f542..6c8d612 100644 --- a/chrome/common/extensions/manifest.h +++ b/chrome/common/extensions/manifest.h @@ -49,6 +49,7 @@ class Manifest {    bool is_legacy_packaged_app() const {      return type_ == Extension::TYPE_LEGACY_PACKAGED_APP;    } +  bool is_extension() const { return type_ == Extension::TYPE_EXTENSION; }    // These access the wrapped manifest value, returning false when the property    // does not exist or if the manifest type can't access it. diff --git a/chrome/common/extensions/permissions/api_permission.cc b/chrome/common/extensions/permissions/api_permission.cc index 20b2693..2d35b95 100644 --- a/chrome/common/extensions/permissions/api_permission.cc +++ b/chrome/common/extensions/permissions/api_permission.cc @@ -245,6 +245,8 @@ void APIPermissionInfo::RegisterAllPermissions(        kFlagCannotBeOptional },      { APIPermission::kChromeosInfoPrivate, "chromeosInfoPrivate",        kFlagCannotBeOptional }, +    { APIPermission::kDeveloperPrivate, "developerPrivate", +      kFlagCannotBeOptional },      { APIPermission::kDial, "dial", kFlagCannotBeOptional },      { APIPermission::kFileBrowserHandlerInternal, "fileBrowserHandlerInternal",        kFlagCannotBeOptional }, diff --git a/chrome/common/extensions/permissions/api_permission.h b/chrome/common/extensions/permissions/api_permission.h index b819d03..26603537 100644 --- a/chrome/common/extensions/permissions/api_permission.h +++ b/chrome/common/extensions/permissions/api_permission.h @@ -63,6 +63,7 @@ class APIPermission {      kDebugger,      kDeclarative,      kDeclarativeWebRequest, +    kDeveloperPrivate,      kDevtools,      kDownloads,      kEchoPrivate, diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc index 54752f8..a976d10 100644 --- a/chrome/common/extensions/permissions/permission_set_unittest.cc +++ b/chrome/common/extensions/permissions/permission_set_unittest.cc @@ -704,6 +704,7 @@ TEST(PermissionsTest, PermissionMessages) {    skip.insert(APIPermission::kBookmarkManagerPrivate);    skip.insert(APIPermission::kChromeosInfoPrivate);    skip.insert(APIPermission::kCloudPrintPrivate); +  skip.insert(APIPermission::kDeveloperPrivate);    skip.insert(APIPermission::kDial);    skip.insert(APIPermission::kEchoPrivate);    skip.insert(APIPermission::kFileBrowserHandlerInternal); diff --git a/chrome/test/data/extensions/api_test/developer/hosted_app/manifest.json b/chrome/test/data/extensions/api_test/developer/hosted_app/manifest.json new file mode 100644 index 0000000..40a274f --- /dev/null +++ b/chrome/test/data/extensions/api_test/developer/hosted_app/manifest.json @@ -0,0 +1,12 @@ +{ +  "name": "hosted_app", +  "version": "0.1", +  "manifest_version": 2, +  "app": { +    "launch": { +      "web_url": "http://www.google.com" +    } +  }, +  "offline_enabled": true, +  "update_url": "http://example.com/update.xml" +} diff --git a/chrome/test/data/extensions/api_test/developer/packaged_app/main.html b/chrome/test/data/extensions/api_test/developer/packaged_app/main.html new file mode 100644 index 0000000..4e24caa --- /dev/null +++ b/chrome/test/data/extensions/api_test/developer/packaged_app/main.html @@ -0,0 +1,10 @@ +<!-- + * Copyright (c) 2012 The Chromium Authors. All rights reserved.  Use of this + * source code is governed by a BSD-style license that can be found in the + * LICENSE file. +--> +<html> +<body> +Hello World +</body> +</html> diff --git a/chrome/test/data/extensions/api_test/developer/packaged_app/main.js b/chrome/test/data/extensions/api_test/developer/packaged_app/main.js new file mode 100644 index 0000000..d6a03fe --- /dev/null +++ b/chrome/test/data/extensions/api_test/developer/packaged_app/main.js @@ -0,0 +1,12 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +chrome.test.sendMessage("app_launched"); + +chrome.app.runtime.onLaunched.addListener(function() { +  chrome.app.window.create('main.html', { +    'width': 600, +    'height': 600 +  }); +}); diff --git a/chrome/test/data/extensions/api_test/developer/packaged_app/manifest.json b/chrome/test/data/extensions/api_test/developer/packaged_app/manifest.json new file mode 100644 index 0000000..09077cf --- /dev/null +++ b/chrome/test/data/extensions/api_test/developer/packaged_app/manifest.json @@ -0,0 +1,10 @@ +{ +  "name": "packaged_app", +  "version": "0.1", +  "manifest_version": 2, +  "app": { +    "background": { +      "scripts": ["main.js"] +    } +  } +} diff --git a/chrome/test/data/extensions/api_test/developer/simple_extension/manifest.json b/chrome/test/data/extensions/api_test/developer/simple_extension/manifest.json new file mode 100644 index 0000000..c349893 --- /dev/null +++ b/chrome/test/data/extensions/api_test/developer/simple_extension/manifest.json @@ -0,0 +1,7 @@ +{ +  "name": "simple_extension", +  "version": "0.1", +  "manifest_version": 2, +  "options_page": "pages/options.html", +  "homepage_url": "http://example.com" +} diff --git a/chrome/test/data/extensions/api_test/developer/simple_extension/pages/options.html b/chrome/test/data/extensions/api_test/developer/simple_extension/pages/options.html new file mode 100644 index 0000000..c4e30aa --- /dev/null +++ b/chrome/test/data/extensions/api_test/developer/simple_extension/pages/options.html @@ -0,0 +1,7 @@ +<!-- + * Copyright (c) 2012 The Chromium Authors. All rights reserved.  Use of this + * source code is governed by a BSD-style license that can be found in the + * LICENSE file. +--> +<html> +</html> diff --git a/chrome/test/data/extensions/api_test/developer/test/basics.html b/chrome/test/data/extensions/api_test/developer/test/basics.html new file mode 100644 index 0000000..670a5cb --- /dev/null +++ b/chrome/test/data/extensions/api_test/developer/test/basics.html @@ -0,0 +1,7 @@ +<!-- + * Copyright (c) 2012 The Chromium Authors. All rights reserved.  Use of this + * source code is governed by a BSD-style license that can be found in the + * LICENSE file. +--> +<script src="common.js"></script> +<script src="basics.js"></script> diff --git a/chrome/test/data/extensions/api_test/developer/test/basics.js b/chrome/test/data/extensions/api_test/developer/test/basics.js new file mode 100644 index 0000000..046b6b6 --- /dev/null +++ b/chrome/test/data/extensions/api_test/developer/test/basics.js @@ -0,0 +1,28 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var tests = [ +  function simple() { +    chrome.developerPrivate.getItemsInfo(true, // include disabled +                                         true, // include terminated +                                         callback(function(items) { +      chrome.test.assertEq(3, items.length); + +      checkItemInList(items, "hosted_app", true, "hosted_app", +          { "app_launch_url": "http://www.google.com/", +            "offline_enabled": true, +            "update_url": "http://example.com/update.xml" }); + +      checkItemInList(items, "simple_extension", true, "extension", +          { "homepage_url": "http://example.com/", +            "options_url": "chrome-extension://<ID>/pages/options.html"}); + +      var extension = getItemNamed(items, "packaged_app"); +      checkItemInList(items, "packaged_app", true, "packaged_app", +          { "offline_enabled": true}); +    })); +  } +]; + +chrome.test.runTests(tests); diff --git a/chrome/test/data/extensions/api_test/developer/test/common.js b/chrome/test/data/extensions/api_test/developer/test/common.js new file mode 100644 index 0000000..f2d1f62 --- /dev/null +++ b/chrome/test/data/extensions/api_test/developer/test/common.js @@ -0,0 +1,44 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var assertEq = chrome.test.assertEq; +var assertTrue = chrome.test.assertTrue; +var fail = chrome.test.fail; +var callback = chrome.test.callback; + +function getItemNamed(list, name) { +  for (var i = 0; i < list.length; i++) { +    if (list[i].name == name) { +      return list[i]; +    } +  } +  fail("didn't find item with name: " + name); +  return null; +} + +// Verifies that the item's name, enabled, and type properties match |name|, +// |enabled|, and |type|, and checks against any additional name/value +// properties from |additional_properties|. +function checkItem(item, name, enabled, type, additional_properties) { +  assertTrue(item !== null); +  assertEq(name, item.name); +  assertEq(type, item.type); +  assertEq(enabled, item.enabled); + +  for (var propname in additional_properties) { +    var value = additional_properties[propname]; +    if (typeof value === 'string') +      value = value.replace("<ID>", item.id); +    assertTrue(propname in item); +    assertEq(value, item[propname]); +  } +} + +// Gets an extension/app with |name| in |list|, verifies that its enabled +// and type properties match |enabled| and |type|, and checks against any +// additional name/value properties from |additional_properties|. +function checkItemInList(list, name, enabled, type, additional_properties) { +  var item = getItemNamed(list, name); +  checkItem(item, name, enabled, type, additional_properties); +} diff --git a/chrome/test/data/extensions/api_test/developer/test/manifest.json b/chrome/test/data/extensions/api_test/developer/test/manifest.json new file mode 100644 index 0000000..3fb3249 --- /dev/null +++ b/chrome/test/data/extensions/api_test/developer/test/manifest.json @@ -0,0 +1,7 @@ +{ +  "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOuJ3c1uShZCBR1uKjWQIx/EeCIQheyWvD9jsUA39o4yO+Q6JYvCLAjF+L0zr7cbU1YV+39XDo8i0/KVnpo21MVm7TxwWnrGhe8CWpfLRQp2OZ1e8S2O1YA7cISygGlcd7Cjs8I/lBR5t1jBZzpCe2hCx8551/QUyWCBnhpoVhNwIDAQAB", +  "name": "Apps Debugger API Test", +  "version": "0.1", +  "manifest_version": 2, +  "permissions": ["developerPrivate"] +} | 
