Asynchronous extension API calls "abandoned" by an extension tab can keep the extension loaded indefinitely |
||
Issue descriptionChrome Version: 57.0.2970.0 (Official Build) dev (64-bit) OS: ChromeOS What steps will reproduce the problem? (1) Create a new Chrome profile. (2) Install Chrome Remote Desktop into it, from the Chrome Web Store. (3) Click to run Chrome Remote Desktop. (4) Open Task Manager and observe Chrome Remote Desktop process is listed. (5) Close the sign-in tab. (6) Close Chrome Remote Desktop. What is the expected result? Expect that shortly after closing both the sign-in tab and Chrome Remote Desktop, the CRD process is closed down. What happens instead? The CRD process never closes down. This happens because CRD uses the getAuthToken() API, which triggers the Chrome sign-in tab to load, if Chrome is not presently signed-in, and: 1. getAuthToken() assumes that the user will eventually sign-in, so only monitors for an OAuth2 token becoming available, but not for the sign-in tab closing. This problem doesn't appear to affect ChromeOS, which has a different sign-in model. 2. Even though the Chrome Remote Desktop tab/window which called the extension API is gone, the getAuthToken API retains its own self-reference, which in turn retains a keep-alive reference to the extension background page, preventing it from unloading correctly. It's not clear how widespread this problem is in the extension APIs, but I observed something similar with the asynchronous socket I/O APIs in CRD previously. We could remove instances of self-referencing and decouple async interactions in other ways (e.g. WeakPtrs), which would also allow async logic to be cancelled on function-call object teardown.
,
Jan 23 2017
A few thoughts here. First, it seems like this is definitely a bug in the identity API. Closing the window should terminate the function. That's pretty actionable. At a higher level, this is somewhat WAI, in that extension functions *should* keep an extension loaded while running. Some extension functions may take longer than 5 - 10s to complete (e.g. anything with user interaction), and our current model was never designed for being torn down during active execution. In some future model, it could make sense to take a different approach, where extensions can expect to be torn down and then woken up from an event (e.g., onAuthed, rather than waiting for getAuthToken to return), but that's a pretty massive breaking change. I've also wanted to clean up the extension function implementation to use less excessive ref-counting. Unfortunately, it's a bit of a rat's nest at the moment. One step is to reduce the number of different custom implementations we have of the function infrastructure - issue 648275 tracks that. Eventually, I would like to move to a WeakPtr model where we could invalidate those pointers when either the extension is removed, the profile is torn down, etc. That said, it wouldn't necessarily help in this case, because the extension is still loaded (it has a running background page even if the active window is closed), and, for the reasons mentioned above, that's unlikely to change in the near future. Re how widespread this is, it's definitely something we need to investigate more. There are a couple of UMA metrics for extension functions that take a long time to execute (Extensions.Functions.[Succeeded|Failed]Time.Over10ms) that we can audit, but I think we will need to see if we can add some for functions that never finish. Unfortunately, if they're kept alive until the end of execution, determining that is a bit tricky (though certainly not impossible).
,
Jan 23 2017
Re #2: Agreed that there is a bug in the identity.getAuthToken() API in that it never completes. I understand that it is WAI to keep-alive the extension while async APIs are in-progress, so that it retains in-memory state to process the results with, and avoid complex tracking of semi-orphaned extension functions. However, in this case the call originates from extension content running in a visible window, so when that content goes out of scope it is perfectly reasonable to cancel any outstanding async API call, since there is no receiving content for the results any more. Re the ref-counting stuff, SGTM, I'll star that bug. ;) |
||
►
Sign in to add a comment |
||
Comment 1 by w...@chromium.org
, Jan 23 2017