Back-End/Java

[Java] 외부 jar 실행 후 pid(process id) 가져오기(Java 8)

유자맛바나나 2022. 2. 11. 03:40

 

In Java9

java 9 버전부터 Process Class가 pid 라는 메서드를 제공하므로 쉽게 얻을 수 있다

 

pid
public long pid​()
Returns the native process ID of the process. The native process ID is an identification number that the operating system assigns to the process.

Implementation Requirements:

The implementation of this method returns the process id as: toHandle().pid().

Returns: the native process id of the process

Throws: UnsupportedOperationException - if the Process implementation does not support this operation

Since:

9

출처: Oracle Official Doc | https://docs.oracle.com/javase/9/docs/api/java/lang/Process.html#pid--

 

In Java8

java 8 버전에서는 pid 메서드가 제공되지 않는다. java Process의 구현 객체는 OS에 따라 나뉘는데, Windows일 경우 ProcessImpl(또는 Win32Process) 구현체가, Unix 계열일 경우 UnixProcess 구현체가 인스턴스로 생성된다.

각 OS의 구현체에 따라 다른 방법을 적용해야 한다.

Unix 계열(Linux & MacOS)

Unix 계열의 구현체 UnixProcess는 'pid'라는 private field를 갖고 있다. 따라서 Reflection을 이용해 쉽게 값을 가져올 수 있다.

1) Code

public static long getProcessId(Process p) {
    long pid = -1;

    try {
        if (p.getClass().getName().equals("java.lang.UNIXProcess")) {
            Field f = p.getClass().getDeclaredField("pid");
            f.setAccessible(true);
            pid = f.getLong(p);
            f.setAccessible(false);
        }
    } catch (Exception e) {
        pid = -1;
    }
    return pid;
}

 

Windows 계열(Linux & MacOS)

Windows 계열의 구현체는 ProcessImpl 또는 Win32Process 구현체가 생성된다. 그리고 해당 구현체는 pid가 아닌 'handle' 이라는 private field가 있는데, process가 Windows API를 사용하는데 사용된다. 즉, handle을 이용해 Windows에게 pid를 묻는 query를 작성해야 한다. 이 과정을 JNA(Java Native Access) 라이브러리가 도와준다.

 

1) jna-platform Dependency 추가(그냥 jna 라이브러리도 가능)

https://search.maven.org/artifact/net.java.dev.jna/jna-platform/5.10.0/jar

 

Maven Central Repository Search

 

search.maven.org

2) Code

 

public static long getProcessId(Process p) {
    long pid = -1;

    try {
        if (p.getClass().getName().equals("java.lang.Win32Process") ||
                p.getClass().getName().equals("java.lang.ProcessImpl"))
        {
            Field f = p.getClass().getDeclaredField("handle");
            f.setAccessible(true);
            long handl = f.getLong(p);
            Kernel32 kernel = Kernel32.INSTANCE;
            WinNT.HANDLE hand = new WinNT.HANDLE();
            hand.setPointer(Pointer.createConstant(handl));
            pid = kernel.GetProcessId(hand);
            f.setAccessible(false);
        }
    } catch (Exception e) {
        pid = -1;
    }
    return pid;
}

 

합친 코드(OS 관계 없이 PID를 구한다)

public static long getProcessId(Process p) {
    long pid = -1;

    try {
        if (p.getClass().getName().equals("java.lang.UNIXProcess")) {
            Field f = p.getClass().getDeclaredField("pid");
            f.setAccessible(true);
            pid = f.getLong(p);
            f.setAccessible(false);
        } else if (p.getClass().getName().equals("java.lang.Win32Process") ||
                p.getClass().getName().equals("java.lang.ProcessImpl")) {
            Field f = p.getClass().getDeclaredField("handle");
            f.setAccessible(true);
            long handl = f.getLong(p);
            Kernel32 kernel = Kernel32.INSTANCE;
            WinNT.HANDLE hand = new WinNT.HANDLE();
            hand.setPointer(Pointer.createConstant(handl));
            pid = kernel.GetProcessId(hand);
            f.setAccessible(false);
        }
    } catch (Exception e) {
        pid = -1;
    }
    return pid;
}

 

 

 

References

https://stackoverflow.com/questions/4750470/how-to-get-pid-of-process-ive-just-started-within-java-program