| Index: extensions/browser/api/api_resource_manager.h
|
| diff --git a/extensions/browser/api/api_resource_manager.h b/extensions/browser/api/api_resource_manager.h
|
| index 7cff1732c1b068112c2f3bb78331a14745134f62..3f63b612f74a4ace04e0db301bff3088effd64a9 100644
|
| --- a/extensions/browser/api/api_resource_manager.h
|
| +++ b/extensions/browser/api/api_resource_manager.h
|
| @@ -36,8 +36,45 @@ class TCPSocketEventDispatcher;
|
| class UDPSocketEventDispatcher;
|
| }
|
|
|
| +template <typename T>
|
| +struct NamedThreadTraits {
|
| + static bool IsCalledOnValidThread() {
|
| + return content::BrowserThread::CurrentlyOn(T::kThreadId);
|
| + }
|
| +
|
| + static bool IsMessageLoopValid() {
|
| + return content::BrowserThread::IsMessageLoopValid(T::kThreadId);
|
| + }
|
| +
|
| + static scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner() {
|
| + return content::BrowserThread::GetMessageLoopProxyForThread(T::kThreadId);
|
| + }
|
| +};
|
| +
|
| +template <typename T>
|
| +struct TestThreadTraits {
|
| + static bool IsCalledOnValidThread() {
|
| + return content::BrowserThread::CurrentlyOn(thread_id_);
|
| + }
|
| +
|
| + static bool IsMessageLoopValid() {
|
| + return content::BrowserThread::IsMessageLoopValid(thread_id_);
|
| + }
|
| +
|
| + static scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner() {
|
| + return content::BrowserThread::GetMessageLoopProxyForThread(thread_id_);
|
| + }
|
| +
|
| + static content::BrowserThread::ID thread_id_;
|
| +};
|
| +
|
| +template <typename T>
|
| +content::BrowserThread::ID TestThreadTraits<T>::thread_id_ =
|
| + content::BrowserThread::IO;
|
| +
|
| // An ApiResourceManager manages the lifetime of a set of resources that
|
| -// ApiFunctions use. Examples are sockets or USB connections.
|
| +// that live on named threads (i.e. BrowserThread::IO) which ApiFunctions use.
|
| +// Examples of such resources 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.
|
| @@ -72,13 +109,13 @@ class UDPSocketEventDispatcher;
|
| // ApiResourceManager<Resource>::GetFactoryInstance() {
|
| // return g_factory.Pointer();
|
| // }
|
| -template <class T>
|
| +template <class T, typename ThreadingTraits = NamedThreadTraits<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_)) {
|
| + : data_(new ApiResourceData()) {
|
| registrar_.Add(this,
|
| chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
|
| content::NotificationService::AllSources());
|
| @@ -86,20 +123,19 @@ class ApiResourceManager : public BrowserContextKeyedAPI,
|
| 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);
|
| + static ApiResourceManager<T, TestThreadTraits<T> >*
|
| + CreateApiResourceManagerForTest(content::BrowserContext* context,
|
| + content::BrowserThread::ID thread_id) {
|
| + TestThreadTraits<T>::thread_id_ = thread_id;
|
| + ApiResourceManager<T, TestThreadTraits<T> >* manager =
|
| + new ApiResourceManager<T, TestThreadTraits<T> >(context);
|
| return manager;
|
| }
|
|
|
| virtual ~ApiResourceManager() {
|
| DCHECK(CalledOnValidThread());
|
| - DCHECK(content::BrowserThread::IsMessageLoopValid(thread_id_))
|
| + DCHECK(ThreadingTraits::IsMessageLoopValid())
|
| << "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.";
|
| @@ -107,15 +143,6 @@ class ApiResourceManager : public BrowserContextKeyedAPI,
|
| 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); }
|
|
|
| @@ -131,6 +158,18 @@ class ApiResourceManager : public BrowserContextKeyedAPI,
|
| return data_->GetResourceIds(extension_id);
|
| }
|
|
|
| + // 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);
|
| + }
|
| +
|
| + // BrowserContextKeyedAPI implementation.
|
| + static const char* service_name() { return T::service_name(); }
|
| +
|
| protected:
|
| // content::NotificationObserver:
|
| virtual void Observe(int type,
|
| @@ -163,9 +202,6 @@ class ApiResourceManager : public BrowserContextKeyedAPI,
|
| friend class core_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;
|
|
|
| @@ -177,11 +213,10 @@ class ApiResourceManager : public BrowserContextKeyedAPI,
|
| // 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) {}
|
| + ApiResourceData() : next_id_(1) {}
|
|
|
| int Add(T* api_resource) {
|
| - DCHECK_CURRENTLY_ON(thread_id_);
|
| + DCHECK(ThreadingTraits::IsCalledOnValidThread());
|
| int id = GenerateId();
|
| if (id > 0) {
|
| linked_ptr<T> resource_ptr(api_resource);
|
| @@ -200,7 +235,7 @@ class ApiResourceManager : public BrowserContextKeyedAPI,
|
| }
|
|
|
| void Remove(const std::string& extension_id, int api_resource_id) {
|
| - DCHECK_CURRENTLY_ON(thread_id_);
|
| + DCHECK(ThreadingTraits::IsCalledOnValidThread());
|
| if (GetOwnedResource(extension_id, api_resource_id) != NULL) {
|
| DCHECK(extension_resource_map_.find(extension_id) !=
|
| extension_resource_map_.end());
|
| @@ -210,21 +245,20 @@ class ApiResourceManager : public BrowserContextKeyedAPI,
|
| }
|
|
|
| T* Get(const std::string& extension_id, int api_resource_id) {
|
| - DCHECK_CURRENTLY_ON(thread_id_);
|
| + DCHECK(ThreadingTraits::IsCalledOnValidThread());
|
| return GetOwnedResource(extension_id, api_resource_id);
|
| }
|
|
|
| base::hash_set<int>* GetResourceIds(const std::string& extension_id) {
|
| - DCHECK_CURRENTLY_ON(thread_id_);
|
| + DCHECK(ThreadingTraits::IsCalledOnValidThread());
|
| return GetOwnedResourceIds(extension_id);
|
| }
|
|
|
| void InitiateExtensionUnloadedCleanup(const std::string& extension_id) {
|
| - if (content::BrowserThread::CurrentlyOn(thread_id_)) {
|
| + if (ThreadingTraits::IsCalledOnValidThread()) {
|
| CleanupResourcesFromUnloadedExtension(extension_id);
|
| } else {
|
| - content::BrowserThread::PostTask(
|
| - thread_id_,
|
| + ThreadingTraits::GetSequencedTaskRunner()->PostTask(
|
| FROM_HERE,
|
| base::Bind(&ApiResourceData::CleanupResourcesFromUnloadedExtension,
|
| this,
|
| @@ -233,11 +267,10 @@ class ApiResourceManager : public BrowserContextKeyedAPI,
|
| }
|
|
|
| void InitiateExtensionSuspendedCleanup(const std::string& extension_id) {
|
| - if (content::BrowserThread::CurrentlyOn(thread_id_)) {
|
| + if (ThreadingTraits::IsCalledOnValidThread()) {
|
| CleanupResourcesFromSuspendedExtension(extension_id);
|
| } else {
|
| - content::BrowserThread::PostTask(
|
| - thread_id_,
|
| + ThreadingTraits::GetSequencedTaskRunner()->PostTask(
|
| FROM_HERE,
|
| base::Bind(&ApiResourceData::CleanupResourcesFromSuspendedExtension,
|
| this,
|
| @@ -246,11 +279,11 @@ class ApiResourceManager : public BrowserContextKeyedAPI,
|
| }
|
|
|
| void InititateCleanup() {
|
| - if (content::BrowserThread::CurrentlyOn(thread_id_)) {
|
| + if (ThreadingTraits::IsCalledOnValidThread()) {
|
| Cleanup();
|
| } else {
|
| - content::BrowserThread::PostTask(
|
| - thread_id_, FROM_HERE, base::Bind(&ApiResourceData::Cleanup, this));
|
| + ThreadingTraits::GetSequencedTaskRunner()->PostTask(
|
| + FROM_HERE, base::Bind(&ApiResourceData::Cleanup, this));
|
| }
|
| }
|
|
|
| @@ -268,7 +301,7 @@ class ApiResourceManager : public BrowserContextKeyedAPI,
|
| }
|
|
|
| base::hash_set<int>* GetOwnedResourceIds(const std::string& extension_id) {
|
| - DCHECK_CURRENTLY_ON(thread_id_);
|
| + DCHECK(ThreadingTraits::IsCalledOnValidThread());
|
| if (extension_resource_map_.find(extension_id) ==
|
| extension_resource_map_.end())
|
| return NULL;
|
| @@ -288,7 +321,7 @@ class ApiResourceManager : public BrowserContextKeyedAPI,
|
|
|
| void CleanupResourcesFromExtension(const std::string& extension_id,
|
| bool remove_all) {
|
| - DCHECK_CURRENTLY_ON(thread_id_);
|
| + DCHECK(ThreadingTraits::IsCalledOnValidThread());
|
|
|
| if (extension_resource_map_.find(extension_id) ==
|
| extension_resource_map_.end()) {
|
| @@ -324,7 +357,7 @@ class ApiResourceManager : public BrowserContextKeyedAPI,
|
| }
|
|
|
| void Cleanup() {
|
| - DCHECK_CURRENTLY_ON(thread_id_);
|
| + DCHECK(ThreadingTraits::IsCalledOnValidThread());
|
|
|
| api_resource_map_.clear();
|
| extension_resource_map_.clear();
|
| @@ -333,16 +366,80 @@ class ApiResourceManager : public BrowserContextKeyedAPI,
|
| 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_;
|
| };
|
|
|
| +// With WorkerPoolThreadTraits, ApiResourceManager can be used to manage the
|
| +// lifetime of a set of resources that live on sequenced task runner threads
|
| +// which ApiFunctions use. Examples of such resources are temporary file
|
| +// resources produced by certain API calls.
|
| +//
|
| +// Instead of kThreadId. classes used for tracking such resources should define
|
| +// kSequenceToken and kShutdownBehavior to identify sequence task runner for
|
| +// ApiResourceManager to work on and how pending tasks should behave on
|
| +// shutdown.
|
| +// The user must also define a static const char* service_name() that returns
|
| +// the name of the service, and in order for ApiWorkerPoolResourceManager 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 PoolResource {
|
| +// public:
|
| +// static const char kSequenceToken[] = "temp_files";
|
| +// static const base::SequencedWorkerPool::WorkerShutdown kShutdownBehavior =
|
| +// base::SequencedWorkerPool::BLOCK_SHUTDOWN;
|
| +// private:
|
| +// friend class ApiResourceManager<WorkerPoolResource,
|
| +// WorkerPoolThreadTraits>;
|
| +// static const char* service_name() {
|
| +// return "TempFilesResourceManager";
|
| +// }
|
| +// };
|
| +//
|
| +// In the cc file:
|
| +//
|
| +// static base::LazyInstance<BrowserContextKeyedAPIFactory<
|
| +// ApiResourceManager<Resource, WorkerPoolThreadTraits> > >
|
| +// g_factory = LAZY_INSTANCE_INITIALIZER;
|
| +//
|
| +//
|
| +// template <>
|
| +// BrowserContextKeyedAPIFactory<ApiResourceManager<WorkerPoolResource> >*
|
| +// ApiResourceManager<WorkerPoolPoolResource,
|
| +// WorkerPoolThreadTraits>::GetFactoryInstance() {
|
| +// return g_factory.Pointer();
|
| +// }
|
| +template <typename T>
|
| +struct WorkerPoolThreadTraits {
|
| + static bool IsCalledOnValidThread() {
|
| + return content::BrowserThread::GetBlockingPool()
|
| + ->IsRunningSequenceOnCurrentThread(
|
| + content::BrowserThread::GetBlockingPool()->GetNamedSequenceToken(
|
| + T::kSequenceToken));
|
| + }
|
| +
|
| + static bool IsMessageLoopValid() {
|
| + return content::BrowserThread::GetBlockingPool() != NULL;
|
| + }
|
| +
|
| + static scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner() {
|
| + return content::BrowserThread::GetBlockingPool()
|
| + ->GetSequencedTaskRunnerWithShutdownBehavior(
|
| + content::BrowserThread::GetBlockingPool()->GetNamedSequenceToken(
|
| + T::kSequenceToken),
|
| + T::kShutdownBehavior);
|
| + }
|
| +};
|
| +
|
| } // namespace extensions
|
|
|
| #endif // EXTENSIONS_BROWSER_API_API_RESOURCE_MANAGER_H_
|
|
|