Bug 1755381 - Manually connect surface allocators when rendering is (re)initialized. r=agi,aosmond

Rather than lazily attempting to connect the SurfaceAllocator if
required whenever the content process tries to allocate a surface,
instead give control over the connection to the parent process. Make
it connect after the content process has been created, and
additionally after rendering has being reinitialized following a GPU
process loss. This aligns with how we reconnect various IPDL protocols
between content processes and the compositor.

This avoids content processes attempting to connect to the GPU
process' surface allocator before it has been started, which is
important for the next patch in this series where we want to delay
restarting the GPU process if the app is in the background.

If the content process attempts to allocate a surface inbetween the
old connection dying and the new connection being made then it will
gracefully fail. If the GPU process dies again whilst the connection
is being made then that is okay, a new connection will be made shortly
afterwards.

Differential Revision: https://phabricator.services.mozilla.com/D139041
This commit is contained in:
Jamie Nicol 2022-02-18 13:38:27 +00:00
Родитель 1b7cfb0901
Коммит b78abc197a
8 изменённых файлов: 104 добавлений и 67 удалений

Просмотреть файл

@ -48,6 +48,7 @@
#include "SandboxHal.h"
#include "SourceSurfaceRawData.h"
#include "mozilla/ipc/URIUtils.h"
#include "gfxConfig.h"
#include "gfxPlatform.h"
#include "gfxPlatformFontList.h"
#include "mozilla/AutoRestore.h"
@ -3053,6 +3054,8 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) {
std::move(vrBridge), std::move(videoManager),
namespaces);
InitSurfaceAllocator();
gpm->AddListener(this);
nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
@ -3225,6 +3228,28 @@ void ContentParent::OnCompositorUnexpectedShutdown() {
Unused << SendReinitRendering(std::move(compositor), std::move(imageBridge),
std::move(vrBridge), std::move(videoManager),
namespaces);
InitSurfaceAllocator();
}
void ContentParent::InitSurfaceAllocator() {
#ifdef MOZ_WIDGET_ANDROID
nsCOMPtr<nsIEventTarget> launcherThread(GetIPCLauncher());
MOZ_ASSERT(launcherThread);
auto selector = java::GeckoProcessManager::Selector::New(
java::GeckoProcessType::CONTENT(), OtherPid());
bool gpuProcessEnabled = gfx::gfxConfig::IsEnabled(gfx::Feature::GPU_PROCESS);
launcherThread->Dispatch(NS_NewRunnableFunction(
"ContentParent::InitSurfaceAllocator()",
[selector = java::GeckoProcessManager::Selector::GlobalRef(selector),
gpuProcessEnabled]() {
java::GeckoProcessManager::SetChildProcessSurfaceAllocator(
selector, gpuProcessEnabled);
}));
#endif
}
void ContentParent::OnCompositorDeviceReset() {

Просмотреть файл

@ -722,6 +722,11 @@ class ContentParent final
void OnVarChanged(const GfxVarUpdate& aVar) override;
void OnCompositorUnexpectedShutdown() override;
// Sets the SurfaceAllocator the content process should use to allocate
// Surfaces on Android. Ideally this should be done in (Re)InitRendering,
// but unfortunately we must go via Java and AIDL rather than IPDL.
void InitSurfaceAllocator();
private:
/**
* A map of the remote content process type to a list of content parents

Просмотреть файл

@ -42,5 +42,12 @@ interface IChildProcess {
* Returns the interface that other processes should use to allocate Surfaces to be
* consumed by the GPU process. Must only be called for a GPU child process type.
*/
ISurfaceAllocator getSurfaceAllocator();
ISurfaceAllocator getSurfaceAllocatorFromGpuProcess();
/**
* Connects the child process' SurfaceAllocator to the specified RemoteSurfaceAllocator.
* Must be called after creating the child process and after rendering has been reinitialized
* following the GPU process being killed, to allow the child process to allocate Surfaces.
*/
oneway void setSurfaceAllocator(in ISurfaceAllocator surfaceAllocator);
}

Просмотреть файл

@ -9,6 +9,4 @@ import org.mozilla.gecko.gfx.ISurfaceAllocator;
interface IProcessManager {
void getEditableParent(in IGeckoEditableChild child, long contentId, long tabId);
// Returns the interface that child processes should use to allocate Surfaces.
ISurfaceAllocator getSurfaceAllocator();
}

Просмотреть файл

@ -9,12 +9,10 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.util.SparseArray;
import org.mozilla.gecko.GeckoAppShell;
import androidx.annotation.NonNull;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.process.GeckoProcessManager;
import org.mozilla.gecko.process.GeckoServiceChildProcess;
/* package */ final class SurfaceAllocator {
public final class SurfaceAllocator {
private static final String LOGTAG = "SurfaceAllocator";
private static ISurfaceAllocator sAllocator;
@ -23,23 +21,13 @@ import org.mozilla.gecko.process.GeckoServiceChildProcess;
// connection to the allocator service.
private static final SparseArray<GeckoSurface> sSurfaces = new SparseArray<GeckoSurface>();
private static synchronized void ensureConnection() {
if (sAllocator != null) {
return;
public static synchronized void connect(final @NonNull ISurfaceAllocator allocator) {
if (allocator == null) {
throw new IllegalArgumentException("SurfaceAllocator.connect() allocator must be non-null");
}
try {
if (GeckoAppShell.isParentProcess()) {
sAllocator = GeckoProcessManager.getInstance().getSurfaceAllocator();
} else {
sAllocator = GeckoServiceChildProcess.getSurfaceAllocator();
}
if (sAllocator == null) {
Log.w(LOGTAG, "Failed to connect to RemoteSurfaceAllocator");
return;
}
sAllocator
allocator
.asBinder()
.linkToDeath(
new IBinder.DeathRecipient() {
@ -59,6 +47,7 @@ import org.mozilla.gecko.process.GeckoServiceChildProcess;
}
},
0);
sAllocator = allocator;
} catch (final RemoteException e) {
Log.w(LOGTAG, "Failed to connect to RemoteSurfaceAllocator", e);
sAllocator = null;
@ -69,8 +58,6 @@ import org.mozilla.gecko.process.GeckoServiceChildProcess;
public static synchronized GeckoSurface acquireSurface(
final int width, final int height, final boolean singleBufferMode) {
try {
ensureConnection();
if (sAllocator == null) {
Log.w(LOGTAG, "Failed to acquire GeckoSurface: not connected");
return null;

Просмотреть файл

@ -66,37 +66,6 @@ public final class GeckoProcessManager extends IProcessManager.Stub {
nativeGetEditableParent(child, contentId, tabId);
}
/**
* 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.
*/
@Override // IProcessManager
public ISurfaceAllocator getSurfaceAllocator() {
final GeckoResult<Boolean> gpuReady = GeckoAppShell.ensureGpuProcessReady();
try {
final GeckoResult<ISurfaceAllocator> allocator = new GeckoResult<>();
if (gpuReady.poll(1000)) {
// The GPU process is enabled and ready, so ask it for its surface allocator.
XPCOMEventTarget.runOnLauncherThread(
() -> {
final Selector selector = new Selector(GeckoProcessType.GPU);
final GpuProcessConnection conn =
(GpuProcessConnection) INSTANCE.mConnections.getExistingConnection(selector);
allocator.complete(conn.getSurfaceAllocator());
});
} else {
// The GPU process is disabled, so return the parent process allocator instance.
allocator.complete(RemoteSurfaceAllocator.getInstance());
}
return allocator.poll(100);
} catch (final Throwable e) {
Log.e(LOGTAG, "Error in getSurfaceAllocator", e);
return null;
}
}
@WrapForJNI
public static CompositorSurfaceManager getCompositorSurfaceManager() {
final Selector selector = new Selector(GeckoProcessType.GPU);
@ -105,6 +74,43 @@ public final class GeckoProcessManager extends IProcessManager.Stub {
return conn.getCompositorSurfaceManager();
}
/**
* Connects the specified child process' SurfaceAllocator. Should be called after creating the
* child process, and after rendering has been reinitialized following the a GPU process loss, to
* allow the child process to allocate Surfaces.
*
* @param selector Selector identifying the child process to connect.
* @param gpuProcessEnabled Whether the GPU process is enabled.
*/
@WrapForJNI
public static void setChildProcessSurfaceAllocator(
final Selector selector, final boolean gpuProcessEnabled) {
XPCOMEventTarget.assertOnLauncherThread();
final ChildConnection conn = INSTANCE.mConnections.getExistingConnection(selector);
if (conn == null) {
return;
}
if (gpuProcessEnabled) {
// If the GPU process is enabled then attempt to connect the child process to the GPU process'
// surface allocator. If the GPU process has died then we may be unable to find the
// connection, in which case do nothing - this function will be called again once rendering
// has been reinitialized.
final Selector gpuSelector = new Selector(GeckoProcessType.GPU);
final GpuProcessConnection gpuConn =
(GpuProcessConnection) INSTANCE.mConnections.getExistingConnection(gpuSelector);
if (gpuConn != null) {
conn.setSurfaceAllocator(gpuConn.getSurfaceAllocator());
} else {
Log.w(LOGTAG, "setSurfaceAllocator called with GPU process enabled but not running");
}
} else {
// If the GPU process is disabled then connect the child process to the parent process'
// surface allocator
conn.setSurfaceAllocator(RemoteSurfaceAllocator.getInstance());
}
}
/** Gecko uses this class to uniquely identify a process managed by GeckoProcessManager. */
public static final class Selector {
private final GeckoProcessType mType;
@ -245,6 +251,14 @@ public final class GeckoProcessManager extends IProcessManager.Stub {
return GeckoResult.fromValue(null);
}
public void setSurfaceAllocator(final ISurfaceAllocator surfaceAllocator) {
try {
mChild.setSurfaceAllocator(surfaceAllocator);
} catch (final RemoteException e) {
Log.w(LOGTAG, "Error calling IChildProcess.setSurfaceAllocator()", e);
}
}
@Override
protected void onBinderConnected(final IBinder service) {
XPCOMEventTarget.assertOnLauncherThread();
@ -322,7 +336,7 @@ public final class GeckoProcessManager extends IProcessManager.Stub {
@Override
protected void onBinderConnected(@NonNull final IChildProcess child) throws RemoteException {
mCompositorSurfaceManager = new CompositorSurfaceManager(child.getCompositorSurfaceManager());
mSurfaceAllocator = child.getSurfaceAllocator();
mSurfaceAllocator = child.getSurfaceAllocatorFromGpuProcess();
}
public CompositorSurfaceManager getCompositorSurfaceManager() {

Просмотреть файл

@ -14,6 +14,7 @@ import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
import androidx.annotation.NonNull;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoThread;
import org.mozilla.gecko.GeckoThread.FileDescriptors;
@ -22,6 +23,7 @@ import org.mozilla.gecko.IGeckoEditableChild;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.gfx.ICompositorSurfaceManager;
import org.mozilla.gecko.gfx.ISurfaceAllocator;
import org.mozilla.gecko.gfx.SurfaceAllocator;
import org.mozilla.gecko.util.ThreadUtils;
public class GeckoServiceChildProcess extends Service {
@ -163,10 +165,17 @@ public class GeckoServiceChildProcess extends Service {
}
@Override
public ISurfaceAllocator getSurfaceAllocator() {
Log.e(LOGTAG, "Invalid call to IChildProcess.getSurfaceAllocator for non-GPU process");
public ISurfaceAllocator getSurfaceAllocatorFromGpuProcess() {
Log.e(
LOGTAG,
"Invalid call to IChildProcess.getSurfaceAllocatorFromGpuProcess for non-GPU process");
throw new AssertionError(
"Invalid call to IChildProcess.getSurfaceAllocator for non-GPU process.");
"Invalid call to IChildProcess.getSurfaceAllocatorFromGpuProcess for non-GPU process.");
}
@Override
public void setSurfaceAllocator(final @NonNull ISurfaceAllocator surfaceAllocator) {
SurfaceAllocator.connect(surfaceAllocator);
}
}
@ -202,12 +211,4 @@ public class GeckoServiceChildProcess extends Service {
mMemoryController.onLowMemory();
super.onLowMemory();
}
/**
* Returns the surface allocator interface that should be used by this process to allocate
* Surfaces, for consumption in either the GPU process or parent process.
*/
public static ISurfaceAllocator getSurfaceAllocator() throws RemoteException {
return sProcessManager.getSurfaceAllocator();
}
}

Просмотреть файл

@ -23,7 +23,7 @@ public class GeckoServiceGpuProcess extends GeckoServiceChildProcess {
}
@Override
public ISurfaceAllocator getSurfaceAllocator() {
public ISurfaceAllocator getSurfaceAllocatorFromGpuProcess() {
return RemoteSurfaceAllocator.getInstance();
}
}