1/*
2 * Copyright (C) 2008 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/*
18 * dalvik.system.Zygote
19 */
20#include "Dalvik.h"
21#include "native/InternalNativePriv.h"
22
23#ifdef HAVE_SELINUX
24#include <selinux/android.h>
25#endif
26
27#include <signal.h>
28#include <sys/types.h>
29#include <sys/wait.h>
30#include <grp.h>
31#include <errno.h>
32#include <paths.h>
33#include <sys/personality.h>
34#include <sys/stat.h>
35#include <sys/mount.h>
36#include <linux/fs.h>
37#include <cutils/fs.h>
38#include <cutils/sched_policy.h>
39#include <cutils/multiuser.h>
40#include <sched.h>
41
42#if defined(HAVE_PRCTL)
43# include <sys/prctl.h>
44#endif
45
46#define ZYGOTE_LOG_TAG "Zygote"
47
48/* must match values in dalvik.system.Zygote */
49enum {
50    DEBUG_ENABLE_DEBUGGER           = 1,
51    DEBUG_ENABLE_CHECKJNI           = 1 << 1,
52    DEBUG_ENABLE_ASSERT             = 1 << 2,
53    DEBUG_ENABLE_SAFEMODE           = 1 << 3,
54    DEBUG_ENABLE_JNI_LOGGING        = 1 << 4,
55};
56
57/* must match values in dalvik.system.Zygote */
58enum {
59    MOUNT_EXTERNAL_NONE = 0,
60    MOUNT_EXTERNAL_SINGLEUSER = 1,
61    MOUNT_EXTERNAL_MULTIUSER = 2,
62    MOUNT_EXTERNAL_MULTIUSER_ALL = 3,
63};
64
65/*
66 * This signal handler is for zygote mode, since the zygote
67 * must reap its children
68 */
69static void sigchldHandler(int s)
70{
71    pid_t pid;
72    int status;
73
74    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
75        /* Log process-death status that we care about.  In general it is not
76           safe to call ALOG(...) from a signal handler because of possible
77           reentrancy.  However, we know a priori that the current implementation
78           of ALOG() is safe to call from a SIGCHLD handler in the zygote process.
79           If the ALOG() implementation changes its locking strategy or its use
80           of syscalls within the lazy-init critical section, its use here may
81           become unsafe. */
82        if (WIFEXITED(status)) {
83            if (WEXITSTATUS(status)) {
84                ALOG(LOG_DEBUG, ZYGOTE_LOG_TAG, "Process %d exited cleanly (%d)",
85                    (int) pid, WEXITSTATUS(status));
86            } else {
87                IF_ALOGV(/*should use ZYGOTE_LOG_TAG*/) {
88                    ALOG(LOG_VERBOSE, ZYGOTE_LOG_TAG,
89                        "Process %d exited cleanly (%d)",
90                        (int) pid, WEXITSTATUS(status));
91                }
92            }
93        } else if (WIFSIGNALED(status)) {
94            if (WTERMSIG(status) != SIGKILL) {
95                ALOG(LOG_DEBUG, ZYGOTE_LOG_TAG,
96                    "Process %d terminated by signal (%d)",
97                    (int) pid, WTERMSIG(status));
98            } else {
99                IF_ALOGV(/*should use ZYGOTE_LOG_TAG*/) {
100                    ALOG(LOG_VERBOSE, ZYGOTE_LOG_TAG,
101                        "Process %d terminated by signal (%d)",
102                        (int) pid, WTERMSIG(status));
103                }
104            }
105#ifdef WCOREDUMP
106            if (WCOREDUMP(status)) {
107                ALOG(LOG_INFO, ZYGOTE_LOG_TAG, "Process %d dumped core",
108                    (int) pid);
109            }
110#endif /* ifdef WCOREDUMP */
111        }
112
113        /*
114         * If the just-crashed process is the system_server, bring down zygote
115         * so that it is restarted by init and system server will be restarted
116         * from there.
117         */
118        if (pid == gDvm.systemServerPid) {
119            ALOG(LOG_INFO, ZYGOTE_LOG_TAG,
120                "Exit zygote because system server (%d) has terminated",
121                (int) pid);
122            kill(getpid(), SIGKILL);
123        }
124    }
125
126    if (pid < 0) {
127        ALOG(LOG_WARN, ZYGOTE_LOG_TAG,
128            "Zygote SIGCHLD error in waitpid: %s",strerror(errno));
129    }
130}
131
132/*
133 * configure sigchld handler for the zygote process
134 * This is configured very late, because earlier in the dalvik lifecycle
135 * we can fork() and exec() for the verifier/optimizer, and we
136 * want to waitpid() for those rather than have them be harvested immediately.
137 *
138 * This ends up being called repeatedly before each fork(), but there's
139 * no real harm in that.
140 */
141static void setSignalHandler()
142{
143    int err;
144    struct sigaction sa;
145
146    memset(&sa, 0, sizeof(sa));
147
148    sa.sa_handler = sigchldHandler;
149
150    err = sigaction (SIGCHLD, &sa, NULL);
151
152    if (err < 0) {
153        ALOGW("Error setting SIGCHLD handler: %s", strerror(errno));
154    }
155}
156
157/*
158 * Set the SIGCHLD handler back to default behavior in zygote children
159 */
160static void unsetSignalHandler()
161{
162    int err;
163    struct sigaction sa;
164
165    memset(&sa, 0, sizeof(sa));
166
167    sa.sa_handler = SIG_DFL;
168
169    err = sigaction (SIGCHLD, &sa, NULL);
170
171    if (err < 0) {
172        ALOGW("Error unsetting SIGCHLD handler: %s", strerror(errno));
173    }
174}
175
176/*
177 * Calls POSIX setgroups() using the int[] object as an argument.
178 * A NULL argument is tolerated.
179 */
180
181static int setgroupsIntarray(ArrayObject* gidArray)
182{
183    gid_t *gids;
184    u4 i;
185    s4 *contents;
186
187    if (gidArray == NULL) {
188        return 0;
189    }
190
191    /* just in case gid_t and u4 are different... */
192    gids = (gid_t *)alloca(sizeof(gid_t) * gidArray->length);
193    contents = (s4 *)(void *)gidArray->contents;
194
195    for (i = 0 ; i < gidArray->length ; i++) {
196        gids[i] = (gid_t) contents[i];
197    }
198
199    return setgroups((size_t) gidArray->length, gids);
200}
201
202/*
203 * Sets the resource limits via setrlimit(2) for the values in the
204 * two-dimensional array of integers that's passed in. The second dimension
205 * contains a tuple of length 3: (resource, rlim_cur, rlim_max). NULL is
206 * treated as an empty array.
207 *
208 * -1 is returned on error.
209 */
210static int setrlimitsFromArray(ArrayObject* rlimits)
211{
212    u4 i;
213    struct rlimit rlim;
214
215    if (rlimits == NULL) {
216        return 0;
217    }
218
219    memset (&rlim, 0, sizeof(rlim));
220
221    ArrayObject** tuples = (ArrayObject **)(void *)rlimits->contents;
222
223    for (i = 0; i < rlimits->length; i++) {
224        ArrayObject * rlimit_tuple = tuples[i];
225        s4* contents = (s4 *)(void *)rlimit_tuple->contents;
226        int err;
227
228        if (rlimit_tuple->length != 3) {
229            ALOGE("rlimits array must have a second dimension of size 3");
230            return -1;
231        }
232
233        rlim.rlim_cur = contents[1];
234        rlim.rlim_max = contents[2];
235
236        err = setrlimit(contents[0], &rlim);
237
238        if (err < 0) {
239            return -1;
240        }
241    }
242
243    return 0;
244}
245
246/*
247 * Create a private mount namespace and bind mount appropriate emulated
248 * storage for the given user.
249 */
250static int mountEmulatedStorage(uid_t uid, u4 mountMode) {
251    // See storage config details at http://source.android.com/tech/storage/
252    userid_t userid = multiuser_get_user_id(uid);
253
254    // Create a second private mount namespace for our process
255    if (unshare(CLONE_NEWNS) == -1) {
256        SLOGE("Failed to unshare(): %s", strerror(errno));
257        return -1;
258    }
259
260    // Create bind mounts to expose external storage
261    if (mountMode == MOUNT_EXTERNAL_MULTIUSER
262            || mountMode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
263        // These paths must already be created by init.rc
264        const char* source = getenv("EMULATED_STORAGE_SOURCE");
265        const char* target = getenv("EMULATED_STORAGE_TARGET");
266        const char* legacy = getenv("EXTERNAL_STORAGE");
267        if (source == NULL || target == NULL || legacy == NULL) {
268            SLOGE("Storage environment undefined; unable to provide external storage");
269            return -1;
270        }
271
272        // Prepare source paths
273        char source_user[PATH_MAX];
274        char source_obb[PATH_MAX];
275        char target_user[PATH_MAX];
276
277        // /mnt/shell/emulated/0
278        snprintf(source_user, PATH_MAX, "%s/%d", source, userid);
279        // /mnt/shell/emulated/obb
280        snprintf(source_obb, PATH_MAX, "%s/obb", source);
281        // /storage/emulated/0
282        snprintf(target_user, PATH_MAX, "%s/%d", target, userid);
283
284        if (fs_prepare_dir(source_user, 0000, 0, 0) == -1
285                || fs_prepare_dir(source_obb, 0000, 0, 0) == -1
286                || fs_prepare_dir(target_user, 0000, 0, 0) == -1) {
287            return -1;
288        }
289
290        if (mountMode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
291            // Mount entire external storage tree for all users
292            if (mount(source, target, NULL, MS_BIND, NULL) == -1) {
293                SLOGE("Failed to mount %s to %s: %s", source, target, strerror(errno));
294                return -1;
295            }
296        } else {
297            // Only mount user-specific external storage
298            if (mount(source_user, target_user, NULL, MS_BIND, NULL) == -1) {
299                SLOGE("Failed to mount %s to %s: %s", source_user, target_user, strerror(errno));
300                return -1;
301            }
302        }
303
304        // Now that user is mounted, prepare and mount OBB storage
305        // into place for current user
306        char target_android[PATH_MAX];
307        char target_obb[PATH_MAX];
308
309        // /storage/emulated/0/Android
310        snprintf(target_android, PATH_MAX, "%s/%d/Android", target, userid);
311        // /storage/emulated/0/Android/obb
312        snprintf(target_obb, PATH_MAX, "%s/%d/Android/obb", target, userid);
313
314        if (fs_prepare_dir(target_android, 0000, 0, 0) == -1
315                || fs_prepare_dir(target_obb, 0000, 0, 0) == -1
316                || fs_prepare_dir(legacy, 0000, 0, 0) == -1) {
317            return -1;
318        }
319        if (mount(source_obb, target_obb, NULL, MS_BIND, NULL) == -1) {
320            SLOGE("Failed to mount %s to %s: %s", source_obb, target_obb, strerror(errno));
321            return -1;
322        }
323
324        // Finally, mount user-specific path into place for legacy users
325        if (mount(target_user, legacy, NULL, MS_BIND | MS_REC, NULL) == -1) {
326            SLOGE("Failed to mount %s to %s: %s", target_user, legacy, strerror(errno));
327            return -1;
328        }
329
330    } else {
331        SLOGE("Mount mode %d unsupported", mountMode);
332        return -1;
333    }
334
335    return 0;
336}
337
338/* native public static int fork(); */
339static void Dalvik_dalvik_system_Zygote_fork(const u4* args, JValue* pResult)
340{
341    pid_t pid;
342
343    if (!gDvm.zygote) {
344        dvmThrowIllegalStateException(
345            "VM instance not started with -Xzygote");
346
347        RETURN_VOID();
348    }
349
350    if (!dvmGcPreZygoteFork()) {
351        ALOGE("pre-fork heap failed");
352        dvmAbort();
353    }
354
355    setSignalHandler();
356
357    dvmDumpLoaderStats("zygote");
358    pid = fork();
359
360#ifdef HAVE_ANDROID_OS
361    if (pid == 0) {
362        /* child process */
363        extern int gMallocLeakZygoteChild;
364        gMallocLeakZygoteChild = 1;
365    }
366#endif
367
368    RETURN_INT(pid);
369}
370
371/*
372 * Enable/disable debug features requested by the caller.
373 *
374 * debugger
375 *   If set, enable debugging; if not set, disable debugging.  This is
376 *   easy to handle, because the JDWP thread isn't started until we call
377 *   dvmInitAfterZygote().
378 * checkjni
379 *   If set, make sure "check JNI" is enabled.
380 * assert
381 *   If set, make sure assertions are enabled.  This gets fairly weird,
382 *   because it affects the result of a method called by class initializers,
383 *   and hence can't affect pre-loaded/initialized classes.
384 * safemode
385 *   If set, operates the VM in the safe mode. The definition of "safe mode" is
386 *   implementation dependent and currently only the JIT compiler is disabled.
387 *   This is easy to handle because the compiler thread and associated resources
388 *   are not requested until we call dvmInitAfterZygote().
389 */
390static void enableDebugFeatures(u4 debugFlags)
391{
392    ALOGV("debugFlags is 0x%02x", debugFlags);
393
394    gDvm.jdwpAllowed = ((debugFlags & DEBUG_ENABLE_DEBUGGER) != 0);
395
396    if ((debugFlags & DEBUG_ENABLE_CHECKJNI) != 0) {
397        /* turn it on if it's not already enabled */
398        dvmLateEnableCheckedJni();
399    }
400
401    if ((debugFlags & DEBUG_ENABLE_JNI_LOGGING) != 0) {
402        gDvmJni.logThirdPartyJni = true;
403    }
404
405    if ((debugFlags & DEBUG_ENABLE_ASSERT) != 0) {
406        /* turn it on if it's not already enabled */
407        dvmLateEnableAssertions();
408    }
409
410    if ((debugFlags & DEBUG_ENABLE_SAFEMODE) != 0) {
411#if defined(WITH_JIT)
412        /* turn off the jit if it is explicitly requested by the app */
413        if (gDvm.executionMode == kExecutionModeJit)
414            gDvm.executionMode = kExecutionModeInterpFast;
415#endif
416    }
417
418#ifdef HAVE_ANDROID_OS
419    if ((debugFlags & DEBUG_ENABLE_DEBUGGER) != 0) {
420        /* To let a non-privileged gdbserver attach to this
421         * process, we must set its dumpable bit flag. However
422         * we are not interested in generating a coredump in
423         * case of a crash, so also set the coredump size to 0
424         * to disable that
425         */
426        if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
427            ALOGE("could not set dumpable bit flag for pid %d: %s",
428                 getpid(), strerror(errno));
429        } else {
430            struct rlimit rl;
431            rl.rlim_cur = 0;
432            rl.rlim_max = RLIM_INFINITY;
433            if (setrlimit(RLIMIT_CORE, &rl) < 0) {
434                ALOGE("could not disable core file generation for pid %d: %s",
435                    getpid(), strerror(errno));
436            }
437        }
438    }
439#endif
440}
441
442/*
443 * Set Linux capability flags.
444 *
445 * Returns 0 on success, errno on failure.
446 */
447static int setCapabilities(int64_t permitted, int64_t effective)
448{
449#ifdef HAVE_ANDROID_OS
450    struct __user_cap_header_struct capheader;
451    struct __user_cap_data_struct capdata;
452
453    memset(&capheader, 0, sizeof(capheader));
454    memset(&capdata, 0, sizeof(capdata));
455
456    capheader.version = _LINUX_CAPABILITY_VERSION;
457    capheader.pid = 0;
458
459    capdata.effective = effective;
460    capdata.permitted = permitted;
461
462    ALOGV("CAPSET perm=%llx eff=%llx", permitted, effective);
463    if (capset(&capheader, &capdata) != 0)
464        return errno;
465#endif /*HAVE_ANDROID_OS*/
466
467    return 0;
468}
469
470#ifdef HAVE_SELINUX
471/*
472 * Set SELinux security context.
473 *
474 * Returns 0 on success, -1 on failure.
475 */
476static int setSELinuxContext(uid_t uid, bool isSystemServer,
477                             const char *seInfo, const char *niceName)
478{
479#ifdef HAVE_ANDROID_OS
480    return selinux_android_setcontext(uid, isSystemServer, seInfo, niceName);
481#else
482    return 0;
483#endif
484}
485#endif
486
487/*
488 * Utility routine to fork zygote and specialize the child process.
489 */
490static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
491{
492    pid_t pid;
493
494    uid_t uid = (uid_t) args[0];
495    gid_t gid = (gid_t) args[1];
496    ArrayObject* gids = (ArrayObject *)args[2];
497    u4 debugFlags = args[3];
498    ArrayObject *rlimits = (ArrayObject *)args[4];
499    u4 mountMode = MOUNT_EXTERNAL_NONE;
500    int64_t permittedCapabilities, effectiveCapabilities;
501#ifdef HAVE_SELINUX
502    char *seInfo = NULL;
503    char *niceName = NULL;
504#endif
505
506    if (isSystemServer) {
507        /*
508         * Don't use GET_ARG_LONG here for now.  gcc is generating code
509         * that uses register d8 as a temporary, and that's coming out
510         * scrambled in the child process.  b/3138621
511         */
512        //permittedCapabilities = GET_ARG_LONG(args, 5);
513        //effectiveCapabilities = GET_ARG_LONG(args, 7);
514        permittedCapabilities = args[5] | (int64_t) args[6] << 32;
515        effectiveCapabilities = args[7] | (int64_t) args[8] << 32;
516    } else {
517        mountMode = args[5];
518        permittedCapabilities = effectiveCapabilities = 0;
519#ifdef HAVE_SELINUX
520        StringObject* seInfoObj = (StringObject*)args[6];
521        if (seInfoObj) {
522            seInfo = dvmCreateCstrFromString(seInfoObj);
523            if (!seInfo) {
524                ALOGE("seInfo dvmCreateCstrFromString failed");
525                dvmAbort();
526            }
527        }
528        StringObject* niceNameObj = (StringObject*)args[7];
529        if (niceNameObj) {
530            niceName = dvmCreateCstrFromString(niceNameObj);
531            if (!niceName) {
532                ALOGE("niceName dvmCreateCstrFromString failed");
533                dvmAbort();
534            }
535        }
536#endif
537    }
538
539    if (!gDvm.zygote) {
540        dvmThrowIllegalStateException(
541            "VM instance not started with -Xzygote");
542
543        return -1;
544    }
545
546    if (!dvmGcPreZygoteFork()) {
547        ALOGE("pre-fork heap failed");
548        dvmAbort();
549    }
550
551    setSignalHandler();
552
553    dvmDumpLoaderStats("zygote");
554    pid = fork();
555
556    if (pid == 0) {
557        int err;
558        /* The child process */
559
560#ifdef HAVE_ANDROID_OS
561        extern int gMallocLeakZygoteChild;
562        gMallocLeakZygoteChild = 1;
563
564        /* keep caps across UID change, unless we're staying root */
565        if (uid != 0) {
566            err = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
567
568            if (err < 0) {
569                ALOGE("cannot PR_SET_KEEPCAPS: %s", strerror(errno));
570                dvmAbort();
571            }
572        }
573
574#endif /* HAVE_ANDROID_OS */
575
576        if (mountMode != MOUNT_EXTERNAL_NONE) {
577            err = mountEmulatedStorage(uid, mountMode);
578            if (err < 0) {
579                ALOGE("cannot mountExternalStorage(): %s", strerror(errno));
580
581                if (errno == ENOTCONN || errno == EROFS) {
582                    // When device is actively encrypting, we get ENOTCONN here
583                    // since FUSE was mounted before the framework restarted.
584                    // When encrypted device is booting, we get EROFS since
585                    // FUSE hasn't been created yet by init.
586                    // In either case, continue without external storage.
587                } else {
588                    dvmAbort();
589                }
590            }
591        }
592
593        err = setgroupsIntarray(gids);
594        if (err < 0) {
595            ALOGE("cannot setgroups(): %s", strerror(errno));
596            dvmAbort();
597        }
598
599        err = setrlimitsFromArray(rlimits);
600        if (err < 0) {
601            ALOGE("cannot setrlimit(): %s", strerror(errno));
602            dvmAbort();
603        }
604
605        err = setgid(gid);
606        if (err < 0) {
607            ALOGE("cannot setgid(%d): %s", gid, strerror(errno));
608            dvmAbort();
609        }
610
611        err = setuid(uid);
612        if (err < 0) {
613            ALOGE("cannot setuid(%d): %s", uid, strerror(errno));
614            dvmAbort();
615        }
616
617        int current = personality(0xffffFFFF);
618        int success = personality((ADDR_NO_RANDOMIZE | current));
619        if (success == -1) {
620          ALOGW("Personality switch failed. current=%d error=%d\n", current, errno);
621        }
622
623        err = setCapabilities(permittedCapabilities, effectiveCapabilities);
624        if (err != 0) {
625            ALOGE("cannot set capabilities (%llx,%llx): %s",
626                permittedCapabilities, effectiveCapabilities, strerror(err));
627            dvmAbort();
628        }
629
630        err = set_sched_policy(0, SP_DEFAULT);
631        if (err < 0) {
632            ALOGE("cannot set_sched_policy(0, SP_DEFAULT): %s", strerror(-err));
633            dvmAbort();
634        }
635
636#ifdef HAVE_SELINUX
637        err = setSELinuxContext(uid, isSystemServer, seInfo, niceName);
638        if (err < 0) {
639            ALOGE("cannot set SELinux context: %s\n", strerror(errno));
640            dvmAbort();
641        }
642        // These free(3) calls are safe because we know we're only ever forking
643        // a single-threaded process, so we know no other thread held the heap
644        // lock when we forked.
645        free(seInfo);
646        free(niceName);
647#endif
648
649        /*
650         * Our system thread ID has changed.  Get the new one.
651         */
652        Thread* thread = dvmThreadSelf();
653        thread->systemTid = dvmGetSysThreadId();
654
655        /* configure additional debug options */
656        enableDebugFeatures(debugFlags);
657
658        unsetSignalHandler();
659        gDvm.zygote = false;
660        if (!dvmInitAfterZygote()) {
661            ALOGE("error in post-zygote initialization");
662            dvmAbort();
663        }
664    } else if (pid > 0) {
665        /* the parent process */
666#ifdef HAVE_SELINUX
667        free(seInfo);
668        free(niceName);
669#endif
670    }
671
672    return pid;
673}
674
675/*
676 * native public static int nativeForkAndSpecialize(int uid, int gid,
677 *     int[] gids, int debugFlags, int[][] rlimits, int mountExternal,
678 *     String seInfo, String niceName);
679 */
680static void Dalvik_dalvik_system_Zygote_forkAndSpecialize(const u4* args,
681    JValue* pResult)
682{
683    pid_t pid;
684
685    pid = forkAndSpecializeCommon(args, false);
686
687    RETURN_INT(pid);
688}
689
690/*
691 * native public static int nativeForkSystemServer(int uid, int gid,
692 *     int[] gids, int debugFlags, int[][] rlimits,
693 *     long permittedCapabilities, long effectiveCapabilities);
694 */
695static void Dalvik_dalvik_system_Zygote_forkSystemServer(
696        const u4* args, JValue* pResult)
697{
698    pid_t pid;
699    pid = forkAndSpecializeCommon(args, true);
700
701    /* The zygote process checks whether the child process has died or not. */
702    if (pid > 0) {
703        int status;
704
705        ALOGI("System server process %d has been created", pid);
706        gDvm.systemServerPid = pid;
707        /* There is a slight window that the system server process has crashed
708         * but it went unnoticed because we haven't published its pid yet. So
709         * we recheck here just to make sure that all is well.
710         */
711        if (waitpid(pid, &status, WNOHANG) == pid) {
712            ALOGE("System server process %d has died. Restarting Zygote!", pid);
713            kill(getpid(), SIGKILL);
714        }
715    }
716    RETURN_INT(pid);
717}
718
719/* native private static void nativeExecShell(String command);
720 */
721static void Dalvik_dalvik_system_Zygote_execShell(
722        const u4* args, JValue* pResult)
723{
724    StringObject* command = (StringObject*)args[0];
725
726    const char *argp[] = {_PATH_BSHELL, "-c", NULL, NULL};
727    argp[2] = dvmCreateCstrFromString(command);
728
729    ALOGI("Exec: %s %s %s", argp[0], argp[1], argp[2]);
730
731    execv(_PATH_BSHELL, (char**)argp);
732    exit(127);
733}
734
735const DalvikNativeMethod dvm_dalvik_system_Zygote[] = {
736    { "nativeFork", "()I",
737      Dalvik_dalvik_system_Zygote_fork },
738    { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;)I",
739      Dalvik_dalvik_system_Zygote_forkAndSpecialize },
740    { "nativeForkSystemServer", "(II[II[[IJJ)I",
741      Dalvik_dalvik_system_Zygote_forkSystemServer },
742    { "nativeExecShell", "(Ljava/lang/String;)V",
743      Dalvik_dalvik_system_Zygote_execShell },
744    { NULL, NULL, NULL },
745};
746