• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.internal.os;
18 
19 import android.content.pm.ActivityInfo;
20 import android.content.res.Resources;
21 import android.content.res.TypedArray;
22 import android.graphics.drawable.Drawable;
23 import android.net.LocalServerSocket;
24 import android.os.Debug;
25 import android.os.SystemClock;
26 import android.os.SystemProperties;
27 import android.util.Config;
28 import android.util.EventLog;
29 import android.util.Log;
30 
31 import dalvik.system.VMRuntime;
32 import dalvik.system.Zygote;
33 import dalvik.system.SamplingProfiler;
34 
35 import java.io.BufferedReader;
36 import java.io.FileDescriptor;
37 import java.io.IOException;
38 import java.io.InputStream;
39 import java.io.InputStreamReader;
40 import java.lang.reflect.InvocationTargetException;
41 import java.lang.reflect.Method;
42 import java.lang.reflect.Modifier;
43 import java.util.ArrayList;
44 
45 /**
46  * Startup class for the zygote process.
47  *
48  * Pre-initializes some classes, and then waits for commands on a UNIX domain
49  * socket. Based on these commands, forks of child processes that inherit
50  * the initial state of the VM.
51  *
52  * Please see {@link ZygoteConnection.Arguments} for documentation on the
53  * client protocol.
54  *
55  * @hide
56  */
57 public class ZygoteInit {
58 
59     private static final String TAG = "Zygote";
60 
61     private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";
62 
63     private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
64     private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
65 
66     /** when preloading, GC after allocating this many bytes */
67     private static final int PRELOAD_GC_THRESHOLD = 50000;
68 
69     private static LocalServerSocket sServerSocket;
70 
71     /**
72      * Used to pre-load resources.  We hold a global reference on it so it
73      * never gets destroyed.
74      */
75     private static Resources mResources;
76 
77     /**
78      * The number of times that the main Zygote loop
79      * should run before calling gc() again.
80      */
81     static final int GC_LOOP_COUNT = 10;
82 
83     /**
84      * If true, zygote forks for each peer. If false, a select loop is used
85      * inside a single process. The latter is preferred.
86      */
87     private static final boolean ZYGOTE_FORK_MODE = false;
88 
89     /**
90      * The name of a resource file that contains classes to preload.
91      */
92     private static final String PRELOADED_CLASSES = "preloaded-classes";
93 
94     /** Controls whether we should preload resources during zygote init. */
95     private static final boolean PRELOAD_RESOURCES = true;
96 
97     /**
98      * List of methods we "warm up" in the register map cache.  These were
99      * chosen because they appeared on the stack in GCs in multiple
100      * applications.
101      *
102      * This is in a VM-ready format, to minimize string processing.  If a
103      * class is not already loaded, or a method is not found, the entry
104      * will be skipped.
105      *
106      * This doesn't really merit a separately-generated input file at this
107      * time.  The list is fairly short, and the consequences of failure
108      * are minor.
109      */
110     private static final String[] REGISTER_MAP_METHODS = {
111         // (currently not doing any)
112         //"Landroid/app/Activity;.setContentView:(I)V",
113     };
114 
115 
116     /**
117      * Invokes a static "main(argv[]) method on class "className".
118      * Converts various failing exceptions into RuntimeExceptions, with
119      * the assumption that they will then cause the VM instance to exit.
120      *
121      * @param loader class loader to use
122      * @param className Fully-qualified class name
123      * @param argv Argument vector for main()
124      */
invokeStaticMain(ClassLoader loader, String className, String[] argv)125     static void invokeStaticMain(ClassLoader loader,
126             String className, String[] argv)
127             throws ZygoteInit.MethodAndArgsCaller {
128         Class<?> cl;
129 
130         try {
131             cl = loader.loadClass(className);
132         } catch (ClassNotFoundException ex) {
133             throw new RuntimeException(
134                     "Missing class when invoking static main " + className,
135                     ex);
136         }
137 
138         Method m;
139         try {
140             m = cl.getMethod("main", new Class[] { String[].class });
141         } catch (NoSuchMethodException ex) {
142             throw new RuntimeException(
143                     "Missing static main on " + className, ex);
144         } catch (SecurityException ex) {
145             throw new RuntimeException(
146                     "Problem getting static main on " + className, ex);
147         }
148 
149         int modifiers = m.getModifiers();
150         if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
151             throw new RuntimeException(
152                     "Main method is not public and static on " + className);
153         }
154 
155         /*
156          * This throw gets caught in ZygoteInit.main(), which responds
157          * by invoking the exception's run() method. This arrangement
158          * clears up all the stack frames that were required in setting
159          * up the process.
160          */
161         throw new ZygoteInit.MethodAndArgsCaller(m, argv);
162     }
163 
164     /**
165      * Registers a server socket for zygote command connections
166      *
167      * @throws RuntimeException when open fails
168      */
registerZygoteSocket()169     private static void registerZygoteSocket() {
170         if (sServerSocket == null) {
171             int fileDesc;
172             try {
173                 String env = System.getenv(ANDROID_SOCKET_ENV);
174                 fileDesc = Integer.parseInt(env);
175             } catch (RuntimeException ex) {
176                 throw new RuntimeException(
177                         ANDROID_SOCKET_ENV + " unset or invalid", ex);
178             }
179 
180             try {
181                 sServerSocket = new LocalServerSocket(
182                         createFileDescriptor(fileDesc));
183             } catch (IOException ex) {
184                 throw new RuntimeException(
185                         "Error binding to local socket '" + fileDesc + "'", ex);
186             }
187         }
188     }
189 
190     /**
191      * Waits for and accepts a single command connection. Throws
192      * RuntimeException on failure.
193      */
acceptCommandPeer()194     private static ZygoteConnection acceptCommandPeer() {
195         try {
196             return new ZygoteConnection(sServerSocket.accept());
197         } catch (IOException ex) {
198             throw new RuntimeException(
199                     "IOException during accept()", ex);
200         }
201     }
202 
203     /**
204      * Close and clean up zygote sockets. Called on shutdown and on the
205      * child's exit path.
206      */
closeServerSocket()207     static void closeServerSocket() {
208         try {
209             if (sServerSocket != null) {
210                 sServerSocket.close();
211             }
212         } catch (IOException ex) {
213             Log.e(TAG, "Zygote:  error closing sockets", ex);
214         }
215 
216         sServerSocket = null;
217     }
218 
219     private static final int UNPRIVILEGED_UID = 9999;
220     private static final int UNPRIVILEGED_GID = 9999;
221 
222     private static final int ROOT_UID = 0;
223     private static final int ROOT_GID = 0;
224 
225     /**
226      * Sets effective user ID.
227      */
setEffectiveUser(int uid)228     private static void setEffectiveUser(int uid) {
229         int errno = setreuid(ROOT_UID, uid);
230         if (errno != 0) {
231             Log.e(TAG, "setreuid() failed. errno: " + errno);
232         }
233     }
234 
235     /**
236      * Sets effective group ID.
237      */
setEffectiveGroup(int gid)238     private static void setEffectiveGroup(int gid) {
239         int errno = setregid(ROOT_GID, gid);
240         if (errno != 0) {
241             Log.e(TAG, "setregid() failed. errno: " + errno);
242         }
243     }
244 
245     /**
246      * Performs Zygote process initialization. Loads and initializes
247      * commonly used classes.
248      *
249      * Most classes only cause a few hundred bytes to be allocated, but
250      * a few will allocate a dozen Kbytes (in one case, 500+K).
251      */
preloadClasses()252     private static void preloadClasses() {
253         final VMRuntime runtime = VMRuntime.getRuntime();
254 
255         InputStream is = ZygoteInit.class.getClassLoader().getResourceAsStream(
256                 PRELOADED_CLASSES);
257         if (is == null) {
258             Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
259         } else {
260             Log.i(TAG, "Preloading classes...");
261             long startTime = SystemClock.uptimeMillis();
262 
263             // Drop root perms while running static initializers.
264             setEffectiveGroup(UNPRIVILEGED_GID);
265             setEffectiveUser(UNPRIVILEGED_UID);
266 
267             // Alter the target heap utilization.  With explicit GCs this
268             // is not likely to have any effect.
269             float defaultUtilization = runtime.getTargetHeapUtilization();
270             runtime.setTargetHeapUtilization(0.8f);
271 
272             // Start with a clean slate.
273             runtime.gcSoftReferences();
274             runtime.runFinalizationSync();
275             Debug.startAllocCounting();
276 
277             try {
278                 BufferedReader br
279                     = new BufferedReader(new InputStreamReader(is), 256);
280 
281                 int count = 0;
282                 String line;
283                 String missingClasses = null;
284                 while ((line = br.readLine()) != null) {
285                     // Skip comments and blank lines.
286                     line = line.trim();
287                     if (line.startsWith("#") || line.equals("")) {
288                         continue;
289                     }
290 
291                     try {
292                         if (Config.LOGV) {
293                             Log.v(TAG, "Preloading " + line + "...");
294                         }
295                         Class.forName(line);
296                         if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
297                             if (Config.LOGV) {
298                                 Log.v(TAG,
299                                     " GC at " + Debug.getGlobalAllocSize());
300                             }
301                             runtime.gcSoftReferences();
302                             runtime.runFinalizationSync();
303                             Debug.resetGlobalAllocSize();
304                         }
305                         count++;
306                     } catch (ClassNotFoundException e) {
307                         Log.e(TAG, "Class not found for preloading: " + line);
308                         if (missingClasses == null) {
309                             missingClasses = line;
310                         } else {
311                             missingClasses += " " + line;
312                         }
313                     } catch (Throwable t) {
314                         Log.e(TAG, "Error preloading " + line + ".", t);
315                         if (t instanceof Error) {
316                             throw (Error) t;
317                         }
318                         if (t instanceof RuntimeException) {
319                             throw (RuntimeException) t;
320                         }
321                         throw new RuntimeException(t);
322                     }
323                 }
324 
325                 if (missingClasses != null &&
326                         "1".equals(SystemProperties.get("persist.service.adb.enable"))) {
327                     throw new IllegalStateException(
328                             "Missing class(es) for preloading, update preloaded-classes ["
329                             + missingClasses + "]");
330                 }
331 
332                 Log.i(TAG, "...preloaded " + count + " classes in "
333                         + (SystemClock.uptimeMillis()-startTime) + "ms.");
334             } catch (IOException e) {
335                 Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
336             } finally {
337                 // Restore default.
338                 runtime.setTargetHeapUtilization(defaultUtilization);
339 
340                 Debug.stopAllocCounting();
341 
342                 // Bring back root. We'll need it later.
343                 setEffectiveUser(ROOT_UID);
344                 setEffectiveGroup(ROOT_GID);
345             }
346         }
347     }
348 
349     /**
350      * Pre-caches register maps for methods that are commonly used.
351      */
cacheRegisterMaps()352     private static void cacheRegisterMaps() {
353         String failed = null;
354         int failure;
355         long startTime = System.nanoTime();
356 
357         failure = 0;
358 
359         for (int i = 0; i < REGISTER_MAP_METHODS.length; i++) {
360             String str = REGISTER_MAP_METHODS[i];
361 
362             if (!Debug.cacheRegisterMap(str)) {
363                 if (failed == null)
364                     failed = str;
365                 failure++;
366             }
367         }
368 
369         long delta = System.nanoTime() - startTime;
370 
371         if (failure == REGISTER_MAP_METHODS.length) {
372             if (REGISTER_MAP_METHODS.length > 0) {
373                 Log.i(TAG,
374                     "Register map caching failed (precise GC not enabled?)");
375             }
376             return;
377         }
378 
379         Log.i(TAG, "Register map cache: found " +
380             (REGISTER_MAP_METHODS.length - failure) + " of " +
381             REGISTER_MAP_METHODS.length + " methods in " +
382             (delta / 1000000L) + "ms");
383         if (failure > 0) {
384             Log.i(TAG, "  First failure: " + failed);
385         }
386     }
387 
388     /**
389      * Load in commonly used resources, so they can be shared across
390      * processes.
391      *
392      * These tend to be a few Kbytes, but are frequently in the 20-40K
393      * range, and occasionally even larger.
394      */
preloadResources()395     private static void preloadResources() {
396         final VMRuntime runtime = VMRuntime.getRuntime();
397 
398         Debug.startAllocCounting();
399         try {
400             runtime.gcSoftReferences();
401             runtime.runFinalizationSync();
402             mResources = Resources.getSystem();
403             mResources.startPreloading();
404             if (PRELOAD_RESOURCES) {
405                 Log.i(TAG, "Preloading resources...");
406 
407                 long startTime = SystemClock.uptimeMillis();
408                 TypedArray ar = mResources.obtainTypedArray(
409                         com.android.internal.R.array.preloaded_drawables);
410                 int N = preloadDrawables(runtime, ar);
411                 Log.i(TAG, "...preloaded " + N + " resources in "
412                         + (SystemClock.uptimeMillis()-startTime) + "ms.");
413 
414                 startTime = SystemClock.uptimeMillis();
415                 ar = mResources.obtainTypedArray(
416                         com.android.internal.R.array.preloaded_color_state_lists);
417                 N = preloadColorStateLists(runtime, ar);
418                 Log.i(TAG, "...preloaded " + N + " resources in "
419                         + (SystemClock.uptimeMillis()-startTime) + "ms.");
420             }
421             mResources.finishPreloading();
422         } catch (RuntimeException e) {
423             Log.w(TAG, "Failure preloading resources", e);
424         } finally {
425             Debug.stopAllocCounting();
426         }
427     }
428 
preloadColorStateLists(VMRuntime runtime, TypedArray ar)429     private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) {
430         int N = ar.length();
431         for (int i=0; i<N; i++) {
432             if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
433                 if (Config.LOGV) {
434                     Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
435                 }
436                 runtime.gcSoftReferences();
437                 runtime.runFinalizationSync();
438                 Debug.resetGlobalAllocSize();
439             }
440             int id = ar.getResourceId(i, 0);
441             if (Config.LOGV) {
442                 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
443             }
444             if (id != 0) {
445                 mResources.getColorStateList(id);
446             }
447         }
448         return N;
449     }
450 
451 
preloadDrawables(VMRuntime runtime, TypedArray ar)452     private static int preloadDrawables(VMRuntime runtime, TypedArray ar) {
453         int N = ar.length();
454         for (int i=0; i<N; i++) {
455             if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
456                 if (Config.LOGV) {
457                     Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
458                 }
459                 runtime.gcSoftReferences();
460                 runtime.runFinalizationSync();
461                 Debug.resetGlobalAllocSize();
462             }
463             int id = ar.getResourceId(i, 0);
464             if (Config.LOGV) {
465                 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
466             }
467             if (id != 0) {
468                 Drawable dr = mResources.getDrawable(id);
469                 if ((dr.getChangingConfigurations()&~ActivityInfo.CONFIG_FONT_SCALE) != 0) {
470                     Log.w(TAG, "Preloaded drawable resource #0x"
471                             + Integer.toHexString(id)
472                             + " (" + ar.getString(i) + ") that varies with configuration!!");
473                 }
474             }
475         }
476         return N;
477     }
478 
479     /**
480      * Runs several special GCs to try to clean up a few generations of
481      * softly- and final-reachable objects, along with any other garbage.
482      * This is only useful just before a fork().
483      */
gc()484     /*package*/ static void gc() {
485         final VMRuntime runtime = VMRuntime.getRuntime();
486 
487         /* runFinalizationSync() lets finalizers be called in Zygote,
488          * which doesn't have a HeapWorker thread.
489          */
490         runtime.gcSoftReferences();
491         runtime.runFinalizationSync();
492         runtime.gcSoftReferences();
493         runtime.runFinalizationSync();
494         runtime.gcSoftReferences();
495         runtime.runFinalizationSync();
496     }
497 
498     /**
499      * Finish remaining work for the newly forked system server process.
500      */
handleSystemServerProcess( ZygoteConnection.Arguments parsedArgs)501     private static void handleSystemServerProcess(
502             ZygoteConnection.Arguments parsedArgs)
503             throws ZygoteInit.MethodAndArgsCaller {
504         /*
505          * First, set the capabilities if necessary
506          */
507 
508         if (parsedArgs.uid != 0) {
509             try {
510                 setCapabilities(parsedArgs.permittedCapabilities,
511                                 parsedArgs.effectiveCapabilities);
512             } catch (IOException ex) {
513                 Log.e(TAG, "Error setting capabilities", ex);
514             }
515         }
516 
517         closeServerSocket();
518 
519         /*
520          * Pass the remaining arguments to SystemServer.
521          * "--nice-name=system_server com.android.server.SystemServer"
522          */
523         RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
524         /* should never reach here */
525     }
526 
527     /**
528      * Prepare the arguments and fork for the system server process.
529      */
startSystemServer()530     private static boolean startSystemServer()
531             throws MethodAndArgsCaller, RuntimeException {
532         /* Hardcoded command line to start the system server */
533         String args[] = {
534             "--setuid=1000",
535             "--setgid=1000",
536             "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
537             "--capabilities=130104352,130104352",
538             "--runtime-init",
539             "--nice-name=system_server",
540             "com.android.server.SystemServer",
541         };
542         ZygoteConnection.Arguments parsedArgs = null;
543 
544         int pid;
545 
546         try {
547             parsedArgs = new ZygoteConnection.Arguments(args);
548 
549             /*
550              * Enable debugging of the system process if *either* the command line flags
551              * indicate it should be debuggable or the ro.debuggable system property
552              * is set to "1"
553              */
554             int debugFlags = parsedArgs.debugFlags;
555             if ("1".equals(SystemProperties.get("ro.debuggable")))
556                 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
557 
558             /* Request to fork the system server process */
559             pid = Zygote.forkSystemServer(
560                     parsedArgs.uid, parsedArgs.gid,
561                     parsedArgs.gids, debugFlags, null);
562         } catch (IllegalArgumentException ex) {
563             throw new RuntimeException(ex);
564         }
565 
566         /* For child process */
567         if (pid == 0) {
568             handleSystemServerProcess(parsedArgs);
569         }
570 
571         return true;
572     }
573 
main(String argv[])574     public static void main(String argv[]) {
575         try {
576             // Start profiling the zygote initialization.
577             SamplingProfilerIntegration.start();
578 
579             registerZygoteSocket();
580             EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
581                 SystemClock.uptimeMillis());
582             preloadClasses();
583             //cacheRegisterMaps();
584             preloadResources();
585             EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
586                 SystemClock.uptimeMillis());
587 
588             if (SamplingProfilerIntegration.isEnabled()) {
589                 SamplingProfiler sp = SamplingProfiler.getInstance();
590                 sp.pause();
591                 SamplingProfilerIntegration.writeZygoteSnapshot();
592                 sp.shutDown();
593             }
594 
595             // Do an initial gc to clean up after startup
596             gc();
597 
598             // If requested, start system server directly from Zygote
599             if (argv.length != 2) {
600                 throw new RuntimeException(
601                         "ZygoteInit.main expects two arguments");
602             }
603 
604             if (argv[1].equals("true")) {
605                 startSystemServer();
606             }
607 
608             Log.i(TAG, "Accepting command socket connections");
609 
610             if (ZYGOTE_FORK_MODE) {
611                 runForkMode();
612             } else {
613                 runSelectLoopMode();
614             }
615 
616             closeServerSocket();
617         } catch (MethodAndArgsCaller caller) {
618             caller.run();
619         } catch (RuntimeException ex) {
620             Log.e(TAG, "Zygote died with exception", ex);
621             closeServerSocket();
622             throw ex;
623         }
624     }
625 
626     /**
627      * Runs the zygote in accept-and-fork mode. In this mode, each peer
628      * gets its own zygote spawner process. This code is retained for
629      * reference only.
630      *
631      * @throws MethodAndArgsCaller in a child process when a main() should
632      * be executed.
633      */
runForkMode()634     private static void runForkMode() throws MethodAndArgsCaller {
635         while (true) {
636             ZygoteConnection peer = acceptCommandPeer();
637 
638             int pid;
639 
640             pid = Zygote.fork();
641 
642             if (pid == 0) {
643                 // The child process should handle the peer requests
644 
645                 // The child does not accept any more connections
646                 try {
647                     sServerSocket.close();
648                 } catch (IOException ex) {
649                     Log.e(TAG, "Zygote Child: error closing sockets", ex);
650                 } finally {
651                     sServerSocket = null;
652                 }
653 
654                 peer.run();
655                 break;
656             } else if (pid > 0) {
657                 peer.closeSocket();
658             } else {
659                 throw new RuntimeException("Error invoking fork()");
660             }
661         }
662     }
663 
664     /**
665      * Runs the zygote process's select loop. Accepts new connections as
666      * they happen, and reads commands from connections one spawn-request's
667      * worth at a time.
668      *
669      * @throws MethodAndArgsCaller in a child process when a main() should
670      * be executed.
671      */
runSelectLoopMode()672     private static void runSelectLoopMode() throws MethodAndArgsCaller {
673         ArrayList<FileDescriptor> fds = new ArrayList();
674         ArrayList<ZygoteConnection> peers = new ArrayList();
675         FileDescriptor[] fdArray = new FileDescriptor[4];
676 
677         fds.add(sServerSocket.getFileDescriptor());
678         peers.add(null);
679 
680         int loopCount = GC_LOOP_COUNT;
681         while (true) {
682             int index;
683 
684             /*
685              * Call gc() before we block in select().
686              * It's work that has to be done anyway, and it's better
687              * to avoid making every child do it.  It will also
688              * madvise() any free memory as a side-effect.
689              *
690              * Don't call it every time, because walking the entire
691              * heap is a lot of overhead to free a few hundred bytes.
692              */
693             if (loopCount <= 0) {
694                 gc();
695                 loopCount = GC_LOOP_COUNT;
696             } else {
697                 loopCount--;
698             }
699 
700 
701             try {
702                 fdArray = fds.toArray(fdArray);
703                 index = selectReadable(fdArray);
704             } catch (IOException ex) {
705                 throw new RuntimeException("Error in select()", ex);
706             }
707 
708             if (index < 0) {
709                 throw new RuntimeException("Error in select()");
710             } else if (index == 0) {
711                 ZygoteConnection newPeer = acceptCommandPeer();
712                 peers.add(newPeer);
713                 fds.add(newPeer.getFileDesciptor());
714             } else {
715                 boolean done;
716                 done = peers.get(index).runOnce();
717 
718                 if (done) {
719                     peers.remove(index);
720                     fds.remove(index);
721                 }
722             }
723         }
724     }
725 
726     /**
727      * The Linux syscall "setreuid()"
728      * @param ruid real uid
729      * @param euid effective uid
730      * @return 0 on success, non-zero errno on fail
731      */
setreuid(int ruid, int euid)732     static native int setreuid(int ruid, int euid);
733 
734     /**
735      * The Linux syscall "setregid()"
736      * @param rgid real gid
737      * @param egid effective gid
738      * @return 0 on success, non-zero errno on fail
739      */
setregid(int rgid, int egid)740     static native int setregid(int rgid, int egid);
741 
742     /**
743      * Invokes the linux syscall "setpgid"
744      *
745      * @param pid pid to change
746      * @param pgid new process group of pid
747      * @return 0 on success or non-zero errno on fail
748      */
setpgid(int pid, int pgid)749     static native int setpgid(int pid, int pgid);
750 
751     /**
752      * Invokes the linux syscall "getpgid"
753      *
754      * @param pid pid to query
755      * @return pgid of pid in question
756      * @throws IOException on error
757      */
getpgid(int pid)758     static native int getpgid(int pid) throws IOException;
759 
760     /**
761      * Invokes the syscall dup2() to copy the specified descriptors into
762      * stdin, stdout, and stderr. The existing stdio descriptors will be
763      * closed and errors during close will be ignored. The specified
764      * descriptors will also remain open at their original descriptor numbers,
765      * so the caller may want to close the original descriptors.
766      *
767      * @param in new stdin
768      * @param out new stdout
769      * @param err new stderr
770      * @throws IOException
771      */
reopenStdio(FileDescriptor in, FileDescriptor out, FileDescriptor err)772     static native void reopenStdio(FileDescriptor in,
773             FileDescriptor out, FileDescriptor err) throws IOException;
774 
775     /**
776      * Calls close() on a file descriptor
777      *
778      * @param fd descriptor to close
779      * @throws IOException
780      */
closeDescriptor(FileDescriptor fd)781     static native void closeDescriptor(FileDescriptor fd)
782             throws IOException;
783 
784     /**
785      * Toggles the close-on-exec flag for the specified file descriptor.
786      *
787      * @param fd non-null; file descriptor
788      * @param flag desired close-on-exec flag state
789      * @throws IOException
790      */
setCloseOnExec(FileDescriptor fd, boolean flag)791     static native void setCloseOnExec(FileDescriptor fd, boolean flag)
792             throws IOException;
793 
794     /**
795      * Retrieves the permitted capability set from another process.
796      *
797      * @param pid &gt;=0 process ID or 0 for this process
798      * @throws IOException on error
799      */
capgetPermitted(int pid)800     static native long capgetPermitted(int pid)
801             throws IOException;
802 
803     /**
804      * Sets the permitted and effective capability sets of this process.
805      *
806      * @param permittedCapabilities permitted set
807      * @param effectiveCapabilities effective set
808      * @throws IOException on error
809      */
setCapabilities( long permittedCapabilities, long effectiveCapabilities)810     static native void setCapabilities(
811             long permittedCapabilities,
812             long effectiveCapabilities) throws IOException;
813 
814     /**
815      * Invokes select() on the provider array of file descriptors (selecting
816      * for readability only). Array elements of null are ignored.
817      *
818      * @param fds non-null; array of readable file descriptors
819      * @return index of descriptor that is now readable or -1 for empty array.
820      * @throws IOException if an error occurs
821      */
selectReadable(FileDescriptor[] fds)822     static native int selectReadable(FileDescriptor[] fds) throws IOException;
823 
824     /**
825      * Creates a file descriptor from an int fd.
826      *
827      * @param fd integer OS file descriptor
828      * @return non-null; FileDescriptor instance
829      * @throws IOException if fd is invalid
830      */
createFileDescriptor(int fd)831     static native FileDescriptor createFileDescriptor(int fd)
832             throws IOException;
833 
834     /**
835      * Class not instantiable.
836      */
ZygoteInit()837     private ZygoteInit() {
838     }
839 
840     /**
841      * Helper exception class which holds a method and arguments and
842      * can call them. This is used as part of a trampoline to get rid of
843      * the initial process setup stack frames.
844      */
845     public static class MethodAndArgsCaller extends Exception
846             implements Runnable {
847         /** method to call */
848         private final Method mMethod;
849 
850         /** argument array */
851         private final String[] mArgs;
852 
MethodAndArgsCaller(Method method, String[] args)853         public MethodAndArgsCaller(Method method, String[] args) {
854             mMethod = method;
855             mArgs = args;
856         }
857 
run()858         public void run() {
859             try {
860                 mMethod.invoke(null, new Object[] { mArgs });
861             } catch (IllegalAccessException ex) {
862                 throw new RuntimeException(ex);
863             } catch (InvocationTargetException ex) {
864                 Throwable cause = ex.getCause();
865                 if (cause instanceof RuntimeException) {
866                     throw (RuntimeException) cause;
867                 } else if (cause instanceof Error) {
868                     throw (Error) cause;
869                 }
870                 throw new RuntimeException(ex);
871             }
872         }
873     }
874 }
875