Index: extensions/browser/extension_api_frame_id_map.h |
diff --git a/extensions/browser/extension_api_frame_id_map.h b/extensions/browser/extension_api_frame_id_map.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c3af8b3da24a9db946b1df8cd90af3200d683525 |
--- /dev/null |
+++ b/extensions/browser/extension_api_frame_id_map.h |
@@ -0,0 +1,168 @@ |
+// Copyright 2015 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_EXTENSION_API_FRAME_ID_MAP_H_ |
+#define EXTENSIONS_BROWSER_EXTENSION_API_FRAME_ID_MAP_H_ |
+ |
+#include <list> |
+#include <map> |
+ |
+#include "base/callback.h" |
+#include "base/lazy_instance.h" |
+#include "base/macros.h" |
+#include "base/synchronization/lock.h" |
+ |
+namespace content { |
+class RenderFrameHost; |
+class WebContents; |
+} // namespace content |
+ |
+namespace extensions { |
+ |
+// Extension frame IDs are exposed through the chrome.* APIs and have the |
+// following characteristics: |
+// - The top-level frame has ID 0. |
+// - Any child frame has a positive ID. |
+// - A non-existant frame has ID -1. |
+// - They are only guaranteed to be unique within a tab. |
+// - The ID does not change during the frame's lifetime and is not re-used after |
+// the frame is removed. The frame may change its current RenderFrameHost over |
+// time, so multiple RenderFrameHosts may map to the same extension frame ID. |
+ |
+// This class provides a mapping from a (render_process_id, frame_routing_id) |
+// pair that maps a RenderFrameHost to an extension frame ID. |
+// Unless stated otherwise, the methods can only be called on the UI thread. |
+// |
+// The non-static methods of this class use an internal cache. This cache is |
+// used to minimize IO->UI->IO round-trips of GetFrameIdOnIO. If the cost of |
+// attaching FrameTreeNode IDs to requests is negligible (crbug.com/524228), |
+// then we can remove all key caching and remove the cache from this class. |
+// TODO(robwu): Keep an eye on crbug.com/524228 and act upon the outcome. |
+class ExtensionApiFrameIdMap { |
+ public: |
+ using FrameIdCallback = |
+ base::Callback<void(int extension_api_frame_id, |
+ int extension_api_parent_frame_id)>; |
+ |
+ // An invalid extension API frame ID. |
+ static const int kInvalidFrameId; |
+ |
+ static ExtensionApiFrameIdMap* Get(); |
+ |
+ // Get the extension API frame ID for |rfh|. |
+ static int GetFrameId(content::RenderFrameHost* rfh); |
+ |
+ // Get the extension API frame ID for the parent of |rfh|. |
+ static int GetParentFrameId(content::RenderFrameHost* rfh); |
+ |
+ // Find the current RenderFrameHost for a given WebContents and extension |
+ // frame ID. |
+ // Returns nullptr if not found. |
+ static content::RenderFrameHost* GetRenderFrameHostById( |
+ content::WebContents* web_contents, |
+ int frame_id); |
+ |
+ // Runs |callback| with the result that is equivalent to calling GetFrameId() |
+ // on the UI thread. Thread hopping is minimized if possible. Callbacks for |
+ // the same |render_process_id| and |frame_routing_id| are guaranteed to be |
+ // run in order. The order of other callbacks is undefined. |
+ void GetFrameIdOnIO(int render_process_id, |
+ int frame_routing_id, |
+ const FrameIdCallback& callback); |
+ |
+ // Looks up the frame ID and stores it in the map. This method should be |
+ // called as early as possible, e.g. in a |
+ // WebContentsObserver::RenderFrameCreated notification. |
+ void CacheFrameId(content::RenderFrameHost* rfh); |
+ |
+ // Removes the frame ID mapping for a given frame. This method can be called |
+ // at any time, but it is typically called when a frame is destroyed. |
+ // If this method is not called, the cached mapping for the frame is retained |
+ // forever. |
+ void RemoveFrameId(content::RenderFrameHost* rfh); |
+ |
+ protected: |
+ friend struct base::DefaultLazyInstanceTraits<ExtensionApiFrameIdMap>; |
+ |
+ // A set of identifiers that uniquely identifies a RenderFrame. |
+ struct RenderFrameIdKey { |
+ RenderFrameIdKey(); |
+ RenderFrameIdKey(int render_process_id, int frame_routing_id); |
+ |
+ // The process ID of the renderer that contains the RenderFrame. |
+ int render_process_id; |
+ |
+ // The routing ID of the RenderFrame. |
+ int frame_routing_id; |
+ |
+ bool operator<(const RenderFrameIdKey& other) const; |
+ bool operator==(const RenderFrameIdKey& other) const; |
+ }; |
+ |
+ // The cached pair of frame IDs of the frame. Every RenderFrameIdKey |
+ // maps to a CachedFrameIdPair. |
+ struct CachedFrameIdPair { |
+ CachedFrameIdPair(); |
+ CachedFrameIdPair(int frame_id, int parent_frame_id); |
+ |
+ // The extension API frame ID of the frame. |
+ int frame_id; |
+ |
+ // The extension API frame ID of the parent of the frame. |
+ int parent_frame_id; |
+ }; |
+ |
+ struct FrameIdCallbacks { |
+ FrameIdCallbacks(); |
+ ~FrameIdCallbacks(); |
+ |
+ // This is a std::list so that iterators are not invalidated when the list |
+ // is modified during an iteration. |
+ std::list<FrameIdCallback> callbacks; |
+ |
+ // To avoid re-entrant processing of callbacks. |
+ bool is_iterating; |
+ }; |
+ |
+ using FrameIdMap = std::map<RenderFrameIdKey, CachedFrameIdPair>; |
+ using FrameIdCallbacksMap = std::map<RenderFrameIdKey, FrameIdCallbacks>; |
+ |
+ ExtensionApiFrameIdMap(); |
+ ~ExtensionApiFrameIdMap(); |
+ |
+ // Determines the value to be stored in |frame_id_map_| for a given key. This |
+ // method is only called when |key| is not in |frame_id_map_|. |
+ // virtual for testing. |
+ virtual CachedFrameIdPair KeyToValue(const RenderFrameIdKey& key) const; |
+ |
+ CachedFrameIdPair LookupFrameIdOnUI(const RenderFrameIdKey& key); |
+ |
+ // Called as soon as the frame ID is found for the given |key|, and runs all |
+ // queued callbacks with |cached_frame_id_pair|. |
+ void ReceivedFrameIdOnIO(const RenderFrameIdKey& key, |
+ const CachedFrameIdPair& cached_frame_id_pair); |
+ |
+ // Implementation of CacheFrameId(RenderFrameHost), separated for testing. |
+ void CacheFrameId(const RenderFrameIdKey& key); |
+ |
+ // Implementation of RemoveFrameId(RenderFrameHost), separated for testing. |
+ void RemoveFrameId(const RenderFrameIdKey& key); |
+ |
+ // Queued callbacks for use on the IO thread. |
+ FrameIdCallbacksMap callbacks_map_; |
+ |
+ // This map is only modified on the UI thread and is used to minimize the |
+ // number of thread hops on the IO thread. |
+ FrameIdMap frame_id_map_; |
+ |
+ // This lock protects |frame_id_map_| from being concurrently written on the |
+ // UI thread and read on the IO thread. |
+ base::Lock frame_id_map_lock_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ExtensionApiFrameIdMap); |
+}; |
+ |
+} // namespace extensions |
+ |
+#endif // EXTENSIONS_BROWSER_EXTENSION_API_FRAME_ID_MAP_H_ |