diff options
author | rockot@chromium.org <rockot@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-07 10:17:29 +0000 |
---|---|---|
committer | rockot@chromium.org <rockot@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-07 10:17:29 +0000 |
commit | 57afedf31f8f1ccf343e58be09b77b11d4b20110 (patch) | |
tree | eea8e37907f7eb867922daee34a20fa8a9949ae1 /extensions | |
parent | 9f848f5f3d321338e2bbaa09620bd8fe68e0233e (diff) | |
download | chromium_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.cc | 21 | ||||
-rw-r--r-- | extensions/browser/api/api_resource.h | 43 | ||||
-rw-r--r-- | extensions/browser/api/api_resource_manager.h | 326 | ||||
-rw-r--r-- | extensions/extensions.gyp | 3 |
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', |