OSDN Git Service

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