• 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 = ClassLoader.getSystemClassLoader().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                 ar.recycle();
352                 Log.i(TAG, "...preloaded " + N + " resources in "
353                         + (SystemClock.uptimeMillis()-startTime) + "ms.");
354 
355                 startTime = SystemClock.uptimeMillis();
356                 ar = mResources.obtainTypedArray(
357                         com.android.internal.R.array.preloaded_color_state_lists);
358                 N = preloadColorStateLists(runtime, ar);
359                 ar.recycle();
360                 Log.i(TAG, "...preloaded " + N + " resources in "
361                         + (SystemClock.uptimeMillis()-startTime) + "ms.");
362             }
363             mResources.finishPreloading();
364         } catch (RuntimeException e) {
365             Log.w(TAG, "Failure preloading resources", e);
366         } finally {
367             Debug.stopAllocCounting();
368         }
369     }
370 
preloadColorStateLists(VMRuntime runtime, TypedArray ar)371     private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) {
372         int N = ar.length();
373         for (int i=0; i<N; i++) {
374             if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
375                 if (false) {
376                     Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
377                 }
378                 System.gc();
379                 runtime.runFinalizationSync();
380                 Debug.resetGlobalAllocSize();
381             }
382             int id = ar.getResourceId(i, 0);
383             if (false) {
384                 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
385             }
386             if (id != 0) {
387                 mResources.getColorStateList(id);
388             }
389         }
390         return N;
391     }
392 
393 
preloadDrawables(VMRuntime runtime, TypedArray ar)394     private static int preloadDrawables(VMRuntime runtime, TypedArray ar) {
395         int N = ar.length();
396         for (int i=0; i<N; i++) {
397             if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
398                 if (false) {
399                     Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
400                 }
401                 System.gc();
402                 runtime.runFinalizationSync();
403                 Debug.resetGlobalAllocSize();
404             }
405             int id = ar.getResourceId(i, 0);
406             if (false) {
407                 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
408             }
409             if (id != 0) {
410                 Drawable dr = mResources.getDrawable(id);
411                 if ((dr.getChangingConfigurations()&~ActivityInfo.CONFIG_FONT_SCALE) != 0) {
412                     Log.w(TAG, "Preloaded drawable resource #0x"
413                             + Integer.toHexString(id)
414                             + " (" + ar.getString(i) + ") that varies with configuration!!");
415                 }
416             }
417         }
418         return N;
419     }
420 
421     /**
422      * Runs several special GCs to try to clean up a few generations of
423      * softly- and final-reachable objects, along with any other garbage.
424      * This is only useful just before a fork().
425      */
gc()426     /*package*/ static void gc() {
427         final VMRuntime runtime = VMRuntime.getRuntime();
428 
429         /* runFinalizationSync() lets finalizers be called in Zygote,
430          * which doesn't have a HeapWorker thread.
431          */
432         System.gc();
433         runtime.runFinalizationSync();
434         System.gc();
435         runtime.runFinalizationSync();
436         System.gc();
437         runtime.runFinalizationSync();
438     }
439 
440     /**
441      * Finish remaining work for the newly forked system server process.
442      */
handleSystemServerProcess( ZygoteConnection.Arguments parsedArgs)443     private static void handleSystemServerProcess(
444             ZygoteConnection.Arguments parsedArgs)
445             throws ZygoteInit.MethodAndArgsCaller {
446 
447         closeServerSocket();
448 
449         // set umask to 0077 so new files and directories will default to owner-only permissions.
450         FileUtils.setUMask(FileUtils.S_IRWXG | FileUtils.S_IRWXO);
451 
452         if (parsedArgs.niceName != null) {
453             Process.setArgV0(parsedArgs.niceName);
454         }
455 
456         if (parsedArgs.invokeWith != null) {
457             WrapperInit.execApplication(parsedArgs.invokeWith,
458                     parsedArgs.niceName, parsedArgs.targetSdkVersion,
459                     null, parsedArgs.remainingArgs);
460         } else {
461             /*
462              * Pass the remaining arguments to SystemServer.
463              */
464             RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
465         }
466 
467         /* should never reach here */
468     }
469 
470     /**
471      * Prepare the arguments and fork for the system server process.
472      */
startSystemServer()473     private static boolean startSystemServer()
474             throws MethodAndArgsCaller, RuntimeException {
475         /* Hardcoded command line to start the system server */
476         String args[] = {
477             "--setuid=1000",
478             "--setgid=1000",
479             "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006,3007",
480             "--capabilities=130104352,130104352",
481             "--runtime-init",
482             "--nice-name=system_server",
483             "com.android.server.SystemServer",
484         };
485         ZygoteConnection.Arguments parsedArgs = null;
486 
487         int pid;
488 
489         try {
490             parsedArgs = new ZygoteConnection.Arguments(args);
491             ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
492             ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
493 
494             /* Request to fork the system server process */
495             pid = Zygote.forkSystemServer(
496                     parsedArgs.uid, parsedArgs.gid,
497                     parsedArgs.gids,
498                     parsedArgs.debugFlags,
499                     null,
500                     parsedArgs.permittedCapabilities,
501                     parsedArgs.effectiveCapabilities);
502         } catch (IllegalArgumentException ex) {
503             throw new RuntimeException(ex);
504         }
505 
506         /* For child process */
507         if (pid == 0) {
508             handleSystemServerProcess(parsedArgs);
509         }
510 
511         return true;
512     }
513 
main(String argv[])514     public static void main(String argv[]) {
515         try {
516             // Start profiling the zygote initialization.
517             SamplingProfilerIntegration.start();
518 
519             registerZygoteSocket();
520             EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
521                 SystemClock.uptimeMillis());
522             preload();
523             EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
524                 SystemClock.uptimeMillis());
525 
526             // Finish profiling the zygote initialization.
527             SamplingProfilerIntegration.writeZygoteSnapshot();
528 
529             // Do an initial gc to clean up after startup
530             gc();
531 
532             // If requested, start system server directly from Zygote
533             if (argv.length != 2) {
534                 throw new RuntimeException(argv[0] + USAGE_STRING);
535             }
536 
537             if (argv[1].equals("start-system-server")) {
538                 startSystemServer();
539             } else if (!argv[1].equals("")) {
540                 throw new RuntimeException(argv[0] + USAGE_STRING);
541             }
542 
543             Log.i(TAG, "Accepting command socket connections");
544 
545             if (ZYGOTE_FORK_MODE) {
546                 runForkMode();
547             } else {
548                 runSelectLoopMode();
549             }
550 
551             closeServerSocket();
552         } catch (MethodAndArgsCaller caller) {
553             caller.run();
554         } catch (RuntimeException ex) {
555             Log.e(TAG, "Zygote died with exception", ex);
556             closeServerSocket();
557             throw ex;
558         }
559     }
560 
561     /**
562      * Runs the zygote in accept-and-fork mode. In this mode, each peer
563      * gets its own zygote spawner process. This code is retained for
564      * reference only.
565      *
566      * @throws MethodAndArgsCaller in a child process when a main() should
567      * be executed.
568      */
runForkMode()569     private static void runForkMode() throws MethodAndArgsCaller {
570         while (true) {
571             ZygoteConnection peer = acceptCommandPeer();
572 
573             int pid;
574 
575             pid = Zygote.fork();
576 
577             if (pid == 0) {
578                 // The child process should handle the peer requests
579 
580                 // The child does not accept any more connections
581                 try {
582                     sServerSocket.close();
583                 } catch (IOException ex) {
584                     Log.e(TAG, "Zygote Child: error closing sockets", ex);
585                 } finally {
586                     sServerSocket = null;
587                 }
588 
589                 peer.run();
590                 break;
591             } else if (pid > 0) {
592                 peer.closeSocket();
593             } else {
594                 throw new RuntimeException("Error invoking fork()");
595             }
596         }
597     }
598 
599     /**
600      * Runs the zygote process's select loop. Accepts new connections as
601      * they happen, and reads commands from connections one spawn-request's
602      * worth at a time.
603      *
604      * @throws MethodAndArgsCaller in a child process when a main() should
605      * be executed.
606      */
runSelectLoopMode()607     private static void runSelectLoopMode() throws MethodAndArgsCaller {
608         ArrayList<FileDescriptor> fds = new ArrayList();
609         ArrayList<ZygoteConnection> peers = new ArrayList();
610         FileDescriptor[] fdArray = new FileDescriptor[4];
611 
612         fds.add(sServerSocket.getFileDescriptor());
613         peers.add(null);
614 
615         int loopCount = GC_LOOP_COUNT;
616         while (true) {
617             int index;
618 
619             /*
620              * Call gc() before we block in select().
621              * It's work that has to be done anyway, and it's better
622              * to avoid making every child do it.  It will also
623              * madvise() any free memory as a side-effect.
624              *
625              * Don't call it every time, because walking the entire
626              * heap is a lot of overhead to free a few hundred bytes.
627              */
628             if (loopCount <= 0) {
629                 gc();
630                 loopCount = GC_LOOP_COUNT;
631             } else {
632                 loopCount--;
633             }
634 
635 
636             try {
637                 fdArray = fds.toArray(fdArray);
638                 index = selectReadable(fdArray);
639             } catch (IOException ex) {
640                 throw new RuntimeException("Error in select()", ex);
641             }
642 
643             if (index < 0) {
644                 throw new RuntimeException("Error in select()");
645             } else if (index == 0) {
646                 ZygoteConnection newPeer = acceptCommandPeer();
647                 peers.add(newPeer);
648                 fds.add(newPeer.getFileDesciptor());
649             } else {
650                 boolean done;
651                 done = peers.get(index).runOnce();
652 
653                 if (done) {
654                     peers.remove(index);
655                     fds.remove(index);
656                 }
657             }
658         }
659     }
660 
661     /**
662      * The Linux syscall "setreuid()"
663      * @param ruid real uid
664      * @param euid effective uid
665      * @return 0 on success, non-zero errno on fail
666      */
setreuid(int ruid, int euid)667     static native int setreuid(int ruid, int euid);
668 
669     /**
670      * The Linux syscall "setregid()"
671      * @param rgid real gid
672      * @param egid effective gid
673      * @return 0 on success, non-zero errno on fail
674      */
setregid(int rgid, int egid)675     static native int setregid(int rgid, int egid);
676 
677     /**
678      * Invokes the linux syscall "setpgid"
679      *
680      * @param pid pid to change
681      * @param pgid new process group of pid
682      * @return 0 on success or non-zero errno on fail
683      */
setpgid(int pid, int pgid)684     static native int setpgid(int pid, int pgid);
685 
686     /**
687      * Invokes the linux syscall "getpgid"
688      *
689      * @param pid pid to query
690      * @return pgid of pid in question
691      * @throws IOException on error
692      */
getpgid(int pid)693     static native int getpgid(int pid) throws IOException;
694 
695     /**
696      * Invokes the syscall dup2() to copy the specified descriptors into
697      * stdin, stdout, and stderr. The existing stdio descriptors will be
698      * closed and errors during close will be ignored. The specified
699      * descriptors will also remain open at their original descriptor numbers,
700      * so the caller may want to close the original descriptors.
701      *
702      * @param in new stdin
703      * @param out new stdout
704      * @param err new stderr
705      * @throws IOException
706      */
reopenStdio(FileDescriptor in, FileDescriptor out, FileDescriptor err)707     static native void reopenStdio(FileDescriptor in,
708             FileDescriptor out, FileDescriptor err) throws IOException;
709 
710     /**
711      * Toggles the close-on-exec flag for the specified file descriptor.
712      *
713      * @param fd non-null; file descriptor
714      * @param flag desired close-on-exec flag state
715      * @throws IOException
716      */
setCloseOnExec(FileDescriptor fd, boolean flag)717     static native void setCloseOnExec(FileDescriptor fd, boolean flag)
718             throws IOException;
719 
720     /**
721      * Retrieves the permitted capability set from another process.
722      *
723      * @param pid &gt;=0 process ID or 0 for this process
724      * @throws IOException on error
725      */
capgetPermitted(int pid)726     static native long capgetPermitted(int pid)
727             throws IOException;
728 
729     /**
730      * Sets the permitted and effective capability sets of this process.
731      *
732      * @param permittedCapabilities permitted set
733      * @param effectiveCapabilities effective set
734      * @throws IOException on error
735      */
setCapabilities( long permittedCapabilities, long effectiveCapabilities)736     static native void setCapabilities(
737             long permittedCapabilities,
738             long effectiveCapabilities) throws IOException;
739 
740     /**
741      * Invokes select() on the provider array of file descriptors (selecting
742      * for readability only). Array elements of null are ignored.
743      *
744      * @param fds non-null; array of readable file descriptors
745      * @return index of descriptor that is now readable or -1 for empty array.
746      * @throws IOException if an error occurs
747      */
selectReadable(FileDescriptor[] fds)748     static native int selectReadable(FileDescriptor[] fds) throws IOException;
749 
750     /**
751      * Creates a file descriptor from an int fd.
752      *
753      * @param fd integer OS file descriptor
754      * @return non-null; FileDescriptor instance
755      * @throws IOException if fd is invalid
756      */
createFileDescriptor(int fd)757     static native FileDescriptor createFileDescriptor(int fd)
758             throws IOException;
759 
760     /**
761      * Class not instantiable.
762      */
ZygoteInit()763     private ZygoteInit() {
764     }
765 
766     /**
767      * Helper exception class which holds a method and arguments and
768      * can call them. This is used as part of a trampoline to get rid of
769      * the initial process setup stack frames.
770      */
771     public static class MethodAndArgsCaller extends Exception
772             implements Runnable {
773         /** method to call */
774         private final Method mMethod;
775 
776         /** argument array */
777         private final String[] mArgs;
778 
MethodAndArgsCaller(Method method, String[] args)779         public MethodAndArgsCaller(Method method, String[] args) {
780             mMethod = method;
781             mArgs = args;
782         }
783 
run()784         public void run() {
785             try {
786                 mMethod.invoke(null, new Object[] { mArgs });
787             } catch (IllegalAccessException ex) {
788                 throw new RuntimeException(ex);
789             } catch (InvocationTargetException ex) {
790                 Throwable cause = ex.getCause();
791                 if (cause instanceof RuntimeException) {
792                     throw (RuntimeException) cause;
793                 } else if (cause instanceof Error) {
794                     throw (Error) cause;
795                 }
796                 throw new RuntimeException(ex);
797             }
798         }
799     }
800 }
801