com_android_internal_os_ZygoteInit.cpp revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
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#define LOG_TAG "Zygote"
18
19#include <sys/types.h>
20#include <unistd.h>
21#include <fcntl.h>
22#include <utils/misc.h>
23#include <errno.h>
24#include <sys/select.h>
25
26#include "jni.h"
27#include <JNIHelp.h>
28#include "android_runtime/AndroidRuntime.h"
29
30#ifdef HAVE_ANDROID_OS
31#include <linux/capability.h>
32#include <linux/prctl.h>
33#include <sys/prctl.h>
34extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
35extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
36#endif
37
38
39namespace android {
40
41/*
42 * In class com.android.internal.os.ZygoteInit:
43 * private static native boolean setreuid(int ruid, int euid)
44 */
45static jint com_android_internal_os_ZygoteInit_setreuid(
46    JNIEnv* env, jobject clazz, jint ruid, jint euid)
47{
48    int err;
49
50    errno = 0;
51    err = setreuid(ruid, euid);
52
53    //LOGI("setreuid(%d,%d) err %d errno %d", ruid, euid, err, errno);
54
55    return errno;
56}
57
58/*
59 * In class com.android.internal.os.ZygoteInit:
60 * private static native int setregid(int rgid, int egid)
61 */
62static jint com_android_internal_os_ZygoteInit_setregid(
63    JNIEnv* env, jobject clazz, jint rgid, jint egid)
64{
65    int err;
66
67    errno = 0;
68    err = setregid(rgid, egid);
69
70    //LOGI("setregid(%d,%d) err %d errno %d", rgid, egid, err, errno);
71
72    return errno;
73}
74
75/*
76 * In class com.android.internal.os.ZygoteInit:
77 * private static native int setpgid(int rgid, int egid)
78 */
79static jint com_android_internal_os_ZygoteInit_setpgid(
80    JNIEnv* env, jobject clazz, jint pid, jint pgid)
81{
82    int err;
83
84    errno = 0;
85
86    err = setpgid(pid, pgid);
87
88    return errno;
89}
90
91/*
92 * In class com.android.internal.os.ZygoteInit:
93 * private static native int getpgid(int pid)
94 */
95static jint com_android_internal_os_ZygoteInit_getpgid(
96    JNIEnv* env, jobject clazz, jint pid)
97{
98    pid_t ret;
99    ret = getpgid(pid);
100
101    if (ret < 0) {
102        jniThrowIOException(env, errno);
103    }
104
105    return ret;
106}
107
108static void com_android_internal_os_ZygoteInit_reopenStdio(JNIEnv* env,
109        jobject clazz, jobject in, jobject out, jobject errfd)
110{
111    int fd;
112    int err;
113
114    fd = jniGetFDFromFileDescriptor(env, in);
115
116    if  (env->ExceptionOccurred() != NULL) {
117        return;
118    }
119
120    do {
121        err = dup2(fd, STDIN_FILENO);
122    } while (err < 0 && errno == EINTR);
123
124    fd = jniGetFDFromFileDescriptor(env, out);
125
126    if  (env->ExceptionOccurred() != NULL) {
127        return;
128    }
129
130    do {
131        err = dup2(fd, STDOUT_FILENO);
132    } while (err < 0 && errno == EINTR);
133
134    fd = jniGetFDFromFileDescriptor(env, errfd);
135
136    if  (env->ExceptionOccurred() != NULL) {
137        return;
138    }
139
140    do {
141        err = dup2(fd, STDERR_FILENO);
142    } while (err < 0 && errno == EINTR);
143}
144
145static void com_android_internal_os_ZygoteInit_closeDescriptor(JNIEnv* env,
146        jobject clazz, jobject descriptor)
147{
148    int fd;
149    int err;
150
151    fd = jniGetFDFromFileDescriptor(env, descriptor);
152
153    if  (env->ExceptionOccurred() != NULL) {
154        return;
155    }
156
157    do {
158        err = close(fd);
159    } while (err < 0 && errno == EINTR);
160
161    if (err < 0) {
162        jniThrowIOException(env, errno);
163        return;
164    }
165}
166
167static void com_android_internal_os_ZygoteInit_setCloseOnExec (JNIEnv *env,
168    jobject clazz, jobject descriptor, jboolean flag)
169{
170    int fd;
171    int err;
172    int fdFlags;
173
174    fd = jniGetFDFromFileDescriptor(env, descriptor);
175
176    if  (env->ExceptionOccurred() != NULL) {
177        return;
178    }
179
180    fdFlags = fcntl(fd, F_GETFD);
181
182    if (fdFlags < 0) {
183        jniThrowIOException(env, errno);
184        return;
185    }
186
187    if (flag) {
188        fdFlags |= FD_CLOEXEC;
189    } else {
190        fdFlags &= ~FD_CLOEXEC;
191    }
192
193    err = fcntl(fd, F_SETFD, fdFlags);
194
195    if (err < 0) {
196        jniThrowIOException(env, errno);
197        return;
198    }
199}
200
201static void com_android_internal_os_ZygoteInit_setCapabilities (JNIEnv *env,
202    jobject clazz, jlong permitted, jlong effective)
203{
204#ifdef HAVE_ANDROID_OS
205    struct __user_cap_header_struct capheader;
206    struct __user_cap_data_struct capdata;
207    int err;
208
209    memset (&capheader, 0, sizeof(capheader));
210    memset (&capdata, 0, sizeof(capdata));
211
212    capheader.version = _LINUX_CAPABILITY_VERSION;
213    capheader.pid = 0;
214
215    // As of this writing, capdata is __u32, but that's expected
216    // to change...
217    capdata.effective = effective;
218    capdata.permitted = permitted;
219
220    err = capset (&capheader, &capdata);
221
222    if (err < 0) {
223        jniThrowIOException(env, errno);
224        return;
225    }
226#endif /* HAVE_ANDROID_OS */
227}
228
229static jlong com_android_internal_os_ZygoteInit_capgetPermitted (JNIEnv *env,
230    jobject clazz, jint pid)
231{
232#ifndef HAVE_ANDROID_OS
233    return (jlong)0;
234#else
235    struct __user_cap_header_struct capheader;
236    struct __user_cap_data_struct capdata;
237    int err;
238
239    memset (&capheader, 0, sizeof(capheader));
240    memset (&capdata, 0, sizeof(capdata));
241
242    capheader.version = _LINUX_CAPABILITY_VERSION;
243    capheader.pid = pid;
244
245    err = capget (&capheader, &capdata);
246
247    if (err < 0) {
248        jniThrowIOException(env, errno);
249        return 0;
250    }
251
252    return (jlong) capdata.permitted;
253#endif /* HAVE_ANDROID_OS */
254}
255
256static jint com_android_internal_os_ZygoteInit_selectReadable (
257        JNIEnv *env, jobject clazz, jobjectArray fds)
258{
259    if (fds == NULL) {
260        jniThrowException(env, "java/lang/NullPointerException",
261            "fds == null");
262        return -1;
263    }
264
265    jsize length = env->GetArrayLength(fds);
266    fd_set fdset;
267
268    if (env->ExceptionOccurred() != NULL) {
269        return -1;
270    }
271
272    FD_ZERO(&fdset);
273
274    int nfds = 0;
275    for (jsize i = 0; i < length; i++) {
276        jobject fdObj = env->GetObjectArrayElement(fds, i);
277        if  (env->ExceptionOccurred() != NULL) {
278            return -1;
279        }
280        if (fdObj == NULL) {
281            continue;
282        }
283        int fd = jniGetFDFromFileDescriptor(env, fdObj);
284        if  (env->ExceptionOccurred() != NULL) {
285            return -1;
286        }
287
288        FD_SET(fd, &fdset);
289
290        if (fd >= nfds) {
291            nfds = fd + 1;
292        }
293    }
294
295    int err;
296    do {
297        err = select (nfds, &fdset, NULL, NULL, NULL);
298    } while (err < 0 && errno == EINTR);
299
300    if (err < 0) {
301        jniThrowIOException(env, errno);
302        return -1;
303    }
304
305    for (jsize i = 0; i < length; i++) {
306        jobject fdObj = env->GetObjectArrayElement(fds, i);
307        if  (env->ExceptionOccurred() != NULL) {
308            return -1;
309        }
310        if (fdObj == NULL) {
311            continue;
312        }
313        int fd = jniGetFDFromFileDescriptor(env, fdObj);
314        if  (env->ExceptionOccurred() != NULL) {
315            return -1;
316        }
317        if (FD_ISSET(fd, &fdset)) {
318            return (jint)i;
319        }
320    }
321    return -1;
322}
323
324static jobject com_android_internal_os_ZygoteInit_createFileDescriptor (
325        JNIEnv *env, jobject clazz, jint fd)
326{
327    return jniCreateFileDescriptor(env, fd);
328}
329
330/*
331 * JNI registration.
332 */
333static JNINativeMethod gMethods[] = {
334    /* name, signature, funcPtr */
335    { "setreuid", "(II)I",
336      (void*) com_android_internal_os_ZygoteInit_setreuid },
337    { "setregid", "(II)I",
338      (void*) com_android_internal_os_ZygoteInit_setregid },
339    { "setpgid", "(II)I",
340      (void *) com_android_internal_os_ZygoteInit_setpgid },
341    { "getpgid", "(I)I",
342      (void *) com_android_internal_os_ZygoteInit_getpgid },
343    { "reopenStdio",
344        "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;"
345        "Ljava/io/FileDescriptor;)V",
346            (void *) com_android_internal_os_ZygoteInit_reopenStdio},
347    { "closeDescriptor", "(Ljava/io/FileDescriptor;)V",
348        (void *) com_android_internal_os_ZygoteInit_closeDescriptor},
349    { "setCloseOnExec", "(Ljava/io/FileDescriptor;Z)V",
350        (void *)  com_android_internal_os_ZygoteInit_setCloseOnExec},
351    { "setCapabilities", "(JJ)V",
352        (void *) com_android_internal_os_ZygoteInit_setCapabilities },
353    { "capgetPermitted", "(I)J",
354        (void *) com_android_internal_os_ZygoteInit_capgetPermitted },
355    { "selectReadable", "([Ljava/io/FileDescriptor;)I",
356        (void *) com_android_internal_os_ZygoteInit_selectReadable },
357    { "createFileDescriptor", "(I)Ljava/io/FileDescriptor;",
358        (void *) com_android_internal_os_ZygoteInit_createFileDescriptor }
359};
360int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
361{
362    return AndroidRuntime::registerNativeMethods(env,
363            "com/android/internal/os/ZygoteInit", gMethods, NELEM(gMethods));
364}
365
366}; // namespace android
367
368