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