jdk/src/java.base/windows/native/libjava/ProcessHandleImpl_win.c
changeset 30899 d2408e757489
child 30955 9f660470002c
equal deleted inserted replaced
30898:6027a68229dc 30899:d2408e757489
       
     1 /*
       
     2  * Copyright (c) 2014, 2015, 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 
       
    27 #include "jni.h"
       
    28 #include "jvm.h"
       
    29 #include "jni_util.h"
       
    30 #include "java_lang_ProcessHandleImpl.h"
       
    31 #include "java_lang_ProcessHandleImpl_Info.h"
       
    32 
       
    33 #include <windows.h>
       
    34 #include <tlhelp32.h>
       
    35 
       
    36 static void getStatInfo(JNIEnv *env, HANDLE handle, jobject jinfo);
       
    37 static void getCmdlineInfo(JNIEnv *env, HANDLE handle, jobject jinfo);
       
    38 static void procToUser( JNIEnv *env, HANDLE handle, jobject jinfo);
       
    39 
       
    40 /**************************************************************
       
    41  * Implementation of ProcessHandleImpl_Info native methods.
       
    42  */
       
    43 
       
    44 /* Field id for jString 'command' in java.lang.ProcessHandle.Info */
       
    45 static jfieldID ProcessHandleImpl_Info_commandID;
       
    46 
       
    47 /* Field id for jString[] 'arguments' in java.lang.ProcessHandle.Info */
       
    48 static jfieldID ProcessHandleImpl_Info_argumentsID;
       
    49 
       
    50 /* Field id for jlong 'totalTime' in java.lang.ProcessHandle.Info */
       
    51 static jfieldID ProcessHandleImpl_Info_totalTimeID;
       
    52 
       
    53 /* Field id for jlong 'startTime' in java.lang.ProcessHandle.Info */
       
    54 static jfieldID ProcessHandleImpl_Info_startTimeID;
       
    55 
       
    56 /* Field id for jString 'accountName' in java.lang.ProcessHandleImpl.UserPrincipal */
       
    57 static jfieldID ProcessHandleImpl_Info_userID;
       
    58 
       
    59 /**************************************************************
       
    60  * Static method to initialize field IDs.
       
    61  *
       
    62  * Class:     java_lang_ProcessHandleImpl_Info
       
    63  * Method:    initIDs
       
    64  * Signature: ()V
       
    65  */
       
    66 JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_initIDs
       
    67   (JNIEnv *env, jclass clazz) {
       
    68 
       
    69     CHECK_NULL(ProcessHandleImpl_Info_commandID = (*env)->GetFieldID(env,
       
    70         clazz, "command", "Ljava/lang/String;"));
       
    71     CHECK_NULL(ProcessHandleImpl_Info_argumentsID = (*env)->GetFieldID(env,
       
    72         clazz, "arguments", "[Ljava/lang/String;"));
       
    73     CHECK_NULL(ProcessHandleImpl_Info_totalTimeID = (*env)->GetFieldID(env,
       
    74         clazz, "totalTime", "J"));
       
    75     CHECK_NULL(ProcessHandleImpl_Info_startTimeID = (*env)->GetFieldID(env,
       
    76         clazz, "startTime", "J"));
       
    77     CHECK_NULL(ProcessHandleImpl_Info_userID = (*env)->GetFieldID(env,
       
    78         clazz, "user", "Ljava/lang/String;"));
       
    79 }
       
    80 
       
    81 /*
       
    82  * Block until a child process exits and return its exit code.
       
    83  */
       
    84 JNIEXPORT jint JNICALL
       
    85 Java_java_lang_ProcessHandleImpl_waitForProcessExit0(JNIEnv* env,
       
    86                                               jclass junk,
       
    87                                               jlong jpid,
       
    88                                               jboolean reapStatus) {
       
    89     DWORD pid = (DWORD)jpid;
       
    90     DWORD exitValue = -1;
       
    91     HANDLE handle = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION,
       
    92                                 FALSE, pid);
       
    93     if (handle == NULL) {
       
    94         return exitValue;          // No process with that pid is alive
       
    95     }
       
    96     do {
       
    97         if (!GetExitCodeProcess(handle, &exitValue)) {
       
    98             JNU_ThrowByNameWithLastError(env,
       
    99                 "java/lang/Runtime", "GetExitCodeProcess");
       
   100             break;
       
   101         }
       
   102         if (exitValue == STILL_ACTIVE) {
       
   103             HANDLE events[2];
       
   104             events[0] = handle;
       
   105             events[1] = JVM_GetThreadInterruptEvent();
       
   106 
       
   107             if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
       
   108                                        FALSE,    /* Wait for ANY event */
       
   109                                        INFINITE) /* Wait forever */
       
   110                 == WAIT_FAILED) {
       
   111                 JNU_ThrowByNameWithLastError(env,
       
   112                     "java/lang/Runtime", "WaitForMultipleObjects");
       
   113                 break;
       
   114             }
       
   115         }
       
   116     } while (exitValue == STILL_ACTIVE);
       
   117     CloseHandle(handle);         // Ignore return code
       
   118     return exitValue;
       
   119 }
       
   120 
       
   121 /*
       
   122  * Returns the pid of the caller.
       
   123  *
       
   124  * Class:     java_lang_ProcessHandleImpl
       
   125  * Method:    getCurrentPid0
       
   126  * Signature: ()J
       
   127  */
       
   128 JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_getCurrentPid0
       
   129 (JNIEnv *env, jclass clazz) {
       
   130     DWORD  pid = GetCurrentProcessId();
       
   131     return (jlong)pid;
       
   132 }
       
   133 
       
   134 /*
       
   135  * Returns the parent pid of the requested pid.
       
   136  *
       
   137  * Class:     java_lang_ProcessHandleImpl
       
   138  * Method:    parent0
       
   139  * Signature: (J)J
       
   140  */
       
   141 JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_parent0
       
   142 (JNIEnv *env, jclass clazz, jlong jpid) {
       
   143 
       
   144     DWORD ppid = -1;
       
   145     DWORD wpid = (DWORD)jpid;
       
   146     PROCESSENTRY32 pe32;
       
   147     HANDLE hProcessSnap;
       
   148 
       
   149     // Take a snapshot of all processes in the system.
       
   150     hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
       
   151     if (hProcessSnap == INVALID_HANDLE_VALUE) {
       
   152         JNU_ThrowByName(env,
       
   153             "java/lang/RuntimeException", "snapshot not available");
       
   154         return -1;
       
   155     }
       
   156 
       
   157     // Retrieve information about the first process,
       
   158     pe32.dwSize = sizeof (PROCESSENTRY32);
       
   159     if (Process32First(hProcessSnap, &pe32)) {
       
   160         // Now walk the snapshot of processes, and
       
   161         do {
       
   162             if (wpid == pe32.th32ProcessID) {
       
   163                 ppid = pe32.th32ParentProcessID;
       
   164                 break;
       
   165             }
       
   166         } while (Process32Next(hProcessSnap, &pe32));
       
   167     } else {
       
   168         JNU_ThrowByName(env,
       
   169             "java/lang/RuntimeException", "snapshot not available");
       
   170         return -1;
       
   171     }
       
   172     CloseHandle(hProcessSnap); // Ignore return code
       
   173     return (jlong)ppid;
       
   174 }
       
   175 
       
   176 /*
       
   177  * Returns the children of the requested pid and optionally each parent.
       
   178  *
       
   179  * Class:     java_lang_ProcessHandleImpl
       
   180  * Method:    getChildPids
       
   181  * Signature: (J[J[J)I
       
   182  */
       
   183 JNIEXPORT jint JNICALL Java_java_lang_ProcessHandleImpl_getProcessPids0
       
   184 (JNIEnv *env, jclass clazz, jlong jpid,
       
   185     jlongArray jarray, jlongArray jparentArray) {
       
   186 
       
   187     HANDLE hProcessSnap;
       
   188     PROCESSENTRY32 pe32;
       
   189     DWORD ppid = (DWORD)jpid;
       
   190     size_t count = 0;
       
   191     jlong* pids = NULL;
       
   192     jlong* ppids = NULL;
       
   193     size_t parentArraySize = 0;
       
   194     size_t arraySize = 0;
       
   195 
       
   196     arraySize = (*env)->GetArrayLength(env, jarray);
       
   197     JNU_CHECK_EXCEPTION_RETURN(env, -1);
       
   198     if (jparentArray != NULL) {
       
   199         parentArraySize = (*env)->GetArrayLength(env, jparentArray);
       
   200         JNU_CHECK_EXCEPTION_RETURN(env, -1);
       
   201 
       
   202         if (arraySize != parentArraySize) {
       
   203             JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
       
   204             return 0;
       
   205         }
       
   206     }
       
   207 
       
   208     // Take a snapshot of all processes in the system.
       
   209     hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
       
   210     if (hProcessSnap == INVALID_HANDLE_VALUE) {
       
   211         JNU_ThrowByName(env,
       
   212             "java/lang/RuntimeException", "snapshot not available");
       
   213         return 0;
       
   214     }
       
   215 
       
   216     // Retrieve information about the first process,
       
   217     pe32.dwSize = sizeof (PROCESSENTRY32);
       
   218     if (Process32First(hProcessSnap, &pe32)) {
       
   219         do { // Block to break out of on Exception
       
   220             pids = (*env)->GetLongArrayElements(env, jarray, NULL);
       
   221             if (pids == NULL) {
       
   222                 break;
       
   223             }
       
   224             if (jparentArray != NULL) {
       
   225                 ppids  = (*env)->GetLongArrayElements(env, jparentArray, NULL);
       
   226                 if (ppids == NULL) {
       
   227                     break;
       
   228                 }
       
   229             }
       
   230             // Now walk the snapshot of processes, and
       
   231             // save information about each process in turn
       
   232             do {
       
   233                 if (ppid == 0 ||
       
   234                     (pe32.th32ParentProcessID > 0
       
   235                     && (pe32.th32ParentProcessID == ppid))) {
       
   236                     if (count < arraySize) {
       
   237                         // Only store if it fits
       
   238                         pids[count] = (jlong)pe32.th32ProcessID;
       
   239                         if (ppids != NULL) {
       
   240                             // Store the parentPid
       
   241                             ppids[count] = (jlong) pe32.th32ParentProcessID;
       
   242                         }
       
   243                     }
       
   244                     count++;    // Count to tabulate size needed
       
   245                 }
       
   246             } while (Process32Next(hProcessSnap, &pe32));
       
   247         } while (0);
       
   248 
       
   249         if (pids != NULL) {
       
   250             (*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
       
   251         }
       
   252         if (ppids != NULL) {
       
   253             (*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
       
   254         }
       
   255     } else {
       
   256         JNU_ThrowByName(env,
       
   257             "java/lang/RuntimeException", "snapshot not available");
       
   258         return 0;
       
   259     }
       
   260     CloseHandle(hProcessSnap);
       
   261     // If more pids than array had size for;  count will be greater than array size
       
   262     return (jint)count;
       
   263 }
       
   264 
       
   265 /*
       
   266  * Destroy the process.
       
   267  *
       
   268  * Class:     java_lang_ProcessHandleImpl
       
   269  * Method:    destroy0
       
   270  * Signature: (Z)V
       
   271  */
       
   272 JNIEXPORT jboolean JNICALL Java_java_lang_ProcessHandleImpl_destroy0
       
   273 (JNIEnv *env, jclass clazz, jlong jpid, jboolean force) {
       
   274     DWORD pid = (DWORD)jpid;
       
   275     HANDLE handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
       
   276     if (handle != NULL) {
       
   277         TerminateProcess(handle, 1);
       
   278         CloseHandle(handle);         // Ignore return code
       
   279         return JNI_TRUE;
       
   280     }
       
   281     return JNI_FALSE;
       
   282 }
       
   283 
       
   284 /*
       
   285  * Class:     java_lang_ProcessHandleImpl
       
   286  * Method:    isAlive0
       
   287  * Signature: (J)Z
       
   288  */
       
   289 JNIEXPORT jboolean JNICALL Java_java_lang_ProcessHandleImpl_isAlive0
       
   290 (JNIEnv *env, jclass clazz, jlong jpid) {
       
   291     DWORD pid = (DWORD)jpid;
       
   292 
       
   293     jboolean ret = JNI_FALSE;
       
   294     HANDLE handle =
       
   295         OpenProcess(THREAD_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION,
       
   296                     FALSE, pid);
       
   297     if (handle != NULL) {
       
   298         DWORD dwExitStatus;
       
   299 
       
   300         GetExitCodeProcess(handle, &dwExitStatus);
       
   301         CloseHandle(handle); // Ignore return code
       
   302         ret = (dwExitStatus == STILL_ACTIVE);
       
   303     }
       
   304     return ret;
       
   305 }
       
   306 
       
   307 /**
       
   308  * Assemble a 64 bit value from two 32 bit values.
       
   309  */
       
   310 static jlong jlong_from(jint high, jint low) {
       
   311     jlong result = 0;
       
   312     result = ((jlong)high << 32) | ((0x000000000ffffffff) & (jlong)low);
       
   313     return result;
       
   314 }
       
   315 
       
   316 /*
       
   317  * Fill in the Info object from the OS information about the process.
       
   318  *
       
   319  * Class:     java_lang_ProcessHandleImpl
       
   320  * Method:    info0
       
   321  * Signature: (J)V
       
   322  */
       
   323 JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_info0
       
   324   (JNIEnv *env, jobject jinfo, jlong jpid) {
       
   325     DWORD pid = (DWORD)jpid;
       
   326     int ret = 0;
       
   327     HANDLE handle =
       
   328         OpenProcess(THREAD_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION,
       
   329                     FALSE, pid);
       
   330     if (handle == NULL) {
       
   331         return;
       
   332     }
       
   333     getStatInfo(env, handle, jinfo);
       
   334     getCmdlineInfo(env, handle, jinfo);
       
   335     procToUser(env, handle, jinfo);
       
   336 
       
   337     CloseHandle(handle);                // Ignore return code
       
   338 }
       
   339 
       
   340 /**
       
   341  * Read /proc/<pid>/stat and fill in the fields of the Info object.
       
   342  * The executable name, plus the user, system, and start times are gathered.
       
   343  */
       
   344 static void getStatInfo(JNIEnv *env, HANDLE handle, jobject jinfo) {
       
   345     FILETIME CreationTime;
       
   346     FILETIME ExitTime;
       
   347     FILETIME KernelTime;
       
   348     FILETIME UserTime;
       
   349     jlong userTime;             // nanoseconds
       
   350     jlong totalTime;            // nanoseconds
       
   351     jlong startTime;            // nanoseconds
       
   352     UserTime.dwHighDateTime = 0;
       
   353     UserTime.dwLowDateTime = 0;
       
   354     KernelTime.dwHighDateTime = 0;
       
   355     KernelTime.dwLowDateTime = 0;
       
   356     CreationTime.dwHighDateTime = 0;
       
   357     CreationTime.dwLowDateTime = 0;
       
   358 
       
   359     if (GetProcessTimes(handle, &CreationTime, &ExitTime, &KernelTime, &UserTime)) {
       
   360         userTime = jlong_from(UserTime.dwHighDateTime, UserTime.dwLowDateTime);
       
   361         totalTime = jlong_from( KernelTime.dwHighDateTime, KernelTime.dwLowDateTime);
       
   362         totalTime = (totalTime + userTime) * 100;  // convert sum to nano-seconds
       
   363 
       
   364         startTime = jlong_from(CreationTime.dwHighDateTime,
       
   365                                CreationTime.dwLowDateTime) / 10000;
       
   366         startTime -= 11644473600000L; // Rebase Epoch from 1601 to 1970
       
   367 
       
   368         (*env)->SetLongField(env, jinfo,
       
   369                              ProcessHandleImpl_Info_totalTimeID, totalTime);
       
   370         JNU_CHECK_EXCEPTION(env);
       
   371         (*env)->SetLongField(env, jinfo,
       
   372                              ProcessHandleImpl_Info_startTimeID, startTime);
       
   373         JNU_CHECK_EXCEPTION(env);
       
   374     }
       
   375 }
       
   376 
       
   377 static void getCmdlineInfo(JNIEnv *env, HANDLE handle, jobject jinfo) {
       
   378     char exeName[1024];
       
   379     int bufsize = sizeof exeName;
       
   380     jstring commandObj;
       
   381 
       
   382     if (QueryFullProcessImageName(handle, 0,  exeName, &bufsize)) {
       
   383         commandObj = (*env)->NewStringUTF(env, exeName);
       
   384         CHECK_NULL(commandObj);
       
   385         (*env)->SetObjectField(env, jinfo,
       
   386                                ProcessHandleImpl_Info_commandID, commandObj);
       
   387     }
       
   388 }
       
   389 
       
   390 static void procToUser( JNIEnv *env, HANDLE handle, jobject jinfo) {
       
   391 #define TOKEN_LEN 256
       
   392     DWORD token_len = TOKEN_LEN;
       
   393     char token_buf[TOKEN_LEN];
       
   394     TOKEN_USER *token_user = (TOKEN_USER*)token_buf;
       
   395     HANDLE tokenHandle;
       
   396     WCHAR domain[255];
       
   397     WCHAR name[255];
       
   398     DWORD domainLen = sizeof(domain);
       
   399     DWORD nameLen = sizeof(name);
       
   400     SID_NAME_USE use;
       
   401     jstring s;
       
   402     int ret;
       
   403 
       
   404     if (!OpenProcessToken(handle, TOKEN_READ, &tokenHandle)) {
       
   405         return;
       
   406     }
       
   407 
       
   408     ret = GetTokenInformation(tokenHandle, TokenUser, token_user,
       
   409                               token_len, &token_len);
       
   410     CloseHandle(tokenHandle);           // always close handle
       
   411     if (!ret) {
       
   412         JNU_ThrowByNameWithLastError(env,
       
   413             "java/lang/RuntimeException", "GetTokenInformation");
       
   414         return;
       
   415     }
       
   416 
       
   417     if (LookupAccountSidW(NULL, token_user->User.Sid, &name[0], &nameLen,
       
   418                           &domain[0], &domainLen, &use) == 0) {
       
   419         // Name not available
       
   420         return;
       
   421     }
       
   422 
       
   423     s = (*env)->NewString(env, (const jchar *)name, (jsize)wcslen(name));
       
   424     CHECK_NULL(s);
       
   425     (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, s);
       
   426 }