Treestyletab: Sending multiple tabs via "Send tabs to device" results in strange relationships

Created on 12 Nov 2019  路  18Comments  路  Source: piroor/treestyletab

Environment

Windows 10 \ FF 70.0.1 \ TST 3.2.4

Situation

I normally start the day checking my phone for interesting news or articles I might want to read. Once you install Firefox on your phone, it installs a means to articles directly in Firefox or to send it to Firefox on another machine (Share -> Add to Firefox -> Send to other devices -> device name list) Some articles I don't want to read on the phone or want to read later and I will send it to my desktop.

If I send multiple tabs, when the synchronization starts, it adds all of the tabs currently queued up under the currently selected tab.

Problem

The behavior of how the tabs are created is not consistent. All tabs are properly created but the relationship (child vs. sibling), the sequencing (are all 5 next to each other) is not consistent, and the "depth" of each tab can potentially be different.

How to reproduce

  1. Send multiple items to be shared with Firefox using the "Send to other devices" method. (I also tested this just using Firefox on 2 different machines by selecting multiple tabs from one Firefox instance and using the "Send tabs to device" right-click option on the tabs.)
  2. On the "receiving" Firefox, just wait for the tabs to come across or manually trigger the synchronization by clicking your Firefox profile icon -> Sync now.

Results

Snag_628b3b

In this example, "Paid Services" is the currently selected tab and the 6 loaded tabs with the blue globes under the favicons were the tabs sent to my desktop. Notice that the first 2 tabs were loaded under the paid services tab but are not actually related to that tab ... if I collapse "Paid Services" the first 2 tabs remain outside. The third tab ("Exploring the ...") WAS created as a child of that tab. The fourth tab ("Handling synonyms...") wasn't created next to the third as the discarded tab "WIRED" was between them. The 5th and 6th tabs followed a similar pattern.

Snag_62aa0e

I wanted to try some other scenarios and in this one (different starting tab with different tabs being sent across) The pattern looks to be the same.

Snag_6ddd7d

In this example, I sent the same 5 tabs across but used a different active tab. Here it creates the first 3 as siblings, skips over one discarded tab before creating the 4th. The last is added as a child of an existing tab.

Expected Results

I would expect any number of tabs to be sent across and ALL to be placed consecutively either as siblings or children of the currently selected tab. This behavior has been around for quite some time, I just found some time to finally write it up. This should not be related to any recently FF or TST changes. I would also expect there is a good chance this might be a "bug of Firefox itself".

bug of Firefox itself partially fixed

All 18 comments

@piroor ... one other side affect of this is that in the first example with the tabs under "Paid Services", if I leave things just as they are and restart Firefox, all of the tabs lose the "Paid Services" tab as their parent and they all become siblings. I was able to reproduce this affect twice in a row. (Below is my 2nd attempt and after restarting Firefox)

Snag_e28c27

Received tabs are opened as tabs like opened from bookmarks or history entries. Thus "how opened tabs are treated" depends on options of Firefox, TST, and other addons. (For example, on my environment they are opened at the end of the tab bar as independent tabs, not children of the active tab.)

I've tried to determine a tab is sent from another device or not, but sadly there is no hint...

@piroor I spent some more time on this and have more information and it all seems related to browser.tabs.insertAfterCurrent = true. When this value is false, I see the same behavior as you where the tabs are created sequentially (at the same level) at the end of the tab list.

In a clean profile with only TST installed, browser.tabs.insertAfterCurrent = true, sending over 5 tabs, and the active tab is:

... the last tab - all 5 tabs are created in sequence and at the same level. (Good)
Snag_5f20f7

... next to last tab - tabs are created in sequence and at the same level. (Good)
Snag_622fcd

... tab in the middle of a tree - first 3 tabs are created in sequence, but last 2 have existing tabs in between. (Bad)
Snag_64d3c4

... root tab of a tree - I see a mix of indentation of the tabs. (Bad)
Snag_66be2f

... in addition, restarting Firefox at this point results in the tree losing its relationships.
Snag_680e00

... root tab of a tree that isn't group-tab.html - again tab sequencing and relationships are wrong. (bad)
Snag_6c1b89

... tab above a tree - again first 3 are created properly, but the next 2 created with tabs in between which are part of the tree below it.
Snag_744ab0

@piroor this is pretty easy for me to try different things if you want me to. I just launch Firefox, then launch another Firefox (different profile) using the -no-remote option and just try different scenarios. No phone\tablet are needed.

Thanks! I've successfully reproduced this problem on my desktop PC. I'm using both Firefox 70 and Nightly 72.0a1, and this happens when I send multiple tabs from one to another with the setting. (I've confirmed that Firefox Android is unnecessary for debugging.)

And after more trying I've realized that Sync is also unnecessary to reproduce the problem. I've successfully reproduced this problem just a script in the console:

for (let i = 0; i < 3; i++) {
  openUILinkIn(`about:blank#${i}`, 'tabshifted', {
    triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()
  });
}

On this case, only the first opened tab is attached and all rest tabs are not attached to the existing tree. This means that this problem may happen on any Firefox feature opening multiple tabs synchronously...

The commit 817bf64 partially fixes this issue: now tabs opened in the middle of an existing tree are correctly attached based on their position. However still there is another problem: received tabs are not opened successively. If you send 5 or more tabs they are received as gapped tabs.

Finally I've understood why tabs are opened with gap. I think this is an inconsistency problem of webExtensions API itself.

I tested a simple tabs.onCreated handler and multiple received tabs, without TST. This screenshot indicates what was happen:
image
Please look at their id and index. They are identified sequentially but index of last four tabs are reversed. This means that their index property doesn't mean the index when they are opened. So, for example, when the tab 29 is notified:

  • Originally there are existing tabs: [3, 2, 27, 5, 10, 11, 12, 13, 14, 15]

    • 5 is a parent and the active tab.

    • 10-14 are children of 5.

  • 28 is notified with an index 4, so it is inserted to the position: [3, 2, 27, 5, 28, 10, 11, 12, 13, 14, 15]

    • 28 is inserted between 5 (parent) and 10 (child).

    • Then TST attaches 28 to 5 as its new first child.

  • 29 is notified with an index 7, so it is inserted to the position: [3, 2, 27, 5, 28, 10, 11, 29, 12, 13, 14, 15]

    • Please note it should be inserted as [3, 2, 27, 5, 29, 28, 10, 11, 12, 13, 14, 15] because it is opened at the next to the active tab 5 - its expected index is 4 not 7 on this timing.

Currently I have no good idea to solve this problem on TST side. Buffering and re-indexing looks to be a solution, but I cannot determine which tabs are opened at same time.

Thus I think that Firefox should notify 5 as the index of the tab 29 on such cases. In other words this should be tracked as a bug of WebExtensions API and should be fixed on Firefox side...

@piroor thank you for the partial fix and investigating this situation. It definitely looks like an issue on the Firefox side. Did you plan on submitting a defect to them on this?

I'm planning to file a bug to bugzilla, and now researching a minimum steps to reproduce.

Finally I've understood that Sync opens received tabs like this:

(async () => {
  const uris = [];
  for (let i = 0; i < 5; i++) {
    uris.push(`about:blank#${i}`);
  }
  const openTab = async uri => {
    gBrowser.addWebTab(uri);
  };
  const firstTab = await openTab(uris[0]);
  uris.slice(1).map(openTab);
})()

More short version:

(async () => {
  await gBrowser.addWebTab(`about:blank#first`)
  for (let i = 0; i < 5; i++) {
    gBrowser.addWebTab(`about:blank#${i}`);
  }
})()

The most important point to reproduce is: we need to do await for the first tab.

Thank you sir. Your effort and knowledge is appreciated and amazing. (I've added my vote to the issue and will watch its progress)

@piroor I see you were marked the "assignee" for the Bugzilla defect 2 months ago. Are you continuing to work on this one on the Firefox side? (I don't think so, but thought I would ask)

Sadly my approach is stuck in mud on bugzilla. Currently I have no good idea to solve concerns presented by the reviewer and I need help from tab and WebExtensions expert...

@piroor Did you want to leave a similar comment on Bugzilla and unassign yourself from the bug? (That would at least indicate to any triage team that no one is progressing the issue) It is obviously still an issue, but affects very few people.

Because the bug https://bugzilla.mozilla.org/show_bug.cgi?id=1417183 (about genuine WebExtensions API proposal around Firefox Sync) became WONTFIX, now I'm trying to simulate "Send Tab to Device" features based on the sync storage. It allows us to send multiple tabs including their tree structure. I think the change will make this issue obsolete.

@piroor I saw your work on this based on the bug feedback. Keep in mind, this issue specifically is when tabs are sent to a machine with TST on it and how TST handles receiving them. (Although I love that TST will be able to emulate initiating sending tabs as well)

I have actually been meaning to update this issue with some additional details, but it hasn't been a big issue as I understand tabs I send from my mobile to my PC need to be handled differently. For example, I believe if multiple tabs are sent from my mobile while the PC has not yet started, then when the PC starts and Firefox loads that the behavior of the inserted tabs is different than if the PC and Firefox were already running. (If sent before Firefox is running, I believe they are all inserted at the root indentation level, but already running they are inserted at the proper indentation)

The 2 biggest issues are:

  • How the tabs are inserted into a tree. (Both indentation and possibly tab order)
  • How some inserted tabs can cause the tree into which it was inserted to become "flatten" after Firefox restarts. (I haven't seen this often, but I think it is possible when the tab is inserted at the root indentation and I don't close or move the tab [thus re-establishing its relationship in the tree] and restart Firefox as the tree from that tab down are all then at the same level)

I'll see if I can get more current examples written up to see if there is anything that can be done. It may not be worth the effort.

Was this page helpful?
0 / 5 - 0 ratings