Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/platforms/AllocationPolicy.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 "AllocationPolicy.h"
8
9
#include "PDMFactory.h"
10
#include "MediaInfo.h"
11
#include "mozilla/ClearOnShutdown.h"
12
#include "mozilla/SystemGroup.h"
13
#ifdef MOZ_WIDGET_ANDROID
14
#include "mozilla/jni/Utils.h"
15
#endif
16
17
namespace mozilla {
18
19
using TrackType = TrackInfo::TrackType;
20
21
StaticMutex GlobalAllocPolicy::sMutex;
22
23
class GlobalAllocPolicy::AutoDeallocToken : public Token
24
{
25
public:
26
0
  explicit AutoDeallocToken(GlobalAllocPolicy& aPolicy) : mPolicy(aPolicy) { }
27
28
private:
29
  ~AutoDeallocToken()
30
0
  {
31
0
    mPolicy.Dealloc();
32
0
  }
33
34
  GlobalAllocPolicy& mPolicy; // reference to a singleton object.
35
};
36
37
static int32_t
38
MediaDecoderLimitDefault()
39
0
{
40
#ifdef MOZ_WIDGET_ANDROID
41
  if (jni::GetAPIVersion() < 18) {
42
    // Older Android versions have broken support for multiple simultaneous
43
    // decoders, see bug 1278574.
44
    return 1;
45
  }
46
#endif
47
  // Otherwise, set no decoder limit.
48
0
  return -1;
49
0
}
50
51
GlobalAllocPolicy::GlobalAllocPolicy()
52
  : mMonitor("DecoderAllocPolicy::mMonitor")
53
  , mDecoderLimit(MediaDecoderLimitDefault())
54
0
{
55
0
  SystemGroup::Dispatch(
56
0
    TaskCategory::Other,
57
0
    NS_NewRunnableFunction("GlobalAllocPolicy::GlobalAllocPolicy", [this]() {
58
0
      ClearOnShutdown(this, ShutdownPhase::ShutdownThreads);
59
0
    }));
60
0
}
61
62
GlobalAllocPolicy::~GlobalAllocPolicy()
63
0
{
64
0
  while (!mPromises.empty()) {
65
0
    RefPtr<PromisePrivate> p = mPromises.front().forget();
66
0
    mPromises.pop();
67
0
    p->Reject(true, __func__);
68
0
  }
69
0
}
70
71
GlobalAllocPolicy&
72
GlobalAllocPolicy::Instance(TrackType aTrack)
73
0
{
74
0
  StaticMutexAutoLock lock(sMutex);
75
0
  if (aTrack == TrackType::kAudioTrack) {
76
0
    static auto sAudioPolicy = new GlobalAllocPolicy();
77
0
    return *sAudioPolicy;
78
0
  } else {
79
0
    static auto sVideoPolicy = new GlobalAllocPolicy();
80
0
    return *sVideoPolicy;
81
0
  }
82
0
}
83
84
auto
85
GlobalAllocPolicy::Alloc() -> RefPtr<Promise>
86
0
{
87
0
  // No decoder limit set.
88
0
  if (mDecoderLimit < 0) {
89
0
    return Promise::CreateAndResolve(new Token(), __func__);
90
0
  }
91
0
92
0
  ReentrantMonitorAutoEnter mon(mMonitor);
93
0
  RefPtr<PromisePrivate> p = new PromisePrivate(__func__);
94
0
  mPromises.push(p);
95
0
  ResolvePromise(mon);
96
0
  return p.forget();
97
0
}
98
99
void
100
GlobalAllocPolicy::Dealloc()
101
0
{
102
0
  ReentrantMonitorAutoEnter mon(mMonitor);
103
0
  ++mDecoderLimit;
104
0
  ResolvePromise(mon);
105
0
}
106
107
void
108
GlobalAllocPolicy::ResolvePromise(ReentrantMonitorAutoEnter& aProofOfLock)
109
0
{
110
0
  MOZ_ASSERT(mDecoderLimit >= 0);
111
0
112
0
  if (mDecoderLimit > 0 && !mPromises.empty()) {
113
0
    --mDecoderLimit;
114
0
    RefPtr<PromisePrivate> p = mPromises.front().forget();
115
0
    mPromises.pop();
116
0
    p->Resolve(new AutoDeallocToken(*this), __func__);
117
0
  }
118
0
}
119
120
void
121
GlobalAllocPolicy::operator=(std::nullptr_t)
122
0
{
123
0
  delete this;
124
0
}
125
126
AllocationWrapper::AllocationWrapper(
127
  already_AddRefed<MediaDataDecoder> aDecoder,
128
  already_AddRefed<Token> aToken)
129
  : mDecoder(aDecoder)
130
  , mToken(aToken)
131
0
{
132
0
  DecoderDoctorLogger::LogConstructionAndBase(
133
0
    "AllocationWrapper", this, static_cast<const MediaDataDecoder*>(this));
134
0
  DecoderDoctorLogger::LinkParentAndChild(
135
0
    "AllocationWrapper", this, "decoder", mDecoder.get());
136
0
}
137
138
AllocationWrapper::~AllocationWrapper()
139
0
{
140
0
  DecoderDoctorLogger::LogDestruction("AllocationWrapper", this);
141
0
}
142
143
RefPtr<ShutdownPromise>
144
AllocationWrapper::Shutdown()
145
0
{
146
0
  RefPtr<MediaDataDecoder> decoder = mDecoder.forget();
147
0
  RefPtr<Token> token = mToken.forget();
148
0
  return decoder->Shutdown()->Then(
149
0
    AbstractThread::GetCurrent(), __func__, [token]() {
150
0
      return ShutdownPromise::CreateAndResolve(true, __func__);
151
0
    });
152
0
}
153
/* static */ RefPtr<AllocationWrapper::AllocateDecoderPromise>
154
AllocationWrapper::CreateDecoder(const CreateDecoderParams& aParams)
155
0
{
156
0
  // aParams.mConfig is guaranteed to stay alive during the lifetime of the
157
0
  // MediaDataDecoder, so keeping a pointer to the object is safe.
158
0
  const TrackInfo* config = &aParams.mConfig;
159
0
  RefPtr<TaskQueue> taskQueue = aParams.mTaskQueue;
160
0
  DecoderDoctorDiagnostics* diagnostics = aParams.mDiagnostics;
161
0
  RefPtr<layers::ImageContainer> imageContainer = aParams.mImageContainer;
162
0
  RefPtr<layers::KnowsCompositor> knowsCompositor = aParams.mKnowsCompositor;
163
0
  RefPtr<GMPCrashHelper> crashHelper = aParams.mCrashHelper;
164
0
  CreateDecoderParams::UseNullDecoder useNullDecoder = aParams.mUseNullDecoder;
165
0
  CreateDecoderParams::NoWrapper noWrapper = aParams.mNoWrapper;
166
0
  TrackInfo::TrackType type = aParams.mType;
167
0
  MediaEventProducer<TrackInfo::TrackType>* onWaitingForKeyEvent =
168
0
    aParams.mOnWaitingForKeyEvent;
169
0
  CreateDecoderParams::OptionSet options = aParams.mOptions;
170
0
  CreateDecoderParams::VideoFrameRate rate = aParams.mRate;
171
0
172
0
  RefPtr<AllocateDecoderPromise> p =
173
0
    GlobalAllocPolicy::Instance(aParams.mType)
174
0
      .Alloc()
175
0
      ->Then(
176
0
        AbstractThread::GetCurrent(),
177
0
        __func__,
178
0
        [=](RefPtr<Token> aToken) {
179
0
          // result may not always be updated by PDMFactory::CreateDecoder
180
0
          // either when the creation succeeded or failed, as such it must be
181
0
          // initialized to a fatal error by default.
182
0
          MediaResult result = MediaResult(
183
0
            NS_ERROR_DOM_MEDIA_FATAL_ERR,
184
0
            nsPrintfCString("error creating %s decoder", TrackTypeToStr(type)));
185
0
          RefPtr<PDMFactory> pdm = new PDMFactory();
186
0
          CreateDecoderParams params{ *config,
187
0
                                      taskQueue,
188
0
                                      diagnostics,
189
0
                                      imageContainer,
190
0
                                      &result,
191
0
                                      knowsCompositor,
192
0
                                      crashHelper,
193
0
                                      useNullDecoder,
194
0
                                      noWrapper,
195
0
                                      type,
196
0
                                      onWaitingForKeyEvent,
197
0
                                      options,
198
0
                                      rate };
199
0
          RefPtr<MediaDataDecoder> decoder = pdm->CreateDecoder(params);
200
0
          if (decoder) {
201
0
            RefPtr<AllocationWrapper> wrapper =
202
0
              new AllocationWrapper(decoder.forget(), aToken.forget());
203
0
            return AllocateDecoderPromise::CreateAndResolve(wrapper, __func__);
204
0
          }
205
0
          return AllocateDecoderPromise::CreateAndReject(result, __func__);
206
0
        },
207
0
        []() {
208
0
          return AllocateDecoderPromise::CreateAndReject(
209
0
            MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
210
0
                        "Allocation policy expired"),
211
0
            __func__);
212
0
        });
213
0
  return p;
214
0
}
215
216
} // namespace mozilla