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