Partial failure when loading multiple embedded google maps
Reported by
co...@redguava.com.au,
Oct 13
|
||||||||||
Issue descriptionUserAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 Example URL: https://www.billiam.org/chrome-embedded-maps/ Steps to reproduce the problem: 1. Load a page containing two or more simple embedded google maps (via iframes). 2. Click map to open larger map in new tab What is the expected behavior? 1. All maps load correctly. Google copyright appears. 'View larger map' panel appears. 2. Map opens correctly in new tab What went wrong? 1. Maps which load simultaneously do not load completely. Map background and pin appear, but copyright and 'View larger map' panel do not. 2. Clicking partially loaded map opens new tab pointing to google.com/maps/embed/v1/undefined, and 404s Does it occur on multiple sites: Yes Is it a problem with a plugin? No Did this work before? Yes 65.0.3325.181 Does this work in other browsers? Yes Chrome version: 69.0.3497.100 Channel: stable OS Version: 10.0 Flash Version: Screenshot shows 2 partially loaded maps, and one successful one, under Chrome 69. All map loading succeeds for me in Firefox, IE11 & Edge, Chrome 56 and 65 in windows, even with 10 or more visible maps. Fails under Chrome 69(stable, windows) and 71(dev, linux)
,
Oct 14
Bisect tool gave me: You are probably looking for a change made after 552588 (known good), but no later than 552589 (first known bad). CHANGELOG URL: https://chromium.googlesource.com/chromium/src/+log/7bbdb70b2643201e9ec6236443b7b2003deaf03d..fb1ccf02ee8ca79e1404abfd3a3a7d540b7d2dbd
,
Oct 14
Opting out of site isolation via chrome://flags/#site-isolation-trial-opt-out in 69.0.3497.100 also "fixes" the issue.
,
Oct 15
Thanks for filing the issue! Unable to reproduce the issue on reported chrome version 69.0.3497.100 using Windows 10 with the below mentioned steps. 1. Launched Chrome 2. Navigated to https://www.billiam.org/chrome-embedded-maps/ Observed all maps load correctly and 'View larger map' panel is seen. Attaching the screen cast of the same for reference. Note: Checked the same by Opting out chrome://flags/#site-isolation-trial-opt-out and by keeping it as Default, In neither of the cases we didn't see any issue. @Reporter: Could you please have a look at the screen cast and let us now if we have missed anything in the process. Any further inputs from your en may be helpful. CC'ing "Lukasz Anforowicz" for further inputs from Comment#2.
,
Oct 15
I can repro on 69.0.3497.95 on a Chromebook. Adding Internals>Sandbox>SiteIsolation label per #c2 and #c3.
,
Oct 15
I can definitely reproduce this as well. I've seen it successful too. I found you might need to Ctrl-Refresh to cause it to happen which makes me thing this is a resource loading problem. Changing the URI of the iframes (so they aren't exactly the same lat/long) doesn't seem to fix it either.
,
Oct 15
Looking at DevTools->Network tab and comparing requests made by the 1st (successful) and the 2nd (broken) maps subframe, I see that the 1st subframe issued the following additional requests: - https://maps.googleapis.com/maps-api-v3/api/js/34/13/controls.js - data:image/svg+xml,... - https://maps.googleapis.com/maps/api/js/QuotaService.RecordEvent?1shttps%3A%2F%2Fwww.google.com%2Fmaps%2Fembed%2Fv1%2Fplace%3Fq%3D51.5033635%2C-0.1276248%26zoom%3D15%26key%3DAIzaSyDXbDVMNsMoFdQM1lK5hZqroj5rdjO5jgY&2sgoogle-maps-embed&7sahfexn&10e1&callback=_xdc_._ipqd9y&client=google-maps-embed&token=15393
,
Oct 15
> Could you please have a look at the screen cast and let us now if we have missed anything in the process Screencast looks fine to me, but may be down to differences in networking. Could you try disabling the cache in dev tools/network conditions, and then reloading? Possibly try network throttling as well?
,
Oct 15
FWIW, when control.js is successfully included, it is happening from the native/js callstacks shown below. When control.js is not included (i.e. when the bug repros), I don't see a call to content::URLLoaderFactoryBundle::CreateLoaderAndStart where the URL's path is "/maps-api-v3/api/js/34/13/controls.js". [1:1:1015/100518.577785:ERROR:url_loader_factory_bundle.cc(108)] URLLoaderFactoryBundle::CreateLoaderAndStart; request.url = https://maps.googleapis.com/maps-api-v3/api/js/34/13/controls.js; stack = #0 0x7f3da14465ff base::debug::StackTrace::StackTrace() #1 0x7f3d9e283f40 content::URLLoaderFactoryBundle::CreateLoaderAndStart() #2 0x7f3d9ef3b382 content::ChildURLLoaderFactoryBundle::CreateLoaderAndStart() #3 0x7f3d9e27dc47 content::ThrottlingURLLoader::StartNow() #4 0x7f3d9e27d037 content::ThrottlingURLLoader::Start() #5 0x7f3d9e27ca3a content::ThrottlingURLLoader::CreateLoaderAndStart() #6 0x7f3d9ef437d5 content::ResourceDispatcher::StartAsync() #7 0x7f3d9ef51ca1 content::WebURLLoaderImpl::Context::Start() #8 0x7f3d9ef57837 content::WebURLLoaderImpl::LoadAsynchronously() #9 0x7f3d97082178 blink::ResourceLoader::StartWith() #10 0x7f3d9707c73d blink::ResourceLoadScheduler::Run() #11 0x7f3d9707bdee blink::ResourceLoadScheduler::MaybeRun() #12 0x7f3d9707c334 blink::ResourceLoadScheduler::Request() #13 0x7f3d97081c70 blink::ResourceLoader::Start() #14 0x7f3d97068ac9 blink::ResourceFetcher::StartLoad() #15 0x7f3d97067284 blink::ResourceFetcher::RequestResource() #16 0x7f3d98f7f2fb blink::ScriptResource::Fetch() #17 0x7f3d99107150 blink::ClassicPendingScript::Fetch() #18 0x7f3d9911d05b blink::ScriptLoader::FetchClassicScript() #19 0x7f3d9911c227 blink::ScriptLoader::PrepareScript() #20 0x7f3d9911b822 blink::ScriptLoader::DidNotifySubtreeInsertionsToDocument() #21 0x7f3d985fd2d3 blink::ContainerNode::DidInsertNodeVector() #22 0x7f3d985fe168 blink::ContainerNode::AppendChild() #23 0x7f3d986c5428 blink::Node::appendChild() #24 0x7f3d99369378 blink::V8Node::appendChildMethodCallbackForMainWorld() #25 0x7f3d99c6ffe4 v8::internal::FunctionCallbackArguments::Call() #26 0x7f3d99c6e668 v8::internal::(anonymous namespace)::HandleApiCallHelper<>() #27 0x7f3d99c6caa1 v8::internal::Builtin_Impl_HandleApiCall() #28 0x7f3d99c6c53f v8::internal::Builtin_HandleApiCall() #29 0x7f3d9a97baf5 <unknown> ; js stack = ze (https://maps.googleapis.com/maps/api/js?client=google-maps-embed&paint_origin=&libraries=geometry,search&v=3.exp&language=en_US:71:503) https://maps.googleapis.com/maps/api/js?client=google-maps-embed&paint_origin=&libraries=geometry,search&v=3.exp&language=en_US:73:128 Fe (https://maps.googleapis.com/maps/api/js?client=google-maps-embed&paint_origin=&libraries=geometry,search&v=3.exp&language=en_US:73:478) Ge (https://maps.googleapis.com/maps/api/js?client=google-maps-embed&paint_origin=&libraries=geometry,search&v=3.exp&language=en_US:73:37) Object._.U (https://maps.googleapis.com/maps/api/js?client=google-maps-embed&paint_origin=&libraries=geometry,search&v=3.exp&language=en_US:74:158) zd (https://maps.googleapis.com/maps-api-v3/api/js/34/13/map.js:100:75) _.jl.Zd (https://maps.googleapis.com/maps-api-v3/api/js/34/13/map.js:93:97) Nr.Zd (https://maps.googleapis.com/maps-api-v3/api/js/34/13/map.js:58:106) Kr (https://maps.googleapis.com/maps-api-v3/api/js/34/13/map.js:2:295) HTMLDivElement.<anonymous> (https://maps.googleapis.com/maps-api-v3/api/js/34/13/map.js:3:18) The callstacks above were generated via: void URLLoaderFactoryBundle::CreateLoaderAndStart( network::mojom::URLLoaderRequest loader, int32_t routing_id, int32_t request_id, uint32_t options, const network::ResourceRequest& request, network::mojom::URLLoaderClientPtr client, const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) { if (request.url.path_piece() == "/maps-api-v3/api/js/34/13/controls.js") { LOG(ERROR) << "URLLoaderFactoryBundle::CreateLoaderAndStart" << "; request.url = " << request.url << "; stack = " << base::debug::StackTrace().ToString() << "; js stack = " << [](){ char* buf = nullptr; size_t size = 0; FILE* f = open_memstream(&buf, &size); if (!f) return std::string("<mem error>"); v8::Message::PrintCurrentStackTrace( v8::Isolate::GetCurrent(), f); fflush(f); fclose(f); std::string result(buf, size); free(buf); return result; }();; }
,
Oct 15
I think I can confirm that this bug is related to Site Isolation: - It usually repros when Site Isolation is turned on (I note that it was turned on by default in M67) - It never reproed for me after turning Site Isolation off by --disable-site-isolation-trials (I tried around 10 times) Give obfuscated Javascript in #c9 above, we'll probably need help from the Maps team to understand what is the root cause of the bug. I've opened an internal b/117769016 to ask for help from the Maps team.
,
Oct 16
zwarts@ has kindly looked at this bug and suggested that this might be something similar to issue 807164, where load event for images was missing in OOPIFs. I was able to confirm this theory, by logging how many times HTMLImageLoader::DispatchLoadEvent is called for each frame. If it is called 8 times, the map is loaded completely (including the "View larger map" button). If it is called less times, the bug repros (i.e. the "View larger map" button is missing). In my attempts to repro sometimes 1 frame fails, sometimes 2 fail and sometimes all 3 fail and so far this was always consistent with the number of observed hits of HTMLImageLoader::DispatchLoadEvent method.
,
Oct 16
vmpstr@, could you PTAL (since you've fixed a possibly related issue 807164)?
,
Oct 16
I'm guessing that the load event failing to fire is the thing that is causing the rest of the page not to be constructed here? Looking at devtools, it seems that the "bad" frames don't have a chunk of html that the good ones have. (see screenshots) issue 807164 specifically dealt with the img decode api not resolving things correctly, but that was for the map content itself not for the decorations around. I'll take a look to see if it's the same issue
,
Oct 17
Update: I can reproduce on my dev channel and stable, but I can't seem to make it happen on a locally build version. Someone near me reproduced it and from the logs that we've added it seems that there are a total of 14 image decodes that are requested and each of them is processed and the promise is resolved, which is different from the cited issue. For #11, I think the differences is that the dom for the overlay (large map, logo, etc) is simply not inserted if something before it prevents it, so that could account for the smaller number of DispatchLoadEvent()s lukasza@ is it possible to match up the number of times the image would have fired as compared to how many times it does fire (ie possibly the number of times a src is set on an image, or maybe the number of HTMLImageElements that is created?) I'll keep trying to repro but it seems that locally my timing is different and causes the page to work :\
,
Oct 17
,
Oct 17
It looks like the load of controls.js is triggered via a 'transitionend' event, and the transition (of opacity) itself is (supposed to be) triggered via a rAF callback. So that could be another angle to consider.
,
Oct 17
Is it possible to get the author(s) of the iframe content to help in debugging this? Ie, which event is expected to fire to continue loading the content. From #16, it's an opacity transition event, but maybe that transition is started by an image load? From my brief debugging, it seems that the decode api part of the process is in fact working as intended with every requested decode finishing successfully and resolving the corresponding promise, so I'm leaning towards the issue being elsewhere. Reassigning back to lukasza@, since I don't think I can help more here (largely due to the fact that I still can't reproduce this on a local build :\)
,
Oct 17
Thank you fs@ and zwarts@ for providing suggestions and details in https://crbug.com/895102#c16 and b/117769016#comment4. I've tried to gather again info on how many images are inserted, loaded, decoded (limiting to images with src containing "maps/vt" substrung) and how many times transitionend event fires. In my repro there was one successful frame and two broken frames. All 3 frames saw the same number of the following events: - 4 x HTMLImageLoader::DispatchLoadEvent.*maps/vt - 8 x InsertedInto.*maps/vt - 4 x DecodeRequest::Resolve.*maps/vt 1 frame saw: - 4 x transitionend 2 frames saw: - 0 x transitionend So - yes, the problem seems to be the missing transitionend event.
,
Oct 17
fsamuel@, I wonder if you could please help understand why transitionend event is not firing for some OOPIFs in the repro? I am afraid that I am not able to help much with rAF and compositor stuff - this goes way beyond what I know about Chrome... :-/
,
Oct 17
BTW: I also wonder what guarantees the specs offer wrt 1) css animations, 2) transitionend events, 3) rAF. Are all of these guaranteed to happen, even if a frame is not invisible (scrolled away / below the fold / in invisible parent / in a background tab)?
,
Oct 18
rAFs [1] should be guaranteed to fire [2]. CSS Transitions (are specced to) trigger[3] on style changes (but don't define exactly when that is...) 'transitionend'[4] should fire if the associated transition completes. [1] https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#animation-frames [2] Not necessarily in a timely fashion - I believe the spec provides a fair amount of leeway here. [3] https://drafts.csswg.org/css-transitions/#starting [4] https://drafts.csswg.org/css-transitions/#transitionend
,
Oct 22
Would love to know what [2] means. What does the "leeway" entail here? If [2] is not guaranteed are we supposed to race it with a timeout of a certain value? It would be sad if for neatness purposes.
,
Oct 22
It boils down to this: https://html.spec.whatwg.org/multipage/webappapis.html#update-the-rendering specifically, step 7.3: "Rendering opportunites: If there are browsing contexts browsingContexts that do not have a rendering opportunity, then remove from docs all Document objects whose browsing context is in browsingContexts. A browsing context has a rendering opportunity if the user agent is currently able to present the contents of the browsing context to the user, accounting for hardware refresh rate constraints and user agent throttling for performance reasons, but considering content presentable even if it's outside the viewport. Browsing context rendering opportunities are determined based on hardware constraints such as display refresh rates and other factors such as page performance or whether the page is in the background. Rendering opportunities typically occur at regular intervals." So there are cases (some of which lukasza listed) where, from a spec perspective, the callbacks could be deferred. That being said though, I don't think there any such cases likely being surfaced here - or that they would affect functionality in general in this case (i.e callbacks could be deferred but would always be run at some point in time.)
,
Oct 30
Passing along to flackr@ who's probably a better fit to figure out this bug. Please pass along to me if it's a viz bug.
,
Oct 30
Any tips for reproducing this? I've tried refreshing the site dozens of times and haven't seen it fail to load on tip of tree (72.0.3597.0) and dev channel (72.0.3590.0).
Re #23, the transition code seems to come down to the following:
requestAnimationFrame(() => {
element.style.transition = 'opacity 200ms linear';
element.style.opacity = '0';
requestAnimationFrame(() => {
element.style.opacity = '';
});
element.addEventListener('transitionend', () {
finish();
});
});
Updating the styles on one requestAnimationFrame and then removing on the next requestAnimationFrame should reliably cause a rendering opportunity before the style is removed allowing the transition to start.
,
Oct 30
Our team has added a race between the transitionend and a 400ms timer to avoid this. We pushed that to production yesterday. So I understand the issue no longer is reproducible easily, though the underlying issue may persist if it is a chrome bug. |
||||||||||
►
Sign in to add a comment |
||||||||||
Comment 1 by viswa.karala@chromium.org
, Oct 14