Bug 1586057 - Avoid stepping on docShells of unrelated docs in MediaManager device stopping code. r=bzbarsky,pehrsons

Differential Revision: https://phabricator.services.mozilla.com/D52427

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jan-Ivar Bruaroey 2019-11-11 21:56:15 +00:00
Родитель b439b62977
Коммит 94286593e7
1 изменённых файлов: 48 добавлений и 26 удалений

Просмотреть файл

@ -2187,9 +2187,11 @@ void MediaManager::DeviceListChanged() {
deviceIDs.AppendElement(id);
}
}
// For any removed devices, notify their listeners cleanly that the
// source has stopped, so JS knows and usage indicators update.
for (auto& id : mDeviceIDs) {
if (deviceIDs.Contains(id)) {
// Device has not been removed
continue;
}
@ -2197,11 +2199,25 @@ void MediaManager::DeviceListChanged() {
nsGlobalWindowInner::InnerWindowByIdTable* windowsById =
nsGlobalWindowInner::GetWindowsTable();
if (!windowsById) {
// We're in shutdown
continue;
}
for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
nsGlobalWindowInner* window = iter.Data();
if (!window->IsCurrentInnerWindow()) {
// Ignore non-current inner windows
continue;
}
if (!window->GetOuterWindow()->IsTopLevelWindow()) {
// Ignore non-top-level inner windows, to avoid hitting them
// twice, since we'll be using IterateWindowListeners(). This
// shouldn't miss any iframes, as they generally can't be
// removed from DOM without OnNavigation. If it does miss them
// OnNavigation does a comparable job (minus notifying the JS
// that's about to be unloaded).
continue;
}
IterateWindowListeners(
window,
[&id](const RefPtr<GetUserMediaWindowListener>& aListener) {
@ -2234,7 +2250,7 @@ nsresult MediaManager::GenerateUUID(nsAString& aResult) {
static bool IsFullyActive(nsPIDOMWindowInner* aWindow) {
while (true) {
if (!aWindow) {
if (!aWindow || nsGlobalWindowInner::Cast(aWindow)->IsDying()) {
return false;
}
Document* document = aWindow->GetExtantDoc();
@ -3368,6 +3384,12 @@ void MediaManager::OnNavigation(uint64_t aWindowID) {
// be added to from the main-thread
auto* window = nsGlobalWindowInner::GetInnerWindowWithId(aWindowID);
if (window) {
// We have cleanup to do when we're the current window. OnNavigation is also
// called by nsGlobalWindowInner::FreeInnerObjects, which MAY happen later
// when window is not current. In that case, cleanup has already happened.
if (!window->IsCurrentInnerWindow()) {
return;
}
IterateWindowListeners(
window, [self = RefPtr<MediaManager>(this),
windowID = DebugOnly<decltype(aWindowID)>(aWindowID)](
@ -3895,11 +3917,11 @@ MediaManager::SanitizeDeviceIds(int64_t aSinceWhen) {
}
void MediaManager::StopScreensharing(uint64_t aWindowID) {
// We need to stop window/screensharing for all streams in all innerwindows
// that correspond to that outerwindow.
// We need to stop window/screensharing for all streams in this innerwindow
// and all its sub frames.
auto* window = nsGlobalWindowInner::GetInnerWindowWithId(aWindowID);
if (!window) {
if (!window || !window->IsCurrentInnerWindow()) {
return;
}
IterateWindowListeners(
@ -3913,29 +3935,29 @@ void MediaManager::IterateWindowListeners(nsPIDOMWindowInner* aWindow,
const FunctionType& aCallback) {
// Iterate the docshell tree to find all the child windows, and for each
// invoke the callback
if (aWindow) {
{
uint64_t windowID = aWindow->WindowID();
RefPtr<GetUserMediaWindowListener> listener = GetWindowListener(windowID);
if (listener) {
aCallback(listener);
}
// NB: `listener` might have been destroyed.
MOZ_DIAGNOSTIC_ASSERT(aWindow);
MOZ_DIAGNOSTIC_ASSERT(aWindow->IsCurrentInnerWindow());
{
uint64_t windowID = aWindow->WindowID();
RefPtr<GetUserMediaWindowListener> listener = GetWindowListener(windowID);
if (listener) {
aCallback(listener);
}
// NB: `listener` might have been destroyed.
}
// iterate any children of *this* window (iframes, etc)
nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
if (docShell) {
int32_t i, count;
docShell->GetInProcessChildCount(&count);
for (i = 0; i < count; ++i) {
nsCOMPtr<nsIDocShellTreeItem> item;
docShell->GetInProcessChildAt(i, getter_AddRefs(item));
nsCOMPtr<nsPIDOMWindowOuter> winOuter =
item ? item->GetWindow() : nullptr;
if (winOuter) {
IterateWindowListeners(winOuter->GetCurrentInnerWindow(), aCallback);
// iterate any children of *this* window (iframes, etc)
nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
if (docShell) {
int32_t i, count;
docShell->GetInProcessChildCount(&count);
for (i = 0; i < count; ++i) {
nsCOMPtr<nsIDocShellTreeItem> item;
docShell->GetInProcessChildAt(i, getter_AddRefs(item));
nsCOMPtr<nsPIDOMWindowOuter> child = item ? item->GetWindow() : nullptr;
if (child) {
if (auto* innerChild = child->GetCurrentInnerWindow()) {
IterateWindowListeners(innerChild, aCallback);
}
}
}