diff options
author | rob <rob@robwu.nl> | 2016-01-06 13:22:09 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-01-06 21:22:58 +0000 |
commit | 3e2a0730e0dfb9c4dcbce45eea275270db900e90 (patch) | |
tree | bb5daf2237e4791771a94c2341d8764a7fe7d7b7 /extensions/browser/extension_api_frame_id_map.h | |
parent | 8bdc571018faac493cb358ea1f8b7314b9178aa4 (diff) | |
download | chromium_src-3e2a0730e0dfb9c4dcbce45eea275270db900e90.zip chromium_src-3e2a0730e0dfb9c4dcbce45eea275270db900e90.tar.gz chromium_src-3e2a0730e0dfb9c4dcbce45eea275270db900e90.tar.bz2 |
Use FrameTreeNode ID as frameId in extension APIs
Use FrameTreeNode IDs instead of RenderFrame routing IDs as "frame id"
in the extension APIs (webNavigation, webRequest, extension messaging)
because FTN IDs are globally unique, and RFH IDs are not.
This extends the public content API with:
- RenderFrameHost::FromFrameTreeNodeId
- RenderFrameHost::GetFrameTreeNodeId
- WebContents::FindFrameByFrameTreeNodeId
The extension APIs are modified as follows:
- webRequest:
* Frame IDs may be unavailable after frame removal (crbug.com/572930).
* Blocking webRequest handlers may be slower than before due to an
extra IO->UI->IO hop to determine the frameId (but this happens only
once per frame load).
- webNavigation:
* processId is no longer required in chrome.webNavigation.getFrame,
but marked as optional (deprecated) to make sure that the API is
backwards-compatible.
* frameId is constant across navigations.
- Extension messaging (chrome.runtime.connect and friends):
* Small change for extension developers in the following scenario:
1. Open port to tab.
2. Accept the port by listening to onConnect *in a child frame*.
3. Unload the document in the frame.
Old behavior: onDisconnect was not triggered in the background until
the tab was reloaded or closed.
New behavior: onDisconnect is called.
* Extension messaging works correctly in out-of-process frames.
* Move port lifetime management from renderer to browser.
* Tie port lifetime to frames instead of processes.
* Only notify frames in renderers if they have accepted the port.
* Remove obsolete work-around for crbug.com/520303.
* Unify open/close/postMessage logic in ChromeExtensionMessageFilter
(crbug.com/394383#c7)
- The extension frameId logic is no longer scattered over several files,
but resides in a single class (ExtensionApiFrameIdMap).
- IDs are now guaranteed to be -1 or higher (before this, -2 was
occasionally seen).
Depends on https://codereview.chromium.org/1413853005/
BUG=432875
TEST=browser_tests --gtest_filter=\
ExtensionWebRequestApiTest.*:\
WebNavigationApiTest.*:\
ExtensionApiTest.Messaging*:\
ExternallyConnectableMessagingTest.*:\
ExternallyConnectableMessagingWithTlsChannelIdTest.*
Review URL: https://codereview.chromium.org/1413543005
Cr-Commit-Position: refs/heads/master@{#367914}
Diffstat (limited to 'extensions/browser/extension_api_frame_id_map.h')
-rw-r--r-- | extensions/browser/extension_api_frame_id_map.h | 168 |
1 files changed, 168 insertions, 0 deletions
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 0000000..c3af8b3 --- /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_ |