Verified Commit 9c9ae74b authored by Jamie Nicol's avatar Jamie Nicol Committed by ma1
Browse files

Bug 2048345 - Make RemoteSurfaceAllocator ensure that surfaces are owned by...

Bug 2048345 - Make RemoteSurfaceAllocator ensure that surfaces are owned by the calling client.  a=pascalc

Original Revision: https://phabricator.services.mozilla.com/D308282

Differential Revision: https://phabricator.services.mozilla.com/D308986
parent 3922d26b
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ import org.mozilla.gecko.gfx.ISurfaceAllocator;
import org.mozilla.gecko.process.IProcessManager;

import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;

interface IChildProcess {
@@ -39,6 +40,9 @@ interface IChildProcess {
     * consumed by the GPU process. Must only be called for a GPU child process type.
     * @param allocatorId A unique ID used to identify the GPU process instance the allocator
     *     belongs to.
     * @param client An IBinder identifying the process connecting to the surface allocator. For
     *     content processes this will have been passed from the content process through the parent,
     *     and finally to the GPU process here.
     */
    ISurfaceAllocator getSurfaceAllocator(int allocatorId);
    ISurfaceAllocator getSurfaceAllocator(int allocatorId, in IBinder client);
}
+3 −1
Original line number Diff line number Diff line
@@ -7,8 +7,10 @@ package org.mozilla.gecko.process;
import org.mozilla.gecko.IGeckoEditableChild;
import org.mozilla.gecko.gfx.ISurfaceAllocator;

import android.os.IBinder;

interface IProcessManager {
    void getEditableParent(in IGeckoEditableChild child, long contentId, long tabId);
    // Returns the interface that child processes should use to allocate Surfaces.
    ISurfaceAllocator getSurfaceAllocator();
    ISurfaceAllocator getSurfaceAllocator(in IBinder client);
}
+61 −14
Original line number Diff line number Diff line
@@ -5,39 +5,60 @@

package org.mozilla.gecko.gfx;

import android.os.IBinder;
import android.os.RemoteException;
import android.util.LongSparseArray;
import java.util.concurrent.atomic.AtomicInteger;
import org.mozilla.gecko.GeckoThread;

public final class RemoteSurfaceAllocator extends ISurfaceAllocator.Stub {
public final class RemoteSurfaceAllocator extends ISurfaceAllocator.Stub
    implements IBinder.DeathRecipient {
  private static final String LOGTAG = "RemoteSurfaceAllocator";

  private static RemoteSurfaceAllocator mInstance;

  /// Unique ID identifying the process this instance belongs to, which must be 0 for the parent
  /// process. This is used so that following a GPU process shutdown, surface handles allocated by
  /// the new compositor process (either a new GPU process, or the parent process) do not clash with
  /// surface handles allocated by a previous GPU process.
  private final int mAllocatorId;
  /// Monotonically increasing counter used to generate unique handles
  /// for each SurfaceTexture by combining with mAllocatorId.
  private static AtomicInteger sNextHandle = new AtomicInteger(1);

  ///  List of Surface handles owned by this instance.
  private final LongSparseArray<Boolean> mOwnedHandles = new LongSparseArray<Boolean>();
  ///  Whether the client is still connected to this allocator.
  private boolean mClientConnected = true;

  /**
   * Retrieves the singleton allocator instance for this process.
   * Retrieves the allocator instance for the provided client.
   *
   * @param allocatorId A unique ID identifying the process this instance belongs to, which must be
   *     0 for the parent process instance.
   *     0 for a parent process instance.
   * @param client An IBinder identifying the process for which we will be allocating surfaces.
   */
  public static synchronized RemoteSurfaceAllocator getInstance(final int allocatorId) {
    if (mInstance == null && GeckoThread.isStateAtLeast(GeckoThread.State.JNI_READY)) {
      mInstance = new RemoteSurfaceAllocator(allocatorId);
  public static RemoteSurfaceAllocator create(final int allocatorId, final IBinder client) {
    if (GeckoThread.isStateAtLeast(GeckoThread.State.JNI_READY)) {
      try {
        return new RemoteSurfaceAllocator(allocatorId, client);
      } catch (final RemoteException ignored) {
      }
    return mInstance;
    }
    return null;
  }

  private RemoteSurfaceAllocator(final int allocatorId) {
  private RemoteSurfaceAllocator(final int allocatorId, final IBinder client)
      throws RemoteException {
    mAllocatorId = allocatorId;
    client.linkToDeath(this, 0);
  }

  @Override
  public GeckoSurface acquireSurface(
  public synchronized GeckoSurface acquireSurface(
      final int width, final int height, final boolean singleBufferMode) {
    if (!mClientConnected) {
      return null;
    }

    final long handle = ((long) mAllocatorId << 32) | sNextHandle.getAndIncrement();
    final GeckoSurfaceTexture gst = GeckoSurfaceTexture.acquire(singleBufferMode, handle);

@@ -49,11 +70,15 @@ public final class RemoteSurfaceAllocator extends ISurfaceAllocator.Stub {
      gst.setDefaultBufferSize(width, height);
    }

    mOwnedHandles.put(handle, true);
    return new GeckoSurface(gst);
  }

  @Override
  public void releaseSurface(final long handle) {
  public synchronized void releaseSurface(final long handle) {
    ensureOwned(handle);
    mOwnedHandles.remove(handle);

    final GeckoSurfaceTexture gst = GeckoSurfaceTexture.lookup(handle);
    if (gst != null) {
      gst.decrementUse();
@@ -61,7 +86,9 @@ public final class RemoteSurfaceAllocator extends ISurfaceAllocator.Stub {
  }

  @Override
  public void configureSync(final SyncConfig config) {
  public synchronized void configureSync(final SyncConfig config) {
    ensureOwned(config.sourceTextureHandle);

    final GeckoSurfaceTexture gst = GeckoSurfaceTexture.lookup(config.sourceTextureHandle);
    if (gst != null) {
      gst.configureSnapshot(config.targetSurface, config.width, config.height);
@@ -69,10 +96,30 @@ public final class RemoteSurfaceAllocator extends ISurfaceAllocator.Stub {
  }

  @Override
  public void sync(final long handle) {
  public synchronized void sync(final long handle) {
    ensureOwned(handle);

    final GeckoSurfaceTexture gst = GeckoSurfaceTexture.lookup(handle);
    if (gst != null) {
      gst.takeSnapshot();
    }
  }

  @Override
  public synchronized void binderDied() {
    mClientConnected = false;
    for (int i = 0; i < mOwnedHandles.size(); i++) {
      final GeckoSurfaceTexture gst = GeckoSurfaceTexture.lookup(mOwnedHandles.keyAt(i));
      if (gst != null) {
        gst.decrementUse();
      }
    }
    mOwnedHandles.clear();
  }

  private void ensureOwned(final long handle) {
    if (mOwnedHandles.indexOfKey(handle) < 0) {
      throw new SecurityException("Surface handle is not owned by this allocator session");
    }
  }
}
+4 −2
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@

package org.mozilla.gecko.gfx;

import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -18,6 +19,7 @@ import org.mozilla.gecko.process.GeckoServiceChildProcess;
  private static final String LOGTAG = "SurfaceAllocator";

  private static ISurfaceAllocator sAllocator;
  private static final IBinder sClient = new Binder();

  // Keep a reference to all allocated Surfaces, so that we can release them if we lose the
  // connection to the allocator service.
@@ -31,9 +33,9 @@ import org.mozilla.gecko.process.GeckoServiceChildProcess;

    try {
      if (GeckoAppShell.isParentProcess()) {
        sAllocator = GeckoProcessManager.getInstance().getSurfaceAllocator();
        sAllocator = GeckoProcessManager.getInstance().getSurfaceAllocator(sClient);
      } else {
        sAllocator = GeckoServiceChildProcess.getSurfaceAllocator();
        sAllocator = GeckoServiceChildProcess.getSurfaceAllocator(sClient);
      }

      if (sAllocator == null) {
+12 −12
Original line number Diff line number Diff line
@@ -67,11 +67,12 @@ public final class GeckoProcessManager extends IProcessManager.Stub {
  }

  /**
   * Returns the surface allocator interface to be used by child processes to allocate Surfaces. The
   * service bound to the returned interface may live in either the GPU process or parent process.
   * Returns the surface allocator interface to be used by the client process to allocate Surfaces.
   * The service bound to the returned interface may live in either the GPU process or parent
   * process.
   */
  @Override // IProcessManager
  public ISurfaceAllocator getSurfaceAllocator() {
  public ISurfaceAllocator getSurfaceAllocator(final IBinder client) {
    final boolean gpuEnabled = GeckoAppShell.isGpuProcessEnabled();

    try {
@@ -84,19 +85,19 @@ public final class GeckoProcessManager extends IProcessManager.Stub {
              final GpuProcessConnection conn =
                  (GpuProcessConnection) INSTANCE.mConnections.getExistingConnection(selector);
              if (conn != null) {
                allocator.complete(conn.getSurfaceAllocator());
                allocator.complete(conn.getSurfaceAllocator(client));
              } else {
                // If we cannot find a GPU process, it has probably been killed and not yet
                // restarted. Return null here, and allow the caller to try again later.
                // We definitely do *not* want to return the parent process allocator instead, as
                // We definitely do *not* want to return a parent process allocator instead, as
                // that will result in surfaces being allocated in the parent process, which
                // therefore won't be usable when the GPU process is eventually launched.
                allocator.complete(null);
              }
            });
      } else {
        // The GPU process is disabled, so return the parent process allocator instance.
        allocator.complete(RemoteSurfaceAllocator.getInstance(0));
        // The GPU process is disabled, so return a parent process allocator instance.
        allocator.complete(RemoteSurfaceAllocator.create(0, client));
      }
      return allocator.poll(100);
    } catch (final Throwable e) {
@@ -323,7 +324,6 @@ public final class GeckoProcessManager extends IProcessManager.Stub {

  private static final class GpuProcessConnection extends NonContentConnection {
    private CompositorSurfaceManager mCompositorSurfaceManager;
    private ISurfaceAllocator mSurfaceAllocator;

    // Unique ID used to identify each GPU process instance. Will always be non-zero,
    // and unlike the process' pid cannot be the same value for successive instances.
@@ -353,14 +353,14 @@ public final class GeckoProcessManager extends IProcessManager.Stub {
      return mCompositorSurfaceManager;
    }

    public ISurfaceAllocator getSurfaceAllocator() {
      if (mSurfaceAllocator == null && getChild() != null) {
    public ISurfaceAllocator getSurfaceAllocator(final IBinder client) {
      if (getChild() != null) {
        try {
          mSurfaceAllocator = getChild().getSurfaceAllocator(mUniqueGpuProcessId);
          return getChild().getSurfaceAllocator(mUniqueGpuProcessId, client);
        } catch (final RemoteException ignored) {
        }
      }
      return mSurfaceAllocator;
      return null;
    }
  }

Loading