bookmarks.onCreated should not be fired for bookmarks automatically created for the Library window

VERIFIED FIXED in Firefox 61

Status

()

Toolkit
WebExtensions: General
P3
normal
VERIFIED FIXED
a year ago
2 months ago

People

(Reporter: Sören Hentzschel, Assigned: bsilverberg, Mentored)

Tracking

({good-first-bug})

Trunk
mozilla61
good-first-bug
Points:
---
Dependency tree / graph

Firefox Tracking Flags

(firefox60 fix-optional, firefox61 verified)

Details

(Whiteboard: [bookmarks][good first bug] triaged investigate)

MozReview Requests

()

Submitter Diff Changes Open Issues Last Updated
Loading...
Error loading review requests:

Attachments

(2 attachments)

(Reporter)

Description

a year ago
Install a WebExtension with browser.bookmarks.onCreated.addListener. After opening the bookmarks library the onCreated event is fired 8x! It's reproducible in a new Firefox profile with Firefox Stable 52 and with Firefox Nightly 55.

STR:

1. You can use my add-on https://addons.mozilla.org/en-US/firefox/addon/bookmarks-organizer/ to test (it's not yet reviewed, so it's not yet signed; use version 1.0.3 because I will disable the code in the upcoming version 1.0.4 until this bug is fixed)
2. Start Firefox
3. click the browserAction button and have a look at the number of total bookmarks.
4. open the bookmarks library
5. repeat step 3

Actual result:

In Firefox Stable you can see a number of 7 bookmarks after step 3 and 15 bookmarks after step 5. In Firefox Nightly 55 there are 10 bookmarks after step 3 and 18 bookmarks after step 5.

Expected result:

No change of the total number of bookmarks.

In my add-on I use browser.bookmarks.onCreated.addListener and browser.bookmarks.onRemoved.addListener. I added a debug output in my local development version. Only the onCreated event is fired 8 times, the onRemoved event is not fired.

cc @bsilverberg who added these events.
(Reporter)

Comment 1

a year ago
Oh, after uploading 1.0.4 I will delete 1.0.3 from AMO because it's not yet reviewed. Here youou can find all old versions:
https://github.com/cadeyrn/bookmarks-organizer/tree/master/dist
(Assignee)

Updated

a year ago
Assignee: nobody → bob.silverberg
Whiteboard: investigate
(Assignee)

Comment 2

a year ago
Thanks for reporting the bug, Sören. The extra onCreated events are being fired for all of the bookmarks that are created automatically by Firefox for the left pane of the Library window when it is first opened. We should not be firing events for those bookmarks, but we do not currently have a way of knowing that those bookmarks should not be tracked.

Bug 1310295 has been created which should either fix the issue, or allow us to fix the issue, so I am going to update the title of this bug and set it up as blocked by bug 1310295.

Marco, do you agree with my assessment of this, or is there something we can currently do to exclude those events in our API code?
Assignee: bob.silverberg → nobody
Depends on: 1310295
Flags: needinfo?(mak77)
Priority: -- → P3
Summary: Opening the bookmarks library triggers 8x the onCreated event → bookmarks.onCreated should not be fired for bookmarks automatically created for the Library window
Whiteboard: investigate → [bookmarks]triaged
(In reply to Bob Silverberg [:bsilverberg] from comment #2)
> Bug 1310295 has been created which should either fix the issue, or allow us
> to fix the issue, so I am going to update the title of this bug and set it
> up as blocked by bug 1310295.
> 
> Marco, do you agree with my assessment of this, or is there something we can
> currently do to exclude those events in our API code?

As a workaround for now you could exclude these notifications by checking parentId in onItemAdded, if it's PlacesUIUtils.leftPaneFolderId or PlacesUIUtils.allBookmarksFolderId, then you can exclude them.

Obviously bug 1310295 is a better long term fix.
Flags: needinfo?(mak77)
(Assignee)

Comment 4

a year ago
Thanks Marco. That sounds pretty reasonable for now. I'm not sure how urgent this is, and it's going to be pretty simple to fix, so I'm going to mark it as a good first bug for now.
Mentor: bob.silverberg
Whiteboard: [bookmarks]triaged → [bookmarks][good first bug]triaged
(Assignee)

Comment 5

a year ago
Removing the priority and triaged tag for now so that an appropriate priority can be assigned during triage. It seems like a P3 to me, but others may disagree.
Priority: P3 → --
Whiteboard: [bookmarks][good first bug]triaged → [bookmarks][good first bug]

Updated

a year ago
Keywords: good-first-bug
(Reporter)

Comment 6

a year ago
(In reply to Bob Silverberg [:bsilverberg] from comment #5)
> Removing the priority and triaged tag for now so that an appropriate
> priority can be assigned during triage. It seems like a P3 to me, but others
> may disagree.

I would say a broken API or part of a API should have a bit more priority because shipping nothing is almost always better than shipping something broken and this event is already part of Firefox 52. And if it's really pretty simple to fix then that's a reason more to do this as soon as possible. ;)

This API cannot really be used until this bug is fixed because it can give wrong results. And the bug is not mentioned in the documention, so other add-on developers don't know that this event is broken. They could use this event and release broken add-ons. Maybe there should be a warning in the documentation in the meantime. ;)

Updated

11 months ago
Priority: -- → P3
Whiteboard: [bookmarks][good first bug] → [bookmarks][good first bug] triaged

Comment 7

11 months ago
I just tried the obvious fix, but it doesn't work. When I first open the bookmark panel (say with ctrl-b), PlacesUIUtils.(leftPaneFolderId|allBookmarksFolderId) are both undefined for the first 7 bookmarks sent to onItemAdded, and the eighth only has one of them defined. It looks like they're lazy getters, and I'm not sure how easy it would be to make a blocking getter for this purpose (or if we'd even want to do so).
(Reporter)

Comment 8

10 months ago
Since the bug is still not fixed - is there a way for me as WebExtension developer to work around the issue?
Flags: needinfo?(bob.silverberg)
(Assignee)

Comment 9

10 months ago
It sounds like Thomas tried to fix this using the approach suggested by Marco, but was unsuccessful. I will take a look to see if I can figure out what needs to be done. As a stop-gap you could see if there's anything in the data returned for these bookmarks that would allow you to exclude them yourself. This is obviously not an ideal approach, but might allow you to proceed for now.
Assignee: nobody → bob.silverberg
Flags: needinfo?(bob.silverberg)
Whiteboard: [bookmarks][good first bug] triaged → [bookmarks][good first bug] triaged investigate
(Assignee)

Comment 10

9 months ago
I see what Thomas means about PlacesUIUtils.leftPaneFolderId being lazy. It seems that it is created asynchronously the first time it is referenced, so just referencing it directly in onItemAdded doesn't work. If I create a const in ext-bookmarks.js that points to PlacesUIUtils.leftPaneFolderId, as well as one for PlacesUIUtils.allBookmarksFolderId, it seems to work, in that they are not undefined during onItemAdded, but I think that is also causing all of the virtual bookmarks to be created when I first call PlacesUIUtils.leftPaneFolderId, so that in itself seems to make the problem go away.

Marco, do you think defining consts for PlacesUIUtils.leftPaneFolderId and PlacesUIUtils.allBookmarksFolderId in ext-bookmarks.js is a valid thing to do, or is it bad that we're forcing the creation of the queries when they might not be needed? Can you suggest a different approach to the issue?

Oops, Marco isn't accepting needinfo requests as he's on PTO, so I'll flag him once he gets back from PTO.
(In reply to Bob Silverberg [:bsilverberg] from comment #10)
> I see what Thomas means about PlacesUIUtils.leftPaneFolderId being lazy. It
> seems that it is created asynchronously the first time it is referenced

Those are lazy getters, but they are completely synchronous, when you access them, the folders are created.
The problem probably relies in the fact creating them may fire a further onItemAdded. So basically you enter a notifications loop, because to handle a notification you cause another one that you try to handle and so on... It's also likely to break Places.

You may have to do something like (pseudo-code):

if (this.ignoreNotification)
  return;
this.ignoreNotification = true;
try {
  // Check parentId against the left pane ids...
} finally {
  this.ignoreNotification = false;
}

> If I create a
> const in ext-bookmarks.js that points to PlacesUIUtils.leftPaneFolderId, as
> well as one for PlacesUIUtils.allBookmarksFolderId, it seems to work, in
> that they are not undefined during onItemAdded, but I think that is also
> causing all of the virtual bookmarks to be created when I first call
> PlacesUIUtils.leftPaneFolderId, so that in itself seems to make the problem
> go away.

This just seems to initialize all the left pane folder sooner, it may be fine provided it doesn't happen in the browser critical startup time (around the first paint), or it may cause unnecessary startup regressions.
Invoking even just once PlacesUIUtils.leftPaneFolderId should create all the bookmarks, but that also fires notifications, how do you plan to filter those? Is this supposed to happen before the first add-on is registered?
(Assignee)

Comment 12

8 months ago
(In reply to Marco Bonardo [::mak] from comment #11)
> (In reply to Bob Silverberg [:bsilverberg] from comment #10)
> > I see what Thomas means about PlacesUIUtils.leftPaneFolderId being lazy. It
> > seems that it is created asynchronously the first time it is referenced
> 
> Those are lazy getters, but they are completely synchronous, when you access
> them, the folders are created.
> The problem probably relies in the fact creating them may fire a further
> onItemAdded. So basically you enter a notifications loop, because to handle
> a notification you cause another one that you try to handle and so on...
> It's also likely to break Places.
> 
> You may have to do something like (pseudo-code):
> 
> if (this.ignoreNotification)
>   return;
> this.ignoreNotification = true;
> try {
>   // Check parentId against the left pane ids...
> } finally {
>   this.ignoreNotification = false;
> }
> 

But even in this case, won't the value for PlacesUIUtils.leftPaneFolderId be undefined the first time I try to check against it? That would mean that I cannot accurately check against it the first time onItemAdded is fired for a bookmark.

> > If I create a
> > const in ext-bookmarks.js that points to PlacesUIUtils.leftPaneFolderId, as
> > well as one for PlacesUIUtils.allBookmarksFolderId, it seems to work, in
> > that they are not undefined during onItemAdded, but I think that is also
> > causing all of the virtual bookmarks to be created when I first call
> > PlacesUIUtils.leftPaneFolderId, so that in itself seems to make the problem
> > go away.
> 
> This just seems to initialize all the left pane folder sooner, it may be
> fine provided it doesn't happen in the browser critical startup time (around
> the first paint), or it may cause unnecessary startup regressions.
> Invoking even just once PlacesUIUtils.leftPaneFolderId should create all the
> bookmarks, but that also fires notifications, how do you plan to filter
> those? Is this supposed to happen before the first add-on is registered?

Perhaps those constants could be initialized inside the onItemAdded function, so they won't add to startup cost, and the cost will only be incurred the first time an item is actually added. I could then check each item added to make sure that neither its parent is one of the folders, and also make sure that *it* is not one of the folders. 

Does that sound like a reasonable solution?
Flags: needinfo?(mak77)
(In reply to Bob Silverberg [:bsilverberg] from comment #12)
> But even in this case, won't the value for PlacesUIUtils.leftPaneFolderId be
> undefined the first time I try to check against it? That would mean that I
> cannot accurately check against it the first time onItemAdded is fired for a
> bookmark.

That's possible yes. If you get onItemAdded exactly for leftPaneFolderId, trying to get leftPaneFolderId would basically re-enter the getter. So you should at least executeSoon your notification handling... But then this would require delaying all of the notifications, since otherwise you could handle them in the wrong order.

> Perhaps those constants could be initialized inside the onItemAdded
> function, so they won't add to startup cost, and the cost will only be
> incurred the first time an item is actually added. I could then check each
> item added to make sure that neither its parent is one of the folders, and
> also make sure that *it* is not one of the folders.

As I said above, looks like there's potential for re-entering the creation code. You get a notification when leftPaneFolderId is added, you query leftPaneFolderId, but it's not set yet, so the code tries to set it again.

the only solutions I can think of so far are:
1. delay all the notifications handling, so you can use the leftPaneFolderId (maybe even check if it's still a getter so to not initialize it if unneeded). The downside is adding complication to your code.
2. Wait for bug 1310295 to make the Library left pane "virtual", so it won't create real bookmarks
3. Pay the library left pane init cost on Firefox startup. Likely a no-go for Quantum Flow.
Flags: needinfo?(mak77)
(Assignee)

Comment 14

8 months ago
What if I disable notifications, then initialize the values, then turn them back on, in the constructor of the observer, like so:

let observer = new class extends EventEmitter {
  constructor() {
    super();

    this.ignoreOnItemAdded = true;
    this.leftPaneRootId = PlacesUIUtils.leftPaneFolderId;
    this.allBookmarksRootId = PlacesUIUtils.allBookmarksFolderId;
    this.ignoreOnItemAdded = false;
  }

  onItemAdded(id, parentId, index, itemType, uri, title, dateAdded, guid, parentGuid, source) {
    if (this.ignoreOnItemAdded) {
      return;
    }

    do other stuff
  }
}

That will still incur the cost of left pane init, but it won't happen until ext-bookmarks.js is loaded, which I believe happens later in the cycle.

How does that sound?
Flags: needinfo?(mak77)
Comment hidden (mozreview-request)
(Assignee)

Comment 16

8 months ago
Rather than keep asking questions, I figured I'd just produce a patch and submit it for review. Please let me know where I've gone wrong.
Flags: needinfo?(mak77)

Comment 17

8 months ago
mozreview-review
Comment on attachment 8914452 [details]
Bug 1362863 - Do not fire bookmarks.onCreated for bookmarks automatically created for the Library window

https://reviewboard.mozilla.org/r/185784/#review190774

I would much rather see the core of this added to PlacesUIUtils to protect us (any consumer of the api) from any future changes, such as making these async or adding/removing any folders managed this way in PlacesUIUtils.  In onItemAdded we could just do something like

if PUIU.getVirtualFolderIDList().intersects([id, parentid]) return;
Attachment #8914452 - Flags: review?(mixedpuppy) → review-
(In reply to Shane Caraveo (:mixedpuppy) from comment #17)
> if PUIU.getVirtualFolderIDList().intersects([id, parentid]) return;

The problem is that PUIU knows about the new bookmark id only after the notification has fired, because the API returns AFTER notifying.
What we could do, crossing your ideas, is something like PUIU.isAddingLeftPaneItem() and ignore notifications if that returns true. Currently the PUIU creations are synchronous so there should be no big risk, and the only way to make those async would be to fix Bug 1310295, that would also remove this problem completely.
Would that work for you?
Anything that gets us away from knowing PUIU internals is great by me, but if Bug 1310295 will happen soonish (maybe by 60?) and the patch for that can return and clean this side up, then I'm fine with accepting the patch here.
yes, that patch would remove the PUIU tricks like isAddingLeftPaneItem and as such it would also cleanup its consumers.

Comment 21

8 months ago
mozreview-review
Comment on attachment 8914452 [details]
Bug 1362863 - Do not fire bookmarks.onCreated for bookmarks automatically created for the Library window

https://reviewboard.mozilla.org/r/185784/#review191972

I'd like to know if my last idea could work for you first.
Attachment #8914452 - Flags: review?(mak77) → review-
(Reporter)

Comment 22

3 months ago
Bob said in #comment 2 ten months ago:

> Bug 1310295 has been created which should either fix the issue, or allow us to fix the issue, so I am going to update the title of this bug and set it up as blocked by bug 1310295.

Bug 1310295 has a patch now. Does the patch from bug 1310295 fix this issue? And is a fix for this issue still realistic for Firefox 60 (it's already late in the cycle)? I ask because Firefox 60 will be the next ESR release and it would be great if I could use the bookmarks.onCreated event without doing any version detection in my add-on if I want to support Firefox Mainstream and Firefox ESR at the same time once I bump the minimum required Firefox version to 60. A version detection is not the biggest problem, so I can do that if the issue will not be fixed in Firefox 60, but if it can be avoided it's, of course, better for me. ;-)
This has been fixed by bug 1310295. If the add-ons team thinks we should have some sort of hack for Firefox 60, we're open to suggestions.
Status: NEW → RESOLVED
Last Resolved: 2 months ago
status-firefox60: --- → affected
status-firefox61: --- → fixed
Resolution: --- → FIXED
Target Milestone: --- → mozilla61
status-firefox60: affected → fix-optional

Comment 24

2 months ago
Created attachment 8965308 [details]
Bug1362863.gif

I can  reproduce the issue on Firefox 59.0.2 (20180323154952) under Win 7 64-bit and Mac OS X 10.13.2 with the extension v1.0.3 from the comment1.

The number of the bookmarks it is "8" and after I open the bookmarks library it is "16".

This issue is verified as fixed on Firefox 61.0a1 (20180405104009) under Win 7 64-bit and Mac OS X 10.13.2.

Please see the attached video.

Updated

2 months ago
Status: RESOLVED → VERIFIED
status-firefox61: fixed → verified
You need to log in before you can comment on or make changes to this bug.