Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/ipc/CompositorManagerChild.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
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/layers/CompositorManagerChild.h"
8
9
#include "gfxPrefs.h"
10
#include "mozilla/layers/CompositorBridgeChild.h"
11
#include "mozilla/layers/CompositorManagerParent.h"
12
#include "mozilla/layers/CompositorThread.h"
13
#include "mozilla/gfx/gfxVars.h"
14
#include "mozilla/gfx/GPUProcessManager.h"
15
#include "mozilla/dom/ContentChild.h"   // for ContentChild
16
#include "mozilla/dom/TabChild.h"       // for TabChild
17
#include "mozilla/dom/TabGroup.h"       // for TabGroup
18
#include "VsyncSource.h"
19
20
namespace mozilla {
21
namespace layers {
22
23
using gfx::GPUProcessManager;
24
25
StaticRefPtr<CompositorManagerChild> CompositorManagerChild::sInstance;
26
27
/* static */ bool
28
CompositorManagerChild::IsInitialized(uint64_t aProcessToken)
29
0
{
30
0
  MOZ_ASSERT(NS_IsMainThread());
31
0
  return sInstance && sInstance->CanSend() &&
32
0
         sInstance->mProcessToken == aProcessToken;
33
0
}
34
35
/* static */ void
36
CompositorManagerChild::InitSameProcess(uint32_t aNamespace,
37
                                        uint64_t aProcessToken)
38
0
{
39
0
  MOZ_ASSERT(NS_IsMainThread());
40
0
  if (NS_WARN_IF(IsInitialized(aProcessToken))) {
41
0
    MOZ_ASSERT_UNREACHABLE("Already initialized same process");
42
0
    return;
43
0
  }
44
0
45
0
  RefPtr<CompositorManagerParent> parent =
46
0
    CompositorManagerParent::CreateSameProcess();
47
0
  RefPtr<CompositorManagerChild> child =
48
0
    new CompositorManagerChild(parent, aProcessToken, aNamespace);
49
0
  if (NS_WARN_IF(!child->CanSend())) {
50
0
    MOZ_DIAGNOSTIC_ASSERT(false, "Failed to open same process protocol");
51
0
    return;
52
0
  }
53
0
54
0
  parent->BindComplete();
55
0
  sInstance = child.forget();
56
0
}
57
58
/* static */ bool
59
CompositorManagerChild::Init(Endpoint<PCompositorManagerChild>&& aEndpoint,
60
                             uint32_t aNamespace,
61
                             uint64_t aProcessToken /* = 0 */)
62
0
{
63
0
  MOZ_ASSERT(NS_IsMainThread());
64
0
  if (sInstance) {
65
0
    MOZ_ASSERT(sInstance->mNamespace != aNamespace);
66
0
  }
67
0
68
0
  sInstance = new CompositorManagerChild(std::move(aEndpoint), aProcessToken,
69
0
                                         aNamespace);
70
0
  return sInstance->CanSend();
71
0
}
72
73
/* static */ void
74
CompositorManagerChild::Shutdown()
75
0
{
76
0
  MOZ_ASSERT(NS_IsMainThread());
77
0
  CompositorBridgeChild::ShutDown();
78
0
79
0
  if (!sInstance) {
80
0
    return;
81
0
  }
82
0
83
0
  sInstance->Close();
84
0
  sInstance = nullptr;
85
0
}
86
87
/* static */ void
88
CompositorManagerChild::OnGPUProcessLost(uint64_t aProcessToken)
89
0
{
90
0
  MOZ_ASSERT(NS_IsMainThread());
91
0
92
0
  // Since GPUChild and CompositorManagerChild will race on ActorDestroy, we
93
0
  // cannot know if the CompositorManagerChild is about to be released but has
94
0
  // yet to be. As such, we want to pre-emptively set mCanSend to false.
95
0
  if (sInstance && sInstance->mProcessToken == aProcessToken) {
96
0
    sInstance->mCanSend = false;
97
0
  }
98
0
}
99
100
/* static */ bool
101
CompositorManagerChild::CreateContentCompositorBridge(uint32_t aNamespace)
102
0
{
103
0
  MOZ_ASSERT(NS_IsMainThread());
104
0
  if (NS_WARN_IF(!sInstance || !sInstance->CanSend())) {
105
0
    return false;
106
0
  }
107
0
108
0
  CompositorBridgeOptions options = ContentCompositorOptions();
109
0
  PCompositorBridgeChild* pbridge =
110
0
    sInstance->SendPCompositorBridgeConstructor(options);
111
0
  if (NS_WARN_IF(!pbridge)) {
112
0
    return false;
113
0
  }
114
0
115
0
  auto bridge = static_cast<CompositorBridgeChild*>(pbridge);
116
0
  bridge->InitForContent(aNamespace);
117
0
  return true;
118
0
}
119
120
/* static */ already_AddRefed<CompositorBridgeChild>
121
CompositorManagerChild::CreateWidgetCompositorBridge(uint64_t aProcessToken,
122
                                                     LayerManager* aLayerManager,
123
                                                     uint32_t aNamespace,
124
                                                     CSSToLayoutDeviceScale aScale,
125
                                                     const CompositorOptions& aOptions,
126
                                                     bool aUseExternalSurfaceSize,
127
                                                     const gfx::IntSize& aSurfaceSize)
128
0
{
129
0
  MOZ_ASSERT(XRE_IsParentProcess());
130
0
  MOZ_ASSERT(NS_IsMainThread());
131
0
  if (NS_WARN_IF(!sInstance || !sInstance->CanSend())) {
132
0
    return nullptr;
133
0
  }
134
0
135
0
  TimeDuration vsyncRate =
136
0
    gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay().GetVsyncRate();
137
0
138
0
  CompositorBridgeOptions options =
139
0
    WidgetCompositorOptions(aScale, vsyncRate, aOptions,
140
0
                            aUseExternalSurfaceSize, aSurfaceSize);
141
0
  PCompositorBridgeChild* pbridge =
142
0
    sInstance->SendPCompositorBridgeConstructor(options);
143
0
  if (NS_WARN_IF(!pbridge)) {
144
0
    return nullptr;
145
0
  }
146
0
147
0
  RefPtr<CompositorBridgeChild> bridge =
148
0
    static_cast<CompositorBridgeChild*>(pbridge);
149
0
  bridge->InitForWidget(aProcessToken, aLayerManager, aNamespace);
150
0
  return bridge.forget();
151
0
}
152
153
/* static */ already_AddRefed<CompositorBridgeChild>
154
CompositorManagerChild::CreateSameProcessWidgetCompositorBridge(LayerManager* aLayerManager,
155
                                                                uint32_t aNamespace)
156
0
{
157
0
  MOZ_ASSERT(XRE_IsParentProcess() || recordreplay::IsRecordingOrReplaying());
158
0
  MOZ_ASSERT(NS_IsMainThread());
159
0
  if (NS_WARN_IF(!sInstance || !sInstance->CanSend())) {
160
0
    return nullptr;
161
0
  }
162
0
163
0
  CompositorBridgeOptions options = SameProcessWidgetCompositorOptions();
164
0
  PCompositorBridgeChild* pbridge =
165
0
    sInstance->SendPCompositorBridgeConstructor(options);
166
0
  if (NS_WARN_IF(!pbridge)) {
167
0
    return nullptr;
168
0
  }
169
0
170
0
  RefPtr<CompositorBridgeChild> bridge =
171
0
    static_cast<CompositorBridgeChild*>(pbridge);
172
0
  bridge->InitForWidget(1, aLayerManager, aNamespace);
173
0
  return bridge.forget();
174
0
}
175
176
CompositorManagerChild::CompositorManagerChild(CompositorManagerParent* aParent,
177
                                               uint64_t aProcessToken,
178
                                               uint32_t aNamespace)
179
  : mProcessToken(aProcessToken)
180
  , mNamespace(aNamespace)
181
  , mResourceId(0)
182
  , mCanSend(false)
183
0
{
184
0
  MOZ_ASSERT(aParent);
185
0
186
0
  SetOtherProcessId(base::GetCurrentProcId());
187
0
  MessageLoop* loop = CompositorThreadHolder::Loop();
188
0
  ipc::MessageChannel* channel = aParent->GetIPCChannel();
189
0
  if (NS_WARN_IF(!Open(channel, loop, ipc::ChildSide))) {
190
0
    return;
191
0
  }
192
0
193
0
  mCanSend = true;
194
0
  AddRef();
195
0
  SetReplyTimeout();
196
0
}
197
198
CompositorManagerChild::CompositorManagerChild(Endpoint<PCompositorManagerChild>&& aEndpoint,
199
                                               uint64_t aProcessToken,
200
                                               uint32_t aNamespace)
201
  : mProcessToken(aProcessToken)
202
  , mNamespace(aNamespace)
203
  , mResourceId(0)
204
  , mCanSend(false)
205
0
{
206
0
  if (NS_WARN_IF(!aEndpoint.Bind(this))) {
207
0
    return;
208
0
  }
209
0
210
0
  mCanSend = true;
211
0
  AddRef();
212
0
  SetReplyTimeout();
213
0
}
214
215
void
216
CompositorManagerChild::DeallocPCompositorManagerChild()
217
0
{
218
0
  MOZ_ASSERT(!mCanSend);
219
0
  Release();
220
0
}
221
222
void
223
CompositorManagerChild::ActorDestroy(ActorDestroyReason aReason)
224
0
{
225
0
  mCanSend = false;
226
0
  if (sInstance == this) {
227
0
    sInstance = nullptr;
228
0
  }
229
0
}
230
231
PCompositorBridgeChild*
232
CompositorManagerChild::AllocPCompositorBridgeChild(const CompositorBridgeOptions& aOptions)
233
0
{
234
0
  CompositorBridgeChild* child = new CompositorBridgeChild(this);
235
0
  child->AddRef();
236
0
  return child;
237
0
}
238
239
bool
240
CompositorManagerChild::DeallocPCompositorBridgeChild(PCompositorBridgeChild* aActor)
241
0
{
242
0
  static_cast<CompositorBridgeChild*>(aActor)->Release();
243
0
  return true;
244
0
}
245
246
void
247
CompositorManagerChild::HandleFatalError(const char* aMsg) const
248
0
{
249
0
  dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
250
0
}
251
252
void
253
CompositorManagerChild::ProcessingError(Result aCode, const char* aReason)
254
0
{
255
0
  if (aCode != MsgDropped) {
256
0
    gfxDevCrash(gfx::LogReason::ProcessingError) << "Processing error in CompositorBridgeChild: " << int(aCode);
257
0
  }
258
0
}
259
260
already_AddRefed<nsIEventTarget>
261
CompositorManagerChild::GetSpecificMessageEventTarget(const Message& aMsg)
262
0
{
263
0
  if (aMsg.type() == PCompositorBridge::Msg_DidComposite__ID) {
264
0
    LayersId layersId;
265
0
    PickleIterator iter(aMsg);
266
0
    if (!IPC::ReadParam(&aMsg, &iter, &layersId)) {
267
0
      return nullptr;
268
0
    }
269
0
270
0
    TabChild* tabChild = TabChild::GetFrom(layersId);
271
0
    if (!tabChild) {
272
0
      return nullptr;
273
0
    }
274
0
275
0
    return do_AddRef(tabChild->TabGroup()->EventTargetFor(TaskCategory::Other));
276
0
  }
277
0
278
0
  if (aMsg.type() == PCompositorBridge::Msg_ParentAsyncMessages__ID) {
279
0
    return do_AddRef(SystemGroup::EventTargetFor(TaskCategory::Other));
280
0
  }
281
0
282
0
  return nullptr;
283
0
}
284
285
void
286
CompositorManagerChild::SetReplyTimeout()
287
0
{
288
0
#ifndef DEBUG
289
0
  // Add a timeout for release builds to kill GPU process when it hangs.
290
0
  if (XRE_IsParentProcess() &&
291
0
      GPUProcessManager::Get()->GetGPUChild()) {
292
0
    int32_t timeout = gfxPrefs::GPUProcessIPCReplyTimeoutMs();
293
0
    SetReplyTimeoutMs(timeout);
294
0
  }
295
0
#endif
296
0
}
297
298
bool
299
CompositorManagerChild::ShouldContinueFromReplyTimeout()
300
0
{
301
0
  if (XRE_IsParentProcess()) {
302
0
    gfxCriticalNote << "Killing GPU process due to IPC reply timeout";
303
0
    MOZ_DIAGNOSTIC_ASSERT(GPUProcessManager::Get()->GetGPUChild());
304
0
    GPUProcessManager::Get()->KillProcess();
305
0
  }
306
0
  return false;
307
0
}
308
309
} // namespace layers
310
} // namespace mozilla