java_lang_ProcessManager.cpp revision 7cd6760f7045d771faae8080a8c6150bf678f679
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"
30e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes#include "ScopedLocalRef.h"
318545b837c61c3eaea2b8433b6791aa401f37e5f7Elliott Hughes#include "cutils/log.h"
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
33410530d90797fd49ad34c76a05a2c8f5147f88e1crazybob/** Close all open fds > 2 (i.e. everything but stdin/out/err), != skipFd. */
34a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughesstatic void closeNonStandardFds(int skipFd1, int skipFd2) {
3594367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes    // TODO: rather than close all these non-open files, we could look in /proc/self/fd.
36e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes    rlimit rlimit;
37410530d90797fd49ad34c76a05a2c8f5147f88e1crazybob    getrlimit(RLIMIT_NOFILE, &rlimit);
3894367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes    const int max_fd = rlimit.rlim_max;
3994367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes    for (int fd = 3; fd < max_fd; ++fd) {
40a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes        if (fd != skipFd1 && fd != skipFd2) {
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            close(fd);
42410530d90797fd49ad34c76a05a2c8f5147f88e1crazybob        }
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#define PIPE_COUNT (4) // number of pipes used to communicate with child proc
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** Closes all pipes in the given array. */
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectstatic void closePipes(int pipes[], int skipFd) {
50a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    for (int i = 0; i < PIPE_COUNT * 2; i++) {
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int fd = pipes[i];
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (fd == -1) {
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (fd != skipFd) {
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            close(pipes[i]);
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** Executes a command in a child process. */
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectstatic pid_t executeProcess(JNIEnv* env, char** commands, char** environment,
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        const char* workingDirectory, jobject inDescriptor,
641805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes        jobject outDescriptor, jobject errDescriptor,
651805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes        jboolean redirectErrorStream) {
66a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes
67a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    // Keep track of the system properties fd so we don't close it.
68a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    int androidSystemPropertiesFd = -1;
69a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    char* fdString = getenv("ANDROID_PROPERTY_WORKSPACE");
70a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    if (fdString) {
71a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes        androidSystemPropertiesFd = atoi(fdString);
72a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    }
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Create 4 pipes: stdin, stdout, stderr, and an exec() status pipe.
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int pipes[PIPE_COUNT * 2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
76a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    for (int i = 0; i < PIPE_COUNT; i++) {
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (pipe(pipes + i * 2) == -1) {
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            jniThrowIOException(env, errno);
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            closePipes(pipes, -1);
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return -1;
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int stdinIn = pipes[0];
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int stdinOut = pipes[1];
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int stdoutIn = pipes[2];
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int stdoutOut = pipes[3];
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int stderrIn = pipes[4];
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int stderrOut = pipes[5];
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int statusIn = pipes[6];
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int statusOut = pipes[7];
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    pid_t childPid = fork();
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // If fork() failed...
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (childPid == -1) {
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        jniThrowIOException(env, errno);
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        closePipes(pipes, -1);
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return -1;
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // If this is the child process...
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (childPid == 0) {
103410530d90797fd49ad34c76a05a2c8f5147f88e1crazybob        /*
104410530d90797fd49ad34c76a05a2c8f5147f88e1crazybob         * Note: We cannot malloc() or free() after this point!
105410530d90797fd49ad34c76a05a2c8f5147f88e1crazybob         * A no-longer-running thread may be holding on to the heap lock, and
106410530d90797fd49ad34c76a05a2c8f5147f88e1crazybob         * an attempt to malloc() or free() would result in deadlock.
107410530d90797fd49ad34c76a05a2c8f5147f88e1crazybob         */
108410530d90797fd49ad34c76a05a2c8f5147f88e1crazybob
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Replace stdin, out, and err with pipes.
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        dup2(stdinIn, 0);
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        dup2(stdoutOut, 1);
1121805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes        if (redirectErrorStream) {
1131805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes            dup2(stdoutOut, 2);
1141805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes        } else {
1151805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes            dup2(stderrOut, 2);
1161805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes        }
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Close all but statusOut. This saves some work in the next step.
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        closePipes(pipes, statusOut);
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Make statusOut automatically close if execvp() succeeds.
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        fcntl(statusOut, F_SETFD, FD_CLOEXEC);
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
124a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes        // Close remaining unwanted open fds.
125a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes        closeNonStandardFds(statusOut, androidSystemPropertiesFd);
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Switch to working directory.
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (workingDirectory != NULL) {
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (chdir(workingDirectory) == -1) {
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                goto execFailed;
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Set up environment.
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (environment != NULL) {
136a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes            extern char** environ; // Standard, but not in any header file.
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            environ = environment;
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Execute process. By convention, the first argument in the arg array
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // should be the command itself. In fact, I get segfaults when this
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // isn't the case.
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        execvp(commands[0], commands);
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // If we got here, execvp() failed or the working dir was invalid.
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        execFailed:
147a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes            int error = errno;
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            write(statusOut, &error, sizeof(int));
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            close(statusOut);
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            exit(error);
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // This is the parent process.
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Close child's pipe ends.
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    close(stdinIn);
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    close(stdoutOut);
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    close(stderrOut);
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    close(statusOut);
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Check status pipe for an error code. If execvp() succeeds, the other
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // end of the pipe should automatically close, in which case, we'll read
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // nothing.
164a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    int result;
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int count = read(statusIn, &result, sizeof(int));
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    close(statusIn);
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (count > 0) {
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        jniThrowIOException(env, result);
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        close(stdoutIn);
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        close(stdinOut);
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        close(stderrIn);
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return -1;
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Fill in file descriptor wrappers.
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    jniSetFileDescriptorOfFD(env, inDescriptor, stdoutIn);
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    jniSetFileDescriptorOfFD(env, outDescriptor, stdinOut);
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    jniSetFileDescriptorOfFD(env, errDescriptor, stderrIn);
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    return childPid;
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** Converts a Java String[] to a 0-terminated char**. */
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectstatic char** convertStrings(JNIEnv* env, jobjectArray javaArray) {
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (javaArray == NULL) {
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return NULL;
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
19194367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes    jsize length = env->GetArrayLength(javaArray);
192583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes    char** array = new char*[length + 1];
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    array[length] = 0;
194e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes    for (jsize i = 0; i < length; ++i) {
195e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes        ScopedLocalRef<jstring> javaEntry(env, reinterpret_cast<jstring>(env->GetObjectArrayElement(javaArray, i)));
196583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes        // We need to pass these strings to const-unfriendly code.
197e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes        char* entry = const_cast<char*>(env->GetStringUTFChars(javaEntry.get(), NULL));
198e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes        array[i] = entry;
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    return array;
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** Frees a char** which was converted from a Java String[]. */
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectstatic void freeStrings(JNIEnv* env, jobjectArray javaArray, char** array) {
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (javaArray == NULL) {
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return;
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
21094367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes    jsize length = env->GetArrayLength(javaArray);
211e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes    for (jsize i = 0; i < length; ++i) {
212e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes        ScopedLocalRef<jstring> javaEntry(env, reinterpret_cast<jstring>(env->GetObjectArrayElement(javaArray, i)));
213e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes        env->ReleaseStringUTFChars(javaEntry.get(), array[i]);
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
216583ce47780cae3a014ca46534e08f5c2adc8fa88Elliott Hughes    delete[] array;
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Converts Java String[] to char** and delegates to executeProcess().
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
222a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughesstatic pid_t ProcessManager_exec(JNIEnv* env, jclass, jobjectArray javaCommands,
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        jobjectArray javaEnvironment, jstring javaWorkingDirectory,
2241805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes        jobject inDescriptor, jobject outDescriptor, jobject errDescriptor,
2251805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes        jboolean redirectErrorStream) {
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Copy commands into char*[].
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    char** commands = convertStrings(env, javaCommands);
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Extract working directory string.
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    const char* workingDirectory = NULL;
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (javaWorkingDirectory != NULL) {
23394367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes        workingDirectory = env->GetStringUTFChars(javaWorkingDirectory, NULL);
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Convert environment array.
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    char** environment = convertStrings(env, javaEnvironment);
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
239a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    pid_t result = executeProcess(env, commands, environment, workingDirectory,
2401805727c24b2b80161fef93c4b7742cf2322bdeaElliott Hughes            inDescriptor, outDescriptor, errDescriptor, redirectErrorStream);
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Temporarily clear exception so we can clean up.
24394367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes    jthrowable exception = env->ExceptionOccurred();
24494367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes    env->ExceptionClear();
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    freeStrings(env, javaEnvironment, environment);
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Clean up working directory string.
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (javaWorkingDirectory != NULL) {
25094367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes        env->ReleaseStringUTFChars(javaWorkingDirectory, workingDirectory);
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    freeStrings(env, javaCommands, commands);
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Re-throw exception if present.
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (exception != NULL) {
25794367e0ead84fc2228799a78ec207ea52e203f1aElliott Hughes        if (env->Throw(exception) < 0) {
258679cf68b607e9b4a3beb8bcdee06868ae583386fSteve Block            ALOGE("Error rethrowing exception!");
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    return result;
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectstatic JNINativeMethod methods[] = {
266e22935d3c7040c22b48d53bd18878844f381287cElliott 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"),
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project};
2687cd6760f7045d771faae8080a8c6150bf678f679Elliott Hughesvoid register_java_lang_ProcessManager(JNIEnv* env) {
2697cd6760f7045d771faae8080a8c6150bf678f679Elliott Hughes    jniRegisterNativeMethods(env, "java/lang/ProcessManager", methods, NELEM(methods));
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
271