OSDN Git Service

am 34d4fd8d: Merge from jb-mr1-aah-dev
[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 #include <sys/utsname.h>
42
43 #if defined(HAVE_PRCTL)
44 # include <sys/prctl.h>
45 #endif
46
47 #define ZYGOTE_LOG_TAG "Zygote"
48
49 /* must match values in dalvik.system.Zygote */
50 enum {
51     DEBUG_ENABLE_DEBUGGER           = 1,
52     DEBUG_ENABLE_CHECKJNI           = 1 << 1,
53     DEBUG_ENABLE_ASSERT             = 1 << 2,
54     DEBUG_ENABLE_SAFEMODE           = 1 << 3,
55     DEBUG_ENABLE_JNI_LOGGING        = 1 << 4,
56 };
57
58 /* must match values in dalvik.system.Zygote */
59 enum {
60     MOUNT_EXTERNAL_NONE = 0,
61     MOUNT_EXTERNAL_SINGLEUSER = 1,
62     MOUNT_EXTERNAL_MULTIUSER = 2,
63     MOUNT_EXTERNAL_MULTIUSER_ALL = 3,
64 };
65
66 /*
67  * This signal handler is for zygote mode, since the zygote
68  * must reap its children
69  */
70 static void sigchldHandler(int s)
71 {
72     pid_t pid;
73     int status;
74
75     while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
76         /* Log process-death status that we care about.  In general it is not
77            safe to call ALOG(...) from a signal handler because of possible
78            reentrancy.  However, we know a priori that the current implementation
79            of ALOG() is safe to call from a SIGCHLD handler in the zygote process.
80            If the ALOG() implementation changes its locking strategy or its use
81            of syscalls within the lazy-init critical section, its use here may
82            become unsafe. */
83         if (WIFEXITED(status)) {
84             if (WEXITSTATUS(status)) {
85                 ALOG(LOG_DEBUG, ZYGOTE_LOG_TAG, "Process %d exited cleanly (%d)",
86                     (int) pid, WEXITSTATUS(status));
87             } else {
88                 IF_ALOGV(/*should use ZYGOTE_LOG_TAG*/) {
89                     ALOG(LOG_VERBOSE, ZYGOTE_LOG_TAG,
90                         "Process %d exited cleanly (%d)",
91                         (int) pid, WEXITSTATUS(status));
92                 }
93             }
94         } else if (WIFSIGNALED(status)) {
95             if (WTERMSIG(status) != SIGKILL) {
96                 ALOG(LOG_DEBUG, ZYGOTE_LOG_TAG,
97                     "Process %d terminated by signal (%d)",
98                     (int) pid, WTERMSIG(status));
99             } else {
100                 IF_ALOGV(/*should use ZYGOTE_LOG_TAG*/) {
101                     ALOG(LOG_VERBOSE, ZYGOTE_LOG_TAG,
102                         "Process %d terminated by signal (%d)",
103                         (int) pid, WTERMSIG(status));
104                 }
105             }
106 #ifdef WCOREDUMP
107             if (WCOREDUMP(status)) {
108                 ALOG(LOG_INFO, ZYGOTE_LOG_TAG, "Process %d dumped core",
109                     (int) pid);
110             }
111 #endif /* ifdef WCOREDUMP */
112         }
113
114         /*
115          * If the just-crashed process is the system_server, bring down zygote
116          * so that it is restarted by init and system server will be restarted
117          * from there.
118          */
119         if (pid == gDvm.systemServerPid) {
120             ALOG(LOG_INFO, ZYGOTE_LOG_TAG,
121                 "Exit zygote because system server (%d) has terminated",
122                 (int) pid);
123             kill(getpid(), SIGKILL);
124         }
125     }
126
127     if (pid < 0) {
128         ALOG(LOG_WARN, ZYGOTE_LOG_TAG,
129             "Zygote SIGCHLD error in waitpid: %s",strerror(errno));
130     }
131 }
132
133 /*
134  * configure sigchld handler for the zygote process
135  * This is configured very late, because earlier in the dalvik lifecycle
136  * we can fork() and exec() for the verifier/optimizer, and we
137  * want to waitpid() for those rather than have them be harvested immediately.
138  *
139  * This ends up being called repeatedly before each fork(), but there's
140  * no real harm in that.
141  */
142 static void setSignalHandler()
143 {
144     int err;
145     struct sigaction sa;
146
147     memset(&sa, 0, sizeof(sa));
148
149     sa.sa_handler = sigchldHandler;
150
151     err = sigaction (SIGCHLD, &sa, NULL);
152
153     if (err < 0) {
154         ALOGW("Error setting SIGCHLD handler: %s", strerror(errno));
155     }
156 }
157
158 /*
159  * Set the SIGCHLD handler back to default behavior in zygote children
160  */
161 static void unsetSignalHandler()
162 {
163     int err;
164     struct sigaction sa;
165
166     memset(&sa, 0, sizeof(sa));
167
168     sa.sa_handler = SIG_DFL;
169
170     err = sigaction (SIGCHLD, &sa, NULL);
171
172     if (err < 0) {
173         ALOGW("Error unsetting SIGCHLD handler: %s", strerror(errno));
174     }
175 }
176
177 /*
178  * Calls POSIX setgroups() using the int[] object as an argument.
179  * A NULL argument is tolerated.
180  */
181
182 static int setgroupsIntarray(ArrayObject* gidArray)
183 {
184     gid_t *gids;
185     u4 i;
186     s4 *contents;
187
188     if (gidArray == NULL) {
189         return 0;
190     }
191
192     /* just in case gid_t and u4 are different... */
193     gids = (gid_t *)alloca(sizeof(gid_t) * gidArray->length);
194     contents = (s4 *)(void *)gidArray->contents;
195
196     for (i = 0 ; i < gidArray->length ; i++) {
197         gids[i] = (gid_t) contents[i];
198     }
199
200     return setgroups((size_t) gidArray->length, gids);
201 }
202
203 /*
204  * Sets the resource limits via setrlimit(2) for the values in the
205  * two-dimensional array of integers that's passed in. The second dimension
206  * contains a tuple of length 3: (resource, rlim_cur, rlim_max). NULL is
207  * treated as an empty array.
208  *
209  * -1 is returned on error.
210  */
211 static int setrlimitsFromArray(ArrayObject* rlimits)
212 {
213     u4 i;
214     struct rlimit rlim;
215
216     if (rlimits == NULL) {
217         return 0;
218     }
219
220     memset (&rlim, 0, sizeof(rlim));
221
222     ArrayObject** tuples = (ArrayObject **)(void *)rlimits->contents;
223
224     for (i = 0; i < rlimits->length; i++) {
225         ArrayObject * rlimit_tuple = tuples[i];
226         s4* contents = (s4 *)(void *)rlimit_tuple->contents;
227         int err;
228
229         if (rlimit_tuple->length != 3) {
230             ALOGE("rlimits array must have a second dimension of size 3");
231             return -1;
232         }
233
234         rlim.rlim_cur = contents[1];
235         rlim.rlim_max = contents[2];
236
237         err = setrlimit(contents[0], &rlim);
238
239         if (err < 0) {
240             return -1;
241         }
242     }
243
244     return 0;
245 }
246
247 /*
248  * Create a private mount namespace and bind mount appropriate emulated
249  * storage for the given user.
250  */
251 static int mountEmulatedStorage(uid_t uid, u4 mountMode) {
252     // See storage config details at http://source.android.com/tech/storage/
253     userid_t userid = multiuser_get_user_id(uid);
254
255     // Create a second private mount namespace for our process
256     if (unshare(CLONE_NEWNS) == -1) {
257         SLOGE("Failed to unshare(): %s", strerror(errno));
258         return -1;
259     }
260
261     // Create bind mounts to expose external storage
262     if (mountMode == MOUNT_EXTERNAL_MULTIUSER
263             || mountMode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
264         // These paths must already be created by init.rc
265         const char* source = getenv("EMULATED_STORAGE_SOURCE");
266         const char* target = getenv("EMULATED_STORAGE_TARGET");
267         const char* legacy = getenv("EXTERNAL_STORAGE");
268         if (source == NULL || target == NULL || legacy == NULL) {
269             SLOGE("Storage environment undefined; unable to provide external storage");
270             return -1;
271         }
272
273         // Prepare source paths
274         char source_user[PATH_MAX];
275         char source_obb[PATH_MAX];
276         char target_user[PATH_MAX];
277
278         // /mnt/shell/emulated/0
279         snprintf(source_user, PATH_MAX, "%s/%d", source, userid);
280         // /mnt/shell/emulated/obb
281         snprintf(source_obb, PATH_MAX, "%s/obb", source);
282         // /storage/emulated/0
283         snprintf(target_user, PATH_MAX, "%s/%d", target, userid);
284
285         if (fs_prepare_dir(source_user, 0000, 0, 0) == -1
286                 || fs_prepare_dir(source_obb, 0000, 0, 0) == -1
287                 || fs_prepare_dir(target_user, 0000, 0, 0) == -1) {
288             return -1;
289         }
290
291         if (mountMode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
292             // Mount entire external storage tree for all users
293             if (mount(source, target, NULL, MS_BIND, NULL) == -1) {
294                 SLOGE("Failed to mount %s to %s: %s", source, target, strerror(errno));
295                 return -1;
296             }
297         } else {
298             // Only mount user-specific external storage
299             if (mount(source_user, target_user, NULL, MS_BIND, NULL) == -1) {
300                 SLOGE("Failed to mount %s to %s: %s", source_user, target_user, strerror(errno));
301                 return -1;
302             }
303         }
304
305         // Now that user is mounted, prepare and mount OBB storage
306         // into place for current user
307         char target_android[PATH_MAX];
308         char target_obb[PATH_MAX];
309
310         // /storage/emulated/0/Android
311         snprintf(target_android, PATH_MAX, "%s/%d/Android", target, userid);
312         // /storage/emulated/0/Android/obb
313         snprintf(target_obb, PATH_MAX, "%s/%d/Android/obb", target, userid);
314
315         if (fs_prepare_dir(target_android, 0000, 0, 0) == -1
316                 || fs_prepare_dir(target_obb, 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(); */
339 static 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  */
390 static 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  */
447 static 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  */
476 static 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 static bool needsNoRandomizeWorkaround() {
488     int major;
489     int minor;
490     struct utsname uts;
491     if (uname(&uts) == -1) {
492         return false;
493     }
494
495     if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
496         return false;
497     }
498
499     // Kernels before 3.4.* need the workaround.
500     return (major < 3) || ((major == 3) && (minor < 4));
501 }
502
503 /*
504  * Utility routine to fork zygote and specialize the child process.
505  */
506 static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
507 {
508     pid_t pid;
509
510     uid_t uid = (uid_t) args[0];
511     gid_t gid = (gid_t) args[1];
512     ArrayObject* gids = (ArrayObject *)args[2];
513     u4 debugFlags = args[3];
514     ArrayObject *rlimits = (ArrayObject *)args[4];
515     u4 mountMode = MOUNT_EXTERNAL_NONE;
516     int64_t permittedCapabilities, effectiveCapabilities;
517 #ifdef HAVE_SELINUX
518     char *seInfo = NULL;
519     char *niceName = NULL;
520 #endif
521
522     if (isSystemServer) {
523         /*
524          * Don't use GET_ARG_LONG here for now.  gcc is generating code
525          * that uses register d8 as a temporary, and that's coming out
526          * scrambled in the child process.  b/3138621
527          */
528         //permittedCapabilities = GET_ARG_LONG(args, 5);
529         //effectiveCapabilities = GET_ARG_LONG(args, 7);
530         permittedCapabilities = args[5] | (int64_t) args[6] << 32;
531         effectiveCapabilities = args[7] | (int64_t) args[8] << 32;
532     } else {
533         mountMode = args[5];
534         permittedCapabilities = effectiveCapabilities = 0;
535 #ifdef HAVE_SELINUX
536         StringObject* seInfoObj = (StringObject*)args[6];
537         if (seInfoObj) {
538             seInfo = dvmCreateCstrFromString(seInfoObj);
539             if (!seInfo) {
540                 ALOGE("seInfo dvmCreateCstrFromString failed");
541                 dvmAbort();
542             }
543         }
544         StringObject* niceNameObj = (StringObject*)args[7];
545         if (niceNameObj) {
546             niceName = dvmCreateCstrFromString(niceNameObj);
547             if (!niceName) {
548                 ALOGE("niceName dvmCreateCstrFromString failed");
549                 dvmAbort();
550             }
551         }
552 #endif
553     }
554
555     if (!gDvm.zygote) {
556         dvmThrowIllegalStateException(
557             "VM instance not started with -Xzygote");
558
559         return -1;
560     }
561
562     if (!dvmGcPreZygoteFork()) {
563         ALOGE("pre-fork heap failed");
564         dvmAbort();
565     }
566
567     setSignalHandler();
568
569     dvmDumpLoaderStats("zygote");
570     pid = fork();
571
572     if (pid == 0) {
573         int err;
574         /* The child process */
575
576 #ifdef HAVE_ANDROID_OS
577         extern int gMallocLeakZygoteChild;
578         gMallocLeakZygoteChild = 1;
579
580         /* keep caps across UID change, unless we're staying root */
581         if (uid != 0) {
582             err = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
583
584             if (err < 0) {
585                 ALOGE("cannot PR_SET_KEEPCAPS: %s", strerror(errno));
586                 dvmAbort();
587             }
588         }
589
590 #endif /* HAVE_ANDROID_OS */
591
592         if (mountMode != MOUNT_EXTERNAL_NONE) {
593             err = mountEmulatedStorage(uid, mountMode);
594             if (err < 0) {
595                 ALOGE("cannot mountExternalStorage(): %s", strerror(errno));
596
597                 if (errno == ENOTCONN || errno == EROFS) {
598                     // When device is actively encrypting, we get ENOTCONN here
599                     // since FUSE was mounted before the framework restarted.
600                     // When encrypted device is booting, we get EROFS since
601                     // FUSE hasn't been created yet by init.
602                     // In either case, continue without external storage.
603                 } else {
604                     dvmAbort();
605                 }
606             }
607         }
608
609         err = setgroupsIntarray(gids);
610         if (err < 0) {
611             ALOGE("cannot setgroups(): %s", strerror(errno));
612             dvmAbort();
613         }
614
615         err = setrlimitsFromArray(rlimits);
616         if (err < 0) {
617             ALOGE("cannot setrlimit(): %s", strerror(errno));
618             dvmAbort();
619         }
620
621         err = setgid(gid);
622         if (err < 0) {
623             ALOGE("cannot setgid(%d): %s", gid, strerror(errno));
624             dvmAbort();
625         }
626
627         err = setuid(uid);
628         if (err < 0) {
629             ALOGE("cannot setuid(%d): %s", uid, strerror(errno));
630             dvmAbort();
631         }
632
633         if (needsNoRandomizeWorkaround()) {
634             int current = personality(0xffffFFFF);
635             int success = personality((ADDR_NO_RANDOMIZE | current));
636             if (success == -1) {
637                 ALOGW("Personality switch failed. current=%d error=%d\n", current, errno);
638             }
639         }
640
641         err = setCapabilities(permittedCapabilities, effectiveCapabilities);
642         if (err != 0) {
643             ALOGE("cannot set capabilities (%llx,%llx): %s",
644                 permittedCapabilities, effectiveCapabilities, strerror(err));
645             dvmAbort();
646         }
647
648         err = set_sched_policy(0, SP_DEFAULT);
649         if (err < 0) {
650             ALOGE("cannot set_sched_policy(0, SP_DEFAULT): %s", strerror(-err));
651             dvmAbort();
652         }
653
654 #ifdef HAVE_SELINUX
655         err = setSELinuxContext(uid, isSystemServer, seInfo, niceName);
656         if (err < 0) {
657             ALOGE("cannot set SELinux context: %s\n", strerror(errno));
658             dvmAbort();
659         }
660         // These free(3) calls are safe because we know we're only ever forking
661         // a single-threaded process, so we know no other thread held the heap
662         // lock when we forked.
663         free(seInfo);
664         free(niceName);
665 #endif
666
667         /*
668          * Our system thread ID has changed.  Get the new one.
669          */
670         Thread* thread = dvmThreadSelf();
671         thread->systemTid = dvmGetSysThreadId();
672
673         /* configure additional debug options */
674         enableDebugFeatures(debugFlags);
675
676         unsetSignalHandler();
677         gDvm.zygote = false;
678         if (!dvmInitAfterZygote()) {
679             ALOGE("error in post-zygote initialization");
680             dvmAbort();
681         }
682     } else if (pid > 0) {
683         /* the parent process */
684 #ifdef HAVE_SELINUX
685         free(seInfo);
686         free(niceName);
687 #endif
688     }
689
690     return pid;
691 }
692
693 /*
694  * native public static int nativeForkAndSpecialize(int uid, int gid,
695  *     int[] gids, int debugFlags, int[][] rlimits, int mountExternal,
696  *     String seInfo, String niceName);
697  */
698 static void Dalvik_dalvik_system_Zygote_forkAndSpecialize(const u4* args,
699     JValue* pResult)
700 {
701     pid_t pid;
702
703     pid = forkAndSpecializeCommon(args, false);
704
705     RETURN_INT(pid);
706 }
707
708 /*
709  * native public static int nativeForkSystemServer(int uid, int gid,
710  *     int[] gids, int debugFlags, int[][] rlimits,
711  *     long permittedCapabilities, long effectiveCapabilities);
712  */
713 static void Dalvik_dalvik_system_Zygote_forkSystemServer(
714         const u4* args, JValue* pResult)
715 {
716     pid_t pid;
717     pid = forkAndSpecializeCommon(args, true);
718
719     /* The zygote process checks whether the child process has died or not. */
720     if (pid > 0) {
721         int status;
722
723         ALOGI("System server process %d has been created", pid);
724         gDvm.systemServerPid = pid;
725         /* There is a slight window that the system server process has crashed
726          * but it went unnoticed because we haven't published its pid yet. So
727          * we recheck here just to make sure that all is well.
728          */
729         if (waitpid(pid, &status, WNOHANG) == pid) {
730             ALOGE("System server process %d has died. Restarting Zygote!", pid);
731             kill(getpid(), SIGKILL);
732         }
733     }
734     RETURN_INT(pid);
735 }
736
737 /* native private static void nativeExecShell(String command);
738  */
739 static void Dalvik_dalvik_system_Zygote_execShell(
740         const u4* args, JValue* pResult)
741 {
742     StringObject* command = (StringObject*)args[0];
743
744     const char *argp[] = {_PATH_BSHELL, "-c", NULL, NULL};
745     argp[2] = dvmCreateCstrFromString(command);
746
747     ALOGI("Exec: %s %s %s", argp[0], argp[1], argp[2]);
748
749     execv(_PATH_BSHELL, (char**)argp);
750     exit(127);
751 }
752
753 const DalvikNativeMethod dvm_dalvik_system_Zygote[] = {
754     { "nativeFork", "()I",
755       Dalvik_dalvik_system_Zygote_fork },
756     { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;)I",
757       Dalvik_dalvik_system_Zygote_forkAndSpecialize },
758     { "nativeForkSystemServer", "(II[II[[IJJ)I",
759       Dalvik_dalvik_system_Zygote_forkSystemServer },
760     { "nativeExecShell", "(Ljava/lang/String;)V",
761       Dalvik_dalvik_system_Zygote_execShell },
762     { NULL, NULL, NULL },
763 };