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