Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/security/testlibrary/Proc.java
38812 views
1
/*
2
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
import java.io.BufferedReader;
25
import java.io.File;
26
import java.io.IOException;
27
import java.io.InputStreamReader;
28
import java.net.URL;
29
import java.net.URLClassLoader;
30
import java.nio.file.Files;
31
import java.nio.file.Path;
32
import java.nio.file.Paths;
33
import java.security.Permission;
34
import java.util.ArrayList;
35
import java.util.Base64;
36
import java.util.HashMap;
37
import java.util.List;
38
import java.util.Map;
39
import java.util.Map.Entry;
40
41
/**
42
* This is a test library that makes writing a Java test that spawns multiple
43
* Java processes easily.
44
*
45
* Usage:
46
*
47
* Proc.create("Clazz") // The class to launch
48
* .args("x") // with args
49
* .env("env", "value") // and an environment variable
50
* .prop("key","value") // and a system property
51
* .perm(perm) // with granted permissions
52
* .start(); // and start
53
*
54
* create/start must be called, args/env/prop/perm can be called zero or
55
* multiple times between create and start.
56
*
57
* The controller can call inheritIO to share its I/O to the process.
58
* Otherwise, it can send data into a proc's stdin with write/println, and
59
* read its stdout with readLine. stderr is always redirected to DFILE
60
* unless nodump() is called. A protocol is designed to make
61
* data exchange among the controller and the processes super easy, in which
62
* useful data are always printed with a special prefix ("PROCISFUN:").
63
* If the data is binary, make it BASE64.
64
*
65
* For example:
66
*
67
* - A producer Proc calls Proc.binOut() or Proc.textOut() to send out data.
68
* This method would prints to the stdout something like
69
*
70
* PROCISFUN:[raw text or base64 binary]
71
*
72
* - The controller calls producer.readData() to get the content. This method
73
* ignores all other output and only reads lines starting with "PROCISFUN:".
74
*
75
* - The controller does not care if the context is text or base64, it simply
76
* feeds the data to a consumer Proc by calling consumer.println(data).
77
* This will be printed into System.in of the consumer process.
78
*
79
* - The consumer Proc calls Proc.binIn() or Proc.textIn() to read the data.
80
* The first method de-base64 the input and return a byte[] block.
81
*
82
* Please note only plain ASCII is supported in raw text at the moment.
83
*
84
* As the Proc objects are hidden so deeply, two static methods, d(String) and
85
* d(Throwable) are provided to output info into stderr, where they will
86
* normally be appended messages to DFILE (unless nodump() is called).
87
* Developers can view the messages in real time by calling
88
*
89
* tail -f proc.debug
90
*
91
* TODO:
92
*
93
* . launch java tools, say, keytool
94
* . launch another version of java
95
* . start in another directory
96
* . start and finish using one method
97
*
98
* This is not a test, but is the core of
99
* JDK-8009977: A test library to launch multiple Java processes
100
*/
101
public class Proc {
102
private Process p;
103
private BufferedReader br; // the stdout of a process
104
private String launcher; // Optional: the java program
105
106
private List<Permission> perms = new ArrayList<>();
107
private List<String> args = new ArrayList<>();
108
private Map<String,String> env = new HashMap<>();
109
private Map<String,String> prop = new HashMap();
110
private boolean inheritIO = false;
111
private boolean noDump = false;
112
113
private String clazz; // Class to launch
114
private String debug; // debug flag, controller will show data
115
// transfer between procs
116
117
final private static String PREFIX = "PROCISFUN:";
118
final private static String DFILE = "proc.debug";
119
120
// The following methods are called by controllers
121
122
// Creates a Proc by the Java class name, launcher is an optional
123
// argument to specify the java program
124
public static Proc create(String clazz, String... launcher) {
125
Proc pc = new Proc();
126
pc.clazz = clazz;
127
if (launcher.length > 0) {
128
pc.launcher = launcher[0];
129
}
130
return pc;
131
}
132
// Sets inheritIO flag to proc. If set, proc will same I/O channels as
133
// teh controller. Otherwise, its stdin/stdout is untouched, and its
134
// stderr is redirected to DFILE.
135
public Proc inheritIO() {
136
inheritIO = true;
137
return this;
138
}
139
// When called, stderr inherits parent stderr, otherwise, append to a file
140
public Proc nodump() {
141
noDump = true;
142
return this;
143
}
144
// Specifies some args. Can be called multiple times.
145
public Proc args(String... args) {
146
for (String c: args) {
147
this.args.add(c);
148
}
149
return this;
150
}
151
// Returns debug prefix
152
public String debug() {
153
return debug;
154
}
155
// Enables debug with prefix
156
public Proc debug(String title) {
157
debug = title;
158
return this;
159
}
160
// Specifies an env var. Can be called multiple times.
161
public Proc env(String a, String b) {
162
env.put(a, b);
163
return this;
164
}
165
// Specifies a Java system property. Can be called multiple times.
166
public Proc prop(String a, String b) {
167
prop.put(a, b);
168
return this;
169
}
170
// Adds a perm to policy. Can be called multiple times. In order to make it
171
// effective, please also call prop("java.security.manager", "").
172
public Proc perm(Permission p) {
173
perms.add(p);
174
return this;
175
}
176
// Starts the proc
177
public Proc start() throws IOException {
178
List<String> cmd = new ArrayList<>();
179
if (launcher != null) {
180
cmd.add(launcher);
181
} else {
182
cmd.add(new File(new File(System.getProperty("java.home"), "bin"),
183
"java").getPath());
184
}
185
cmd.add("-cp");
186
StringBuilder cp = new StringBuilder();
187
for (URL url: ((URLClassLoader)Proc.class.getClassLoader()).getURLs()) {
188
if (cp.length() != 0) {
189
cp.append(File.pathSeparatorChar);
190
}
191
cp.append(url.getFile());
192
}
193
cmd.add(cp.toString());
194
for (Entry<String,String> e: prop.entrySet()) {
195
cmd.add("-D" + e.getKey() + "=" + e.getValue());
196
}
197
if (!perms.isEmpty()) {
198
Path p = Files.createTempFile(
199
Paths.get(".").toAbsolutePath(), "policy", null);
200
StringBuilder sb = new StringBuilder();
201
sb.append("grant {\n");
202
for (Permission perm: perms) {
203
// Sometimes a permission has no name or actions.
204
// but it's safe to use an empty string.
205
String s = String.format("%s \"%s\", \"%s\"",
206
perm.getClass().getCanonicalName(),
207
perm.getName()
208
.replace("\\", "\\\\").replace("\"", "\\\""),
209
perm.getActions());
210
sb.append(" permission ").append(s).append(";\n");
211
}
212
sb.append("};\n");
213
Files.write(p, sb.toString().getBytes());
214
cmd.add("-Djava.security.policy=" + p.toString());
215
}
216
cmd.add(clazz);
217
for (String s: args) {
218
cmd.add(s);
219
}
220
if (debug != null) {
221
System.out.println("PROC: " + debug + " cmdline: " + cmd);
222
}
223
ProcessBuilder pb = new ProcessBuilder(cmd);
224
for (Entry<String,String> e: env.entrySet()) {
225
pb.environment().put(e.getKey(), e.getValue());
226
}
227
if (inheritIO) {
228
pb.inheritIO();
229
} else if (noDump) {
230
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
231
} else {
232
pb.redirectError(ProcessBuilder.Redirect.appendTo(new File(DFILE)));
233
}
234
p = pb.start();
235
br = new BufferedReader(new InputStreamReader(p.getInputStream()));
236
return this;
237
}
238
String getId(String suffix) {
239
if (debug != null) {
240
return debug + "." + suffix;
241
} else {
242
return System.identityHashCode(this) + "." + suffix;
243
}
244
}
245
// Reads a line from stdout of proc
246
public String readLine() throws IOException {
247
String s = br.readLine();
248
if (debug != null) {
249
System.out.println("PROC: " + debug + " readline: " +
250
(s == null ? "<EOF>" : s));
251
}
252
return s;
253
}
254
// Reads a special line from stdout of proc
255
public String readData() throws Exception {
256
while (true) {
257
String s = readLine();
258
if (s == null) {
259
if (p.waitFor() != 0) {
260
throw new Exception("Proc abnormal end");
261
} else {
262
return s;
263
}
264
}
265
if (s.startsWith(PREFIX)) {
266
return s.substring(PREFIX.length());
267
}
268
}
269
}
270
// Writes text into stdin of proc
271
public void println(String s) throws IOException {
272
if (debug != null) {
273
System.out.println("PROC: " + debug + " println: " + s);
274
}
275
write((s + "\n").getBytes());
276
}
277
// Writes data into stdin of proc
278
public void write(byte[] b) throws IOException {
279
p.getOutputStream().write(b);
280
p.getOutputStream().flush();
281
}
282
// Reads all output and wait for process end
283
public int waitFor() throws Exception {
284
while (true) {
285
String s = readLine();
286
if (s == null) {
287
break;
288
}
289
}
290
return p.waitFor();
291
}
292
293
// The following methods are used inside a proc
294
295
// Writes out a BASE64 binary with a prefix
296
public static void binOut(byte[] data) {
297
System.out.println(PREFIX + Base64.getEncoder().encodeToString(data));
298
}
299
// Reads in a line of BASE64 binary
300
public static byte[] binIn() throws Exception {
301
return Base64.getDecoder().decode(textIn());
302
}
303
// Writes out a text with a prefix
304
public static void textOut(String data) {
305
System.out.println(PREFIX + data);
306
}
307
// Reads in a line of text
308
public static String textIn() throws Exception {
309
StringBuilder sb = new StringBuilder();
310
boolean isEmpty = true;
311
while (true) {
312
int i = System.in.read();
313
if (i == -1) {
314
break;
315
}
316
isEmpty = false;
317
if (i == '\n') {
318
break;
319
}
320
if (i != 13) {
321
// Force it to a char, so only simple ASCII works.
322
sb.append((char)i);
323
}
324
}
325
return isEmpty ? null : sb.toString();
326
}
327
// Sends string to stderr. If inheritIO is not called, they will
328
// be collected into DFILE
329
public static void d(String s) throws IOException {
330
System.err.println(s);
331
}
332
// Sends an exception to stderr
333
public static void d(Throwable e) throws IOException {
334
e.printStackTrace();
335
}
336
}
337
338