diff options
author | Peter Hallam <peterhal@google.com> | 2010-05-03 12:57:15 -0700 |
---|---|---|
committer | Peter Hallam <peterhal@google.com> | 2010-05-04 16:30:12 -0700 |
commit | 6b811c5daec1b28e6f63b57f98a032236f2c3cf7 (patch) | |
tree | a733f20e87a9739253d495c14d54e7d253e35771 /luni-kernel/src/main/native/java_lang_ProcessManager.cpp | |
parent | 0a98ab45e3566542f2d669eb0ffd28a560d97d28 (diff) | |
download | libcore-6b811c5daec1b28e6f63b57f98a032236f2c3cf7.zip libcore-6b811c5daec1b28e6f63b57f98a032236f2c3cf7.tar.gz libcore-6b811c5daec1b28e6f63b57f98a032236f2c3cf7.tar.bz2 |
Merge awt-kernel, icu, luni-kernel, prefs, security-kernel, x-net into luni
Merge xml except xmlpull and kxml into luni
Diffstat (limited to 'luni-kernel/src/main/native/java_lang_ProcessManager.cpp')
-rw-r--r-- | luni-kernel/src/main/native/java_lang_ProcessManager.cpp | 419 |
1 files changed, 0 insertions, 419 deletions
diff --git a/luni-kernel/src/main/native/java_lang_ProcessManager.cpp b/luni-kernel/src/main/native/java_lang_ProcessManager.cpp deleted file mode 100644 index 666a8c7..0000000 --- a/luni-kernel/src/main/native/java_lang_ProcessManager.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "ProcessManager" - -#include <sys/resource.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> -#include <fcntl.h> -#include <signal.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#include "jni.h" -#include "JNIHelp.h" -#include "utils/Log.h" - -/** Environment variables. */ -extern char **environ; - -static jmethodID onExitMethod = NULL; -static jfieldID descriptorField = NULL; - -#ifdef ANDROID -// Keeps track of the system properties fd so we don't close it. -static int androidSystemPropertiesFd = -1; -#endif - -/* - * These are constants shared with the higher level code in - * ProcessManager.java. - */ -#define WAIT_STATUS_UNKNOWN (-1) // unknown child status -#define WAIT_STATUS_NO_CHILDREN (-2) // no children to wait for -#define WAIT_STATUS_STRANGE_ERRNO (-3) // observed an undocumented errno - -/** Closes a file descriptor. */ -static void java_lang_ProcessManager_close(JNIEnv* env, - jclass, jobject javaDescriptor) { - int fd = env->GetIntField(javaDescriptor, descriptorField); - if (TEMP_FAILURE_RETRY(close(fd)) == -1) { - jniThrowIOException(env, errno); - } -} - -/** - * Kills process with the given ID. - */ -static void java_lang_ProcessManager_kill(JNIEnv* env, jclass clazz, jint pid) { - int result = kill((pid_t) pid, SIGKILL); - if (result == -1) { - jniThrowIOException(env, errno); - } -} - -/** - * Loops indefinitely and calls ProcessManager.onExit() when children exit. - */ -static void java_lang_ProcessManager_watchChildren(JNIEnv* env, jobject o) { - if (onExitMethod == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", - "staticInitialize() must run first."); - } - - while (1) { - int status; - - /* wait for children in our process group */ - pid_t pid = waitpid(0, &status, 0); - - if (pid >= 0) { - // Extract real status. - if (WIFEXITED(status)) { - status = WEXITSTATUS(status); - } else if (WIFSIGNALED(status)) { - status = WTERMSIG(status); - } else if (WIFSTOPPED(status)) { - status = WSTOPSIG(status); - } else { - status = WAIT_STATUS_UNKNOWN; - } - } else { - /* - * The pid should be -1 already, but force it here just in case - * we somehow end up with some other negative value. - */ - pid = -1; - - switch (errno) { - case ECHILD: { - /* - * Expected errno: There are no children to wait() - * for. The callback will sleep until it is - * informed of another child coming to life. - */ - status = WAIT_STATUS_NO_CHILDREN; - break; - } - case EINTR: { - /* - * An unblocked signal came in while waiting; just - * retry the wait(). - */ - continue; - } - default: { - /* - * Unexpected errno, so squawk! Note: Per the - * Linux docs, there are no errnos defined for - * wait() other than the two that are handled - * immediately above. - */ - LOGE("Error %d calling wait(): %s", errno, - strerror(errno)); - status = WAIT_STATUS_STRANGE_ERRNO; - break; - } - } - } - - env->CallVoidMethod(o, onExitMethod, pid, status); - if (env->ExceptionOccurred()) { - /* - * The callback threw, so break out of the loop and return, - * letting the exception percolate up. - */ - break; - } - } -} - -/** Close all open fds > 2 (i.e. everything but stdin/out/err), != skipFd. */ -static void closeNonStandardFds(int skipFd) { - // TODO: rather than close all these non-open files, we could look in /proc/self/fd. - struct rlimit rlimit; - getrlimit(RLIMIT_NOFILE, &rlimit); - const int max_fd = rlimit.rlim_max; - for (int fd = 3; fd < max_fd; ++fd) { - if (fd != skipFd -#ifdef ANDROID - && fd != androidSystemPropertiesFd -#endif - ) { - close(fd); - } - } -} - -#define PIPE_COUNT (4) // number of pipes used to communicate with child proc - -/** Closes all pipes in the given array. */ -static void closePipes(int pipes[], int skipFd) { - int i; - for (i = 0; i < PIPE_COUNT * 2; i++) { - int fd = pipes[i]; - if (fd == -1) { - return; - } - if (fd != skipFd) { - close(pipes[i]); - } - } -} - -/** Executes a command in a child process. */ -static pid_t executeProcess(JNIEnv* env, char** commands, char** environment, - const char* workingDirectory, jobject inDescriptor, - jobject outDescriptor, jobject errDescriptor, - jboolean redirectErrorStream) { - int i, result, error; - - // Create 4 pipes: stdin, stdout, stderr, and an exec() status pipe. - int pipes[PIPE_COUNT * 2] = { -1, -1, -1, -1, -1, -1, -1, -1 }; - for (i = 0; i < PIPE_COUNT; i++) { - if (pipe(pipes + i * 2) == -1) { - jniThrowIOException(env, errno); - closePipes(pipes, -1); - return -1; - } - } - int stdinIn = pipes[0]; - int stdinOut = pipes[1]; - int stdoutIn = pipes[2]; - int stdoutOut = pipes[3]; - int stderrIn = pipes[4]; - int stderrOut = pipes[5]; - int statusIn = pipes[6]; - int statusOut = pipes[7]; - - pid_t childPid = fork(); - - // If fork() failed... - if (childPid == -1) { - jniThrowIOException(env, errno); - closePipes(pipes, -1); - return -1; - } - - // If this is the child process... - if (childPid == 0) { - /* - * Note: We cannot malloc() or free() after this point! - * A no-longer-running thread may be holding on to the heap lock, and - * an attempt to malloc() or free() would result in deadlock. - */ - - // Replace stdin, out, and err with pipes. - dup2(stdinIn, 0); - dup2(stdoutOut, 1); - if (redirectErrorStream) { - dup2(stdoutOut, 2); - } else { - dup2(stderrOut, 2); - } - - // Close all but statusOut. This saves some work in the next step. - closePipes(pipes, statusOut); - - // Make statusOut automatically close if execvp() succeeds. - fcntl(statusOut, F_SETFD, FD_CLOEXEC); - - // Close remaining open fds with the exception of statusOut. - closeNonStandardFds(statusOut); - - // Switch to working directory. - if (workingDirectory != NULL) { - if (chdir(workingDirectory) == -1) { - goto execFailed; - } - } - - // Set up environment. - if (environment != NULL) { - environ = environment; - } - - // Execute process. By convention, the first argument in the arg array - // should be the command itself. In fact, I get segfaults when this - // isn't the case. - execvp(commands[0], commands); - - // If we got here, execvp() failed or the working dir was invalid. - execFailed: - error = errno; - write(statusOut, &error, sizeof(int)); - close(statusOut); - exit(error); - } - - // This is the parent process. - - // Close child's pipe ends. - close(stdinIn); - close(stdoutOut); - close(stderrOut); - close(statusOut); - - // Check status pipe for an error code. If execvp() succeeds, the other - // end of the pipe should automatically close, in which case, we'll read - // nothing. - int count = read(statusIn, &result, sizeof(int)); - close(statusIn); - if (count > 0) { - jniThrowIOException(env, result); - - close(stdoutIn); - close(stdinOut); - close(stderrIn); - - return -1; - } - - // Fill in file descriptor wrappers. - jniSetFileDescriptorOfFD(env, inDescriptor, stdoutIn); - jniSetFileDescriptorOfFD(env, outDescriptor, stdinOut); - jniSetFileDescriptorOfFD(env, errDescriptor, stderrIn); - - return childPid; -} - -/** Converts a Java String[] to a 0-terminated char**. */ -static char** convertStrings(JNIEnv* env, jobjectArray javaArray) { - if (javaArray == NULL) { - return NULL; - } - - char** array = NULL; - jsize length = env->GetArrayLength(javaArray); - array = (char**) malloc(sizeof(char*) * (length + 1)); - array[length] = 0; - jsize index; - for (index = 0; index < length; index++) { - jstring javaEntry = - (jstring) env->GetObjectArrayElement(javaArray, index); - char* entry = (char*) env->GetStringUTFChars(javaEntry, NULL); - array[index] = entry; - } - - return array; -} - -/** Frees a char** which was converted from a Java String[]. */ -static void freeStrings(JNIEnv* env, jobjectArray javaArray, char** array) { - if (javaArray == NULL) { - return; - } - - jsize length = env->GetArrayLength(javaArray); - jsize index; - for (index = 0; index < length; index++) { - jstring javaEntry = - (jstring) env->GetObjectArrayElement(javaArray, index); - env->ReleaseStringUTFChars(javaEntry, array[index]); - } - - free(array); -} - -/** - * Converts Java String[] to char** and delegates to executeProcess(). - */ -static pid_t java_lang_ProcessManager_exec( - JNIEnv* env, jclass clazz, jobjectArray javaCommands, - jobjectArray javaEnvironment, jstring javaWorkingDirectory, - jobject inDescriptor, jobject outDescriptor, jobject errDescriptor, - jboolean redirectErrorStream) { - - // Copy commands into char*[]. - char** commands = convertStrings(env, javaCommands); - - // Extract working directory string. - const char* workingDirectory = NULL; - if (javaWorkingDirectory != NULL) { - workingDirectory = env->GetStringUTFChars(javaWorkingDirectory, NULL); - } - - // Convert environment array. - char** environment = convertStrings(env, javaEnvironment); - - pid_t result = executeProcess( - env, commands, environment, workingDirectory, - inDescriptor, outDescriptor, errDescriptor, redirectErrorStream); - - // Temporarily clear exception so we can clean up. - jthrowable exception = env->ExceptionOccurred(); - env->ExceptionClear(); - - freeStrings(env, javaEnvironment, environment); - - // Clean up working directory string. - if (javaWorkingDirectory != NULL) { - env->ReleaseStringUTFChars(javaWorkingDirectory, workingDirectory); - } - - freeStrings(env, javaCommands, commands); - - // Re-throw exception if present. - if (exception != NULL) { - if (env->Throw(exception) < 0) { - LOGE("Error rethrowing exception!"); - } - } - - return result; -} - -/** - * Looks up Java members. - */ -static void java_lang_ProcessManager_staticInitialize(JNIEnv* env, - jclass clazz) { -#ifdef ANDROID - char* fdString = getenv("ANDROID_PROPERTY_WORKSPACE"); - if (fdString) { - androidSystemPropertiesFd = atoi(fdString); - } -#endif - - onExitMethod = env->GetMethodID(clazz, "onExit", "(II)V"); - if (onExitMethod == NULL) { - return; - } - - jclass fileDescriptorClass = env->FindClass("java/io/FileDescriptor"); - if (fileDescriptorClass == NULL) { - return; - } - descriptorField = env->GetFieldID(fileDescriptorClass, "descriptor", "I"); - if (descriptorField == NULL) { - return; - } -} - -static JNINativeMethod methods[] = { - { "close", "(Ljava/io/FileDescriptor;)V", (void*) java_lang_ProcessManager_close }, - { "kill", "(I)V", (void*) java_lang_ProcessManager_kill }, - { "staticInitialize", "()V", (void*) java_lang_ProcessManager_staticInitialize }, - { "watchChildren", "()V", (void*) java_lang_ProcessManager_watchChildren }, - { "exec", "([Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Z)I", - (void*) java_lang_ProcessManager_exec }, -}; -int register_java_lang_ProcessManager(JNIEnv* env) { - return jniRegisterNativeMethods(env, "java/lang/ProcessManager", methods, NELEM(methods)); -} |