1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
content / shell / android / shell_apk / src / org / chromium / content_shell_apk / ChildProcessLauncherTestUtils.java [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.content_shell_apk;
import org.chromium.base.process_launcher.ChildProcessConnection;
import org.chromium.base.process_launcher.FileDescriptorInfo;
import org.chromium.base.process_launcher.IChildProcessService;
import org.chromium.content.browser.ChildProcessLauncherHelperImpl;
import org.chromium.content.browser.LauncherThread;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.Semaphore;
/** An assortment of static methods used in tests that deal with launching child processes. */
public final class ChildProcessLauncherTestUtils {
// Do not instanciate, use static methods instead.
private ChildProcessLauncherTestUtils() {}
public static void runOnLauncherThreadBlocking(final Runnable runnable) {
if (LauncherThread.runningOnLauncherThread()) {
runnable.run();
return;
}
final Semaphore done = new Semaphore(0);
LauncherThread.post(
new Runnable() {
@Override
public void run() {
runnable.run();
done.release();
}
});
done.acquireUninterruptibly();
}
public static <T> T runOnLauncherAndGetResult(Callable<T> callable) {
if (LauncherThread.runningOnLauncherThread()) {
try {
return callable.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
try {
FutureTask<T> task = new FutureTask<T>(callable);
LauncherThread.post(task);
return task.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static ChildProcessLauncherHelperImpl startForTesting(
final boolean sandboxed,
final String[] commandLine,
final FileDescriptorInfo[] filesToBeMapped,
final boolean doSetupConnection) {
return runOnLauncherAndGetResult(
new Callable<ChildProcessLauncherHelperImpl>() {
@Override
public ChildProcessLauncherHelperImpl call() {
return ChildProcessLauncherHelperImpl.createAndStartForTesting(
commandLine,
filesToBeMapped,
sandboxed,
/* reducePriorityOnBackground= */ false,
/* canUseWarmUpConnection= */ true,
/* binderCallback= */ null,
doSetupConnection);
}
});
}
public static ChildProcessConnection getConnection(
final ChildProcessLauncherHelperImpl childProcessLauncher) {
return runOnLauncherAndGetResult(
new Callable<ChildProcessConnection>() {
@Override
public ChildProcessConnection call() {
return ((ChildProcessLauncherHelperImpl) childProcessLauncher)
.getChildProcessConnection();
}
});
}
// Retrieves the PID of the passed in connection on the launcher thread as to not assert.
public static int getConnectionPid(final ChildProcessConnection connection) {
return runOnLauncherAndGetResult(
new Callable<Integer>() {
@Override
public Integer call() {
return connection.getPid();
}
});
}
// Retrieves the service number of the passed in connection from its service name, or -1 if the
// service number could not be determined.
public static int getConnectionServiceNumber(final ChildProcessConnection connection) {
String serviceName = getConnectionServiceName(connection);
// The service name ends up with the service number.
StringBuilder numberString = new StringBuilder();
for (int i = serviceName.length() - 1; i >= 0; i--) {
char c = serviceName.charAt(i);
if (!Character.isDigit(c)) {
break;
}
numberString.append(c);
}
try {
return Integer.decode(numberString.toString());
} catch (NumberFormatException nfe) {
return -1;
}
}
// Retrieves the service number of the passed in connection on the launcher thread as to not
// assert.
public static String getConnectionServiceName(final ChildProcessConnection connection) {
return runOnLauncherAndGetResult(
new Callable<String>() {
@Override
public String call() {
return connection.getServiceName().getClassName();
}
});
}
// Retrieves the service of the passed in connection on the launcher thread as to not assert.
public static IChildProcessService getConnectionService(
final ChildProcessConnection connection) {
return runOnLauncherAndGetResult(
new Callable<IChildProcessService>() {
@Override
public IChildProcessService call() {
return connection.getService();
}
});
}
}