Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java
40942 views
1
/*
2
* Copyright (c) 2020, 2021, 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
25
/*
26
* @test
27
* @summary Test JFR recording controlled via JMX across container boundary.
28
* @requires docker.support
29
* @library /test/lib
30
* @modules java.base/jdk.internal.misc
31
* java.management
32
* jdk.jartool/sun.tools.jar
33
* @build EventProducer
34
* @run main TestJFRWithJMX
35
*/
36
37
import java.io.BufferedOutputStream;
38
import java.io.File;
39
import java.io.FileOutputStream;
40
import java.io.IOException;
41
import java.lang.management.ManagementFactory;
42
import java.time.Instant;
43
import java.util.concurrent.atomic.AtomicReference;
44
import java.util.function.Consumer;
45
46
import javax.management.MBeanServerConnection;
47
import javax.management.remote.JMXServiceURL;
48
import javax.management.remote.JMXConnectorFactory;
49
import javax.management.remote.JMXConnector;
50
51
import jdk.jfr.consumer.RecordedEvent;
52
import jdk.jfr.consumer.RecordingFile;
53
import jdk.management.jfr.FlightRecorderMXBean;
54
55
import jdk.test.lib.Asserts;
56
import jdk.test.lib.Container;
57
import jdk.test.lib.Platform;
58
import jdk.test.lib.Utils;
59
import jdk.test.lib.containers.docker.Common;
60
import jdk.test.lib.containers.docker.DockerRunOptions;
61
import jdk.test.lib.containers.docker.DockerTestUtils;
62
import jdk.test.lib.process.ProcessTools;
63
64
import jtreg.SkippedException;
65
66
67
public class TestJFRWithJMX {
68
static final String imageName = Common.imageName("jfr-jmx");
69
static final int PORT = 9010;
70
static final int HOW_LONG_TO_RECORD_SECONDS = 10;
71
72
static final AtomicReference<String> ipAddr = new AtomicReference();
73
74
public static void main(String[] args) throws Exception {
75
if (!DockerTestUtils.canTestDocker()) {
76
throw new SkippedException("Docker is not supported on this host");
77
}
78
79
if (isPodman() & !Platform.isRoot()) {
80
throw new SkippedException("test cannot be run under rootless podman configuration");
81
}
82
83
DockerTestUtils.buildJdkDockerImage(imageName, "Dockerfile-BasicTest", "jdk-docker");
84
85
try {
86
test();
87
} finally {
88
DockerTestUtils.removeDockerImage(imageName);
89
}
90
}
91
92
static void test() throws Exception {
93
String containerName = "jmx-jfr-observee" + Instant.now().toString().replace(':', '-');
94
ProcessBuilder pb = buildDockerJavaProcess(containerName);
95
Process p = ProcessTools.startProcess("monitored-container", pb, outputConsumer);
96
97
// wait for the target process to communicate the IP address
98
while(ipAddr.get() == null) {
99
Thread.sleep(100);
100
}
101
102
File transferredRecording = null;
103
try {
104
try ( JMXConnector connector = waitForJmxConnection(ipAddr.get(), PORT) ) {
105
FlightRecorderMXBean bean = getJfrBean(connector);
106
107
long recordingId = record(bean, HOW_LONG_TO_RECORD_SECONDS * 1000);
108
long streamId = bean.openStream(recordingId, null);
109
transferredRecording = transferRecording(bean, streamId);
110
111
bean.closeStream(streamId);
112
bean.closeRecording(recordingId);
113
}
114
} finally {
115
killContainer(containerName);
116
p.waitFor();
117
}
118
119
System.out.println("Recording was transferred to: " + transferredRecording.getPath());
120
verifyRecording(transferredRecording);
121
}
122
123
static ProcessBuilder buildDockerJavaProcess(String containerName) throws Exception {
124
DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "EventProducer")
125
.addDockerOpts("--name", containerName)
126
.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/")
127
.addDockerOpts("--hostname", "jmx-jfr-test")
128
.addDockerOpts("-p", "" + PORT + ":" + PORT)
129
.addJavaOpts("-cp", "/test-classes/")
130
.addJavaOpts("-Dcom.sun.management.jmxremote", "-Dcom.sun.management.jmxremote.port=" + PORT)
131
.addJavaOpts("-Dcom.sun.management.jmxremote.local.only=false")
132
.addJavaOpts("-Dcom.sun.management.jmxremote.authenticate=false")
133
.addJavaOpts("-Dcom.sun.management.jmxremote.ssl=false");
134
135
return new ProcessBuilder(DockerTestUtils.buildJavaCommand(opts));
136
}
137
138
static long record(FlightRecorderMXBean bean, int howLong) throws Exception {
139
long id = bean.newRecording();
140
bean.setPredefinedConfiguration(id, "default");
141
bean.startRecording(id);
142
Thread.sleep(howLong);
143
144
bean.stopRecording(id);
145
146
String fn = "/tmp/recording-" + ProcessHandle.current().pid() + ".jfr";
147
bean.copyTo(id, fn);
148
System.out.println("Wrote recording to: " + fn);
149
return id;
150
}
151
152
static void verifyRecording(File f) throws Exception {
153
boolean foundExpectedEvent = false;
154
String expectedEventName = "EventProducer$SimpleEvent";
155
156
try (RecordingFile recordingFile = new RecordingFile(f.toPath())) {
157
while (recordingFile.hasMoreEvents()) {
158
RecordedEvent event = recordingFile.readEvent();
159
if(event.getEventType().getName().equals(expectedEventName)) {
160
foundExpectedEvent = true;
161
break;
162
}
163
}
164
165
Asserts.assertTrue(foundExpectedEvent,
166
"Could not find the expected event in the recording: " +
167
expectedEventName);
168
}
169
}
170
171
static void killContainer(String containerName) throws Exception {
172
new ProcessBuilder(Container.ENGINE_COMMAND, "kill", containerName)
173
.start()
174
.waitFor();
175
}
176
177
static Consumer<String> outputConsumer = s -> {
178
if (ipAddr.get() != null) {
179
return;
180
}
181
182
if (s.contains(EventProducer.HOST_ADDR_TAG)) {
183
String ip = s.replace(EventProducer.HOST_ADDR_TAG, "");
184
System.out.println("Observee ip: " + ip);
185
ipAddr.set(ip);
186
}
187
};
188
189
// try connecting in a loop, it may take some time for target process to be ready for JMX connection
190
static JMXConnector waitForJmxConnection(String host, int port) throws Exception {
191
String urlPath = "/jndi/rmi://" + host + ":" + port + "/jmxrmi";
192
JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath);
193
while (true) {
194
try {
195
return JMXConnectorFactory.connect(url);
196
} catch (IOException e) {
197
System.out.println("establishJmxConnection() thrown IOException: " + e.getMessage());
198
}
199
Thread.sleep(1000);
200
}
201
}
202
203
static FlightRecorderMXBean getJfrBean(JMXConnector connector) throws Exception {
204
MBeanServerConnection connection = connector.getMBeanServerConnection();
205
return ManagementFactory.newPlatformMXBeanProxy(connection,
206
"jdk.management.jfr:type=FlightRecorder",
207
FlightRecorderMXBean.class);
208
}
209
210
static File transferRecording(FlightRecorderMXBean bean, long streamId) throws Exception {
211
File f = Utils.createTempFile("recording-" + streamId + "-", ".jfr").toFile();
212
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(f))) {
213
while (true) {
214
byte[] data = bean.readStream(streamId);
215
if (data == null) {
216
bos.flush();
217
return f;
218
}
219
bos.write(data);
220
}
221
}
222
}
223
224
static boolean isPodman() {
225
String[] parts = Container.ENGINE_COMMAND
226
.toLowerCase()
227
.split(File.pathSeparator);
228
return "podman".equals(parts[parts.length - 1]);
229
}
230
}
231
232