Add EglThread class wrapping EglConnection and handler.

EglThread can be shared by multiple clients each using their own
EglBase instance, but sharing thread and EglConnection.
go/meet-android-eglcontext-reduction

Bug: b/225229697
Change-Id: I2d18b92bdef51362a9dbd9c0af56cb868e29869d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/305462
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Commit-Queue: Linus Nilsson <lnilsson@webrtc.org>
Reviewed-by: Xavier Lepaul‎ <xalep@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40121}
diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn
index 4c38644..8a3e20c 100644
--- a/sdk/android/BUILD.gn
+++ b/sdk/android/BUILD.gn
@@ -212,6 +212,7 @@
       "api/org/webrtc/EglBase10.java",
       "api/org/webrtc/EglBase14.java",
       "api/org/webrtc/EglRenderer.java",
+      "api/org/webrtc/EglThread.java",
       "api/org/webrtc/GlRectDrawer.java",
       "api/org/webrtc/GlShader.java",
       "api/org/webrtc/GlTextureFrameBuffer.java",
diff --git a/sdk/android/api/org/webrtc/EglThread.java b/sdk/android/api/org/webrtc/EglThread.java
new file mode 100644
index 0000000..0912210
--- /dev/null
+++ b/sdk/android/api/org/webrtc/EglThread.java
@@ -0,0 +1,87 @@
+/*
+ *  Copyright 2022 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+package org.webrtc;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import org.webrtc.EglBase.EglConnection;
+
+/** EGL graphics thread that allows multiple clients to share the same underlying EGLContext. */
+public class EglThread {
+  /** Callback for externally managed reference count. */
+  public interface ReleaseMonitor {
+    /**
+     * Called by EglThread when a client releases its reference. Returns true when there are no more
+     * references and resources should be released.
+     */
+    boolean onRelease(EglThread eglThread);
+  }
+
+  public static EglThread create(@Nullable ReleaseMonitor releaseMonitor,
+      @Nullable final EglBase.Context sharedContext, final int[] configAttributes) {
+    final HandlerThread renderThread = new HandlerThread("EglThread");
+    renderThread.start();
+    Handler handler = new Handler(renderThread.getLooper());
+
+    // If sharedContext is null, then texture frames are disabled. This is typically for old
+    // devices that might not be fully spec compliant, so force EGL 1.0 since EGL 1.4 has
+    // caused trouble on some weird devices.
+    EglConnection eglConnection;
+    if (sharedContext == null) {
+      eglConnection = EglConnection.createEgl10(configAttributes);
+    } else {
+      eglConnection = EglConnection.create(sharedContext, configAttributes);
+    }
+
+    return new EglThread(
+        releaseMonitor != null ? releaseMonitor : eglThread -> true, handler, eglConnection);
+  }
+
+  private final ReleaseMonitor releaseMonitor;
+  private final Handler handler;
+  private final EglConnection eglConnection;
+
+  @VisibleForTesting
+  EglThread(ReleaseMonitor releaseMonitor, Handler handler, EglConnection eglConnection) {
+    this.releaseMonitor = releaseMonitor;
+    this.handler = handler;
+    this.eglConnection = eglConnection;
+  }
+
+  public void release() {
+    if (!releaseMonitor.onRelease(this)) {
+      // Thread is still in use, do not release yet.
+      return;
+    }
+
+    handler.post(eglConnection::release);
+    handler.getLooper().quitSafely();
+  }
+
+  /**
+   * Creates an EglBase instance with the EglThread's EglConnection. This method can be called on
+   * any thread, but the returned EglBase instance should only be used on this EglThread's Handler.
+   */
+  public EglBase createEglBaseWithSharedConnection() {
+    return EglBase.create(eglConnection);
+  }
+
+  /**
+   * Returns the Handler to interact with Gl/EGL on. Callers need to make sure that their own
+   * EglBase is current on the handler before running any graphics operations since the EglThread
+   * can be shared by multiple clients.
+   */
+  public Handler getHandler() {
+    return handler;
+  }
+}