Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.internal.jvmstat/linux/classes/sun/jvmstat/PlatformSupportImpl.java
41152 views
1
/*
2
* Copyright (c) 2018, 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. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.jvmstat;
27
28
import java.io.*;
29
import java.util.*;
30
import java.util.regex.*;
31
import java.nio.file.Path;
32
import java.nio.file.Paths;
33
import java.nio.file.Files;
34
import java.nio.charset.*;
35
36
/*
37
* Linux specific implementation of the PlatformSupport routines
38
* providing process ID and temp directory support for host and
39
* cgroup container processes.
40
*/
41
public class PlatformSupportImpl extends PlatformSupport {
42
private static final String containerTmpPath = "/root" + getTemporaryDirectory();
43
private static final String pidPatternStr = "^[0-9]+$";
44
45
/*
46
* Return the temporary directories that the VM uses for the attach
47
* and perf data files. This function returns the traditional
48
* /tmp directory in addition to paths within the /proc file system
49
* allowing access to container tmp directories such as /proc/{pid}/root/tmp.
50
*
51
* It is important that this directory is well-known and the
52
* same for all VM instances. It cannot be affected by configuration
53
* variables such as java.io.tmpdir.
54
*
55
* Implementation Details:
56
*
57
* Java processes that run in docker containers are typically running
58
* under cgroups with separate pid namespaces which means that pids
59
* within the container are different that the pid which is visible
60
* from the host. The container pids typically start with 1 and
61
* increase. The java process running in the container will use these
62
* pids when creating the hsperfdata files. In order to locate java
63
* processes that are running in containers, we take advantage of
64
* the Linux proc file system which maps the containers tmp directory
65
* to the hosts under /proc/{hostpid}/root/tmp. We use the /proc status
66
* file /proc/{hostpid}/status to determine the containers pid and
67
* then access the hsperfdata file. The status file contains an
68
* entry "NSPid:" which shows the mapping from the hostpid to the
69
* containers pid.
70
*
71
* Example:
72
*
73
* NSPid: 24345 11
74
*
75
* In this example process 24345 is visible from the host,
76
* is running under the PID namespace and has a container specific
77
* pid of 11.
78
*
79
* The search for Java processes is done by first looking in the
80
* traditional /tmp for host process hsperfdata files and then
81
* the search will container in every /proc/{pid}/root/tmp directory.
82
* There are of course added complications to this search that
83
* need to be taken into account.
84
*
85
* 1. duplication of tmp directories
86
*
87
* /proc/{hostpid}/root/tmp directories exist for many processes
88
* that are running on a Linux kernel that has cgroups enabled even
89
* if they are not running in a container. To avoid this duplication,
90
* we compare the inode of the /proc tmp directories to /tmp and
91
* skip these duplicated directories.
92
*
93
* 2. Containerized processes without PID namespaces being enabled.
94
*
95
* If a container is running a Java process without namespaces being
96
* enabled, an hsperfdata file will only be located at
97
* /proc/{hostpid}/root/tmp/{hostpid}. This is handled by
98
* checking the last component in the path for both the hostpid
99
* and potential namespacepids (if one exists).
100
*/
101
public List<String> getTemporaryDirectories(int pid) {
102
FilenameFilter pidFilter;
103
Matcher pidMatcher;
104
Pattern pidPattern = Pattern.compile(pidPatternStr);
105
long tmpInode = 0;
106
107
File procdir = new File("/proc");
108
109
if (pid != 0) {
110
pidPattern = Pattern.compile(Integer.toString(pid));
111
}
112
else {
113
pidPattern = Pattern.compile(pidPatternStr);
114
}
115
pidMatcher = pidPattern.matcher("");
116
117
// Add the default temporary directory first
118
List<String> v = new ArrayList<>();
119
v.add(getTemporaryDirectory());
120
121
try {
122
File f = new File(getTemporaryDirectory());
123
tmpInode = (Long)Files.getAttribute(f.toPath(), "unix:ino");
124
}
125
catch (IOException e) {}
126
127
pidFilter = new FilenameFilter() {
128
public boolean accept(File dir, String name) {
129
if (!dir.isDirectory())
130
return false;
131
pidMatcher.reset(name);
132
return pidMatcher.matches();
133
}
134
};
135
136
File[] dirs = procdir.listFiles(pidFilter);
137
138
// Add all unique /proc/{pid}/root/tmp dirs that are not mapped to /tmp
139
for (File dir : dirs) {
140
String containerTmpDir = dir.getAbsolutePath() + containerTmpPath;
141
File containerFile = new File(containerTmpDir);
142
143
try {
144
long procInode = (Long)Files.getAttribute(containerFile.toPath(), "unix:ino");
145
if (containerFile.exists() && containerFile.isDirectory() &&
146
containerFile.canRead() && procInode != tmpInode) {
147
v.add(containerTmpDir);
148
}
149
}
150
catch (IOException e) {}
151
}
152
153
return v;
154
}
155
156
157
/*
158
* Extract either the host PID or the NameSpace PID
159
* from a file path.
160
*
161
* File path should be in 1 of these 2 forms:
162
*
163
* /proc/{pid}/root/tmp/hsperfdata_{user}/{nspid}
164
* or
165
* /tmp/hsperfdata_{user}/{pid}
166
*
167
* In either case we want to return {pid} and NOT {nspid}
168
*
169
* This function filters out host pids which do not have
170
* associated hsperfdata files. This is due to the fact that
171
* getTemporaryDirectories will return /proc/{pid}/root/tmp
172
* paths for all container processes whether they are java
173
* processes or not causing duplicate matches.
174
*/
175
public int getLocalVmId(File file) throws NumberFormatException {
176
String p = file.getAbsolutePath();
177
String s[] = p.split("\\/");
178
179
// Determine if this file is from a container
180
if (s.length == 7 && s[1].equals("proc")) {
181
int hostpid = Integer.parseInt(s[2]);
182
int nspid = Integer.parseInt(s[6]);
183
if (nspid == hostpid || nspid == getNamespaceVmId(hostpid)) {
184
return hostpid;
185
}
186
else {
187
return -1;
188
}
189
}
190
else {
191
return Integer.parseInt(file.getName());
192
}
193
}
194
195
196
/*
197
* Return the inner most namespaced PID if there is one,
198
* otherwise return the original PID.
199
*/
200
public int getNamespaceVmId(int pid) {
201
// Assuming a real procfs sits beneath, reading this doesn't block
202
// nor will it consume a lot of memory.
203
Path statusPath = Paths.get("/proc", Integer.toString(pid), "status");
204
if (Files.notExists(statusPath)) {
205
return pid; // Likely a bad pid, but this is properly handled later.
206
}
207
208
try {
209
for (String line : Files.readAllLines(statusPath, StandardCharsets.UTF_8)) {
210
String[] parts = line.split(":");
211
if (parts.length == 2 && parts[0].trim().equals("NSpid")) {
212
parts = parts[1].trim().split("\\s+");
213
// The last entry represents the PID the JVM "thinks" it is.
214
// Even in non-namespaced pids these entries should be
215
// valid. You could refer to it as the inner most pid.
216
int ns_pid = Integer.parseInt(parts[parts.length - 1]);
217
return ns_pid;
218
}
219
}
220
// Old kernels may not have NSpid field (i.e. 3.10).
221
// Fallback to original pid in the event we cannot deduce.
222
return pid;
223
} catch (NumberFormatException | IOException x) {
224
return pid;
225
}
226
}
227
}
228
229