Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/MediaShutdownManager.cpp
Line
Count
Source (jump to first uncovered line)
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/. */
6
7
#include "mozilla/Logging.h"
8
#include "mozilla/StaticPtr.h"
9
#include "mozilla/Services.h"
10
11
#include "MediaDecoder.h"
12
#include "MediaShutdownManager.h"
13
14
namespace mozilla {
15
16
#undef LOGW
17
18
extern LazyLogModule gMediaDecoderLog;
19
0
#define DECODER_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
20
0
#define LOGW(...) NS_WARNING(nsPrintfCString(__VA_ARGS__).get())
21
22
NS_IMPL_ISUPPORTS(MediaShutdownManager, nsIAsyncShutdownBlocker)
23
24
MediaShutdownManager::MediaShutdownManager()
25
0
{
26
0
  MOZ_ASSERT(NS_IsMainThread());
27
0
  MOZ_DIAGNOSTIC_ASSERT(sInitPhase == NotInited);
28
0
}
29
30
MediaShutdownManager::~MediaShutdownManager()
31
0
{
32
0
  MOZ_ASSERT(NS_IsMainThread());
33
0
}
34
35
// Note that we don't use ClearOnShutdown() on this StaticRefPtr, as that
36
// may interfere with our shutdown listener.
37
StaticRefPtr<MediaShutdownManager> MediaShutdownManager::sInstance;
38
39
MediaShutdownManager::InitPhase MediaShutdownManager::sInitPhase = MediaShutdownManager::NotInited;
40
41
MediaShutdownManager&
42
MediaShutdownManager::Instance()
43
0
{
44
0
  MOZ_ASSERT(NS_IsMainThread());
45
0
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
46
0
  if (!sInstance) {
47
0
    MOZ_CRASH_UNSAFE_PRINTF("sInstance is null. sInitPhase=%d", int(sInitPhase));
48
0
  }
49
0
#endif
50
0
  return *sInstance;
51
0
}
52
53
static nsCOMPtr<nsIAsyncShutdownClient>
54
GetShutdownBarrier()
55
0
{
56
0
  nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdown();
57
0
  MOZ_RELEASE_ASSERT(svc);
58
0
59
0
  nsCOMPtr<nsIAsyncShutdownClient> barrier;
60
0
  nsresult rv = svc->GetProfileBeforeChange(getter_AddRefs(barrier));
61
0
  if (!barrier) {
62
0
    // We are probably in a content process. We need to do cleanup at
63
0
    // XPCOM shutdown in leakchecking builds.
64
0
    rv = svc->GetXpcomWillShutdown(getter_AddRefs(barrier));
65
0
  }
66
0
  MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
67
0
  MOZ_RELEASE_ASSERT(barrier);
68
0
  return barrier.forget();
69
0
}
70
71
void
72
MediaShutdownManager::InitStatics()
73
0
{
74
0
  MOZ_ASSERT(NS_IsMainThread());
75
0
  if (sInitPhase != NotInited) {
76
0
    return;
77
0
  }
78
0
79
0
  sInstance = new MediaShutdownManager();
80
0
  MOZ_DIAGNOSTIC_ASSERT(sInstance);
81
0
82
0
  nsresult rv = GetShutdownBarrier()->AddBlocker(
83
0
    sInstance, NS_LITERAL_STRING(__FILE__), __LINE__,
84
0
    NS_LITERAL_STRING("MediaShutdownManager shutdown"));
85
0
  if (NS_FAILED(rv)) {
86
0
    LOGW("Failed to add shutdown blocker! rv=%x", uint32_t(rv));
87
0
    sInitPhase = InitFailed;
88
0
    return;
89
0
  }
90
0
  sInitPhase = InitSucceeded;
91
0
}
92
93
void
94
MediaShutdownManager::RemoveBlocker()
95
0
{
96
0
  MOZ_ASSERT(NS_IsMainThread());
97
0
  MOZ_DIAGNOSTIC_ASSERT(sInitPhase == XPCOMShutdownStarted);
98
0
  MOZ_ASSERT(mDecoders.Count() == 0);
99
0
  GetShutdownBarrier()->RemoveBlocker(this);
100
0
  // Clear our singleton reference. This will probably delete
101
0
  // this instance, so don't deref |this| clearing sInstance.
102
0
  sInitPhase = XPCOMShutdownEnded;
103
0
  sInstance = nullptr;
104
0
  DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::BlockShutdown() end."));
105
0
}
106
107
nsresult
108
MediaShutdownManager::Register(MediaDecoder* aDecoder)
109
0
{
110
0
  MOZ_ASSERT(NS_IsMainThread());
111
0
  if (sInitPhase == InitFailed) {
112
0
    return NS_ERROR_NOT_INITIALIZED;
113
0
  }
114
0
  if (sInitPhase == XPCOMShutdownStarted) {
115
0
    return NS_ERROR_ABORT;
116
0
  }
117
0
  // Don't call Register() after you've Unregistered() all the decoders,
118
0
  // that's not going to work.
119
0
  MOZ_ASSERT(!mDecoders.Contains(aDecoder));
120
0
  mDecoders.PutEntry(aDecoder);
121
0
  MOZ_ASSERT(mDecoders.Contains(aDecoder));
122
0
  MOZ_ASSERT(mDecoders.Count() > 0);
123
0
  return NS_OK;
124
0
}
125
126
void
127
MediaShutdownManager::Unregister(MediaDecoder* aDecoder)
128
0
{
129
0
  MOZ_ASSERT(NS_IsMainThread());
130
0
  if (!mDecoders.Contains(aDecoder)) {
131
0
    return;
132
0
  }
133
0
  mDecoders.RemoveEntry(aDecoder);
134
0
  if (sInitPhase == XPCOMShutdownStarted && mDecoders.Count() == 0) {
135
0
    RemoveBlocker();
136
0
  }
137
0
}
138
139
NS_IMETHODIMP
140
MediaShutdownManager::GetName(nsAString& aName)
141
0
{
142
0
  aName = NS_LITERAL_STRING("MediaShutdownManager: shutdown");
143
0
  return NS_OK;
144
0
}
145
146
NS_IMETHODIMP
147
MediaShutdownManager::GetState(nsIPropertyBag**)
148
0
{
149
0
  return NS_OK;
150
0
}
151
152
NS_IMETHODIMP
153
MediaShutdownManager::BlockShutdown(nsIAsyncShutdownClient*)
154
0
{
155
0
  MOZ_ASSERT(NS_IsMainThread());
156
0
  MOZ_DIAGNOSTIC_ASSERT(sInitPhase == InitSucceeded);
157
0
  MOZ_DIAGNOSTIC_ASSERT(sInstance);
158
0
159
0
  DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::BlockShutdown() start..."));
160
0
161
0
  // Set this flag to ensure no Register() is allowed when Shutdown() begins.
162
0
  sInitPhase = XPCOMShutdownStarted;
163
0
164
0
  auto oldCount = mDecoders.Count();
165
0
  if (oldCount == 0) {
166
0
    RemoveBlocker();
167
0
    return NS_OK;
168
0
  }
169
0
170
0
  // Iterate over the decoders and shut them down.
171
0
  for (auto iter = mDecoders.Iter(); !iter.Done(); iter.Next()) {
172
0
    iter.Get()->GetKey()->NotifyXPCOMShutdown();
173
0
    // Check MediaDecoder::Shutdown doesn't call Unregister() synchronously in
174
0
    // order not to corrupt our hashtable traversal.
175
0
    MOZ_ASSERT(mDecoders.Count() == oldCount);
176
0
  }
177
0
178
0
  return NS_OK;
179
0
}
180
181
} // namespace mozilla
182
183
// avoid redefined macro in unified build
184
#undef LOGW