Getting PID in Java/Scala (cross-platform)

The Scala/Java environment has a certain lack of features regarding process management - it's in a very good shape, but sometimes we need more. It's totally understable considering that the underlaying system is the JVM (in most cases), however once in a while we have to leave the sandbox. That was the case I've faced, and it got me to the problem how to get the ID of the process I started in JVM for various operating systems.

The solution I've got is cross-platform, and it requires both Reflection and JNA. It has been verified in:

  • macOS;
  • Windows 10;
  • Linux: both real (ArchLinux) and virtualized (WSL).

Without further ado, let me just share the code - it's compact and pretty much self-explanatory:

\src: GetPidExample.scala

#!/usr/bin/env scalas /*** scalaVersion := "2.12.3" libraryDependencies += "net.java.dev.jna" % "jna-platform" % "4.5.0" */ import com.sun.jna.platform.win32.Kernel32 import com.sun.jna.platform.win32.WinNT.HANDLE import com.sun.jna.Pointer import sys.process.Process def getPrivateLongField(proc: Any, name: String): Long = { val privateField = proc.getClass.getDeclaredField(name) privateField.synchronized { privateField.setAccessible(true) try { privateField.getLong(proc) } finally { privateField.setAccessible(false) } } } def pidJava(proc: Any): Long = { proc match { case unixProc: Any if unixProc.getClass.getName == "java.lang.UNIXProcess" => { getPrivateLongField(unixProc, "pid") } case windowsProc: Any if windowsProc.getClass.getName == "java.lang.ProcessImpl" => { val processHandle = getPrivateLongField(windowsProc, "handle") val kernel = Kernel32.INSTANCE val winHandle = new HANDLE() winHandle.setPointer(Pointer.createConstant(processHandle)) kernel.GetProcessId(winHandle) } case _ => throw new RuntimeException( "Cannot get PID of a " + proc.getClass.getName) } } def pid(p: Process): Long = { val procField = p.getClass.getDeclaredField("p") procField.synchronized { procField.setAccessible(true) val proc = procField.get(p) try { pidJava(proc) } finally { procField.setAccessible(false) } } } val processName = "ping -c1 8.8.8.8" val proc = Process(processName).run val id = pid(proc) println(s"Process '$processName' has PID: $id")
Scalateχ \src: GetPid.scalatex

Comments

Popular posts from this blog

Web application framework comparison by memory consumption

Trac Ticket Workflow

Shellcode detection using libemu