Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(157)

Unified Diff: base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java

Issue 2613183002: Revert of Multiprocess test client: Android child process launcher rework. (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java
diff --git a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java
deleted file mode 100644
index 6c1f3981f9afdc0586d5067047cce5374bef9410..0000000000000000000000000000000000000000
--- a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java
+++ /dev/null
@@ -1,293 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.base;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-
-import org.chromium.base.annotations.CalledByNative;
-import org.chromium.base.annotations.JNINamespace;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Queue;
-
-import javax.annotation.concurrent.GuardedBy;
-
-/**
- * Helper class for launching test client processes for multiprocess unit tests.
- */
-@JNINamespace("base::android")
-public final class MultiprocessTestClientLauncher {
- private static final String TAG = "cr_MProcTCLauncher";
-
- private static ConnectionAllocator sConnectionAllocator = new ConnectionAllocator();
-
- // Not supposed to be instantiated.
- private MultiprocessTestClientLauncher() {}
-
- private static class ConnectionAllocator {
- // Services are identified by a slot number, which is used in the service name to
- // differentiate them (MultiprocessTestClientService0, MultiprocessTestClientService1, ...).
- // They are stored in a FIFO queue in order to minimize the risk of the framework reusing a
- // service without restarting its associated process (which can cause all kind of problems
- // with static native variables already being initialized).
- private static final int MAX_SUBPROCESS_COUNT = 5;
-
- private final Object mLock = new Object();
-
- @GuardedBy("mLock")
- private final Queue<Integer> mFreeServiceSlot = new LinkedList<>();
- @GuardedBy("mLock")
- private final List<ClientServiceConnection> mConnections = new ArrayList<>();
-
- public ConnectionAllocator() {
- synchronized (mLock) {
- for (int i = 0; i < MAX_SUBPROCESS_COUNT; i++) {
- mFreeServiceSlot.add(i);
- }
- }
- }
-
- public ClientServiceConnection allocateConnection(
- String[] commandLine, FileDescriptorInfo[] filesToMap) {
- synchronized (mLock) {
- while (mFreeServiceSlot.isEmpty()) {
- try {
- mLock.wait();
- } catch (InterruptedException ie) {
- Log.e(TAG, "Interrupted while waiting for a free connection.");
- }
- }
-
- int slot = mFreeServiceSlot.remove();
- ClientServiceConnection connection =
- new ClientServiceConnection(slot, commandLine, filesToMap);
- mConnections.add(connection);
- return connection;
- }
- }
-
- public void freeConnection(ClientServiceConnection connection) {
- synchronized (mLock) {
- mFreeServiceSlot.add(connection.getSlot());
- mConnections.remove(connection);
- }
- }
-
- public ClientServiceConnection getConnectionByPid(int pid) {
- synchronized (mLock) {
- // List of connections is short, iterating is OK.
- for (ClientServiceConnection connection : mConnections) {
- if (connection.getPid() == pid) {
- return connection;
- }
- }
- }
- return null;
- }
- }
-
- private static class ClientServiceConnection implements ServiceConnection {
- private final String[] mCommandLine;
- private final FileDescriptorInfo[] mFilesToMap;
- private final Object mConnectedLock = new Object();
- private final int mSlot;
- private ITestClient mService = null;
- @GuardedBy("mConnectedLock")
- private boolean mConnected;
- private int mPid;
-
- ClientServiceConnection(int slot, String[] commandLine, FileDescriptorInfo[] filesToMap) {
- mSlot = slot;
- mCommandLine = commandLine;
- mFilesToMap = filesToMap;
- }
-
- public void waitForConnection() {
- synchronized (mConnectedLock) {
- while (!mConnected) {
- try {
- mConnectedLock.wait();
- } catch (InterruptedException ie) {
- Log.e(TAG, "Interrupted while waiting for connection.");
- }
- }
- }
- }
-
- @Override
- public void onServiceConnected(ComponentName className, IBinder service) {
- try {
- mService = ITestClient.Stub.asInterface(service);
- mPid = mService.launch(mCommandLine, mFilesToMap);
- synchronized (mConnectedLock) {
- mConnected = true;
- mConnectedLock.notifyAll();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Connect failed");
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName className) {
- if (mPid == 0) {
- Log.e(TAG, "Early ClientServiceConnection disconnection.");
- return;
- }
- sConnectionAllocator.freeConnection(this);
- }
-
- public ITestClient getService() {
- return mService;
- }
-
- public String getServiceClassName() {
- // In order to use different processes, we have to declare multiple services in the
- // AndroidManifest.xml file, each service associated with its own process. The various
- // services are functionnaly identical but need to each have their own class.
- // We differentiate them by their class name having a trailing number.
- return MultiprocessTestClientService.class.getName() + mSlot;
- }
-
- public boolean isConnected() {
- synchronized (mConnectedLock) {
- return mConnected;
- }
- }
-
- public int getSlot() {
- return mSlot;
- }
-
- public int getPid() {
- return mPid;
- }
- }
-
- /**
- * Spawns and connects to a child process.
- * May not be called from the main thread.
- *
- * @param context context used to obtain the application context.
- * @param commandLine the child process command line argv.
- * @return the PID of the started process or 0 if the process could not be started.
- */
- @CalledByNative
- private static int launchClient(final Context context, final String[] commandLine,
- final FileDescriptorInfo[] filesToMap) {
- if (ThreadUtils.runningOnUiThread()) {
- // This can't be called on the main thread as the native side will block until
- // onServiceConnected above is called, which cannot happen if the main thread is
- // blocked.
- throw new RuntimeException("launchClient cannot be called on the main thread");
- }
-
- ClientServiceConnection connection =
- sConnectionAllocator.allocateConnection(commandLine, filesToMap);
- Intent intent = new Intent();
- String className = connection.getServiceClassName();
- intent.setComponent(new ComponentName(context.getPackageName(), className));
- if (!context.bindService(
- intent, connection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT)) {
- Log.e(TAG, "Failed to bind service: " + context.getPackageName() + "." + className);
- sConnectionAllocator.freeConnection(connection);
- return 0;
- }
-
- connection.waitForConnection();
-
- return connection.getPid();
- }
-
- /**
- * Blocks until the main method invoked by a previous call to launchClient terminates or until
- * the specified time-out expires.
- * Returns immediately if main has already returned.
- * @param context context used to obtain the application context.
- * @param pid the process ID that was returned by the call to launchClient
- * @param timeoutMs the timeout in milliseconds after which the method returns even if main has
- * not returned.
- * @return the return code returned by the main method or whether it timed-out.
- */
- @CalledByNative
- private static MainReturnCodeResult waitForMainToReturn(
- Context context, int pid, int timeoutMs) {
- ClientServiceConnection connection = sConnectionAllocator.getConnectionByPid(pid);
- if (connection == null) {
- Log.e(TAG, "waitForMainToReturn called on unknown connection for pid " + pid);
- return null;
- }
- try {
- return connection.getService().waitForMainToReturn(timeoutMs);
- } catch (RemoteException e) {
- Log.e(TAG, "Remote call to waitForMainToReturn failed.");
- return null;
- } finally {
- freeConnection(context, connection);
- }
- }
-
- @CalledByNative
- private static boolean terminate(Context context, int pid, int exitCode, boolean wait) {
- ClientServiceConnection connection = sConnectionAllocator.getConnectionByPid(pid);
- if (connection == null) {
- Log.e(TAG, "terminate called on unknown connection for pid " + pid);
- return false;
- }
- try {
- if (wait) {
- connection.getService().forceStopSynchronous(exitCode);
- } else {
- connection.getService().forceStop(exitCode);
- }
- } catch (RemoteException e) {
- // We expect this failure, since the forceStop's service implementation calls
- // System.exit().
- } finally {
- freeConnection(context, connection);
- }
- return true;
- }
-
- private static void freeConnection(Context context, ClientServiceConnection connection) {
- context.unbindService(connection);
- sConnectionAllocator.freeConnection(connection);
- }
-
- /** Does not take ownership of of fds. */
- @CalledByNative
- private static FileDescriptorInfo[] makeFdInfoArray(int[] keys, int[] fds) {
- FileDescriptorInfo[] fdInfos = new FileDescriptorInfo[keys.length];
- for (int i = 0; i < keys.length; i++) {
- FileDescriptorInfo fdInfo = makeFdInfo(keys[i], fds[i]);
- if (fdInfo == null) {
- Log.e(TAG, "Failed to make file descriptor (" + keys[i] + ", " + fds[i] + ").");
- return null;
- }
- fdInfos[i] = fdInfo;
- }
- return fdInfos;
- }
-
- private static FileDescriptorInfo makeFdInfo(int id, int fd) {
- ParcelFileDescriptor parcelableFd = null;
- try {
- parcelableFd = ParcelFileDescriptor.fromFd(fd);
- } catch (IOException e) {
- Log.e(TAG, "Invalid FD provided for process connection, aborting connection.", e);
- return null;
- }
- return new FileDescriptorInfo(id, parcelableFd);
- }
-}

Powered by Google App Engine
This is Rietveld 408576698