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