Add SurfacePackage rendering
Adds logic within CodeHolder to handle requesting
a View from loaded code, and passing this as a
SurfacePackage to SupplementalProcessManager. Each
SurfacePackage is allocated a unique id. When a
SurfacePackage is ready, SupplementalProcessManager
will call back into the calling package.
Test: atest SupplementalProcessTests
Bug: 204989872
Change-Id: I30f06482f91602d1a11d8f1f452bd09694557650
diff --git a/sdksandbox/SupplementalProcess/src/com/android/supplemental/process/CodeHolder.java b/sdksandbox/SupplementalProcess/src/com/android/supplemental/process/CodeHolder.java
index a968f3b..8907426 100644
--- a/sdksandbox/SupplementalProcess/src/com/android/supplemental/process/CodeHolder.java
+++ b/sdksandbox/SupplementalProcess/src/com/android/supplemental/process/CodeHolder.java
@@ -17,10 +17,19 @@
package com.android.supplemental.process;
import android.content.Context;
+import android.hardware.display.DisplayManager;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.RemoteException;
import android.supplementalprocess.CodeProvider;
import android.util.Log;
+import android.util.SparseArray;
+import android.view.SurfaceControlViewHost;
+import android.view.View;
+import android.view.WindowManager;
+
+import java.security.SecureRandom;
+import java.util.Random;
/**
* A holder for loaded code.
@@ -34,6 +43,11 @@
private CodeProvider mCode;
private Context mContext;
+ private DisplayManager mDisplayManager;
+ private final Random mRandom = new SecureRandom();
+ private final SparseArray<SurfaceControlViewHost.SurfacePackage> mSurfacePackages =
+ new SparseArray<>();
+
void init(Context context, Bundle params,
ISupplementalProcessToSupplementalProcessManagerCallback callback,
String codeProviderClassName, ClassLoader loader) {
@@ -43,6 +57,7 @@
mInitialized = true;
mCallback = callback;
mContext = context;
+ mDisplayManager = mContext.getSystemService(DisplayManager.class);
try {
Class<?> clz = Class.forName(codeProviderClassName, true, loader);
mCode = (CodeProvider) clz.getConstructor(Context.class).newInstance(mContext);
@@ -68,9 +83,7 @@
private void sendLoadCodeSuccess() {
try {
- // TODO(b/204989872): return a
- // ISupplementalProcessManagerToSupplementalProcessCallback from here
- mCallback.onLoadCodeSuccess(new Bundle(), /*callback=*/null);
+ mCallback.onLoadCodeSuccess(new Bundle(), new SupplementalProcessCallbackImpl());
} catch (RemoteException e) {
Log.e(TAG, "Could not send onLoadCodeSuccess: " + e);
}
@@ -86,4 +99,44 @@
Log.e(TAG, "Could not send onLoadCodeError: " + e);
}
}
+
+ private int allocateSurfacePackageId(SurfaceControlViewHost.SurfacePackage surfacePackage) {
+ synchronized (mSurfacePackages) {
+ for (int i = 0; i < 32; i++) {
+ int id = mRandom.nextInt();
+ if (!mSurfacePackages.contains(id)) {
+ mSurfacePackages.put(id, surfacePackage);
+ return id;
+ }
+ }
+ throw new IllegalStateException("Could not allocate surfacePackageId");
+ }
+ }
+
+ private class SupplementalProcessCallbackImpl
+ extends ISupplementalProcessManagerToSupplementalProcessCallback.Stub {
+
+ @Override
+ public void onSurfacePackageRequested(IBinder token, int displayId, Bundle params) {
+ try {
+ Context displayContext = mContext.createDisplayContext(
+ mDisplayManager.getDisplay(displayId));
+ // TODO(b/209009304): Support other window contexts?
+ Context windowContext = displayContext.createWindowContext(
+ WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, null);
+ final View view = mCode.getView(windowContext, params);
+ SurfaceControlViewHost host = new SurfaceControlViewHost(windowContext,
+ mDisplayManager.getDisplay(displayId), token);
+ host.setView(view, view.getWidth(), view.getHeight());
+ SurfaceControlViewHost.SurfacePackage surfacePackage = host.getSurfacePackage();
+ int surfacePackageId = allocateSurfacePackageId(surfacePackage);
+ mCallback.onSurfacePackageReady(surfacePackage, surfacePackageId, params);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not send onSurfacePackageReady", e);
+ } catch (Throwable e) {
+ // TODO(b/209396156): pass error back to calling package.
+ Log.e(TAG, "Error thrown while getting surface package", e);
+ }
+ }
+ }
}
diff --git a/sdksandbox/SupplementalProcess/tests/src/com/android/supplemental/process/SupplementalProcessTest.java b/sdksandbox/SupplementalProcess/tests/src/com/android/supplemental/process/SupplementalProcessTest.java
index d4e0c7e..428b57f 100644
--- a/sdksandbox/SupplementalProcess/tests/src/com/android/supplemental/process/SupplementalProcessTest.java
+++ b/sdksandbox/SupplementalProcess/tests/src/com/android/supplemental/process/SupplementalProcessTest.java
@@ -23,12 +23,14 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Process;
import android.view.SurfaceControlViewHost;
import androidx.test.InstrumentationRegistry;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -44,6 +46,11 @@
private ApplicationInfo mApplicationInfo;
private static final String CODE_PROVIDER_CLASS = "com.android.testprovider.TestProvider";
+ @BeforeClass
+ public static void setupClass() {
+ // Required to create a SurfaceControlViewHost
+ Looper.prepare();
+ }
@Before
public void setup() throws Exception {
mService = new FakeSupplementalProcessService();
@@ -92,13 +99,31 @@
assertThat(mRemoteCode2.mSuccessful).isTrue();
}
+ @Test
+ public void testRequestSurfacePackage() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ RemoteCode mRemoteCode = new RemoteCode(latch);
+ mService.loadCode(new Binder(), mApplicationInfo, CODE_PROVIDER_CLASS,
+ new Bundle(), mRemoteCode);
+ assertThat(latch.await(1, TimeUnit.MINUTES)).isTrue();
+ CountDownLatch surfaceLatch = new CountDownLatch(1);
+ mRemoteCode.setLatch(surfaceLatch);
+ mRemoteCode.getCallback().onSurfacePackageRequested(new Binder(),
+ mContext.getDisplayId(), null);
+ assertThat(surfaceLatch.await(1, TimeUnit.MINUTES)).isTrue();
+ assertThat(mRemoteCode.mSurfacePackage).isNotNull();
+ }
+
private static class RemoteCode
extends ISupplementalProcessToSupplementalProcessManagerCallback.Stub {
- private final CountDownLatch mLatch;
+ private CountDownLatch mLatch;
+ private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
boolean mSuccessful = false;
int mErrorCode = -1;
+ private ISupplementalProcessManagerToSupplementalProcessCallback mCallback;
+
RemoteCode(CountDownLatch latch) {
mLatch = latch;
}
@@ -107,6 +132,7 @@
public void onLoadCodeSuccess(Bundle params,
ISupplementalProcessManagerToSupplementalProcessCallback callback) {
mLatch.countDown();
+ mCallback = callback;
mSuccessful = true;
}
@@ -120,7 +146,18 @@
@Override
public void onSurfacePackageReady(
SurfaceControlViewHost.SurfacePackage surfacePackage,
- int displayId, Bundle params) {}
+ int displayId, Bundle params) {
+ mLatch.countDown();
+ mSurfacePackage = surfacePackage;
+ }
+
+ private void setLatch(CountDownLatch latch) {
+ mLatch = latch;
+ }
+
+ private ISupplementalProcessManagerToSupplementalProcessCallback getCallback() {
+ return mCallback;
+ }
}
private static class FakeSupplementalProcessService extends SupplementalProcessServiceImpl {
diff --git a/sdksandbox/SupplementalProcess/tests/test-apps/TestProvider/src/com/android/testprovider/TestProvider.java b/sdksandbox/SupplementalProcess/tests/test-apps/TestProvider/src/com/android/testprovider/TestProvider.java
index 3124596..780cf7d 100644
--- a/sdksandbox/SupplementalProcess/tests/test-apps/TestProvider/src/com/android/testprovider/TestProvider.java
+++ b/sdksandbox/SupplementalProcess/tests/test-apps/TestProvider/src/com/android/testprovider/TestProvider.java
@@ -18,9 +18,8 @@
import android.content.Context;
import android.os.Bundle;
-import android.os.IBinder;
import android.supplementalprocess.CodeProvider;
-import android.view.SurfaceControlViewHost;
+import android.view.View;
import java.util.concurrent.Executor;
@@ -36,9 +35,8 @@
}
@Override
- public SurfaceControlViewHost.SurfacePackage getSurfacePackage(IBinder hostToken, int displayId,
- Bundle params) {
- return null;
+ public View getView(Context windowContext, Bundle params) {
+ return new View(windowContext);
}
@Override
diff --git a/sdksandbox/framework/java/android/supplementalprocess/CodeProvider.java b/sdksandbox/framework/java/android/supplementalprocess/CodeProvider.java
index 6381b4e..ae2410d 100644
--- a/sdksandbox/framework/java/android/supplementalprocess/CodeProvider.java
+++ b/sdksandbox/framework/java/android/supplementalprocess/CodeProvider.java
@@ -20,8 +20,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.os.Bundle;
-import android.os.IBinder;
-import android.view.SurfaceControlViewHost.SurfacePackage;
+import android.view.View;
import java.util.concurrent.Executor;
@@ -48,8 +47,7 @@
* Returns view that will be used for remote rendering.
*/
@NonNull
- public abstract SurfacePackage getSurfacePackage(
- @NonNull IBinder hostToken, int displayId, @NonNull Bundle params);
+ public abstract View getView(Context windowContext, @NonNull Bundle params);
/**
* Called when extra data sent from the app is received by code.