comparison jni/Exec/com_google_ase_Exec.cpp @ 0:0ce5cc452d02

initial version
author Carl Byington <carl@five-ten-sg.com>
date Thu, 22 May 2014 10:41:19 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:0ce5cc452d02
1 /*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "com_google_ase_Exec.h"
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <stdlib.h>
22 #include <sys/ioctl.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <termios.h>
26 #include <unistd.h>
27
28 #include "android/log.h"
29
30 #define LOG_TAG "Exec"
31 #define LOG(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
32
33 void JNU_ThrowByName(JNIEnv * env, const char *name, const char *msg) {
34 jclass clazz = env->FindClass(name);
35 if (clazz != NULL) {
36 env->ThrowNew(clazz, msg);
37 }
38 env->DeleteLocalRef(clazz);
39 }
40
41 char *JNU_GetStringNativeChars(JNIEnv * env, jstring jstr) {
42 if (jstr == NULL) {
43 return NULL;
44 }
45 jbyteArray bytes = 0;
46 jthrowable exc;
47 char *result = 0;
48 if (env->EnsureLocalCapacity(2) < 0) {
49 return 0; /* out of memory error */
50 }
51 jclass Class_java_lang_String = env->FindClass("java/lang/String");
52 jmethodID MID_String_getBytes = env->GetMethodID(Class_java_lang_String, "getBytes", "()[B");
53 bytes = (jbyteArray) env->CallObjectMethod(jstr, MID_String_getBytes);
54 exc = env->ExceptionOccurred();
55 if (!exc) {
56 jint len = env->GetArrayLength(bytes);
57 result = (char *) malloc(len + 1);
58 if (result == 0) {
59 JNU_ThrowByName(env, "java/lang/OutOfMemoryError", 0);
60 env->DeleteLocalRef(bytes);
61 return 0;
62 }
63 env->GetByteArrayRegion(bytes, 0, len, (jbyte *) result);
64 result[len] = 0; /* NULL-terminate */
65 } else {
66 env->DeleteLocalRef(exc);
67 }
68 env->DeleteLocalRef(bytes);
69 return result;
70 }
71
72 int jniGetFDFromFileDescriptor(JNIEnv * env, jobject fileDescriptor) {
73 jclass Class_java_io_FileDescriptor = env->FindClass("java/io/FileDescriptor");
74 jfieldID descriptor = env->GetFieldID(Class_java_io_FileDescriptor,
75 "descriptor", "I");
76 return env->GetIntField(fileDescriptor, descriptor);
77 }
78
79 static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, int *pProcessId) {
80 char *devname;
81 int ptm;
82 pid_t pid;
83
84 ptm = open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
85 if (ptm < 0) {
86 LOG("[ cannot open /dev/ptmx - %s ]\n", strerror(errno));
87 return -1;
88 }
89 fcntl(ptm, F_SETFD, FD_CLOEXEC);
90
91 if (grantpt(ptm) || unlockpt(ptm) || ((devname = (char *) ptsname(ptm)) == 0)) {
92 LOG("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
93 return -1;
94 }
95
96 pid = fork();
97 if (pid < 0) {
98 LOG("- fork failed: %s -\n", strerror(errno));
99 return -1;
100 }
101
102 if (pid == 0) {
103 int pts;
104
105 setsid();
106
107 pts = open(devname, O_RDWR);
108 if (pts < 0)
109 exit(-1);
110
111 dup2(pts, 0);
112 dup2(pts, 1);
113 dup2(pts, 2);
114
115 close(ptm);
116
117 execl(cmd, cmd, arg0, arg1, NULL);
118 exit(-1);
119 } else {
120 *pProcessId = (int) pid;
121 return ptm;
122 }
123 }
124
125 JNIEXPORT jobject JNICALL Java_com_google_ase_Exec_createSubprocess(JNIEnv * env, jclass clazz,
126 jstring cmd, jstring arg0,
127 jstring arg1,
128 jintArray processIdArray) {
129 char *cmd_8 = JNU_GetStringNativeChars(env, cmd);
130 char *arg0_8 = JNU_GetStringNativeChars(env, arg0);
131 char *arg1_8 = JNU_GetStringNativeChars(env, arg1);
132
133 int procId;
134 int ptm = create_subprocess(cmd_8, arg0_8, arg1_8, &procId);
135
136 if (processIdArray) {
137 int procIdLen = env->GetArrayLength(processIdArray);
138 if (procIdLen > 0) {
139 jboolean isCopy;
140 int *pProcId = (int *) env->GetPrimitiveArrayCritical(processIdArray, &isCopy);
141 if (pProcId) {
142 *pProcId = procId;
143 env->ReleasePrimitiveArrayCritical(processIdArray, pProcId, 0);
144 }
145 }
146 }
147
148 jclass Class_java_io_FileDescriptor = env->FindClass("java/io/FileDescriptor");
149 jmethodID init = env->GetMethodID(Class_java_io_FileDescriptor,
150 "<init>", "()V");
151 jobject result = env->NewObject(Class_java_io_FileDescriptor, init);
152
153 if (!result) {
154 LOG("Couldn't create a FileDescriptor.");
155 } else {
156 jfieldID descriptor = env->GetFieldID(Class_java_io_FileDescriptor,
157 "descriptor", "I");
158 env->SetIntField(result, descriptor, ptm);
159 }
160
161 return result;
162 }
163
164 JNIEXPORT void Java_com_google_ase_Exec_setPtyWindowSize(JNIEnv * env, jclass clazz,
165 jobject fileDescriptor, jint row, jint col,
166 jint xpixel, jint ypixel) {
167 int fd;
168 struct winsize sz;
169
170 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
171
172 if (env->ExceptionOccurred() != NULL) {
173 return;
174 }
175
176 sz.ws_row = row;
177 sz.ws_col = col;
178 sz.ws_xpixel = xpixel;
179 sz.ws_ypixel = ypixel;
180
181 ioctl(fd, TIOCSWINSZ, &sz);
182 }
183
184 JNIEXPORT jint Java_com_google_ase_Exec_waitFor(JNIEnv * env, jclass clazz, jint procId) {
185 int status;
186 waitpid(procId, &status, 0);
187 int result = 0;
188 if (WIFEXITED(status)) {
189 result = WEXITSTATUS(status);
190 }
191 return result;
192 }