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