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