Sync removal of mojo remote with destruction of MediaSessionController

As discussed in [1], with the recent migration of legacy IPC messages
we could get into a race condition between the point where the mojo
remote for the media::mojom::MediaPlayer interface associated to a
specific media player gets removed from the map owned by MWCO, and
when exactly the MediaSessionController associated to the same media
player gets destroyed, which is leading to crashes.

To fix this, let's remove the OnMediaDestroyed() legacy IPC message and
handle that event via the disconnect handler for the mojo remote in MWCO
associated to the media player being destroyed, and move the logic from
MWCO::OnMediaDestroyed() in there.

Note that this is also in line with the proposed design in [2], where
it was already proposed to remove this message in favour of the handler.

[1] https://crrev.com/c/2596148/5#message-b8c571524e046ccf53a53c811da629c98c849a0b
[2] https://docs.google.com/document/d/1OLMNxLvGkRO6ju_WfHbRMrgaVnW7bsMnW7XlJQI0A2E

TBR=mlamouri@chromium.org

Bug: 1157572,1157239,1157263,1157241,1039252
Change-Id: I79b9d9cd3e65881db4826b0d058a530d6d249a22
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2596148
Commit-Queue: Mario Sanchez Prada <mario@igalia.com>
Reviewed-by: Chrome Cunningham <chcunningham@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#838819}
diff --git a/content/browser/media/media_web_contents_observer.cc b/content/browser/media/media_web_contents_observer.cc
index 4172a48..9c681c5 100644
--- a/content/browser/media/media_web_contents_observer.cc
+++ b/content/browser/media/media_web_contents_observer.cc
@@ -255,8 +255,6 @@
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MediaWebContentsObserver, msg,
                                    render_frame_host)
-    IPC_MESSAGE_HANDLER(MediaPlayerDelegateHostMsg_OnMediaDestroyed,
-                        OnMediaDestroyed)
     IPC_MESSAGE_HANDLER(MediaPlayerDelegateHostMsg_OnMediaPaused, OnMediaPaused)
     IPC_MESSAGE_HANDLER(MediaPlayerDelegateHostMsg_OnMediaMetadataChanged,
                         OnMediaMetadataChanged)
@@ -404,16 +402,6 @@
   return it != player_info_map_.end() ? it->second.get() : nullptr;
 }
 
-void MediaWebContentsObserver::OnMediaDestroyed(
-    RenderFrameHost* render_frame_host,
-    int delegate_id) {
-  // TODO(liberato): Should we skip power manager notifications in this case?
-  const MediaPlayerId player_id(render_frame_host, delegate_id);
-  player_info_map_.erase(player_id);
-  session_controllers_manager_.OnEnd(player_id);
-  web_contents_impl()->MediaDestroyed(player_id);
-}
-
 void MediaWebContentsObserver::OnMediaPaused(RenderFrameHost* render_frame_host,
                                              int delegate_id,
                                              bool reached_end_of_stream) {
@@ -541,7 +529,7 @@
 MediaWebContentsObserver::GetMediaPlayerRemote(const MediaPlayerId& player_id) {
   DCHECK(media_player_remotes_.contains(player_id));
   DCHECK(media_player_remotes_[player_id].is_bound());
-  return media_player_remotes_[player_id];
+  return media_player_remotes_.at(player_id);
 }
 
 void MediaWebContentsObserver::OnMediaPlayerHostDisconnected(
@@ -611,7 +599,10 @@
   media_player_remotes_[player_id].Bind(std::move(player_remote));
   media_player_remotes_[player_id].set_disconnect_handler(base::BindOnce(
       [](MediaWebContentsObserver* observer, const MediaPlayerId& player_id) {
+        observer->player_info_map_.erase(player_id);
         observer->media_player_remotes_.erase(player_id);
+        observer->session_controllers_manager_.OnEnd(player_id);
+        observer->web_contents_impl()->MediaDestroyed(player_id);
       },
       base::Unretained(this), player_id));
 
diff --git a/content/browser/media/media_web_contents_observer.h b/content/browser/media/media_web_contents_observer.h
index 7795fc7..a1ee47e 100644
--- a/content/browser/media/media_web_contents_observer.h
+++ b/content/browser/media/media_web_contents_observer.h
@@ -215,7 +215,6 @@
   // PlayerInfo exists.
   PlayerInfo* GetPlayerInfo(const MediaPlayerId& id) const;
 
-  void OnMediaDestroyed(RenderFrameHost* render_frame_host, int delegate_id);
   void OnMediaPaused(RenderFrameHost* render_frame_host,
                      int delegate_id,
                      bool reached_end_of_stream);
diff --git a/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc b/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc
index c7bffe79..d936ab7 100644
--- a/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc
+++ b/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc
@@ -112,6 +112,8 @@
     return receiver_.BindNewPipeAndPassRemote();
   }
 
+  mojo::Receiver<media::mojom::MediaPlayer>& receiver() { return receiver_; }
+
   // media::mojom::MediaPlayer implementation.
   void AddMediaPlayerObserver(
       mojo::PendingRemote<media::mojom::MediaPlayerObserver>) override {}
@@ -156,6 +158,8 @@
     return media_player_receiver_.BindMediaPlayerReceiverAndPassRemote();
   }
 
+  void ResetMediaPlayerReceiver() { media_player_receiver_.receiver().reset(); }
+
  private:
   PictureInPictureTestBrowserClient browser_client_;
   PictureInPictureDelegate delegate_;
@@ -221,9 +225,7 @@
   // Picture-in-Picture media player id should not be reset when the media is
   // destroyed (e.g. video stops playing). This allows the Picture-in-Picture
   // window to continue to control the media.
-  contents()->GetMainFrame()->OnMessageReceived(
-      MediaPlayerDelegateHostMsg_OnMediaDestroyed(
-          contents()->GetMainFrame()->GetRoutingID(), kPlayerVideoOnlyId));
+  ResetMediaPlayerReceiver();
   EXPECT_TRUE(controller->active_session_for_testing());
 }
 
diff --git a/content/common/media/media_player_delegate_messages.h b/content/common/media/media_player_delegate_messages.h
index 8bb0735..a8cea24 100644
--- a/content/common/media/media_player_delegate_messages.h
+++ b/content/common/media/media_player_delegate_messages.h
@@ -53,9 +53,6 @@
 // Messages from the renderer notifying the browser of playback state changes.
 // ----------------------------------------------------------------------------
 
-IPC_MESSAGE_ROUTED1(MediaPlayerDelegateHostMsg_OnMediaDestroyed,
-                    int /* delegate_id, distinguishes instances */)
-
 IPC_MESSAGE_ROUTED2(MediaPlayerDelegateHostMsg_OnMediaPaused,
                     int /* delegate_id, distinguishes instances */,
                     bool /* reached end of stream */)
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.cc b/content/renderer/media/renderer_webmediaplayer_delegate.cc
index 4f0dfe9f..99fb0c5 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate.cc
+++ b/content/renderer/media/renderer_webmediaplayer_delegate.cc
@@ -85,9 +85,6 @@
   players_with_video_.erase(player_id);
   playing_videos_.erase(player_id);
 
-  Send(
-      new MediaPlayerDelegateHostMsg_OnMediaDestroyed(routing_id(), player_id));
-
   ScheduleUpdateTask();
 }
 
@@ -145,8 +142,6 @@
   DCHECK(id_map_.Lookup(player_id));
   players_with_video_.erase(player_id);
   playing_videos_.erase(player_id);
-  Send(
-      new MediaPlayerDelegateHostMsg_OnMediaDestroyed(routing_id(), player_id));
 
   // Required to keep background playback statistics up to date.
   ScheduleUpdateTask();
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc b/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
index ee8882b..dfbc855 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
+++ b/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
@@ -152,20 +152,6 @@
     EXPECT_EQ(delegate_id, std::get<0>(result));
     EXPECT_EQ(kReachedEndOfStream, std::get<1>(result));
   }
-
-  // Verify the destruction message.
-  {
-    test_sink().ClearMessages();
-    delegate_manager_->PlayerGone(delegate_id);
-    const IPC::Message* msg = test_sink().GetUniqueMessageMatching(
-        MediaPlayerDelegateHostMsg_OnMediaDestroyed::ID);
-    ASSERT_TRUE(msg);
-
-    std::tuple<int> result;
-    ASSERT_TRUE(
-        MediaPlayerDelegateHostMsg_OnMediaDestroyed::Read(msg, &result));
-    EXPECT_EQ(delegate_id, std::get<0>(result));
-  }
 }
 
 TEST_F(RendererWebMediaPlayerDelegateTest, DeliversObserverNotifications) {