Index: extensions/common/permissions/permissions_data.h |
diff --git a/extensions/common/permissions/permissions_data.h b/extensions/common/permissions/permissions_data.h |
index 43be869029d784ff470ae8db08d9ae3ce46fcd1c..d7d5f27f4cdc3064cf1b60ba45b968fe2a936457 100644 |
--- a/extensions/common/permissions/permissions_data.h |
+++ b/extensions/common/permissions/permissions_data.h |
@@ -9,9 +9,11 @@ |
#include <string> |
#include <vector> |
+#include "base/containers/scoped_ptr_map.h" |
#include "base/memory/ref_counted.h" |
#include "base/strings/string16.h" |
#include "base/synchronization/lock.h" |
+#include "base/threading/thread_checker.h" |
#include "extensions/common/manifest.h" |
#include "extensions/common/permissions/api_permission.h" |
#include "extensions/common/permissions/permission_message.h" |
@@ -25,6 +27,14 @@ class URLPatternSet; |
// A container for the permissions state of an extension, including active, |
// withheld, and tab-specific permissions. |
+// Thread-Safety: Since this is an object on the Extension object, *some* thread |
+// safety is provided. All utility functions for checking if a permission is |
+// present or an operation is allowed are thread-safe. However, permissions can |
+// only be set (or updated) on the thread to which this object is bound. |
+// Permissions may be accessed synchronously on that same thread. |
+// Accessing on an improper thread will DCHECK(). |
+// This is necessary to prevent a scenario in which one thread will access |
+// permissions while another thread changes them. |
class PermissionsData { |
public: |
// The possible types of access for a given frame. |
@@ -35,7 +45,8 @@ class PermissionsData { |
// the given page. |
}; |
- using TabPermissionsMap = std::map<int, scoped_refptr<const PermissionSet>>; |
+ using TabPermissionsMap = |
+ base::ScopedPtrMap<int, scoped_ptr<const PermissionSet>>; |
// Delegate class to allow different contexts (e.g. browser vs renderer) to |
// have control over policy decisions. |
@@ -80,16 +91,22 @@ class PermissionsData { |
const Extension* extension, |
std::string* error); |
+ // Locks the permissions data to the current thread. We don't do this on |
+ // construction, since extensions are initialized across multiple threads. |
+ void BindToCurrentThread() const; |
+ |
// Sets the runtime permissions of the given |extension| to |active| and |
// |withheld|. |
- void SetPermissions(const scoped_refptr<const PermissionSet>& active, |
- const scoped_refptr<const PermissionSet>& withheld) const; |
+ void SetPermissions(scoped_ptr<const PermissionSet> active, |
+ scoped_ptr<const PermissionSet> withheld) const; |
+ |
+ // Sets the active permissions, leaving withheld the same. |
+ void SetActivePermissions(scoped_ptr<const PermissionSet> active) const; |
// Updates the tab-specific permissions of |tab_id| to include those from |
// |permissions|. |
- void UpdateTabSpecificPermissions( |
- int tab_id, |
- scoped_refptr<const PermissionSet> permissions) const; |
+ void UpdateTabSpecificPermissions(int tab_id, |
+ const PermissionSet& permissions) const; |
// Clears the tab-specific permissions of |tab_id|. |
void ClearTabSpecificPermissions(int tab_id) const; |
@@ -182,24 +199,24 @@ class PermissionsData { |
// page itself. |
bool CanCaptureVisiblePage(int tab_id, std::string* error) const; |
- // Returns the tab permissions map. |
- TabPermissionsMap CopyTabSpecificPermissionsMap() const; |
+ const TabPermissionsMap& tab_specific_permissions() const { |
+ DCHECK(!thread_checker_ || thread_checker_->CalledOnValidThread()); |
+ return tab_specific_permissions_; |
+ } |
- scoped_refptr<const PermissionSet> active_permissions() const { |
- // We lock so that we can't also be setting the permissions while returning. |
- base::AutoLock auto_lock(runtime_lock_); |
- return active_permissions_unsafe_; |
+ const PermissionSet* active_permissions() const { |
+ DCHECK(!thread_checker_ || thread_checker_->CalledOnValidThread()); |
+ return active_permissions_unsafe_.get(); |
} |
- scoped_refptr<const PermissionSet> withheld_permissions() const { |
- // We lock so that we can't also be setting the permissions while returning. |
- base::AutoLock auto_lock(runtime_lock_); |
- return withheld_permissions_unsafe_; |
+ const PermissionSet* withheld_permissions() const { |
+ DCHECK(!thread_checker_ || thread_checker_->CalledOnValidThread()); |
+ return withheld_permissions_unsafe_.get(); |
} |
#if defined(UNIT_TEST) |
- scoped_refptr<const PermissionSet> GetTabSpecificPermissionsForTesting( |
- int tab_id) const { |
+ const PermissionSet* GetTabSpecificPermissionsForTesting(int tab_id) const { |
+ base::AutoLock auto_lock(runtime_lock_); |
return GetTabSpecificPermissions(tab_id); |
} |
#endif |
@@ -207,19 +224,21 @@ class PermissionsData { |
private: |
// Gets the tab-specific host permissions of |tab_id|, or NULL if there |
// aren't any. |
- scoped_refptr<const PermissionSet> GetTabSpecificPermissions( |
- int tab_id) const; |
+ // Must be called with |runtime_lock_| acquired. |
+ const PermissionSet* GetTabSpecificPermissions(int tab_id) const; |
// Returns true if the |extension| has tab-specific permission to operate on |
// the tab specified by |tab_id| with the given |url|. |
// Note that if this returns false, it doesn't mean the extension can't run on |
// the given tab, only that it does not have tab-specific permission to do so. |
+ // Must be called with |runtime_lock_| acquired. |
bool HasTabSpecificPermissionToExecuteScript(int tab_id, |
const GURL& url) const; |
// Returns whether or not the extension is permitted to run on the given page, |
// checking against |permitted_url_patterns| in addition to blocking special |
// sites (like the webstore or chrome:// urls). |
+ // Must be called with |runtime_lock_| acquired. |
AccessType CanRunOnPage(const Extension* extension, |
const GURL& document_url, |
int tab_id, |
@@ -241,17 +260,19 @@ class PermissionsData { |
// Unsafe indicates that we must lock anytime this is directly accessed. |
// Unless you need to change |active_permissions_unsafe_|, use the (safe) |
// active_permissions() accessor. |
- mutable scoped_refptr<const PermissionSet> active_permissions_unsafe_; |
+ mutable scoped_ptr<const PermissionSet> active_permissions_unsafe_; |
// The permissions the extension requested, but was not granted due because |
// they are too powerful. This includes things like all_hosts. |
// Unsafe indicates that we must lock anytime this is directly accessed. |
// Unless you need to change |withheld_permissions_unsafe_|, use the (safe) |
// withheld_permissions() accessor. |
- mutable scoped_refptr<const PermissionSet> withheld_permissions_unsafe_; |
+ mutable scoped_ptr<const PermissionSet> withheld_permissions_unsafe_; |
mutable TabPermissionsMap tab_specific_permissions_; |
+ mutable scoped_ptr<base::ThreadChecker> thread_checker_; |
+ |
DISALLOW_COPY_AND_ASSIGN(PermissionsData); |
}; |