Home | History | Annotate | Download | only in os
      1 /*
      2  * Copyright (C) 2014 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 
     20 import dalvik.system.ZygoteHooks;
     21 import android.system.ErrnoException;
     22 import android.system.Os;
     23 import android.os.SystemClock;
     24 import android.util.Slog;
     25 
     26 /** @hide */
     27 public final class Zygote {
     28     private static final String TAG = "Zygote";
     29     /*
     30     * Bit values for "debugFlags" argument.  The definitions are duplicated
     31     * in the native code.
     32     */
     33 
     34     /** enable debugging over JDWP */
     35     public static final int DEBUG_ENABLE_DEBUGGER   = 1;
     36     /** enable JNI checks */
     37     public static final int DEBUG_ENABLE_CHECKJNI   = 1 << 1;
     38     /** enable Java programming language "assert" statements */
     39     public static final int DEBUG_ENABLE_ASSERT     = 1 << 2;
     40     /** disable the JIT compiler */
     41     public static final int DEBUG_ENABLE_SAFEMODE   = 1 << 3;
     42     /** Enable logging of third-party JNI activity. */
     43     public static final int DEBUG_ENABLE_JNI_LOGGING = 1 << 4;
     44 
     45     /** No external storage should be mounted. */
     46     public static final int MOUNT_EXTERNAL_NONE = 0;
     47     /** Single-user external storage should be mounted. */
     48     public static final int MOUNT_EXTERNAL_SINGLEUSER = 1;
     49     /** Multi-user external storage should be mounted. */
     50     public static final int MOUNT_EXTERNAL_MULTIUSER = 2;
     51     /** All multi-user external storage should be mounted. */
     52     public static final int MOUNT_EXTERNAL_MULTIUSER_ALL = 3;
     53 
     54     private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
     55 
     56     private Zygote() {}
     57 
     58     /**
     59      * Forks a new VM instance.  The current VM must have been started
     60      * with the -Xzygote flag. <b>NOTE: new instance keeps all
     61      * root capabilities. The new process is expected to call capset()</b>.
     62      *
     63      * @param uid the UNIX uid that the new process should setuid() to after
     64      * fork()ing and and before spawning any threads.
     65      * @param gid the UNIX gid that the new process should setgid() to after
     66      * fork()ing and and before spawning any threads.
     67      * @param gids null-ok; a list of UNIX gids that the new process should
     68      * setgroups() to after fork and before spawning any threads.
     69      * @param debugFlags bit flags that enable debugging features.
     70      * @param rlimits null-ok an array of rlimit tuples, with the second
     71      * dimension having a length of 3 and representing
     72      * (resource, rlim_cur, rlim_max). These are set via the posix
     73      * setrlimit(2) call.
     74      * @param seInfo null-ok a string specifying SELinux information for
     75      * the new process.
     76      * @param niceName null-ok a string specifying the process name.
     77      * @param fdsToClose an array of ints, holding one or more POSIX
     78      * file descriptor numbers that are to be closed by the child
     79      * (and replaced by /dev/null) after forking.  An integer value
     80      * of -1 in any entry in the array means "ignore this one".
     81      * @param instructionSet null-ok the instruction set to use.
     82      * @param appDataDir null-ok the data directory of the app.
     83      *
     84      * @return 0 if this is the child, pid of the child
     85      * if this is the parent, or -1 on error.
     86      */
     87     public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
     88           int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
     89           String instructionSet, String appDataDir) {
     90         long startTime = SystemClock.elapsedRealtime();
     91         VM_HOOKS.preFork();
     92         checkTime(startTime, "Zygote.preFork");
     93         int pid = nativeForkAndSpecialize(
     94                   uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
     95                   instructionSet, appDataDir);
     96         checkTime(startTime, "Zygote.nativeForkAndSpecialize");
     97         VM_HOOKS.postForkCommon();
     98         checkTime(startTime, "Zygote.postForkCommon");
     99         return pid;
    100     }
    101 
    102     native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int debugFlags,
    103           int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
    104           String instructionSet, String appDataDir);
    105 
    106     /**
    107      * Temporary hack: check time since start time and log if over a fixed threshold.
    108      *
    109      */
    110     private static void checkTime(long startTime, String where) {
    111         long now = SystemClock.elapsedRealtime();
    112         if ((now-startTime) > 1000) {
    113             // If we are taking more than a second, log about it.
    114             Slog.w(TAG, "Slow operation: " + (now-startTime) + "ms so far, now at " + where);
    115         }
    116     }
    117 
    118     /**
    119      * Special method to start the system server process. In addition to the
    120      * common actions performed in forkAndSpecialize, the pid of the child
    121      * process is recorded such that the death of the child process will cause
    122      * zygote to exit.
    123      *
    124      * @param uid the UNIX uid that the new process should setuid() to after
    125      * fork()ing and and before spawning any threads.
    126      * @param gid the UNIX gid that the new process should setgid() to after
    127      * fork()ing and and before spawning any threads.
    128      * @param gids null-ok; a list of UNIX gids that the new process should
    129      * setgroups() to after fork and before spawning any threads.
    130      * @param debugFlags bit flags that enable debugging features.
    131      * @param rlimits null-ok an array of rlimit tuples, with the second
    132      * dimension having a length of 3 and representing
    133      * (resource, rlim_cur, rlim_max). These are set via the posix
    134      * setrlimit(2) call.
    135      * @param permittedCapabilities argument for setcap()
    136      * @param effectiveCapabilities argument for setcap()
    137      *
    138      * @return 0 if this is the child, pid of the child
    139      * if this is the parent, or -1 on error.
    140      */
    141     public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
    142             int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
    143         VM_HOOKS.preFork();
    144         int pid = nativeForkSystemServer(
    145                 uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
    146         VM_HOOKS.postForkCommon();
    147         return pid;
    148     }
    149 
    150     native private static int nativeForkSystemServer(int uid, int gid, int[] gids, int debugFlags,
    151             int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
    152 
    153     private static void callPostForkChildHooks(int debugFlags, String instructionSet) {
    154         long startTime = SystemClock.elapsedRealtime();
    155         VM_HOOKS.postForkChild(debugFlags, instructionSet);
    156         checkTime(startTime, "Zygote.callPostForkChildHooks");
    157     }
    158 
    159 
    160     /**
    161      * Executes "/system/bin/sh -c &lt;command&gt;" using the exec() system call.
    162      * This method throws a runtime exception if exec() failed, otherwise, this
    163      * method never returns.
    164      *
    165      * @param command The shell command to execute.
    166      */
    167     public static void execShell(String command) {
    168         String[] args = { "/system/bin/sh", "-c", command };
    169         try {
    170             Os.execv(args[0], args);
    171         } catch (ErrnoException e) {
    172             throw new RuntimeException(e);
    173         }
    174     }
    175 
    176     /**
    177      * Appends quotes shell arguments to the specified string builder.
    178      * The arguments are quoted using single-quotes, escaped if necessary,
    179      * prefixed with a space, and appended to the command.
    180      *
    181      * @param command A string builder for the shell command being constructed.
    182      * @param args An array of argument strings to be quoted and appended to the command.
    183      * @see #execShell(String)
    184      */
    185     public static void appendQuotedShellArgs(StringBuilder command, String[] args) {
    186         for (String arg : args) {
    187             command.append(" '").append(arg.replace("'", "'\\''")).append("'");
    188         }
    189     }
    190 }
    191