Open Bug 1669356 Opened 5 years ago Updated 4 years ago

tabs.onUpdated: Update notification for tab load completion is ambiguous for discarded tabs

Categories

(WebExtensions :: General, defect, P3)

defect

Tracking

(firefox81 affected, firefox82 affected, firefox83 affected)

Tracking Status
firefox81 --- affected
firefox82 --- affected
firefox83 --- affected

People

(Reporter: julianhofstadter, Unassigned)

References

Details

Attachments

(2 files, 2 obsolete files)

status == "complete" update is sent 3 times when reloading a suspended tab, and it appears that the un-discarding/loading process is not complete until the 3rd time it is sent.

This can be demonstrated by the attached extension:

To use:

  1. Create and open Firefox in new profile.

  2. Install demo addon.

  3. Close all tabs except 1.

  4. Open 6 new additional tabs, and load with the following urls:

en.wikipedia.org/wiki/Train
en.wikipedia.org/wiki/Car
en.wikipedia.org/wiki/Bus
en.wikipedia.org/wiki/Ship
en.wikipedia.org/wiki/Bicycle
en.wikipedia.org/wiki/Motorcycle

(Wikipedia pages are good for this demonstration as their titles and urls are concise and similar.)

  1. Click on the first tab (the non-Wikipedia tab) to make it the active one. (The active tab won't get suspended)

  2. Click on the demo addon toolbar button (Green square with "test" in it.)

  3. In browserAction popup click on the "suspend tabs" button

  4. After a few seconds, in browserAction popup click on the "run script" button

  5. Observe the tab throbbers indicating the suspended tabs are reloading in sequence one by one

  6. After tabs finish reloading, observe the printout of results in the browserAction popup textarea. Several entries will appear for each tab showing the title at a given phase in the process.

Entries preceded by "get" contain titles retrieved from tabs.get(), each time the "complete" notification is sent.

(NOTE: Entries preceded by "update" can be ignored for this demo.)

One can see that "complete" gets sent 3 times for each tab. The fact that the retrieved title is:

tab url on the 1st "complete" occurrence
"New Tab" on the 2nd "complete" occurrence
back to tab url on the 3rd "complete" occurrence

seems to indicate that the full process of un-discarding the tab, then loading it, is not complete until the 3rd "complete" gets fired.

This leaves listeners a bit in the dark regarding whether when calling reload on a suspended tab, if the tab has completely finished reloading. It seems that for a listener to assume "complete" will get fired 3 times in order to determine the completion of loading is relying on an implementation detail that could change in the future.

It seems that when reloading suspended tabs, either

  1. only a single "complete" notification should get sent after the tab is completely done with its process, or

  2. if the intermediate "complete" notifications are needed somewhere for tracking the phases of the process, some other notification should be sent guaranteeing the finality of the process.

Hello,

I’ve managed to reproduce the issue based on the provided STR on the latest Nightly (83.0a1/20201006161706), Beta (82.0b8/20201006142214) and Release (81.0.1/20200930150533) under Windows 10 Pro 64-bit and Ubuntu 16.04 LTS.

The results output in the browserAction popup after running the script are the ones described in the report i.e. 3 occurrences of “complete” per tab.

Status: UNCONFIRMED → NEW
Ever confirmed: true
Attached file demo_reload_suspended.xpi (obsolete) —
Attachment #9179722 - Attachment is obsolete: true

It appears that the behavior for notifying that a discarded tab has finished loading is quite ambiguous. Behavior is different for:

Tab that has been opened in foreground with a url, then discarded using tabs.discard().
Tab that was opened in discarded state using tabs.create({ url, windowId, discarded: true }).
Tab that was opened in discarded state using session restore.

The difference in behavior includes the number of "complete" updates which get sent.

Another demo addon has been uploaded which better demonstrates the various behavior:

  1. Create new profile
  2. In Preferences ensure "Startup" > "Restore previous session" is checked
  3. Install the demo addon https://bugzilla.mozilla.org/attachment.cgi?id=9180588
  4. Remove all but one tab
  5. Open new tab and go to https://en.wikipedia.org/wiki/Car
  6. Make the first tab active (non-Wikipedia one)
  7. Open demo addon browserAction popup by clicking on green "Test" toolbar button. Be sure popup doesn't close during test
  8. Ensure the first tab in each window is the active one
  9. Click "discard tabs" (This calls tabs.discard() on every tab except active ones.)
  10. After a few seconds, click "reload tabs"
  11. After a few seconds, results will be printed in the textarea
  12. Copy text before popup closes and record in a safe place
  13. Observe in results "complete" was sent 3 times on the (discarded) en.wikipedia.org/wiki/Car tab
  14. Observe evolution of title
  15. Observe title in the Wikipedia tabs is now the url
start reload:    tabId: 8    ts: 1602195077474    discarded: true
       title:    tabId: 8    ts: 1602195077573    title: en.wikipedia.org/wiki/Car
    complete:    tabId: 8    ts: 1602195077574    times: 1
       title:    tabId: 8    ts: 1602195077576    title: Car - Wikipedia
       title:    tabId: 8    ts: 1602195077579    title: New Tab
    complete:    tabId: 8    ts: 1602195077580    times: 2
       title:    tabId: 8    ts: 1602195077804    title: en.wikipedia.org/wiki/Car
    complete:    tabId: 8    ts: 1602195078824    times: 3
    executed on 3th "complete"
=======================================
  1. If browserAction popup is closed, reopen
  2. Click "reload tabs" so correct titles are again showing
  3. Ensure the first tab in each window is the active one
  4. Click "discard tabs"
  5. Click "open window"
  6. browserAction popup will close and a new window will open with 2 tabs. The first tab is active, the second tab was opened in a discarded state using tabs.create({ url, windowId, discarded: true }). Its title will be the url.
  7. Open browserAction popup, keep open
  8. Click "reload tabs"
  9. Copy text before popup closes and record in a safe place
  10. Observe (discarded) en.wikipedia.org/wiki/Car tab again sent 3 "complete" updates
  11. Observe (discarded) en.wikipedia.org/wiki/Cattle tab sent 4 "complete" updates
  12. Observe evolution of title for each
  13. Observe title in the Wikipedia tabs is now the url
start reload:    tabId: 8    ts: 1602195781187    discarded: true
       title:    tabId: 8    ts: 1602195781240    title: en.wikipedia.org/wiki/Car
    complete:    tabId: 8    ts: 1602195781242    times: 1
       title:    tabId: 8    ts: 1602195781296    title: Car - Wikipedia
       title:    tabId: 8    ts: 1602195781300    title: New Tab
    complete:    tabId: 8    ts: 1602195781301    times: 2
       title:    tabId: 8    ts: 1602195781549    title: en.wikipedia.org/wiki/Car
    complete:    tabId: 8    ts: 1602195782399    times: 3
    executed on 3th "complete"
=======================================

start reload:    tabId: 10    ts: 1602195782569    discarded: true
    complete:    tabId: 10    ts: 1602195782615    times: 1
    complete:    tabId: 10    ts: 1602195782620    times: 2
       title:    tabId: 10    ts: 1602195782641    title: New Tab
    complete:    tabId: 10    ts: 1602195782644    times: 3
       title:    tabId: 10    ts: 1602195783064    title: en.wikipedia.org/wiki/Cattle
    complete:    tabId: 10    ts: 1602195785372    times: 4
    executed on 4th "complete"
=======================================
  1. If browserAction popup is closed, reopen
  2. Click "reload tabs" so correct titles are showing in the discarded tabs
  3. Ensure the first tab in each window is the active one
  4. Click "discard tabs"
  5. After a few seconds, click "reload tabs"
  6. Copy text before popup closes and record in a safe place
  7. Observe, like before (discarded) en.wikipedia.org/wiki/Car tab again sent 3 "complete" updates
  8. Observe, like before (discarded) en.wikipedia.org/wiki/Cattle tab sent 4 "complete" updates
  9. Observe evolution of title for each is like before
  10. Observe that although we discarded tabs using tabs.discard(), the tabs still retained the characteristics which caused them to send either 3 or 4 "complete" updates previously.
  11. Observe title in the Wikipedia tabs is now the url
start reload:    tabId: 5    ts: 1602196929738    discarded: true
       title:    tabId: 5    ts: 1602196929826    title: en.wikipedia.org/wiki/Car
    complete:    tabId: 5    ts: 1602196929828    times: 1
       title:    tabId: 5    ts: 1602196929835    title: Car - Wikipedia
       title:    tabId: 5    ts: 1602196929844    title: New Tab
    complete:    tabId: 5    ts: 1602196929844    times: 2
       title:    tabId: 5    ts: 1602196929914    title: en.wikipedia.org/wiki/Car
    complete:    tabId: 5    ts: 1602196930938    times: 3
    executed on 3th "complete"
=======================================

start reload:    tabId: 7    ts: 1602196931103    discarded: true
    complete:    tabId: 7    ts: 1602196931149    times: 1
       title:    tabId: 7    ts: 1602196931151    title: en.wikipedia.org/wiki/Cattle
    complete:    tabId: 7    ts: 1602196931154    times: 2
       title:    tabId: 7    ts: 1602196931166    title: Cattle - Wikipedia
       title:    tabId: 7    ts: 1602196931167    title: New Tab
    complete:    tabId: 7    ts: 1602196931169    times: 3
       title:    tabId: 7    ts: 1602196931198    title: en.wikipedia.org/wiki/Cattle
    complete:    tabId: 7    ts: 1602196932331    times: 4
    executed on 4th "complete"
=======================================
  1. If browserAction popup is closed, reopen
  2. Click "reload tabs" so correct titles are showing in the discarded tabs
  3. Ensure the first tab in each window is the active one
  4. Restart Firefox (having ensured that tabs will be restored)
  5. Open browserAction popup, keep open
  6. Click "reload tabs"
  7. Copy text before popup closes and record in a safe place
  8. Observe that now all suspended tabs send 4 "complete" updates
  9. Observe that now with all suspended tabs, there are no "title" updates
  10. Observe that now that none of the titles were corrupted in the tabs
start reload:    tabId: 3    ts: 1602197275721    discarded: true
    complete:    tabId: 3    ts: 1602197275813    times: 1
    complete:    tabId: 3    ts: 1602197275816    times: 2
    complete:    tabId: 3    ts: 1602197275823    times: 3
    complete:    tabId: 3    ts: 1602197277170    times: 4
    executed on 4th "complete"
=======================================

start reload:    tabId: 4    ts: 1602197277354    discarded: true
    complete:    tabId: 4    ts: 1602197277388    times: 1
    complete:    tabId: 4    ts: 1602197277391    times: 2
    complete:    tabId: 4    ts: 1602197277396    times: 3
    complete:    tabId: 4    ts: 1602197278369    times: 4
    executed on 4th "complete"
=======================================
  1. Ensure the first tab in each window is the active one
  2. If browserAction popup is closed, reopen
  3. Click "discard tabs"
  4. After a few seconds, click "reload tabs"
  5. Copy text before popup closes and record in a safe place
  6. Observe again that all suspended tabs send 4 "complete" updates
  7. Observe again that with all suspended tabs, there are no "title" updates
  8. Observe again that that none of the titles were corrupted in the tabs
start reload:    tabId: 3    ts: 1602198152737    discarded: true
    complete:    tabId: 3    ts: 1602198152873    times: 1
    complete:    tabId: 3    ts: 1602198152875    times: 2
    complete:    tabId: 3    ts: 1602198152894    times: 3
    complete:    tabId: 3    ts: 1602198154383    times: 4
    executed on 4th "complete"
=======================================

start reload:    tabId: 4    ts: 1602198154743    discarded: true
    complete:    tabId: 4    ts: 1602198154782    times: 1
    complete:    tabId: 4    ts: 1602198154782    times: 2
    complete:    tabId: 4    ts: 1602198154789    times: 3
    complete:    tabId: 4    ts: 1602198156051    times: 4
    executed on 4th "complete"
=======================================
Summary: tabs.onUpdated: status == "complete" update is sent 3 times when reloading a suspended tab → tabs.onUpdated: Update notification for tab load completion is ambiguous for discarded tabs
Attachment #9180588 - Attachment is obsolete: true

So sorry, I uploaded the wrong file for comment 2 and comment 3.

This is the correct one: https://bugzilla.mozilla.org/attachment.cgi?id=9180594

Is this a recent regression, or has it always worked like this?

Hello,

I’ve attempted a bisection, running a check from 2018-01-01 up until the present day.

Builds up to and including April 2018 behave as described in the report, however, from March 2018 and earlier, the provided extension does not return any results (it gets stuck at “Reloading...” in the pop-up).

Based on the current results, the issue might not be a recent regression since this behavior was exhibited since early 2018.

(In reply to Alex Cornestean from comment #7)

Hello,

I’ve attempted a bisection, running a check from 2018-01-01 up until the present day.

Builds up to and including April 2018 behave as described in the report, however, from March 2018 and earlier, the provided extension does not return any results (it gets stuck at “Reloading...” in the pop-up).

Based on the current results, the issue might not be a recent regression since this behavior was exhibited since early 2018.

On 59.0 (March 2018) I get the following errors:

JavaScript error: moz-extension://802dc965-d3f3-5e4e-9635-49dfe73883d9/background/background.js, line 19: Error: Type error for parameter createProperties (Unexpected property "discarded") for tabs.create.
JavaScript error: moz-extension://802dc965-d3f3-5e4e-9635-49dfe73883d9/browserAction/browserAction.js, line 30: Error: Incorrect argument types for tabs.onUpdated.

Some of the options were not implemented yet, so the demo addon won't work for those earlier versions. (Maybe tab discarding wasn't implemented yet?)

Hi Julian,
What is the url property in the tab events received while reproducing this issue? would you mind to double-check that and let us know?

Flags: needinfo?(julianhofstadter)

This is not the only case where multiple status change notifications are being sent, bug 1635328 is another one.
This issue, of knowing whether the tab is in some "ready" / "final" state, has come up multiple times in the past. The tabs API tries to account for several of them when the tab is created by the tabs.create and tabs.duplicate API, but doesn't account for (un)discarding tabs. I am hesitant to increasing the complexity of the implementation, especially because the behavior is subtle and prone to bugs.

only a single "complete" notification should get sent after the tab is completely done with its process, or

This is probably not feasible. It means that we have to somehow suppress notifications from content. But at the same time, extensions are already able to observe the presence of the page (e.g. through content scripts), which may result in a mismatch in actual state and reported/known state.

if the intermediate "complete" notifications are needed somewhere for tracking the phases of the process, some other notification should be sent guaranteeing the finality of the process.

That desire looks reasonable from the point of view of an extension that needs the information, but it does make the API surface more complicated for extensions that observe onUpdated events without filter.

See Also: → 1635328

To check if only the last event contains the url on restoring discarded tabs.

Flags: needinfo?(julianhofstadter) → needinfo?(lgreco)

Bugbug thinks this bug should belong to this component, but please revert this change in case of error.

Component: Untriaged → Tabbed Browser
Product: WebExtensions → Firefox
Component: Tabbed Browser → General
Product: Firefox → WebExtensions

(In reply to Luca Greco [:rpl] [:luca] [:lgreco] from comment #9)

Hi Julian,
What is the url property in the tab events received while reproducing this issue? would you mind to double-check that and let us know?

Here is the output showing URLs.

Output calling reload() on tabs which were loaded then discarded by calling tabs.discard():

=======================================

start reload:    tabId: 7    ts: 1606393455658    discarded: true
       title:    tabId: 7    ts: 1606393455676    title: Car - Wikipedia
    complete:    tabId: 7    ts: 1606393455688    count: 1
       title:    tabId: 7    ts: 1606393455689    title: en.wikipedia.org/wiki/Car
    complete:    tabId: 7    ts: 1606393455694    count: 2
       url:      tabId: 7    ts: 1606393455694      url: https://en.wikipedia.org/wiki/Car
       title:    tabId: 7    ts: 1606393455707    title: Car - Wikipedia
       title:    tabId: 7    ts: 1606393455715    title: New Tab
    complete:    tabId: 7    ts: 1606393455718    count: 3
       url:      tabId: 7    ts: 1606393455718      url: about:blank
       title:    tabId: 7    ts: 1606393455787    title: en.wikipedia.org/wiki/Car
       url:      tabId: 7    ts: 1606393455795      url: https://en.wikipedia.org/wiki/Car
    complete:    tabId: 7    ts: 1606393456461    count: 4
    executed on 4th "complete"
=======================================

start reload:    tabId: 8    ts: 1606393456461    discarded: true
       title:    tabId: 8    ts: 1606393456480    title: Transport - Wikipedia
    complete:    tabId: 8    ts: 1606393456516    count: 1
       title:    tabId: 8    ts: 1606393456518    title: en.wikipedia.org/wiki/Transport
    complete:    tabId: 8    ts: 1606393456519    count: 2
       url:      tabId: 8    ts: 1606393456519      url: https://en.wikipedia.org/wiki/Transport
       title:    tabId: 8    ts: 1606393456525    title: Transport - Wikipedia
       title:    tabId: 8    ts: 1606393456529    title: New Tab
    complete:    tabId: 8    ts: 1606393456534    count: 3
       url:      tabId: 8    ts: 1606393456534      url: about:blank
       title:    tabId: 8    ts: 1606393456595    title: en.wikipedia.org/wiki/Transport
       url:      tabId: 8    ts: 1606393456598      url: https://en.wikipedia.org/wiki/Transport
    complete:    tabId: 8    ts: 1606393457142    count: 4
    executed on 4th "complete"
=======================================

start reload:    tabId: 9    ts: 1606393457142    discarded: true
       title:    tabId: 9    ts: 1606393457165    title: Developed country - Wikipedia
    complete:    tabId: 9    ts: 1606393457188    count: 1
       title:    tabId: 9    ts: 1606393457190    title: en.wikipedia.org/wiki/Developed_country
    complete:    tabId: 9    ts: 1606393457192    count: 2
       url:      tabId: 9    ts: 1606393457192      url: https://en.wikipedia.org/wiki/Developed_country
       title:    tabId: 9    ts: 1606393457199    title: Developed country - Wikipedia
       title:    tabId: 9    ts: 1606393457210    title: New Tab
    complete:    tabId: 9    ts: 1606393457216    count: 3
       url:      tabId: 9    ts: 1606393457216      url: about:blank
       title:    tabId: 9    ts: 1606393457280    title: en.wikipedia.org/wiki/Developed_country
       url:      tabId: 9    ts: 1606393457289      url: https://en.wikipedia.org/wiki/Developed_country
    complete:    tabId: 9    ts: 1606393457986    count: 4
    executed on 4th "complete"
=======================================

Output calling reload on discarded tabs after fresh restart:

=======================================

start reload:    tabId: 3    ts: 1606393689871    discarded: true
    complete:    tabId: 3    ts: 1606393689908    count: 1
    complete:    tabId: 3    ts: 1606393689911    count: 2
       url:      tabId: 3    ts: 1606393689911      url: https://en.wikipedia.org/wiki/Car
    complete:    tabId: 3    ts: 1606393689919    count: 3
       url:      tabId: 3    ts: 1606393689919      url: about:blank
       url:      tabId: 3    ts: 1606393690238      url: https://en.wikipedia.org/wiki/Car
    complete:    tabId: 3    ts: 1606393690818    count: 4
    executed on 4th "complete"
=======================================

start reload:    tabId: 4    ts: 1606393690818    discarded: true
    complete:    tabId: 4    ts: 1606393690846    count: 1
    complete:    tabId: 4    ts: 1606393690847    count: 2
       url:      tabId: 4    ts: 1606393690847      url: https://en.wikipedia.org/wiki/Transport
    complete:    tabId: 4    ts: 1606393690859    count: 3
       url:      tabId: 4    ts: 1606393690859      url: about:blank
       url:      tabId: 4    ts: 1606393690891      url: https://en.wikipedia.org/wiki/Transport
    complete:    tabId: 4    ts: 1606393691386    count: 4
    executed on 4th "complete"
=======================================

start reload:    tabId: 5    ts: 1606393691386    discarded: true
    complete:    tabId: 5    ts: 1606393691414    count: 1
    complete:    tabId: 5    ts: 1606393691415    count: 2
       url:      tabId: 5    ts: 1606393691415      url: https://en.wikipedia.org/wiki/Developed_country
    complete:    tabId: 5    ts: 1606393691419    count: 3
       url:      tabId: 5    ts: 1606393691419      url: about:blank
       url:      tabId: 5    ts: 1606393691450      url: https://en.wikipedia.org/wiki/Developed_country
    complete:    tabId: 5    ts: 1606393692174    count: 4
    executed on 4th "complete"
=======================================

Demo addon version 0.0.3 also displays url updates.

I did spent some time looking if any of the details we currently send as part of the tabs.onUpdated event could already be used by the extensions to identify which of the tab.onUpdated events represent the actual final loading related to a tab being undiscarded,
but I think that I can confirm that at the moment none of them is enough to let the extension determine which will be the final load, as the reported was also stating.

By taking a more deeper look into the properties and DOM attributes on the native tab in Firefox Desktop builds, I did notice that
the native tab does have the pending attribute set until the tab is completely restored, and at that point the pending attribute is being removed from the restored tab.

At the moment the our discarded attribute getter is only checking if the nativeTab does have a linked panel:

 get discarded() {
    return !this.nativeTab.linkedPanel;
  }

And so, while filtering out all the tabs.onUpdated events emitted between starting to restore a tab and when the tab is completely restored may not be really that practical, one reasonable way to let the extension to better assess on its own which is the final onUpdate "complete" event may be to make the discarded getter to also check if the pending attribute it still set, e.g. something like:

  get discarded() {
    // return discarded true if the nativeTab doesn't have a linked panel (is still fully discarded) or if it does still have the pending attribute
    // (is fully discarded or in the process of being restored).
    return !this.nativeTab.linkedPanel || this.nativeTab.hasAttribute("pending");
  }
Flags: needinfo?(lgreco)

We should make sure that the onUpdated event for the "discarded" filter is correct. From what I understand in comment 15, listening for the discarded event will result in tab.discared == false during the TabBrowserInserted event. If that is indeed the case, we should instead listen for the "pending" attribute using "TabAttrModified".

onUpdated with a discarded filter should fire when a tab is fully discarded or fully restored.

It seems we only have tests that watch for a tab being discarded, but not a test for when a tab is restored. I don't see any test that uses and tests the discarded filter.

[1] https://searchfox.org/mozilla-central/rev/23c25cd32a1e87095301273937b4ee162f41e860/browser/components/extensions/test/browser/browser_ext_tabs_discard.js#55
[2] https://searchfox.org/mozilla-central/rev/23c25cd32a1e87095301273937b4ee162f41e860/browser/components/extensions/test/browser/browser_ext_tabs_discarded.js#79
[3] https://searchfox.org/mozilla-central/rev/23c25cd32a1e87095301273937b4ee162f41e860/browser/components/extensions/test/browser/browser_ext_tabs_onUpdated_filter.js#295

Severity: -- → S3
Priority: -- → P3
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: