Bug 1885602 - Part 5: Implement navigating to the SUMO help topic from the menu heade...
[gecko.git] / dom / media / MediaShutdownManager.cpp
blob4a3c3a4357ba254675f2cc8241ea20d5d5da945a
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "MediaShutdownManager.h"
9 #include "MediaDecoder.h"
10 #include "mozilla/Logging.h"
11 #include "mozilla/media/MediaUtils.h"
12 #include "mozilla/Services.h"
13 #include "mozilla/StaticPtr.h"
14 #include "nsComponentManagerUtils.h"
15 #include "nsIWritablePropertyBag2.h"
17 namespace mozilla {
19 #undef LOGW
21 extern LazyLogModule gMediaDecoderLog;
22 #define DECODER_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
23 #define LOGW(...) NS_WARNING(nsPrintfCString(__VA_ARGS__).get())
25 NS_IMPL_ISUPPORTS(MediaShutdownManager, nsIAsyncShutdownBlocker)
27 MediaShutdownManager::MediaShutdownManager() {
28 MOZ_ASSERT(NS_IsMainThread());
29 MOZ_DIAGNOSTIC_ASSERT(sInitPhase == NotInited);
32 MediaShutdownManager::~MediaShutdownManager() { MOZ_ASSERT(NS_IsMainThread()); }
34 // Note that we don't use ClearOnShutdown() on this StaticRefPtr, as that
35 // may interfere with our shutdown listener.
36 StaticRefPtr<MediaShutdownManager> MediaShutdownManager::sInstance;
38 MediaShutdownManager::InitPhase MediaShutdownManager::sInitPhase =
39 MediaShutdownManager::NotInited;
41 MediaShutdownManager& MediaShutdownManager::Instance() {
42 MOZ_ASSERT(NS_IsMainThread());
43 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
44 if (!sInstance) {
45 MOZ_CRASH_UNSAFE_PRINTF("sInstance is null. sInitPhase=%d",
46 int(sInitPhase));
48 #endif
49 return *sInstance;
52 void MediaShutdownManager::InitStatics() {
53 MOZ_ASSERT(NS_IsMainThread());
54 if (sInitPhase != NotInited) {
55 return;
58 sInstance = new MediaShutdownManager();
59 MOZ_DIAGNOSTIC_ASSERT(sInstance);
61 nsCOMPtr<nsIAsyncShutdownClient> barrier = media::GetShutdownBarrier();
63 if (!barrier) {
64 LOGW("Failed to get barrier, cannot add shutdown blocker!");
65 sInitPhase = InitFailed;
66 return;
69 nsresult rv =
70 barrier->AddBlocker(sInstance, NS_LITERAL_STRING_FROM_CSTRING(__FILE__),
71 __LINE__, u"MediaShutdownManager shutdown"_ns);
72 if (NS_FAILED(rv)) {
73 LOGW("Failed to add shutdown blocker! rv=%x", uint32_t(rv));
74 sInitPhase = InitFailed;
75 return;
77 sInitPhase = InitSucceeded;
80 void MediaShutdownManager::RemoveBlocker() {
81 MOZ_ASSERT(NS_IsMainThread());
82 MOZ_DIAGNOSTIC_ASSERT(sInitPhase == XPCOMShutdownStarted);
83 MOZ_ASSERT(mDecoders.Count() == 0);
84 nsCOMPtr<nsIAsyncShutdownClient> barrier = media::GetShutdownBarrier();
85 // xpcom should still be available because we blocked shutdown by having a
86 // blocker. Until it completely shuts down we should still be able to get
87 // the barrier.
88 MOZ_RELEASE_ASSERT(
89 barrier,
90 "Failed to get shutdown barrier, cannot remove shutdown blocker!");
91 barrier->RemoveBlocker(this);
92 // Clear our singleton reference. This will probably delete
93 // this instance, so don't deref |this| clearing sInstance.
94 sInitPhase = XPCOMShutdownEnded;
95 sInstance = nullptr;
96 DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::BlockShutdown() end."));
99 nsresult MediaShutdownManager::Register(MediaDecoder* aDecoder) {
100 MOZ_ASSERT(NS_IsMainThread());
101 if (sInitPhase == InitFailed) {
102 return NS_ERROR_NOT_INITIALIZED;
104 if (sInitPhase == XPCOMShutdownStarted) {
105 return NS_ERROR_ABORT;
107 // Don't call Register() after you've Unregistered() all the decoders,
108 // that's not going to work.
109 MOZ_ASSERT(!mDecoders.Contains(aDecoder));
110 mDecoders.Insert(aDecoder);
111 MOZ_ASSERT(mDecoders.Contains(aDecoder));
112 MOZ_ASSERT(mDecoders.Count() > 0);
113 return NS_OK;
116 void MediaShutdownManager::Unregister(MediaDecoder* aDecoder) {
117 MOZ_ASSERT(NS_IsMainThread());
118 if (!mDecoders.EnsureRemoved(aDecoder)) {
119 return;
121 if (sInitPhase == XPCOMShutdownStarted && mDecoders.Count() == 0) {
122 RemoveBlocker();
126 NS_IMETHODIMP
127 MediaShutdownManager::GetName(nsAString& aName) {
128 aName = u"MediaShutdownManager: shutdown"_ns;
129 return NS_OK;
132 NS_IMETHODIMP
133 MediaShutdownManager::GetState(nsIPropertyBag** aBagOut) {
134 MOZ_ASSERT(NS_IsMainThread());
135 MOZ_ASSERT(aBagOut);
137 nsCOMPtr<nsIWritablePropertyBag2> propertyBag =
138 do_CreateInstance("@mozilla.org/hash-property-bag;1");
140 if (NS_WARN_IF(!propertyBag)) {
141 return NS_ERROR_OUT_OF_MEMORY;
144 nsresult rv = propertyBag->SetPropertyAsInt32(
145 u"sInitPhase"_ns, static_cast<int32_t>(sInitPhase));
147 if (NS_WARN_IF(NS_FAILED(rv))) {
148 return rv;
151 nsAutoCString decoderInfo;
152 for (const auto& key : mDecoders) {
153 // Grab the full extended type for the decoder. This can be used to help
154 // indicate problems with specific decoders by associating type -> decoder.
155 decoderInfo.Append(key->ContainerType().ExtendedType().OriginalString());
156 decoderInfo.Append(", ");
159 rv = propertyBag->SetPropertyAsACString(u"decoderInfo"_ns, decoderInfo);
161 if (NS_WARN_IF(NS_FAILED(rv))) {
162 return rv;
165 propertyBag.forget(aBagOut);
167 return NS_OK;
170 NS_IMETHODIMP
171 MediaShutdownManager::BlockShutdown(nsIAsyncShutdownClient*) {
172 MOZ_ASSERT(NS_IsMainThread());
173 MOZ_DIAGNOSTIC_ASSERT(sInitPhase == InitSucceeded);
174 MOZ_DIAGNOSTIC_ASSERT(sInstance);
176 DECODER_LOG(LogLevel::Debug,
177 ("MediaShutdownManager::BlockShutdown() start..."));
179 // Set this flag to ensure no Register() is allowed when Shutdown() begins.
180 sInitPhase = XPCOMShutdownStarted;
182 auto oldCount = mDecoders.Count();
183 if (oldCount == 0) {
184 RemoveBlocker();
185 return NS_OK;
188 // Iterate over the decoders and shut them down.
189 for (const auto& key : mDecoders) {
190 key->NotifyXPCOMShutdown();
191 // Check MediaDecoder::Shutdown doesn't call Unregister() synchronously in
192 // order not to corrupt our hashtable traversal.
193 MOZ_ASSERT(mDecoders.Count() == oldCount);
196 return NS_OK;
199 } // namespace mozilla
201 // avoid redefined macro in unified build
202 #undef LOGW