java_lang_ProcessManager.cpp revision 6c1e5f4ad36c1f51687aa2b059e998a7c2db2e36
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * you may not use this file except in compliance with the License.
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * You may obtain a copy of the License at
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License.
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#define LOG_TAG "ProcessManager"
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
19410530d90797fd49ad34c76a05a2c8f5147f88e1crazybob#include <sys/resource.h>
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include <sys/types.h>
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include <unistd.h>
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include <fcntl.h>
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include <stdlib.h>
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include <string.h>
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include <errno.h>
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include "jni.h"
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include "JNIHelp.h"
29a9f5c16a864ff63ba63f810410f8a27c086d5d52Elliott Hughes#include "JniConstants.h"
306c1e5f4ad36c1f51687aa2b059e998a7c2db2e36Elliott Hughes#include "Portability.h"
31e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes#include "ScopedLocalRef.h"
328545b837c61c3eaea2b8433b6791aa401f37e5f7Elliott Hughes#include "cutils/log.h"
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
34410530d90797fd49ad34c76a05a2c8f5147f88e1crazybob/** Close all open fds > 2 (i.e. everything but stdin/out/err), != skipFd. */
35a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughesstatic void closeNonStandardFds(int skipFd1, int skipFd2) {
3694367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes    // TODO: rather than close all these non-open files, we could look in /proc/self/fd.
37e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes    rlimit rlimit;
38410530d90797fd49ad34c76a05a2c8f5147f88e1crazybob    getrlimit(RLIMIT_NOFILE, &rlimit);
3994367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes    const int max_fd = rlimit.rlim_max;
4094367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes    for (int fd = 3; fd < max_fd; ++fd) {
41a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes        if (fd != skipFd1 && fd != skipFd2) {
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            close(fd);
43410530d90797fd49ad34c76a05a2c8f5147f88e1crazybob        }
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#define PIPE_COUNT (4) // number of pipes used to communicate with child proc
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** Closes all pipes in the given array. */
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectstatic void closePipes(int pipes[], int skipFd) {
51a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    for (int i = 0; i < PIPE_COUNT * 2; i++) {
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int fd = pipes[i];
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (fd == -1) {
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (fd != skipFd) {
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            close(pipes[i]);
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** Executes a command in a child process. */
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectstatic pid_t executeProcess(JNIEnv* env, char** commands, char** environment,
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        const char* workingDirectory, jobject inDescriptor,
651805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes        jobject outDescriptor, jobject errDescriptor,
661805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes        jboolean redirectErrorStream) {
67a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes
68a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    // Keep track of the system properties fd so we don't close it.
69a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    int androidSystemPropertiesFd = -1;
70a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    char* fdString = getenv("ANDROID_PROPERTY_WORKSPACE");
71a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    if (fdString) {
72a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes        androidSystemPropertiesFd = atoi(fdString);
73a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    }
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Create 4 pipes: stdin, stdout, stderr, and an exec() status pipe.
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int pipes[PIPE_COUNT * 2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
77a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    for (int i = 0; i < PIPE_COUNT; i++) {
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (pipe(pipes + i * 2) == -1) {
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            jniThrowIOException(env, errno);
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            closePipes(pipes, -1);
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return -1;
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int stdinIn = pipes[0];
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int stdinOut = pipes[1];
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int stdoutIn = pipes[2];
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int stdoutOut = pipes[3];
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int stderrIn = pipes[4];
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int stderrOut = pipes[5];
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int statusIn = pipes[6];
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int statusOut = pipes[7];
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    pid_t childPid = fork();
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // If fork() failed...
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (childPid == -1) {
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        jniThrowIOException(env, errno);
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        closePipes(pipes, -1);
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return -1;
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // If this is the child process...
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (childPid == 0) {
104410530d90797fd49ad34c76a05a2c8f5147f88e1crazybob        /*
1056c1e5f4ad36c1f51687aa2b059e998a7c2db2e36Elliott Hughes         * Note: We cannot malloc(3) or free(3) after this point!
1066c1e5f4ad36c1f51687aa2b059e998a7c2db2e36Elliott Hughes         * A thread in the parent that no longer exists in the child may have held the heap lock
1076c1e5f4ad36c1f51687aa2b059e998a7c2db2e36Elliott Hughes         * when we forked, so an attempt to malloc(3) or free(3) would result in deadlock.
108410530d90797fd49ad34c76a05a2c8f5147f88e1crazybob         */
109410530d90797fd49ad34c76a05a2c8f5147f88e1crazybob
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Replace stdin, out, and err with pipes.
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        dup2(stdinIn, 0);
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        dup2(stdoutOut, 1);
1131805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes        if (redirectErrorStream) {
1141805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes            dup2(stdoutOut, 2);
1151805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes        } else {
1161805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes            dup2(stderrOut, 2);
1171805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes        }
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Close all but statusOut. This saves some work in the next step.
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        closePipes(pipes, statusOut);
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Make statusOut automatically close if execvp() succeeds.
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        fcntl(statusOut, F_SETFD, FD_CLOEXEC);
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
125a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes        // Close remaining unwanted open fds.
126a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes        closeNonStandardFds(statusOut, androidSystemPropertiesFd);
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Switch to working directory.
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (workingDirectory != NULL) {
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (chdir(workingDirectory) == -1) {
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                goto execFailed;
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Set up environment.
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (environment != NULL) {
137a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes            extern char** environ; // Standard, but not in any header file.
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            environ = environment;
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Execute process. By convention, the first argument in the arg array
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // should be the command itself. In fact, I get segfaults when this
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // isn't the case.
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        execvp(commands[0], commands);
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // If we got here, execvp() failed or the working dir was invalid.
1476c1e5f4ad36c1f51687aa2b059e998a7c2db2e36Elliott HughesexecFailed:
1486c1e5f4ad36c1f51687aa2b059e998a7c2db2e36Elliott Hughes        int error = errno;
1496c1e5f4ad36c1f51687aa2b059e998a7c2db2e36Elliott Hughes        write(statusOut, &error, sizeof(int));
1506c1e5f4ad36c1f51687aa2b059e998a7c2db2e36Elliott Hughes        close(statusOut);
1516c1e5f4ad36c1f51687aa2b059e998a7c2db2e36Elliott Hughes        exit(error);
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // This is the parent process.
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Close child's pipe ends.
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    close(stdinIn);
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    close(stdoutOut);
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    close(stderrOut);
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    close(statusOut);
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Check status pipe for an error code. If execvp() succeeds, the other
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // end of the pipe should automatically close, in which case, we'll read
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // nothing.
165a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    int result;
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int count = read(statusIn, &result, sizeof(int));
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    close(statusIn);
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (count > 0) {
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        jniThrowIOException(env, result);
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        close(stdoutIn);
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        close(stdinOut);
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        close(stderrIn);
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return -1;
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Fill in file descriptor wrappers.
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    jniSetFileDescriptorOfFD(env, inDescriptor, stdoutIn);
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    jniSetFileDescriptorOfFD(env, outDescriptor, stdinOut);
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    jniSetFileDescriptorOfFD(env, errDescriptor, stderrIn);
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    return childPid;
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** Converts a Java String[] to a 0-terminated char**. */
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectstatic char** convertStrings(JNIEnv* env, jobjectArray javaArray) {
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (javaArray == NULL) {
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return NULL;
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
19294367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes    jsize length = env->GetArrayLength(javaArray);
193583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes    char** array = new char*[length + 1];
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    array[length] = 0;
195e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes    for (jsize i = 0; i < length; ++i) {
196e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes        ScopedLocalRef<jstring> javaEntry(env, reinterpret_cast<jstring>(env->GetObjectArrayElement(javaArray, i)));
197583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes        // We need to pass these strings to const-unfriendly code.
198e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes        char* entry = const_cast<char*>(env->GetStringUTFChars(javaEntry.get(), NULL));
199e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes        array[i] = entry;
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    return array;
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** Frees a char** which was converted from a Java String[]. */
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectstatic void freeStrings(JNIEnv* env, jobjectArray javaArray, char** array) {
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (javaArray == NULL) {
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return;
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
21194367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes    jsize length = env->GetArrayLength(javaArray);
212e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes    for (jsize i = 0; i < length; ++i) {
213e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes        ScopedLocalRef<jstring> javaEntry(env, reinterpret_cast<jstring>(env->GetObjectArrayElement(javaArray, i)));
214e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes        env->ReleaseStringUTFChars(javaEntry.get(), array[i]);
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
217583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes    delete[] array;
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Converts Java String[] to char** and delegates to executeProcess().
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
223a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughesstatic pid_t ProcessManager_exec(JNIEnv* env, jclass, jobjectArray javaCommands,
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        jobjectArray javaEnvironment, jstring javaWorkingDirectory,
2251805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes        jobject inDescriptor, jobject outDescriptor, jobject errDescriptor,
2261805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes        jboolean redirectErrorStream) {
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Copy commands into char*[].
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    char** commands = convertStrings(env, javaCommands);
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Extract working directory string.
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    const char* workingDirectory = NULL;
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (javaWorkingDirectory != NULL) {
23494367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes        workingDirectory = env->GetStringUTFChars(javaWorkingDirectory, NULL);
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Convert environment array.
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    char** environment = convertStrings(env, javaEnvironment);
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
240a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    pid_t result = executeProcess(env, commands, environment, workingDirectory,
2411805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes            inDescriptor, outDescriptor, errDescriptor, redirectErrorStream);
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Temporarily clear exception so we can clean up.
24494367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes    jthrowable exception = env->ExceptionOccurred();
24594367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes    env->ExceptionClear();
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    freeStrings(env, javaEnvironment, environment);
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Clean up working directory string.
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (javaWorkingDirectory != NULL) {
25194367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes        env->ReleaseStringUTFChars(javaWorkingDirectory, workingDirectory);
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    freeStrings(env, javaCommands, commands);
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Re-throw exception if present.
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (exception != NULL) {
25894367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes        if (env->Throw(exception) < 0) {
259679cf68b607e9b4a3beb8bcdee06868ae583386fSteve Block            ALOGE("Error rethrowing exception!");
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    return result;
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectstatic JNINativeMethod methods[] = {
267e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes    NATIVE_METHOD(ProcessManager, exec, "([Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Z)I"),
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project};
2697cd6760f7045d771faae8080a8c6150bf678f679Elliott Hughesvoid register_java_lang_ProcessManager(JNIEnv* env) {
2707cd6760f7045d771faae8080a8c6150bf678f679Elliott Hughes    jniRegisterNativeMethods(env, "java/lang/ProcessManager", methods, NELEM(methods));
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
272