summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgrv@chromium.org <grv@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-18 01:34:34 +0000
committergrv@chromium.org <grv@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-18 01:34:34 +0000
commitffcf2f9b4acd11504a770dbb4efd5810f6387c1c (patch)
tree70e21e452d36413ed30852e81dec2d651dfdbc4a
parentac18c22ad570f314ee565d12804ef8c752459601 (diff)
downloadchromium_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
-rw-r--r--chrome/browser/extensions/api/developer_private/developer_private_api.cc296
-rw-r--r--chrome/browser/extensions/api/developer_private/developer_private_api.h128
-rw-r--r--chrome/browser/extensions/api/developer_private/developer_private_api_factory.cc51
-rw-r--r--chrome/browser/extensions/api/developer_private/developer_private_api_factory.h39
-rw-r--r--chrome/browser/extensions/api/developer_private/developer_private_apitest.cc55
-rw-r--r--chrome/browser/resources/apps_debugger/manifest.json2
-rw-r--r--chrome/chrome_browser_extensions.gypi4
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/extensions/api/_permission_features.json5
-rw-r--r--chrome/common/extensions/api/api.gyp1
-rw-r--r--chrome/common/extensions/api/developer_private.idl91
-rw-r--r--chrome/common/extensions/extension.cc4
-rw-r--r--chrome/common/extensions/extension.h1
-rw-r--r--chrome/common/extensions/manifest.h1
-rw-r--r--chrome/common/extensions/permissions/api_permission.cc2
-rw-r--r--chrome/common/extensions/permissions/api_permission.h1
-rw-r--r--chrome/common/extensions/permissions/permission_set_unittest.cc1
-rw-r--r--chrome/test/data/extensions/api_test/developer/hosted_app/manifest.json12
-rw-r--r--chrome/test/data/extensions/api_test/developer/packaged_app/main.html10
-rw-r--r--chrome/test/data/extensions/api_test/developer/packaged_app/main.js12
-rw-r--r--chrome/test/data/extensions/api_test/developer/packaged_app/manifest.json10
-rw-r--r--chrome/test/data/extensions/api_test/developer/simple_extension/manifest.json7
-rw-r--r--chrome/test/data/extensions/api_test/developer/simple_extension/pages/options.html7
-rw-r--r--chrome/test/data/extensions/api_test/developer/test/basics.html7
-rw-r--r--chrome/test/data/extensions/api_test/developer/test/basics.js28
-rw-r--r--chrome/test/data/extensions/api_test/developer/test/common.js44
-rw-r--r--chrome/test/data/extensions/api_test/developer/test/manifest.json7
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"]
+}