Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/public/test/web_contents_observer_sanity_checker.h" | 5 #include "content/public/test/web_contents_observer_sanity_checker.h" |
| 6 | 6 |
| 7 #include "base/debug/stack_trace.h" | |
| 7 #include "base/strings/stringprintf.h" | 8 #include "base/strings/stringprintf.h" |
| 9 #include "content/common/frame_messages.h" | |
| 8 #include "content/public/browser/render_frame_host.h" | 10 #include "content/public/browser/render_frame_host.h" |
| 9 #include "content/public/browser/render_process_host.h" | 11 #include "content/public/browser/render_process_host.h" |
| 10 #include "content/public/browser/site_instance.h" | 12 #include "content/public/browser/site_instance.h" |
| 11 #include "content/public/browser/web_contents.h" | 13 #include "content/public/browser/web_contents.h" |
| 12 #include "content/public/browser/web_contents_observer.h" | 14 #include "content/public/browser/web_contents_observer.h" |
| 13 | 15 |
| 14 namespace content { | 16 namespace content { |
| 15 | 17 |
| 16 namespace { | 18 namespace { |
| 17 | 19 |
| 18 const char kWebContentsObserverSanityCheckerKey[] = | 20 const char kWebContentsObserverSanityCheckerKey[] = |
| 19 "WebContentsObserverSanityChecker"; | 21 "WebContentsObserverSanityChecker"; |
| 20 | 22 |
| 23 // Set this variable to true to collect stack traces on each RenderFrameCreated | |
| 24 // and RenderFrameDeleted call, so duplicate calls can be easily debugged. | |
| 25 static bool g_collect_stack_traces = false; | |
| 26 | |
| 21 } // namespace | 27 } // namespace |
| 22 | 28 |
| 23 // static | 29 // static |
| 24 void WebContentsObserverSanityChecker::Enable(WebContents* web_contents) { | 30 void WebContentsObserverSanityChecker::Enable(WebContents* web_contents) { |
| 25 if (web_contents->GetUserData(&kWebContentsObserverSanityCheckerKey)) | 31 if (web_contents->GetUserData(&kWebContentsObserverSanityCheckerKey)) |
| 26 return; | 32 return; |
| 27 web_contents->SetUserData(&kWebContentsObserverSanityCheckerKey, | 33 web_contents->SetUserData(&kWebContentsObserverSanityCheckerKey, |
| 28 new WebContentsObserverSanityChecker(web_contents)); | 34 new WebContentsObserverSanityChecker(web_contents)); |
| 29 } | 35 } |
| 30 | 36 |
| 31 void WebContentsObserverSanityChecker::RenderFrameCreated( | 37 void WebContentsObserverSanityChecker::RenderFrameCreated( |
| 32 RenderFrameHost* render_frame_host) { | 38 RenderFrameHost* render_frame_host) { |
| 33 CHECK(!web_contents_destroyed_); | 39 CHECK(!web_contents_destroyed_); |
| 34 std::pair<int, int> routing_pair = | 40 std::pair<int, int> routing_pair = |
| 35 std::make_pair(render_frame_host->GetProcess()->GetID(), | 41 std::make_pair(render_frame_host->GetProcess()->GetID(), |
| 36 render_frame_host->GetRoutingID()); | 42 render_frame_host->GetRoutingID()); |
| 37 bool frame_exists = !live_routes_.insert(routing_pair).second; | 43 bool frame_exists = !live_routes_.insert(routing_pair).second; |
| 38 bool dead_already = deleted_routes_.count(routing_pair) != 0; | 44 deleted_routes_.erase(routing_pair); |
| 39 | 45 |
| 40 if (frame_exists) { | 46 if (frame_exists) { |
| 41 // TODO(nick): Disabled because of http://crbug.com/425397 | 47 std::string trace; |
| 42 #if 0 | 48 if (g_collect_stack_traces) { |
| 49 trace = "\nPrevious creation stack trace:\n" + | |
| 50 render_frame_created_stacks_[routing_pair]; | |
| 51 } | |
| 43 CHECK(false) << "RenderFrameCreated called more than once for routing pair:" | 52 CHECK(false) << "RenderFrameCreated called more than once for routing pair:" |
| 44 << Format(render_frame_host); | 53 << Format(render_frame_host) << trace; |
| 45 #endif | 54 } |
| 46 } else if (dead_already) { | 55 |
| 47 CHECK(false) << "RenderFrameCreated called for routing pair that was " | 56 if (g_collect_stack_traces) { |
| 48 << "previously deleted: " << Format(render_frame_host); | 57 base::debug::StackTrace stack; |
| 58 render_frame_created_stacks_.insert( | |
| 59 std::make_pair(routing_pair, stack.ToString())); | |
| 60 render_frame_deleted_stacks_.erase(routing_pair); | |
| 49 } | 61 } |
| 50 } | 62 } |
| 51 | 63 |
| 52 void WebContentsObserverSanityChecker::RenderFrameDeleted( | 64 void WebContentsObserverSanityChecker::RenderFrameDeleted( |
| 53 RenderFrameHost* render_frame_host) { | 65 RenderFrameHost* render_frame_host) { |
| 54 CHECK(!web_contents_destroyed_); | 66 CHECK(!web_contents_destroyed_); |
| 55 std::pair<int, int> routing_pair = | 67 std::pair<int, int> routing_pair = |
| 56 std::make_pair(render_frame_host->GetProcess()->GetID(), | 68 std::make_pair(render_frame_host->GetProcess()->GetID(), |
| 57 render_frame_host->GetRoutingID()); | 69 render_frame_host->GetRoutingID()); |
| 58 bool was_live = !!live_routes_.erase(routing_pair); | 70 bool was_live = !!live_routes_.erase(routing_pair); |
| 59 bool was_dead_already = !deleted_routes_.insert(routing_pair).second; | 71 bool was_dead_already = !deleted_routes_.insert(routing_pair).second; |
| 60 | 72 |
| 61 if (was_dead_already) { | 73 if (was_dead_already) { |
| 74 std::string trace; | |
| 75 if (g_collect_stack_traces) { | |
| 76 trace = "\nPrevious deletion stack trace:\n" + | |
| 77 render_frame_deleted_stacks_[routing_pair]; | |
| 78 } | |
| 62 CHECK(false) << "RenderFrameDeleted called more than once for routing pair " | 79 CHECK(false) << "RenderFrameDeleted called more than once for routing pair " |
| 63 << Format(render_frame_host); | 80 << Format(render_frame_host) << trace; |
| 64 } else if (!was_live) { | 81 } else if (!was_live) { |
| 65 // TODO(nick): Clients can easily ignore an unrecognized object, but it | 82 // TODO(nick): Clients can easily ignore an unrecognized object, but it |
| 66 // would be useful from a finding-bugs perspective if we could enable this | 83 // would be useful from a finding-bugs perspective if we could enable this |
| 67 // check. | 84 // check. |
| 68 #if 0 | 85 #if 0 |
|
Charlie Reis
2015/02/12 00:29:31
Can we enable this check now, or is it still broke
nasko
2015/02/12 17:52:26
There are still some failures.
| |
| 69 CHECK(false) << "RenderFrameDeleted called for routing pair " | 86 CHECK(false) << "RenderFrameDeleted called for routing pair " |
| 70 << Format(render_frame_host) | 87 << Format(render_frame_host) |
| 71 << " for which RenderFrameCreated was never called"; | 88 << " for which RenderFrameCreated was never called"; |
| 72 #endif | 89 #endif |
| 73 } | 90 } |
| 91 | |
| 92 if (g_collect_stack_traces) { | |
| 93 base::debug::StackTrace stack; | |
| 94 render_frame_deleted_stacks_.insert( | |
| 95 std::make_pair(routing_pair, stack.ToString())); | |
| 96 render_frame_created_stacks_.erase(routing_pair); | |
| 97 } | |
| 74 } | 98 } |
| 75 | 99 |
| 76 void WebContentsObserverSanityChecker::RenderFrameForInterstitialPageCreated( | 100 void WebContentsObserverSanityChecker::RenderFrameForInterstitialPageCreated( |
| 77 RenderFrameHost* render_frame_host) { | 101 RenderFrameHost* render_frame_host) { |
| 78 // TODO(nick): Record this. | 102 // TODO(nick): Record this. |
| 79 } | 103 } |
| 80 | 104 |
| 81 void WebContentsObserverSanityChecker::RenderFrameHostChanged( | 105 void WebContentsObserverSanityChecker::RenderFrameHostChanged( |
| 82 RenderFrameHost* old_host, | 106 RenderFrameHost* old_host, |
| 83 RenderFrameHost* new_host) { | 107 RenderFrameHost* new_host) { |
| 84 CHECK(new_host); | 108 CHECK(new_host); |
| 85 if (old_host) | 109 CHECK_NE(new_host, old_host); |
| 86 AssertFrameExists(old_host); | 110 |
| 87 AssertFrameExists(new_host); | 111 // TODO(nasko): Implement consistency checking for RenderFrameHostChanged |
| 112 // in follow up CL. | |
| 88 } | 113 } |
| 89 | 114 |
| 90 void WebContentsObserverSanityChecker::FrameDeleted( | 115 void WebContentsObserverSanityChecker::FrameDeleted( |
| 91 RenderFrameHost* render_frame_host) { | 116 RenderFrameHost* render_frame_host) { |
| 92 AssertFrameExists(render_frame_host); | 117 AssertRenderFrameExists(render_frame_host); |
|
Charlie Reis
2015/02/12 00:29:31
Interesting. Does this mean we don't call WCO::Fr
nasko
2015/02/12 17:52:26
I think you are right that we don't do the right t
Charlie Reis
2015/02/12 23:51:25
Agreed.
| |
| 93 } | 118 } |
| 94 | 119 |
| 95 void WebContentsObserverSanityChecker::DidStartProvisionalLoadForFrame( | 120 void WebContentsObserverSanityChecker::DidStartProvisionalLoadForFrame( |
| 96 RenderFrameHost* render_frame_host, | 121 RenderFrameHost* render_frame_host, |
| 97 const GURL& validated_url, | 122 const GURL& validated_url, |
| 98 bool is_error_page, | 123 bool is_error_page, |
| 99 bool is_iframe_srcdoc) { | 124 bool is_iframe_srcdoc) { |
| 100 AssertFrameExists(render_frame_host); | 125 AssertRenderFrameExists(render_frame_host); |
| 101 } | 126 } |
| 102 | 127 |
| 103 void WebContentsObserverSanityChecker::DidCommitProvisionalLoadForFrame( | 128 void WebContentsObserverSanityChecker::DidCommitProvisionalLoadForFrame( |
| 104 RenderFrameHost* render_frame_host, | 129 RenderFrameHost* render_frame_host, |
| 105 const GURL& url, | 130 const GURL& url, |
| 106 ui::PageTransition transition_type) { | 131 ui::PageTransition transition_type) { |
| 107 AssertFrameExists(render_frame_host); | 132 AssertRenderFrameExists(render_frame_host); |
| 108 } | 133 } |
| 109 | 134 |
| 110 void WebContentsObserverSanityChecker::DidFailProvisionalLoad( | 135 void WebContentsObserverSanityChecker::DidFailProvisionalLoad( |
| 111 RenderFrameHost* render_frame_host, | 136 RenderFrameHost* render_frame_host, |
| 112 const GURL& validated_url, | 137 const GURL& validated_url, |
| 113 int error_code, | 138 int error_code, |
| 114 const base::string16& error_description) { | 139 const base::string16& error_description) { |
| 115 AssertFrameExists(render_frame_host); | 140 AssertRenderFrameExists(render_frame_host); |
| 116 } | 141 } |
| 117 | 142 |
| 118 void WebContentsObserverSanityChecker::DidNavigateMainFrame( | 143 void WebContentsObserverSanityChecker::DidNavigateMainFrame( |
| 119 const LoadCommittedDetails& details, | 144 const LoadCommittedDetails& details, |
| 120 const FrameNavigateParams& params) { | 145 const FrameNavigateParams& params) { |
| 121 AssertMainFrameExists(); | 146 AssertMainFrameExists(); |
| 122 } | 147 } |
| 123 | 148 |
| 124 void WebContentsObserverSanityChecker::DidNavigateAnyFrame( | 149 void WebContentsObserverSanityChecker::DidNavigateAnyFrame( |
| 125 RenderFrameHost* render_frame_host, | 150 RenderFrameHost* render_frame_host, |
| 126 const LoadCommittedDetails& details, | 151 const LoadCommittedDetails& details, |
| 127 const FrameNavigateParams& params) { | 152 const FrameNavigateParams& params) { |
| 128 AssertFrameExists(render_frame_host); | 153 AssertRenderFrameExists(render_frame_host); |
| 129 } | 154 } |
| 130 | 155 |
| 131 void WebContentsObserverSanityChecker::DocumentAvailableInMainFrame() { | 156 void WebContentsObserverSanityChecker::DocumentAvailableInMainFrame() { |
| 132 AssertMainFrameExists(); | 157 AssertMainFrameExists(); |
| 133 } | 158 } |
| 134 | 159 |
| 135 void WebContentsObserverSanityChecker::DocumentOnLoadCompletedInMainFrame() { | 160 void WebContentsObserverSanityChecker::DocumentOnLoadCompletedInMainFrame() { |
| 136 AssertMainFrameExists(); | 161 AssertMainFrameExists(); |
| 137 } | 162 } |
| 138 | 163 |
| 139 void WebContentsObserverSanityChecker::DocumentLoadedInFrame( | 164 void WebContentsObserverSanityChecker::DocumentLoadedInFrame( |
| 140 RenderFrameHost* render_frame_host) { | 165 RenderFrameHost* render_frame_host) { |
| 141 AssertFrameExists(render_frame_host); | 166 AssertRenderFrameExists(render_frame_host); |
| 142 } | 167 } |
| 143 | 168 |
| 144 void WebContentsObserverSanityChecker::DidFinishLoad( | 169 void WebContentsObserverSanityChecker::DidFinishLoad( |
| 145 RenderFrameHost* render_frame_host, | 170 RenderFrameHost* render_frame_host, |
| 146 const GURL& validated_url) { | 171 const GURL& validated_url) { |
| 147 AssertFrameExists(render_frame_host); | 172 AssertRenderFrameExists(render_frame_host); |
| 148 } | 173 } |
| 149 | 174 |
| 150 void WebContentsObserverSanityChecker::DidFailLoad( | 175 void WebContentsObserverSanityChecker::DidFailLoad( |
| 151 RenderFrameHost* render_frame_host, | 176 RenderFrameHost* render_frame_host, |
| 152 const GURL& validated_url, | 177 const GURL& validated_url, |
| 153 int error_code, | 178 int error_code, |
| 154 const base::string16& error_description) { | 179 const base::string16& error_description) { |
| 155 AssertFrameExists(render_frame_host); | 180 AssertRenderFrameExists(render_frame_host); |
| 156 } | 181 } |
| 157 | 182 |
| 158 void WebContentsObserverSanityChecker::DidGetRedirectForResourceRequest( | 183 void WebContentsObserverSanityChecker::DidGetRedirectForResourceRequest( |
| 159 RenderFrameHost* render_frame_host, | 184 RenderFrameHost* render_frame_host, |
| 160 const ResourceRedirectDetails& details) { | 185 const ResourceRedirectDetails& details) { |
| 161 AssertFrameExists(render_frame_host); | 186 AssertRenderFrameExists(render_frame_host); |
| 162 } | 187 } |
| 163 | 188 |
| 164 void WebContentsObserverSanityChecker::DidOpenRequestedURL( | 189 void WebContentsObserverSanityChecker::DidOpenRequestedURL( |
| 165 WebContents* new_contents, | 190 WebContents* new_contents, |
| 166 RenderFrameHost* source_render_frame_host, | 191 RenderFrameHost* source_render_frame_host, |
| 167 const GURL& url, | 192 const GURL& url, |
| 168 const Referrer& referrer, | 193 const Referrer& referrer, |
| 169 WindowOpenDisposition disposition, | 194 WindowOpenDisposition disposition, |
| 170 ui::PageTransition transition) { | 195 ui::PageTransition transition) { |
| 171 AssertFrameExists(source_render_frame_host); | 196 AssertRenderFrameExists(source_render_frame_host); |
| 172 } | 197 } |
| 173 | 198 |
| 174 bool WebContentsObserverSanityChecker::OnMessageReceived( | 199 bool WebContentsObserverSanityChecker::OnMessageReceived( |
| 175 const IPC::Message& message, | 200 const IPC::Message& message, |
| 176 RenderFrameHost* render_frame_host) { | 201 RenderFrameHost* render_frame_host) { |
| 202 // TODO(nasko): FrameHostMsg_RenderProcessGone is delivered to | |
| 203 // WebContentsObserver since RenderFrameHost allows the delegate to handle | |
| 204 // the message first. This shouldn't happen, but for now handle it here. | |
|
Charlie Reis
2015/02/12 00:29:31
Let's list a bug number here.
Any ideas on what t
nasko
2015/02/12 17:52:26
Done
| |
| 205 if (message.type() == FrameHostMsg_RenderProcessGone::ID) | |
| 206 return false; | |
| 207 | |
| 177 #if !defined(OS_MACOSX) | 208 #if !defined(OS_MACOSX) |
| 178 // TODO(avi): Disabled because of http://crbug.com/445054 | 209 // TODO(avi): Disabled because of http://crbug.com/445054 |
| 179 AssertFrameExists(render_frame_host); | 210 AssertRenderFrameExists(render_frame_host); |
| 180 #endif | 211 #endif |
| 181 return false; | 212 return false; |
| 182 } | 213 } |
| 183 | 214 |
| 184 void WebContentsObserverSanityChecker::WebContentsDestroyed() { | 215 void WebContentsObserverSanityChecker::WebContentsDestroyed() { |
| 185 CHECK(!web_contents_destroyed_); | 216 CHECK(!web_contents_destroyed_); |
| 186 web_contents_destroyed_ = true; | 217 web_contents_destroyed_ = true; |
| 187 } | 218 } |
| 188 | 219 |
| 189 WebContentsObserverSanityChecker::WebContentsObserverSanityChecker( | 220 WebContentsObserverSanityChecker::WebContentsObserverSanityChecker( |
| 190 WebContents* web_contents) | 221 WebContents* web_contents) |
| 191 : WebContentsObserver(web_contents), web_contents_destroyed_(false) { | 222 : WebContentsObserver(web_contents), web_contents_destroyed_(false) { |
| 192 // Prime the pump with the initial objects. | 223 // Prime the pump with the initial objects. |
| 224 // TODO(nasko): Investigate why this is needed. | |
| 193 RenderViewCreated(web_contents->GetRenderViewHost()); | 225 RenderViewCreated(web_contents->GetRenderViewHost()); |
| 194 RenderFrameCreated(web_contents->GetMainFrame()); | |
| 195 } | 226 } |
| 196 | 227 |
| 197 WebContentsObserverSanityChecker::~WebContentsObserverSanityChecker() { | 228 WebContentsObserverSanityChecker::~WebContentsObserverSanityChecker() { |
| 198 CHECK(web_contents_destroyed_); | 229 CHECK(web_contents_destroyed_); |
| 199 } | 230 } |
| 200 | 231 |
| 201 void WebContentsObserverSanityChecker::AssertFrameExists( | 232 void WebContentsObserverSanityChecker::AssertRenderFrameExists( |
| 202 RenderFrameHost* render_frame_host) { | 233 RenderFrameHost* render_frame_host) { |
| 203 CHECK(!web_contents_destroyed_); | 234 CHECK(!web_contents_destroyed_); |
| 204 std::pair<int, int> routing_pair = | 235 std::pair<int, int> routing_pair = |
| 205 std::make_pair(render_frame_host->GetProcess()->GetID(), | 236 std::make_pair(render_frame_host->GetProcess()->GetID(), |
| 206 render_frame_host->GetRoutingID()); | 237 render_frame_host->GetRoutingID()); |
| 238 | |
| 207 bool render_frame_created_happened = live_routes_.count(routing_pair) != 0; | 239 bool render_frame_created_happened = live_routes_.count(routing_pair) != 0; |
| 208 bool render_frame_deleted_happened = deleted_routes_.count(routing_pair) != 0; | 240 bool render_frame_deleted_happened = deleted_routes_.count(routing_pair) != 0; |
| 209 | 241 |
| 210 CHECK(render_frame_created_happened) | 242 CHECK(render_frame_created_happened) |
| 211 << "A RenderFrameHost pointer was passed to a WebContentsObserver " | 243 << "A RenderFrameHost pointer was passed to a WebContentsObserver " |
| 212 << "method, but WebContentsObserver::RenderFrameCreated was never called " | 244 << "method, but WebContentsObserver::RenderFrameCreated was never called " |
| 213 << "for that RenderFrameHost: " << Format(render_frame_host); | 245 << "for that RenderFrameHost: " << Format(render_frame_host); |
| 214 CHECK(!render_frame_deleted_happened) | 246 CHECK(!render_frame_deleted_happened) |
| 215 << "A RenderFrameHost pointer was passed to a WebContentsObserver " | 247 << "A RenderFrameHost pointer was passed to a WebContentsObserver " |
| 216 << "method, but WebContentsObserver::RenderFrameDeleted had already been " | 248 << "method, but WebContentsObserver::RenderFrameDeleted had already been " |
| 217 << "called on that frame:" << Format(render_frame_host); | 249 << "called on that frame:" << Format(render_frame_host); |
| 218 } | 250 } |
| 219 | 251 |
| 220 void WebContentsObserverSanityChecker::AssertMainFrameExists() { | 252 void WebContentsObserverSanityChecker::AssertMainFrameExists() { |
| 221 AssertFrameExists(web_contents()->GetMainFrame()); | 253 AssertRenderFrameExists(web_contents()->GetMainFrame()); |
| 222 } | 254 } |
| 223 | 255 |
| 224 std::string WebContentsObserverSanityChecker::Format( | 256 std::string WebContentsObserverSanityChecker::Format( |
| 225 RenderFrameHost* render_frame_host) { | 257 RenderFrameHost* render_frame_host) { |
| 226 return base::StringPrintf( | 258 return base::StringPrintf( |
| 227 "(%d, %d -> %s )", render_frame_host->GetProcess()->GetID(), | 259 "(%d, %d -> %s)", render_frame_host->GetProcess()->GetID(), |
| 228 render_frame_host->GetRoutingID(), | 260 render_frame_host->GetRoutingID(), |
| 229 render_frame_host->GetSiteInstance()->GetSiteURL().spec().c_str()); | 261 render_frame_host->GetSiteInstance()->GetSiteURL().spec().c_str()); |
| 230 } | 262 } |
| 231 | 263 |
| 232 } // namespace content | 264 } // namespace content |
| OLD | NEW |