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 "ImageBridgeChild.h"
8 #include <vector>                        // for vector
9 #include "ImageBridgeParent.h"           // for ImageBridgeParent
10 #include "ImageContainer.h"              // for ImageContainer
11 #include "Layers.h"                      // for Layer, etc
12 #include "ShadowLayers.h"                // for ShadowLayerForwarder
13 #include "base/message_loop.h"           // for MessageLoop
14 #include "base/platform_thread.h"        // for PlatformThread
15 #include "base/process.h"                // for ProcessId
16 #include "base/task.h"                   // for NewRunnableFunction, etc
17 #include "base/thread.h"                 // for Thread
18 #include "mozilla/Assertions.h"          // for MOZ_ASSERT, etc
19 #include "mozilla/Monitor.h"             // for Monitor, MonitorAutoLock
20 #include "mozilla/ReentrantMonitor.h"    // for ReentrantMonitor, etc
21 #include "mozilla/ipc/MessageChannel.h"  // for MessageChannel, etc
22 #include "mozilla/ipc/Transport.h"       // for Transport
23 #include "mozilla/gfx/Point.h"           // for IntSize
24 #include "mozilla/layers/AsyncCanvasRenderer.h"
25 #include "mozilla/media/MediaSystemResourceManager.h"  // for MediaSystemResourceManager
26 #include "mozilla/media/MediaSystemResourceManagerChild.h"  // for MediaSystemResourceManagerChild
27 #include "mozilla/layers/CompositableClient.h"  // for CompositableChild, etc
28 #include "mozilla/layers/CompositorThread.h"
29 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
30 #include "mozilla/layers/ImageClient.h"        // for ImageClient
31 #include "mozilla/layers/LayersMessages.h"     // for CompositableOperation
32 #include "mozilla/layers/TextureClient.h"      // for TextureClient
33 #include "mozilla/dom/ContentChild.h"
34 #include "mozilla/mozalloc.h"  // for operator new, etc
35 #include "mtransport/runnable_utils.h"
36 #include "nsContentUtils.h"
37 #include "nsISupportsImpl.h"         // for ImageContainer::AddRef, etc
38 #include "nsTArray.h"                // for AutoTArray, nsTArray, etc
39 #include "nsTArrayForwardDeclare.h"  // for AutoTArray
40 #include "nsThreadUtils.h"           // for NS_IsMainThread
41 #include "nsXULAppAPI.h"             // for XRE_GetIOMessageLoop
42 #include "mozilla/StaticMutex.h"
43 #include "mozilla/StaticPtr.h"  // for StaticRefPtr
44 #include "mozilla/layers/TextureClient.h"
45 #include "SynchronousTask.h"
46 
47 namespace mozilla {
48 namespace ipc {
49 class Shmem;
50 }  // namespace ipc
51 
52 namespace layers {
53 
54 using base::ProcessId;
55 using base::Thread;
56 using namespace mozilla::ipc;
57 using namespace mozilla::gfx;
58 using namespace mozilla::media;
59 
60 typedef std::vector<CompositableOperation> OpVector;
61 typedef nsTArray<OpDestroy> OpDestroyVector;
62 typedef nsTArray<ReadLockInit> ReadLockVector;
63 
64 struct CompositableTransaction {
CompositableTransactionmozilla::layers::CompositableTransaction65   CompositableTransaction() : mReadLockSequenceNumber(0), mFinished(true) {}
~CompositableTransactionmozilla::layers::CompositableTransaction66   ~CompositableTransaction() { End(); }
Finishedmozilla::layers::CompositableTransaction67   bool Finished() const { return mFinished; }
Beginmozilla::layers::CompositableTransaction68   void Begin() {
69     MOZ_ASSERT(mFinished);
70     mFinished = false;
71     mReadLockSequenceNumber = 0;
72     mReadLocks.AppendElement();
73   }
Endmozilla::layers::CompositableTransaction74   void End() {
75     mFinished = true;
76     mOperations.clear();
77     mDestroyedActors.Clear();
78     mReadLocks.Clear();
79   }
IsEmptymozilla::layers::CompositableTransaction80   bool IsEmpty() const {
81     return mOperations.empty() && mDestroyedActors.IsEmpty();
82   }
AddNoSwapEditmozilla::layers::CompositableTransaction83   void AddNoSwapEdit(const CompositableOperation& op) {
84     MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
85     mOperations.push_back(op);
86   }
87 
AddReadLockmozilla::layers::CompositableTransaction88   ReadLockHandle AddReadLock(const ReadLockDescriptor& aReadLock) {
89     ReadLockHandle handle(++mReadLockSequenceNumber);
90     if (mReadLocks.LastElement().Length() >=
91         CompositableForwarder::GetMaxFileDescriptorsPerMessage()) {
92       mReadLocks.AppendElement();
93     }
94     mReadLocks.LastElement().AppendElement(ReadLockInit(aReadLock, handle));
95     return handle;
96   }
97 
98   OpVector mOperations;
99   OpDestroyVector mDestroyedActors;
100   nsTArray<ReadLockVector> mReadLocks;
101   uint64_t mReadLockSequenceNumber;
102 
103   bool mFinished;
104 };
105 
106 struct AutoEndTransaction {
AutoEndTransactionmozilla::layers::AutoEndTransaction107   explicit AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {}
~AutoEndTransactionmozilla::layers::AutoEndTransaction108   ~AutoEndTransaction() { mTxn->End(); }
109   CompositableTransaction* mTxn;
110 };
111 
UseTextures(CompositableClient * aCompositable,const nsTArray<TimedTextureClient> & aTextures)112 void ImageBridgeChild::UseTextures(
113     CompositableClient* aCompositable,
114     const nsTArray<TimedTextureClient>& aTextures) {
115   MOZ_ASSERT(aCompositable);
116   MOZ_ASSERT(aCompositable->GetIPCHandle());
117   MOZ_ASSERT(aCompositable->IsConnected());
118 
119   AutoTArray<TimedTexture, 4> textures;
120 
121   for (auto& t : aTextures) {
122     MOZ_ASSERT(t.mTextureClient);
123     MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
124 
125     if (!t.mTextureClient->IsSharedWithCompositor()) {
126       return;
127     }
128 
129     bool readLocked = t.mTextureClient->OnForwardedToHost();
130     textures.AppendElement(
131         TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(), t.mTimeStamp,
132                      t.mPictureRect, t.mFrameID, t.mProducerID, readLocked));
133 
134     // Wait end of usage on host side if TextureFlags::RECYCLE is set
135     HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
136   }
137   mTxn->AddNoSwapEdit(CompositableOperation(aCompositable->GetIPCHandle(),
138                                             OpUseTexture(textures)));
139 }
140 
UseComponentAlphaTextures(CompositableClient * aCompositable,TextureClient * aTextureOnBlack,TextureClient * aTextureOnWhite)141 void ImageBridgeChild::UseComponentAlphaTextures(
142     CompositableClient* aCompositable, TextureClient* aTextureOnBlack,
143     TextureClient* aTextureOnWhite) {
144   MOZ_CRASH("should not be called");
145 }
146 
HoldUntilCompositableRefReleasedIfNecessary(TextureClient * aClient)147 void ImageBridgeChild::HoldUntilCompositableRefReleasedIfNecessary(
148     TextureClient* aClient) {
149   // Wait ReleaseCompositableRef only when TextureFlags::RECYCLE is set on
150   // ImageBridge.
151   if (!aClient || !(aClient->GetFlags() & TextureFlags::RECYCLE)) {
152     return;
153   }
154   aClient->SetLastFwdTransactionId(GetFwdTransactionId());
155   mTexturesWaitingRecycled.Put(aClient->GetSerial(), aClient);
156 }
157 
NotifyNotUsed(uint64_t aTextureId,uint64_t aFwdTransactionId)158 void ImageBridgeChild::NotifyNotUsed(uint64_t aTextureId,
159                                      uint64_t aFwdTransactionId) {
160   if (auto entry = mTexturesWaitingRecycled.Lookup(aTextureId)) {
161     if (aFwdTransactionId < entry.Data()->GetLastFwdTransactionId()) {
162       // Released on host side, but client already requested newer use texture.
163       return;
164     }
165     entry.Remove();
166   }
167 }
168 
CancelWaitForRecycle(uint64_t aTextureId)169 void ImageBridgeChild::CancelWaitForRecycle(uint64_t aTextureId) {
170   MOZ_ASSERT(InImageBridgeChildThread());
171   mTexturesWaitingRecycled.Remove(aTextureId);
172 }
173 
174 // Singleton
175 static StaticMutex sImageBridgeSingletonLock;
176 static StaticRefPtr<ImageBridgeChild> sImageBridgeChildSingleton;
177 static Thread* sImageBridgeChildThread = nullptr;
178 
179 // dispatched function
ShutdownStep1(SynchronousTask * aTask)180 void ImageBridgeChild::ShutdownStep1(SynchronousTask* aTask) {
181   AutoCompleteTask complete(aTask);
182 
183   MOZ_ASSERT(InImageBridgeChildThread(),
184              "Should be in ImageBridgeChild thread.");
185 
186   MediaSystemResourceManager::Shutdown();
187 
188   // Force all managed protocols to shut themselves down cleanly
189   InfallibleTArray<PTextureChild*> textures;
190   ManagedPTextureChild(textures);
191   for (int i = textures.Length() - 1; i >= 0; --i) {
192     RefPtr<TextureClient> client = TextureClient::AsTextureClient(textures[i]);
193     if (client) {
194       client->Destroy();
195     }
196   }
197 
198   if (mCanSend) {
199     SendWillClose();
200   }
201   MarkShutDown();
202 
203   // From now on, no message can be sent through the image bridge from the
204   // client side except the final Stop message.
205 }
206 
207 // dispatched function
ShutdownStep2(SynchronousTask * aTask)208 void ImageBridgeChild::ShutdownStep2(SynchronousTask* aTask) {
209   AutoCompleteTask complete(aTask);
210 
211   MOZ_ASSERT(InImageBridgeChildThread(),
212              "Should be in ImageBridgeChild thread.");
213   if (!mDestroyed) {
214     Close();
215   }
216 }
217 
ActorDestroy(ActorDestroyReason aWhy)218 void ImageBridgeChild::ActorDestroy(ActorDestroyReason aWhy) {
219   mCanSend = false;
220   mDestroyed = true;
221   {
222     MutexAutoLock lock(mContainerMapLock);
223     mImageContainerListeners.Clear();
224   }
225 }
226 
DeallocPImageBridgeChild()227 void ImageBridgeChild::DeallocPImageBridgeChild() { this->Release(); }
228 
CreateImageClientSync(SynchronousTask * aTask,RefPtr<ImageClient> * result,CompositableType aType,ImageContainer * aImageContainer)229 void ImageBridgeChild::CreateImageClientSync(SynchronousTask* aTask,
230                                              RefPtr<ImageClient>* result,
231                                              CompositableType aType,
232                                              ImageContainer* aImageContainer) {
233   AutoCompleteTask complete(aTask);
234   *result = CreateImageClientNow(aType, aImageContainer);
235 }
236 
237 // dispatched function
CreateCanvasClientSync(SynchronousTask * aTask,CanvasClient::CanvasClientType aType,TextureFlags aFlags,RefPtr<CanvasClient> * const outResult)238 void ImageBridgeChild::CreateCanvasClientSync(
239     SynchronousTask* aTask, CanvasClient::CanvasClientType aType,
240     TextureFlags aFlags, RefPtr<CanvasClient>* const outResult) {
241   AutoCompleteTask complete(aTask);
242   *outResult = CreateCanvasClientNow(aType, aFlags);
243 }
244 
ImageBridgeChild(uint32_t aNamespace)245 ImageBridgeChild::ImageBridgeChild(uint32_t aNamespace)
246     : mNamespace(aNamespace),
247       mCanSend(false),
248       mDestroyed(false),
249       mFwdTransactionId(0),
250       mContainerMapLock("ImageBridgeChild.mContainerMapLock") {
251   MOZ_ASSERT(mNamespace);
252   MOZ_ASSERT(NS_IsMainThread());
253 
254   mTxn = new CompositableTransaction();
255 }
256 
~ImageBridgeChild()257 ImageBridgeChild::~ImageBridgeChild() { delete mTxn; }
258 
MarkShutDown()259 void ImageBridgeChild::MarkShutDown() {
260   mTexturesWaitingRecycled.Clear();
261 
262   mCanSend = false;
263 }
264 
Connect(CompositableClient * aCompositable,ImageContainer * aImageContainer)265 void ImageBridgeChild::Connect(CompositableClient* aCompositable,
266                                ImageContainer* aImageContainer) {
267   MOZ_ASSERT(aCompositable);
268   MOZ_ASSERT(InImageBridgeChildThread());
269   MOZ_ASSERT(CanSend());
270 
271   // Note: this is static, rather than per-IBC, so IDs are not re-used across
272   // ImageBridgeChild instances. This is relevant for the GPU process, where
273   // we don't want old IDs to potentially leak into a recreated ImageBridge.
274   static uint64_t sNextID = 1;
275   uint64_t id = sNextID++;
276 
277   {
278     MutexAutoLock lock(mContainerMapLock);
279     MOZ_ASSERT(!mImageContainerListeners.Contains(id));
280     mImageContainerListeners.Put(id,
281                                  aImageContainer->GetImageContainerListener());
282   }
283 
284   CompositableHandle handle(id);
285   aCompositable->InitIPDL(handle);
286   SendNewCompositable(handle, aCompositable->GetTextureInfo(),
287                       GetCompositorBackendType());
288 }
289 
ForgetImageContainer(const CompositableHandle & aHandle)290 void ImageBridgeChild::ForgetImageContainer(const CompositableHandle& aHandle) {
291   MutexAutoLock lock(mContainerMapLock);
292   mImageContainerListeners.Remove(aHandle.Value());
293 }
294 
GetThread() const295 Thread* ImageBridgeChild::GetThread() const { return sImageBridgeChildThread; }
296 
GetSingleton()297 /* static */ RefPtr<ImageBridgeChild> ImageBridgeChild::GetSingleton() {
298   StaticMutexAutoLock lock(sImageBridgeSingletonLock);
299   return sImageBridgeChildSingleton;
300 }
301 
UpdateImageClient(RefPtr<ImageContainer> aContainer)302 void ImageBridgeChild::UpdateImageClient(RefPtr<ImageContainer> aContainer) {
303   if (!aContainer) {
304     return;
305   }
306 
307   if (!InImageBridgeChildThread()) {
308     RefPtr<Runnable> runnable =
309         WrapRunnable(RefPtr<ImageBridgeChild>(this),
310                      &ImageBridgeChild::UpdateImageClient, aContainer);
311     GetMessageLoop()->PostTask(runnable.forget());
312     return;
313   }
314 
315   if (!CanSend()) {
316     return;
317   }
318 
319   RefPtr<ImageClient> client = aContainer->GetImageClient();
320   if (NS_WARN_IF(!client)) {
321     return;
322   }
323 
324   // If the client has become disconnected before this event was dispatched,
325   // early return now.
326   if (!client->IsConnected()) {
327     return;
328   }
329 
330   BeginTransaction();
331   client->UpdateImage(aContainer, Layer::CONTENT_OPAQUE);
332   EndTransaction();
333 }
334 
UpdateAsyncCanvasRendererSync(SynchronousTask * aTask,AsyncCanvasRenderer * aWrapper)335 void ImageBridgeChild::UpdateAsyncCanvasRendererSync(
336     SynchronousTask* aTask, AsyncCanvasRenderer* aWrapper) {
337   AutoCompleteTask complete(aTask);
338 
339   UpdateAsyncCanvasRendererNow(aWrapper);
340 }
341 
UpdateAsyncCanvasRenderer(AsyncCanvasRenderer * aWrapper)342 void ImageBridgeChild::UpdateAsyncCanvasRenderer(
343     AsyncCanvasRenderer* aWrapper) {
344   aWrapper->GetCanvasClient()->UpdateAsync(aWrapper);
345 
346   if (InImageBridgeChildThread()) {
347     UpdateAsyncCanvasRendererNow(aWrapper);
348     return;
349   }
350 
351   SynchronousTask task("UpdateAsyncCanvasRenderer Lock");
352 
353   RefPtr<Runnable> runnable = WrapRunnable(
354       RefPtr<ImageBridgeChild>(this),
355       &ImageBridgeChild::UpdateAsyncCanvasRendererSync, &task, aWrapper);
356   GetMessageLoop()->PostTask(runnable.forget());
357 
358   task.Wait();
359 }
360 
UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer * aWrapper)361 void ImageBridgeChild::UpdateAsyncCanvasRendererNow(
362     AsyncCanvasRenderer* aWrapper) {
363   MOZ_ASSERT(aWrapper);
364 
365   if (!CanSend()) {
366     return;
367   }
368 
369   BeginTransaction();
370   aWrapper->GetCanvasClient()->Updated();
371   EndTransaction();
372 }
373 
FlushAllImagesSync(SynchronousTask * aTask,ImageClient * aClient,ImageContainer * aContainer)374 void ImageBridgeChild::FlushAllImagesSync(SynchronousTask* aTask,
375                                           ImageClient* aClient,
376                                           ImageContainer* aContainer) {
377   AutoCompleteTask complete(aTask);
378 
379   if (!CanSend()) {
380     return;
381   }
382 
383   MOZ_ASSERT(aClient);
384   BeginTransaction();
385   if (aContainer) {
386     aContainer->ClearImagesFromImageBridge();
387   }
388   aClient->FlushAllImages();
389   EndTransaction();
390 }
391 
FlushAllImages(ImageClient * aClient,ImageContainer * aContainer)392 void ImageBridgeChild::FlushAllImages(ImageClient* aClient,
393                                       ImageContainer* aContainer) {
394   MOZ_ASSERT(aClient);
395   MOZ_ASSERT(!InImageBridgeChildThread());
396 
397   if (InImageBridgeChildThread()) {
398     NS_ERROR(
399         "ImageBridgeChild::FlushAllImages() is called on ImageBridge thread.");
400     return;
401   }
402 
403   SynchronousTask task("FlushAllImages Lock");
404 
405   // RefPtrs on arguments are not needed since this dispatches synchronously.
406   RefPtr<Runnable> runnable = WrapRunnable(
407       RefPtr<ImageBridgeChild>(this), &ImageBridgeChild::FlushAllImagesSync,
408       &task, aClient, aContainer);
409   GetMessageLoop()->PostTask(runnable.forget());
410 
411   task.Wait();
412 }
413 
BeginTransaction()414 void ImageBridgeChild::BeginTransaction() {
415   MOZ_ASSERT(CanSend());
416   MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?");
417   UpdateFwdTransactionId();
418   mTxn->Begin();
419 }
420 
EndTransaction()421 void ImageBridgeChild::EndTransaction() {
422   MOZ_ASSERT(CanSend());
423   MOZ_ASSERT(!mTxn->Finished(), "forgot BeginTransaction?");
424 
425   AutoEndTransaction _(mTxn);
426 
427   if (mTxn->IsEmpty()) {
428     return;
429   }
430 
431   AutoTArray<CompositableOperation, 10> cset;
432   cset.SetCapacity(mTxn->mOperations.size());
433   if (!mTxn->mOperations.empty()) {
434     cset.AppendElements(&mTxn->mOperations.front(), mTxn->mOperations.size());
435   }
436 
437   if (!IsSameProcess()) {
438     ShadowLayerForwarder::PlatformSyncBeforeUpdate();
439   }
440 
441   for (ReadLockVector& locks : mTxn->mReadLocks) {
442     if (locks.Length()) {
443       if (!SendInitReadLocks(locks)) {
444         NS_WARNING("[LayersForwarder] WARNING: sending read locks failed!");
445         return;
446       }
447     }
448   }
449 
450   if (!SendUpdate(cset, mTxn->mDestroyedActors, GetFwdTransactionId())) {
451     NS_WARNING("could not send async texture transaction");
452     return;
453   }
454 }
455 
SendImageBridgeThreadId()456 void ImageBridgeChild::SendImageBridgeThreadId() {}
457 
InitForContent(Endpoint<PImageBridgeChild> && aEndpoint,uint32_t aNamespace)458 bool ImageBridgeChild::InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint,
459                                       uint32_t aNamespace) {
460   MOZ_ASSERT(NS_IsMainThread());
461 
462   gfxPlatform::GetPlatform();
463 
464   if (!sImageBridgeChildThread) {
465     sImageBridgeChildThread = new Thread("ImageBridgeChild");
466     bool success = sImageBridgeChildThread->Start();
467     MOZ_RELEASE_ASSERT(success, "Failed to start ImageBridgeChild thread!");
468   }
469 
470   RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace);
471 
472   RefPtr<Runnable> runnable = NewRunnableMethod<Endpoint<PImageBridgeChild>&&>(
473       "layers::ImageBridgeChild::Bind", child, &ImageBridgeChild::Bind,
474       Move(aEndpoint));
475   child->GetMessageLoop()->PostTask(runnable.forget());
476 
477   // Assign this after so other threads can't post messages before we connect to
478   // IPDL.
479   {
480     StaticMutexAutoLock lock(sImageBridgeSingletonLock);
481     sImageBridgeChildSingleton = child;
482   }
483 
484   return true;
485 }
486 
ReinitForContent(Endpoint<PImageBridgeChild> && aEndpoint,uint32_t aNamespace)487 bool ImageBridgeChild::ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint,
488                                         uint32_t aNamespace) {
489   MOZ_ASSERT(NS_IsMainThread());
490 
491   // Note that at this point, ActorDestroy may not have been called yet,
492   // meaning mCanSend is still true. In this case we will try to send a
493   // synchronous WillClose message to the parent, and will certainly get a
494   // false result and a MsgDropped processing error. This is okay.
495   ShutdownSingleton();
496 
497   return InitForContent(Move(aEndpoint), aNamespace);
498 }
499 
Bind(Endpoint<PImageBridgeChild> && aEndpoint)500 void ImageBridgeChild::Bind(Endpoint<PImageBridgeChild>&& aEndpoint) {
501   if (!aEndpoint.Bind(this)) {
502     return;
503   }
504 
505   // This reference is dropped in DeallocPImageBridgeChild.
506   this->AddRef();
507 
508   mCanSend = true;
509   SendImageBridgeThreadId();
510 }
511 
BindSameProcess(RefPtr<ImageBridgeParent> aParent)512 void ImageBridgeChild::BindSameProcess(RefPtr<ImageBridgeParent> aParent) {
513   MessageLoop* parentMsgLoop = aParent->GetMessageLoop();
514   ipc::MessageChannel* parentChannel = aParent->GetIPCChannel();
515   Open(parentChannel, parentMsgLoop, mozilla::ipc::ChildSide);
516 
517   // This reference is dropped in DeallocPImageBridgeChild.
518   this->AddRef();
519 
520   mCanSend = true;
521   SendImageBridgeThreadId();
522 }
523 
ShutDown()524 /* static */ void ImageBridgeChild::ShutDown() {
525   MOZ_ASSERT(NS_IsMainThread());
526 
527   ShutdownSingleton();
528 
529   delete sImageBridgeChildThread;
530   sImageBridgeChildThread = nullptr;
531 }
532 
ShutdownSingleton()533 /* static */ void ImageBridgeChild::ShutdownSingleton() {
534   MOZ_ASSERT(NS_IsMainThread());
535 
536   if (RefPtr<ImageBridgeChild> child = GetSingleton()) {
537     child->WillShutdown();
538 
539     StaticMutexAutoLock lock(sImageBridgeSingletonLock);
540     sImageBridgeChildSingleton = nullptr;
541   }
542 }
543 
WillShutdown()544 void ImageBridgeChild::WillShutdown() {
545   {
546     SynchronousTask task("ImageBridge ShutdownStep1 lock");
547 
548     RefPtr<Runnable> runnable =
549         WrapRunnable(RefPtr<ImageBridgeChild>(this),
550                      &ImageBridgeChild::ShutdownStep1, &task);
551     GetMessageLoop()->PostTask(runnable.forget());
552 
553     task.Wait();
554   }
555 
556   {
557     SynchronousTask task("ImageBridge ShutdownStep2 lock");
558 
559     RefPtr<Runnable> runnable =
560         WrapRunnable(RefPtr<ImageBridgeChild>(this),
561                      &ImageBridgeChild::ShutdownStep2, &task);
562     GetMessageLoop()->PostTask(runnable.forget());
563 
564     task.Wait();
565   }
566 }
567 
InitSameProcess(uint32_t aNamespace)568 void ImageBridgeChild::InitSameProcess(uint32_t aNamespace) {
569   NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
570 
571   MOZ_ASSERT(!sImageBridgeChildSingleton);
572   MOZ_ASSERT(!sImageBridgeChildThread);
573 
574   sImageBridgeChildThread = new Thread("ImageBridgeChild");
575   if (!sImageBridgeChildThread->IsRunning()) {
576     sImageBridgeChildThread->Start();
577   }
578 
579   RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace);
580   RefPtr<ImageBridgeParent> parent = ImageBridgeParent::CreateSameProcess();
581 
582   RefPtr<Runnable> runnable =
583       WrapRunnable(child, &ImageBridgeChild::BindSameProcess, parent);
584   child->GetMessageLoop()->PostTask(runnable.forget());
585 
586   // Assign this after so other threads can't post messages before we connect to
587   // IPDL.
588   {
589     StaticMutexAutoLock lock(sImageBridgeSingletonLock);
590     sImageBridgeChildSingleton = child;
591   }
592 }
593 
InitWithGPUProcess(Endpoint<PImageBridgeChild> && aEndpoint,uint32_t aNamespace)594 /* static */ void ImageBridgeChild::InitWithGPUProcess(
595     Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace) {
596   MOZ_ASSERT(NS_IsMainThread());
597   MOZ_ASSERT(!sImageBridgeChildSingleton);
598   MOZ_ASSERT(!sImageBridgeChildThread);
599 
600   sImageBridgeChildThread = new Thread("ImageBridgeChild");
601   if (!sImageBridgeChildThread->IsRunning()) {
602     sImageBridgeChildThread->Start();
603   }
604 
605   RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace);
606 
607   MessageLoop* loop = child->GetMessageLoop();
608   loop->PostTask(NewRunnableMethod<Endpoint<PImageBridgeChild>&&>(
609       "layers::ImageBridgeChild::Bind", child, &ImageBridgeChild::Bind,
610       Move(aEndpoint)));
611 
612   // Assign this after so other threads can't post messages before we connect to
613   // IPDL.
614   {
615     StaticMutexAutoLock lock(sImageBridgeSingletonLock);
616     sImageBridgeChildSingleton = child;
617   }
618 }
619 
InImageBridgeChildThread()620 bool InImageBridgeChildThread() {
621   return sImageBridgeChildThread &&
622          sImageBridgeChildThread->thread_id() == PlatformThread::CurrentId();
623 }
624 
GetMessageLoop() const625 MessageLoop* ImageBridgeChild::GetMessageLoop() const {
626   return sImageBridgeChildThread ? sImageBridgeChildThread->message_loop()
627                                  : nullptr;
628 }
629 
IdentifyCompositorTextureHost(const TextureFactoryIdentifier & aIdentifier)630 /* static */ void ImageBridgeChild::IdentifyCompositorTextureHost(
631     const TextureFactoryIdentifier& aIdentifier) {
632   if (RefPtr<ImageBridgeChild> child = GetSingleton()) {
633     child->UpdateTextureFactoryIdentifier(aIdentifier);
634   }
635 }
636 
UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier & aIdentifier)637 void ImageBridgeChild::UpdateTextureFactoryIdentifier(
638     const TextureFactoryIdentifier& aIdentifier) {
639   bool disablingWebRender =
640       GetCompositorBackendType() == LayersBackend::LAYERS_WR &&
641       aIdentifier.mParentBackend != LayersBackend::LAYERS_WR;
642   IdentifyTextureHost(aIdentifier);
643   if (disablingWebRender) {
644     // ImageHost is incompatible between WebRender enabled and WebRender
645     // disabled. Then drop all ImageContainers' ImageClients during disabling
646     // WebRender.
647     nsTArray<RefPtr<ImageContainerListener> > listeners;
648     {
649       MutexAutoLock lock(mContainerMapLock);
650       for (auto iter = mImageContainerListeners.Iter(); !iter.Done();
651            iter.Next()) {
652         RefPtr<ImageContainerListener>& listener = iter.Data();
653         listeners.AppendElement(listener);
654       }
655     }
656     // Drop ImageContainer's ImageClient whithout holding mContainerMapLock to
657     // avoid deadlock.
658     for (auto container : listeners) {
659       container->DropImageClient();
660     }
661   }
662 }
663 
CreateImageClient(CompositableType aType,ImageContainer * aImageContainer)664 RefPtr<ImageClient> ImageBridgeChild::CreateImageClient(
665     CompositableType aType, ImageContainer* aImageContainer) {
666   if (InImageBridgeChildThread()) {
667     return CreateImageClientNow(aType, aImageContainer);
668   }
669 
670   SynchronousTask task("CreateImageClient Lock");
671 
672   RefPtr<ImageClient> result = nullptr;
673 
674   RefPtr<Runnable> runnable = WrapRunnable(
675       RefPtr<ImageBridgeChild>(this), &ImageBridgeChild::CreateImageClientSync,
676       &task, &result, aType, aImageContainer);
677   GetMessageLoop()->PostTask(runnable.forget());
678 
679   task.Wait();
680 
681   return result;
682 }
683 
CreateImageClientNow(CompositableType aType,ImageContainer * aImageContainer)684 RefPtr<ImageClient> ImageBridgeChild::CreateImageClientNow(
685     CompositableType aType, ImageContainer* aImageContainer) {
686   MOZ_ASSERT(InImageBridgeChildThread());
687   if (!CanSend()) {
688     return nullptr;
689   }
690 
691   RefPtr<ImageClient> client =
692       ImageClient::CreateImageClient(aType, this, TextureFlags::NO_FLAGS);
693   MOZ_ASSERT(client, "failed to create ImageClient");
694   if (client) {
695     client->Connect(aImageContainer);
696   }
697   return client;
698 }
699 
CreateCanvasClient(CanvasClient::CanvasClientType aType,TextureFlags aFlag)700 already_AddRefed<CanvasClient> ImageBridgeChild::CreateCanvasClient(
701     CanvasClient::CanvasClientType aType, TextureFlags aFlag) {
702   if (InImageBridgeChildThread()) {
703     return CreateCanvasClientNow(aType, aFlag);
704   }
705 
706   SynchronousTask task("CreateCanvasClient Lock");
707 
708   // RefPtrs on arguments are not needed since this dispatches synchronously.
709   RefPtr<CanvasClient> result = nullptr;
710   RefPtr<Runnable> runnable = WrapRunnable(
711       RefPtr<ImageBridgeChild>(this), &ImageBridgeChild::CreateCanvasClientSync,
712       &task, aType, aFlag, &result);
713   GetMessageLoop()->PostTask(runnable.forget());
714 
715   task.Wait();
716 
717   return result.forget();
718 }
719 
CreateCanvasClientNow(CanvasClient::CanvasClientType aType,TextureFlags aFlag)720 already_AddRefed<CanvasClient> ImageBridgeChild::CreateCanvasClientNow(
721     CanvasClient::CanvasClientType aType, TextureFlags aFlag) {
722   RefPtr<CanvasClient> client =
723       CanvasClient::CreateCanvasClient(aType, this, aFlag);
724   MOZ_ASSERT(client, "failed to create CanvasClient");
725   if (client) {
726     client->Connect();
727   }
728   return client.forget();
729 }
730 
AllocUnsafeShmem(size_t aSize,ipc::SharedMemory::SharedMemoryType aType,ipc::Shmem * aShmem)731 bool ImageBridgeChild::AllocUnsafeShmem(
732     size_t aSize, ipc::SharedMemory::SharedMemoryType aType,
733     ipc::Shmem* aShmem) {
734   if (!InImageBridgeChildThread()) {
735     return DispatchAllocShmemInternal(aSize, aType, aShmem,
736                                       true);  // true: unsafe
737   }
738 
739   if (!CanSend()) {
740     return false;
741   }
742   return PImageBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem);
743 }
744 
AllocShmem(size_t aSize,ipc::SharedMemory::SharedMemoryType aType,ipc::Shmem * aShmem)745 bool ImageBridgeChild::AllocShmem(size_t aSize,
746                                   ipc::SharedMemory::SharedMemoryType aType,
747                                   ipc::Shmem* aShmem) {
748   if (!InImageBridgeChildThread()) {
749     return DispatchAllocShmemInternal(aSize, aType, aShmem,
750                                       false);  // false: unsafe
751   }
752 
753   if (!CanSend()) {
754     return false;
755   }
756   return PImageBridgeChild::AllocShmem(aSize, aType, aShmem);
757 }
758 
759 // NewRunnableFunction accepts a limited number of parameters so we need a
760 // struct here
761 struct AllocShmemParams {
762   size_t mSize;
763   ipc::SharedMemory::SharedMemoryType mType;
764   ipc::Shmem* mShmem;
765   bool mUnsafe;
766   bool mSuccess;
767 };
768 
ProxyAllocShmemNow(SynchronousTask * aTask,AllocShmemParams * aParams)769 void ImageBridgeChild::ProxyAllocShmemNow(SynchronousTask* aTask,
770                                           AllocShmemParams* aParams) {
771   AutoCompleteTask complete(aTask);
772 
773   if (!CanSend()) {
774     return;
775   }
776 
777   bool ok = false;
778   if (aParams->mUnsafe) {
779     ok = AllocUnsafeShmem(aParams->mSize, aParams->mType, aParams->mShmem);
780   } else {
781     ok = AllocShmem(aParams->mSize, aParams->mType, aParams->mShmem);
782   }
783   aParams->mSuccess = ok;
784 }
785 
DispatchAllocShmemInternal(size_t aSize,SharedMemory::SharedMemoryType aType,ipc::Shmem * aShmem,bool aUnsafe)786 bool ImageBridgeChild::DispatchAllocShmemInternal(
787     size_t aSize, SharedMemory::SharedMemoryType aType, ipc::Shmem* aShmem,
788     bool aUnsafe) {
789   SynchronousTask task("AllocatorProxy alloc");
790 
791   AllocShmemParams params = {aSize, aType, aShmem, aUnsafe, false};
792 
793   RefPtr<Runnable> runnable =
794       WrapRunnable(RefPtr<ImageBridgeChild>(this),
795                    &ImageBridgeChild::ProxyAllocShmemNow, &task, &params);
796   GetMessageLoop()->PostTask(runnable.forget());
797 
798   task.Wait();
799 
800   return params.mSuccess;
801 }
802 
ProxyDeallocShmemNow(SynchronousTask * aTask,ipc::Shmem * aShmem,bool * aResult)803 void ImageBridgeChild::ProxyDeallocShmemNow(SynchronousTask* aTask,
804                                             ipc::Shmem* aShmem, bool* aResult) {
805   AutoCompleteTask complete(aTask);
806 
807   if (!CanSend()) {
808     return;
809   }
810   *aResult = DeallocShmem(*aShmem);
811 }
812 
DeallocShmem(ipc::Shmem & aShmem)813 bool ImageBridgeChild::DeallocShmem(ipc::Shmem& aShmem) {
814   if (InImageBridgeChildThread()) {
815     if (!CanSend()) {
816       return false;
817     }
818     return PImageBridgeChild::DeallocShmem(aShmem);
819   }
820 
821   // If we can't post a task, then we definitely cannot send, so there's
822   // no reason to queue up this send.
823   if (!CanPostTask()) {
824     return false;
825   }
826 
827   SynchronousTask task("AllocatorProxy Dealloc");
828   bool result = false;
829 
830   RefPtr<Runnable> runnable = WrapRunnable(
831       RefPtr<ImageBridgeChild>(this), &ImageBridgeChild::ProxyDeallocShmemNow,
832       &task, &aShmem, &result);
833   GetMessageLoop()->PostTask(runnable.forget());
834 
835   task.Wait();
836   return result;
837 }
838 
AllocPTextureChild(const SurfaceDescriptor &,const ReadLockDescriptor &,const LayersBackend &,const TextureFlags &,const uint64_t & aSerial,const wr::MaybeExternalImageId & aExternalImageId)839 PTextureChild* ImageBridgeChild::AllocPTextureChild(
840     const SurfaceDescriptor&, const ReadLockDescriptor&, const LayersBackend&,
841     const TextureFlags&, const uint64_t& aSerial,
842     const wr::MaybeExternalImageId& aExternalImageId) {
843   MOZ_ASSERT(CanSend());
844   return TextureClient::CreateIPDLActor();
845 }
846 
DeallocPTextureChild(PTextureChild * actor)847 bool ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor) {
848   return TextureClient::DestroyIPDLActor(actor);
849 }
850 
851 PMediaSystemResourceManagerChild*
AllocPMediaSystemResourceManagerChild()852 ImageBridgeChild::AllocPMediaSystemResourceManagerChild() {
853   MOZ_ASSERT(CanSend());
854   return new mozilla::media::MediaSystemResourceManagerChild();
855 }
856 
DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild * aActor)857 bool ImageBridgeChild::DeallocPMediaSystemResourceManagerChild(
858     PMediaSystemResourceManagerChild* aActor) {
859   MOZ_ASSERT(aActor);
860   delete static_cast<mozilla::media::MediaSystemResourceManagerChild*>(aActor);
861   return true;
862 }
863 
RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData> && aMessages)864 mozilla::ipc::IPCResult ImageBridgeChild::RecvParentAsyncMessages(
865     InfallibleTArray<AsyncParentMessageData>&& aMessages) {
866   for (AsyncParentMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
867     const AsyncParentMessageData& message = aMessages[i];
868 
869     switch (message.type()) {
870       case AsyncParentMessageData::TOpNotifyNotUsed: {
871         const OpNotifyNotUsed& op = message.get_OpNotifyNotUsed();
872         NotifyNotUsed(op.TextureId(), op.fwdTransactionId());
873         break;
874       }
875       default:
876         NS_ERROR("unknown AsyncParentMessageData type");
877         return IPC_FAIL_NO_REASON(this);
878     }
879   }
880   return IPC_OK();
881 }
882 
RecvDidComposite(InfallibleTArray<ImageCompositeNotification> && aNotifications)883 mozilla::ipc::IPCResult ImageBridgeChild::RecvDidComposite(
884     InfallibleTArray<ImageCompositeNotification>&& aNotifications) {
885   for (auto& n : aNotifications) {
886     RefPtr<ImageContainerListener> listener;
887     {
888       MutexAutoLock lock(mContainerMapLock);
889       if (auto entry =
890               mImageContainerListeners.Lookup(n.compositable().Value())) {
891         listener = entry.Data();
892       }
893     }
894     if (listener) {
895       listener->NotifyComposite(n);
896     }
897   }
898   return IPC_OK();
899 }
900 
CreateTexture(const SurfaceDescriptor & aSharedData,const ReadLockDescriptor & aReadLock,LayersBackend aLayersBackend,TextureFlags aFlags,uint64_t aSerial,wr::MaybeExternalImageId & aExternalImageId,nsIEventTarget * aTarget)901 PTextureChild* ImageBridgeChild::CreateTexture(
902     const SurfaceDescriptor& aSharedData, const ReadLockDescriptor& aReadLock,
903     LayersBackend aLayersBackend, TextureFlags aFlags, uint64_t aSerial,
904     wr::MaybeExternalImageId& aExternalImageId, nsIEventTarget* aTarget) {
905   MOZ_ASSERT(CanSend());
906   return SendPTextureConstructor(aSharedData, aReadLock, aLayersBackend, aFlags,
907                                  aSerial, aExternalImageId);
908 }
909 
IBCAddOpDestroy(CompositableTransaction * aTxn,const OpDestroy & op)910 static bool IBCAddOpDestroy(CompositableTransaction* aTxn,
911                             const OpDestroy& op) {
912   if (aTxn->Finished()) {
913     return false;
914   }
915 
916   aTxn->mDestroyedActors.AppendElement(op);
917   return true;
918 }
919 
DestroyInTransaction(PTextureChild * aTexture)920 bool ImageBridgeChild::DestroyInTransaction(PTextureChild* aTexture) {
921   return IBCAddOpDestroy(mTxn, OpDestroy(aTexture));
922 }
923 
DestroyInTransaction(const CompositableHandle & aHandle)924 bool ImageBridgeChild::DestroyInTransaction(const CompositableHandle& aHandle) {
925   return IBCAddOpDestroy(mTxn, OpDestroy(aHandle));
926 }
927 
RemoveTextureFromCompositable(CompositableClient * aCompositable,TextureClient * aTexture)928 void ImageBridgeChild::RemoveTextureFromCompositable(
929     CompositableClient* aCompositable, TextureClient* aTexture) {
930   MOZ_ASSERT(CanSend());
931   MOZ_ASSERT(aTexture);
932   MOZ_ASSERT(aTexture->IsSharedWithCompositor());
933   MOZ_ASSERT(aCompositable->IsConnected());
934   if (!aTexture || !aTexture->IsSharedWithCompositor() ||
935       !aCompositable->IsConnected()) {
936     return;
937   }
938 
939   mTxn->AddNoSwapEdit(CompositableOperation(
940       aCompositable->GetIPCHandle(),
941       OpRemoveTexture(nullptr, aTexture->GetIPDLActor())));
942 }
943 
IsSameProcess() const944 bool ImageBridgeChild::IsSameProcess() const {
945   return OtherPid() == base::GetCurrentProcId();
946 }
947 
CanPostTask() const948 bool ImageBridgeChild::CanPostTask() const {
949   // During shutdown, the cycle collector may free objects that are holding a
950   // reference to ImageBridgeChild. Since this happens on the main thread,
951   // ImageBridgeChild will attempt to post a task to the ImageBridge thread.
952   // However the thread manager has already been shut down, so the task cannot
953   // post.
954   //
955   // It's okay if this races. We only care about the shutdown case where
956   // everything's happening on the main thread. Even if it races outside of
957   // shutdown, it's still harmless to post the task, since the task must
958   // check CanSend().
959   return !mDestroyed;
960 }
961 
ReleaseCompositable(const CompositableHandle & aHandle)962 void ImageBridgeChild::ReleaseCompositable(const CompositableHandle& aHandle) {
963   if (!InImageBridgeChildThread()) {
964     // If we can't post a task, then we definitely cannot send, so there's
965     // no reason to queue up this send.
966     if (!CanPostTask()) {
967       return;
968     }
969 
970     RefPtr<Runnable> runnable =
971         WrapRunnable(RefPtr<ImageBridgeChild>(this),
972                      &ImageBridgeChild::ReleaseCompositable, aHandle);
973     GetMessageLoop()->PostTask(runnable.forget());
974     return;
975   }
976 
977   if (!CanSend()) {
978     return;
979   }
980 
981   if (!DestroyInTransaction(aHandle)) {
982     SendReleaseCompositable(aHandle);
983   }
984 
985   {
986     MutexAutoLock lock(mContainerMapLock);
987     mImageContainerListeners.Remove(aHandle.Value());
988   }
989 }
990 
CanSend() const991 bool ImageBridgeChild::CanSend() const {
992   MOZ_ASSERT(InImageBridgeChildThread());
993   return mCanSend;
994 }
995 
HandleFatalError(const char * aName,const char * aMsg) const996 void ImageBridgeChild::HandleFatalError(const char* aName,
997                                         const char* aMsg) const {
998   dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
999 }
1000 
GetNextExternalImageId()1001 wr::MaybeExternalImageId ImageBridgeChild::GetNextExternalImageId() {
1002   static uint32_t sNextID = 1;
1003   ++sNextID;
1004   MOZ_RELEASE_ASSERT(sNextID != UINT32_MAX);
1005 
1006   uint64_t imageId = mNamespace;
1007   imageId = imageId << 32 | sNextID;
1008   return Some(wr::ToExternalImageId(imageId));
1009 }
1010 
1011 }  // namespace layers
1012 }  // namespace mozilla
1013