summaryrefslogtreecommitdiffstats
path: root/extensions
diff options
context:
space:
mode:
authorrockot@chromium.org <rockot@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-07 10:17:29 +0000
committerrockot@chromium.org <rockot@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-07 10:17:29 +0000
commit57afedf31f8f1ccf343e58be09b77b11d4b20110 (patch)
treeeea8e37907f7eb867922daee34a20fa8a9949ae1 /extensions
parent9f848f5f3d321338e2bbaa09620bd8fe68e0233e (diff)
downloadchromium_src-57afedf31f8f1ccf343e58be09b77b11d4b20110.zip
chromium_src-57afedf31f8f1ccf343e58be09b77b11d4b20110.tar.gz
chromium_src-57afedf31f8f1ccf343e58be09b77b11d4b20110.tar.bz2
Move api_resource{,manager} out of src/chrome
This is a mechanical change. No new DEPS are introduced into src/extensions. clang_format was also applied to all touched extensions code, for great justice. BUG=349930 TBR=wez@chromium.org,yoz@chromium.org,rpaquay@chromium.org,erg@chromium.org for mechanical changes Review URL: https://codereview.chromium.org/182213005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@255575 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'extensions')
-rw-r--r--extensions/browser/api/api_resource.cc21
-rw-r--r--extensions/browser/api/api_resource.h43
-rw-r--r--extensions/browser/api/api_resource_manager.h326
-rw-r--r--extensions/extensions.gyp3
4 files changed, 393 insertions, 0 deletions
diff --git a/extensions/browser/api/api_resource.cc b/extensions/browser/api/api_resource.cc
new file mode 100644
index 0000000..6e31918
--- /dev/null
+++ b/extensions/browser/api/api_resource.cc
@@ -0,0 +1,21 @@
+// Copyright 2014 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 "extensions/browser/api/api_resource.h"
+
+namespace extensions {
+
+ApiResource::ApiResource(const std::string& owner_extension_id)
+ : owner_extension_id_(owner_extension_id) {
+
+ CHECK(!owner_extension_id_.empty());
+}
+
+ApiResource::~ApiResource() {}
+
+bool ApiResource::IsPersistent() const {
+ return true; // backward-compatible behavior.
+}
+
+} // namespace extensions
diff --git a/extensions/browser/api/api_resource.h b/extensions/browser/api/api_resource.h
new file mode 100644
index 0000000..c696d46
--- /dev/null
+++ b/extensions/browser/api/api_resource.h
@@ -0,0 +1,43 @@
+// Copyright 2014 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 EXTENSIONS_BROWSER_API_API_RESOURCE_H_
+#define EXTENSIONS_BROWSER_API_API_RESOURCE_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "content/public/browser/browser_thread.h"
+#include "extensions/common/extension.h"
+
+namespace extensions {
+
+// An ApiResource represents something that an extension API manages, such as a
+// socket or a serial-port connection. Typically, an ApiResourceManager will
+// control the lifetime of all ApiResources of a specific derived type.
+class ApiResource {
+ public:
+ virtual ~ApiResource();
+
+ const std::string& owner_extension_id() const { return owner_extension_id_; }
+
+ // If this method returns |true|, the resource remains open when the
+ // owning extension is suspended due to inactivity.
+ virtual bool IsPersistent() const;
+
+ static const content::BrowserThread::ID kThreadId =
+ content::BrowserThread::IO;
+
+ protected:
+ explicit ApiResource(const std::string& owner_extension_id);
+
+ private:
+ // The extension that owns this resource.
+ const std::string owner_extension_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(ApiResource);
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_BROWSER_API_API_RESOURCE_H_
diff --git a/extensions/browser/api/api_resource_manager.h b/extensions/browser/api/api_resource_manager.h
new file mode 100644
index 0000000..0513c2c
--- /dev/null
+++ b/extensions/browser/api/api_resource_manager.h
@@ -0,0 +1,326 @@
+// Copyright 2014 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 EXTENSIONS_BROWSER_API_API_RESOURCE_MANAGER_H_
+#define EXTENSIONS_BROWSER_API_API_RESOURCE_MANAGER_H_
+
+#include <map>
+
+#include "base/containers/hash_tables.h"
+#include "base/lazy_instance.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/non_thread_safe.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_service.h"
+#include "extensions/browser/browser_context_keyed_api_factory.h"
+#include "extensions/common/extension.h"
+
+namespace extensions {
+namespace api {
+class SerialEventDispatcher;
+class TCPServerSocketEventDispatcher;
+class TCPSocketEventDispatcher;
+class UDPSocketEventDispatcher;
+}
+}
+
+namespace extensions {
+
+// An ApiResourceManager manages the lifetime of a set of resources that
+// ApiFunctions use. Examples are sockets or USB connections.
+//
+// Users of this class should define kThreadId to be the thread that
+// ApiResourceManager to works on. The default is defined in ApiResource.
+// The user must also define a static const char* service_name() that returns
+// the name of the service, and in order for ApiResourceManager to use
+// service_name() friend this class.
+//
+// In the cc file the user must define a GetFactoryInstance() and manage their
+// own instances (typically using LazyInstance or Singleton).
+//
+// E.g.:
+//
+// class Resource {
+// public:
+// static const BrowserThread::ID kThreadId = BrowserThread::FILE;
+// private:
+// friend class ApiResourceManager<Resource>;
+// static const char* service_name() {
+// return "ResourceManager";
+// }
+// };
+//
+// In the cc file:
+//
+// static base::LazyInstance<BrowserContextKeyedAPIFactory<
+// ApiResourceManager<Resource> > >
+// g_factory = LAZY_INSTANCE_INITIALIZER;
+//
+//
+// template <>
+// BrowserContextKeyedAPIFactory<ApiResourceManager<Resource> >*
+// ApiResourceManager<Resource>::GetFactoryInstance() {
+// return g_factory.Pointer();
+// }
+template <class T>
+class ApiResourceManager : public BrowserContextKeyedAPI,
+ public base::NonThreadSafe,
+ public content::NotificationObserver {
+ public:
+ explicit ApiResourceManager(content::BrowserContext* context)
+ : thread_id_(T::kThreadId), data_(new ApiResourceData(thread_id_)) {
+ registrar_.Add(this,
+ chrome::NOTIFICATION_EXTENSION_UNLOADED,
+ content::NotificationService::AllSources());
+ registrar_.Add(this,
+ chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
+ content::NotificationService::AllSources());
+ }
+
+ // For Testing.
+ static ApiResourceManager<T>* CreateApiResourceManagerForTest(
+ content::BrowserContext* context,
+ content::BrowserThread::ID thread_id) {
+ ApiResourceManager* manager = new ApiResourceManager<T>(context);
+ manager->thread_id_ = thread_id;
+ manager->data_ = new ApiResourceData(thread_id);
+ return manager;
+ }
+
+ virtual ~ApiResourceManager() {
+ DCHECK(CalledOnValidThread());
+ DCHECK(content::BrowserThread::IsMessageLoopValid(thread_id_))
+ << "A unit test is using an ApiResourceManager but didn't provide "
+ "the thread message loop needed for that kind of resource. "
+ "Please ensure that the appropriate message loop is operational.";
+
+ data_->InititateCleanup();
+ }
+
+ // BrowserContextKeyedAPI implementation.
+ static BrowserContextKeyedAPIFactory<ApiResourceManager<T> >*
+ GetFactoryInstance();
+
+ // Convenience method to get the ApiResourceManager for a profile.
+ static ApiResourceManager<T>* Get(content::BrowserContext* context) {
+ return BrowserContextKeyedAPIFactory<ApiResourceManager<T> >::Get(context);
+ }
+
+ // Takes ownership.
+ int Add(T* api_resource) { return data_->Add(api_resource); }
+
+ void Remove(const std::string& extension_id, int api_resource_id) {
+ data_->Remove(extension_id, api_resource_id);
+ }
+
+ T* Get(const std::string& extension_id, int api_resource_id) {
+ return data_->Get(extension_id, api_resource_id);
+ }
+
+ base::hash_set<int>* GetResourceIds(const std::string& extension_id) {
+ return data_->GetResourceIds(extension_id);
+ }
+
+ protected:
+ // content::NotificationObserver:
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE {
+ switch (type) {
+ case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
+ std::string id = content::Details<extensions::UnloadedExtensionInfo>(
+ details)->extension->id();
+ data_->InitiateExtensionUnloadedCleanup(id);
+ break;
+ }
+ case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
+ ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
+ data_->InitiateExtensionSuspendedCleanup(host->extension_id());
+ break;
+ }
+ }
+ }
+
+ private:
+ friend class api::SerialEventDispatcher;
+ friend class api::TCPServerSocketEventDispatcher;
+ friend class api::TCPSocketEventDispatcher;
+ friend class api::UDPSocketEventDispatcher;
+ friend class BrowserContextKeyedAPIFactory<ApiResourceManager<T> >;
+ // BrowserContextKeyedAPI implementation.
+ static const char* service_name() { return T::service_name(); }
+ static const bool kServiceHasOwnInstanceInIncognito = true;
+ static const bool kServiceIsNULLWhileTesting = true;
+
+ // ApiResourceData class handles resource bookkeeping on a thread
+ // where resource lifetime is handled.
+ class ApiResourceData : public base::RefCountedThreadSafe<ApiResourceData> {
+ public:
+ typedef std::map<int, linked_ptr<T> > ApiResourceMap;
+ // Lookup map from extension id's to allocated resource id's.
+ typedef std::map<std::string, base::hash_set<int> > ExtensionToResourceMap;
+
+ explicit ApiResourceData(const content::BrowserThread::ID thread_id)
+ : next_id_(1), thread_id_(thread_id) {}
+
+ int Add(T* api_resource) {
+ DCHECK(content::BrowserThread::CurrentlyOn(thread_id_));
+ int id = GenerateId();
+ if (id > 0) {
+ linked_ptr<T> resource_ptr(api_resource);
+ api_resource_map_[id] = resource_ptr;
+
+ const std::string& extension_id = api_resource->owner_extension_id();
+ if (extension_resource_map_.find(extension_id) ==
+ extension_resource_map_.end()) {
+ extension_resource_map_[extension_id] = base::hash_set<int>();
+ }
+ extension_resource_map_[extension_id].insert(id);
+
+ return id;
+ }
+ return 0;
+ }
+
+ void Remove(const std::string& extension_id, int api_resource_id) {
+ DCHECK(content::BrowserThread::CurrentlyOn(thread_id_));
+ if (GetOwnedResource(extension_id, api_resource_id) != NULL) {
+ DCHECK(extension_resource_map_.find(extension_id) !=
+ extension_resource_map_.end());
+ extension_resource_map_[extension_id].erase(api_resource_id);
+ api_resource_map_.erase(api_resource_id);
+ }
+ }
+
+ T* Get(const std::string& extension_id, int api_resource_id) {
+ DCHECK(content::BrowserThread::CurrentlyOn(thread_id_));
+ return GetOwnedResource(extension_id, api_resource_id);
+ }
+
+ base::hash_set<int>* GetResourceIds(const std::string& extension_id) {
+ DCHECK(content::BrowserThread::CurrentlyOn(thread_id_));
+ return GetOwnedResourceIds(extension_id);
+ }
+
+ void InitiateExtensionUnloadedCleanup(const std::string& extension_id) {
+ content::BrowserThread::PostTask(
+ thread_id_,
+ FROM_HERE,
+ base::Bind(&ApiResourceData::CleanupResourcesFromUnloadedExtension,
+ this,
+ extension_id));
+ }
+
+ void InitiateExtensionSuspendedCleanup(const std::string& extension_id) {
+ content::BrowserThread::PostTask(
+ thread_id_,
+ FROM_HERE,
+ base::Bind(&ApiResourceData::CleanupResourcesFromSuspendedExtension,
+ this,
+ extension_id));
+ }
+
+ void InititateCleanup() {
+ content::BrowserThread::PostTask(
+ thread_id_, FROM_HERE, base::Bind(&ApiResourceData::Cleanup, this));
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<ApiResourceData>;
+
+ virtual ~ApiResourceData() {}
+
+ T* GetOwnedResource(const std::string& extension_id, int api_resource_id) {
+ linked_ptr<T> ptr = api_resource_map_[api_resource_id];
+ T* resource = ptr.get();
+ if (resource && extension_id == resource->owner_extension_id())
+ return resource;
+ return NULL;
+ }
+
+ base::hash_set<int>* GetOwnedResourceIds(const std::string& extension_id) {
+ DCHECK(content::BrowserThread::CurrentlyOn(thread_id_));
+ if (extension_resource_map_.find(extension_id) ==
+ extension_resource_map_.end())
+ return NULL;
+
+ return &extension_resource_map_[extension_id];
+ }
+
+ void CleanupResourcesFromUnloadedExtension(
+ const std::string& extension_id) {
+ CleanupResourcesFromExtension(extension_id, true);
+ }
+
+ void CleanupResourcesFromSuspendedExtension(
+ const std::string& extension_id) {
+ CleanupResourcesFromExtension(extension_id, false);
+ }
+
+ void CleanupResourcesFromExtension(const std::string& extension_id,
+ bool remove_all) {
+ DCHECK(content::BrowserThread::CurrentlyOn(thread_id_));
+
+ if (extension_resource_map_.find(extension_id) ==
+ extension_resource_map_.end()) {
+ return;
+ }
+
+ // Remove all resources, or the non persistent ones only if |remove_all|
+ // is false.
+ base::hash_set<int>& resource_ids = extension_resource_map_[extension_id];
+ for (base::hash_set<int>::iterator it = resource_ids.begin();
+ it != resource_ids.end();) {
+ bool erase = false;
+ if (remove_all) {
+ erase = true;
+ } else {
+ linked_ptr<T> ptr = api_resource_map_[*it];
+ T* resource = ptr.get();
+ erase = (resource && !resource->IsPersistent());
+ }
+
+ if (erase) {
+ api_resource_map_.erase(*it);
+ resource_ids.erase(it++);
+ } else {
+ ++it;
+ }
+ } // end for
+
+ // Remove extension entry if we removed all its resources.
+ if (resource_ids.size() == 0) {
+ extension_resource_map_.erase(extension_id);
+ }
+ }
+
+ void Cleanup() {
+ DCHECK(content::BrowserThread::CurrentlyOn(thread_id_));
+
+ api_resource_map_.clear();
+ extension_resource_map_.clear();
+ }
+
+ int GenerateId() { return next_id_++; }
+
+ int next_id_;
+ const content::BrowserThread::ID thread_id_;
+ ApiResourceMap api_resource_map_;
+ ExtensionToResourceMap extension_resource_map_;
+ };
+
+ content::BrowserThread::ID thread_id_;
+ content::NotificationRegistrar registrar_;
+ scoped_refptr<ApiResourceData> data_;
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_BROWSER_API_API_RESOURCE_MANAGER_H_
diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp
index a3d7635..5e64cf0 100644
--- a/extensions/extensions.gyp
+++ b/extensions/extensions.gyp
@@ -168,6 +168,9 @@
'sources': [
'browser/admin_policy.cc',
'browser/admin_policy.h',
+ 'browser/api/api_resource.cc',
+ 'browser/api/api_resource.h',
+ 'browser/api/api_resource_manager.h',
'browser/api/async_api_function.cc',
'browser/api/async_api_function.h',
'browser/api/extensions_api_client.cc',