1 /* 2 * Copyright (C) 2011 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.os.Process; 20 import android.os.Trace; 21 import android.system.ErrnoException; 22 import android.system.Os; 23 import android.system.OsConstants; 24 import android.system.StructCapUserData; 25 import android.system.StructCapUserHeader; 26 import android.util.Slog; 27 import android.util.TimingsTraceLog; 28 29 import dalvik.system.VMRuntime; 30 31 import libcore.io.IoUtils; 32 33 import java.io.DataOutputStream; 34 import java.io.FileDescriptor; 35 import java.io.FileOutputStream; 36 import java.io.IOException; 37 38 /** 39 * Startup class for the wrapper process. 40 * @hide 41 */ 42 public class WrapperInit { 43 private final static String TAG = "AndroidRuntime"; 44 45 /** 46 * Class not instantiable. 47 */ WrapperInit()48 private WrapperInit() { 49 } 50 51 /** 52 * The main function called when starting a runtime application through a 53 * wrapper process instead of by forking Zygote. 54 * 55 * The first argument specifies the file descriptor for a pipe that should receive 56 * the pid of this process, or 0 if none. 57 * 58 * The second argument is the target SDK version for the app. 59 * 60 * The remaining arguments are passed to the runtime. 61 * 62 * @param args The command-line arguments. 63 */ main(String[] args)64 public static void main(String[] args) { 65 // Parse our mandatory arguments. 66 int fdNum = Integer.parseInt(args[0], 10); 67 int targetSdkVersion = Integer.parseInt(args[1], 10); 68 69 // Tell the Zygote what our actual PID is (since it only knows about the 70 // wrapper that it directly forked). 71 if (fdNum != 0) { 72 FileDescriptor fd = new FileDescriptor(); 73 try { 74 fd.setInt$(fdNum); 75 DataOutputStream os = new DataOutputStream(new FileOutputStream(fd)); 76 os.writeInt(Process.myPid()); 77 os.close(); 78 } catch (IOException ex) { 79 Slog.d(TAG, "Could not write pid of wrapped process to Zygote pipe.", ex); 80 } finally { 81 IoUtils.closeQuietly(fd); 82 } 83 } 84 85 // Mimic system Zygote preloading. 86 ZygoteInit.preload(new TimingsTraceLog("WrapperInitTiming", 87 Trace.TRACE_TAG_DALVIK)); 88 89 // Launch the application. 90 String[] runtimeArgs = new String[args.length - 2]; 91 System.arraycopy(args, 2, runtimeArgs, 0, runtimeArgs.length); 92 Runnable r = wrapperInit(targetSdkVersion, runtimeArgs); 93 94 r.run(); 95 } 96 97 /** 98 * Executes a runtime application with a wrapper command. 99 * This method never returns. 100 * 101 * @param invokeWith The wrapper command. 102 * @param niceName The nice name for the application, or null if none. 103 * @param targetSdkVersion The target SDK version for the app. 104 * @param pipeFd The pipe to which the application's pid should be written, or null if none. 105 * @param args Arguments for {@link RuntimeInit#main}. 106 */ execApplication(String invokeWith, String niceName, int targetSdkVersion, String instructionSet, FileDescriptor pipeFd, String[] args)107 public static void execApplication(String invokeWith, String niceName, 108 int targetSdkVersion, String instructionSet, FileDescriptor pipeFd, 109 String[] args) { 110 StringBuilder command = new StringBuilder(invokeWith); 111 112 final String appProcess; 113 if (VMRuntime.is64BitInstructionSet(instructionSet)) { 114 appProcess = "/system/bin/app_process64"; 115 } else { 116 appProcess = "/system/bin/app_process32"; 117 } 118 command.append(' '); 119 command.append(appProcess); 120 121 // Generate bare minimum of debug information to be able to backtrace through JITed code. 122 // We assume that if the invoke wrapper is used, backtraces are desirable: 123 // * The wrap.sh script can only be used by debuggable apps, which would enable this flag 124 // without the script anyway (the fork-zygote path). So this makes the two consistent. 125 // * The wrap.* property can only be used on userdebug builds and is likely to be used by 126 // developers (e.g. enable debug-malloc), in which case backtraces are also useful. 127 command.append(" -Xcompiler-option --generate-mini-debug-info"); 128 129 command.append(" /system/bin --application"); 130 if (niceName != null) { 131 command.append(" '--nice-name=").append(niceName).append("'"); 132 } 133 command.append(" com.android.internal.os.WrapperInit "); 134 command.append(pipeFd != null ? pipeFd.getInt$() : 0); 135 command.append(' '); 136 command.append(targetSdkVersion); 137 Zygote.appendQuotedShellArgs(command, args); 138 preserveCapabilities(); 139 Zygote.execShell(command.toString()); 140 } 141 142 /** 143 * The main function called when an application is started through a 144 * wrapper process. 145 * 146 * When the wrapper starts, the runtime starts {@link RuntimeInit#main} 147 * which calls {@link main} which then calls this method. 148 * So we don't need to call commonInit() here. 149 * 150 * @param targetSdkVersion target SDK version 151 * @param argv arg strings 152 */ wrapperInit(int targetSdkVersion, String[] argv)153 private static Runnable wrapperInit(int targetSdkVersion, String[] argv) { 154 if (RuntimeInit.DEBUG) { 155 Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from wrapper"); 156 } 157 158 // Check whether the first argument is a "-cp" in argv, and assume the next argument is the 159 // classpath. If found, create a PathClassLoader and use it for applicationInit. 160 ClassLoader classLoader = null; 161 if (argv != null && argv.length > 2 && argv[0].equals("-cp")) { 162 classLoader = ZygoteInit.createPathClassLoader(argv[1], targetSdkVersion); 163 164 // Install this classloader as the context classloader, too. 165 Thread.currentThread().setContextClassLoader(classLoader); 166 167 // Remove the classpath from the arguments. 168 String removedArgs[] = new String[argv.length - 2]; 169 System.arraycopy(argv, 2, removedArgs, 0, argv.length - 2); 170 argv = removedArgs; 171 } 172 // Perform the same initialization that would happen after the Zygote forks. 173 Zygote.nativePreApplicationInit(); 174 return RuntimeInit.applicationInit(targetSdkVersion, /*disabledCompatChanges*/ null, 175 argv, classLoader); 176 } 177 178 /** 179 * Copy current capabilities to ambient capabilities. This is required for apps using 180 * capabilities, as execv will re-evaluate the capability set, and the set of sh is 181 * empty. Ambient capabilities have to be set to inherit them effectively. 182 * 183 * Note: This is BEST EFFORT ONLY. In case capabilities can't be raised, this function 184 * will silently return. In THIS CASE ONLY, as this is a development feature, it 185 * is better to return and try to run anyways, instead of blocking the wrapped app. 186 * This is acceptable here as failure will leave the wrapped app with strictly less 187 * capabilities, which may make it crash, but not exceed its allowances. 188 */ preserveCapabilities()189 private static void preserveCapabilities() { 190 StructCapUserHeader header = new StructCapUserHeader( 191 OsConstants._LINUX_CAPABILITY_VERSION_3, 0); 192 StructCapUserData[] data; 193 try { 194 data = Os.capget(header); 195 } catch (ErrnoException e) { 196 Slog.e(RuntimeInit.TAG, "RuntimeInit: Failed capget", e); 197 return; 198 } 199 200 if (data[0].permitted != data[0].inheritable || 201 data[1].permitted != data[1].inheritable) { 202 data[0] = new StructCapUserData(data[0].effective, data[0].permitted, 203 data[0].permitted); 204 data[1] = new StructCapUserData(data[1].effective, data[1].permitted, 205 data[1].permitted); 206 try { 207 Os.capset(header, data); 208 } catch (ErrnoException e) { 209 Slog.e(RuntimeInit.TAG, "RuntimeInit: Failed capset", e); 210 return; 211 } 212 } 213 214 for (int i = 0; i < 64; i++) { 215 int dataIndex = OsConstants.CAP_TO_INDEX(i); 216 int capMask = OsConstants.CAP_TO_MASK(i); 217 if ((data[dataIndex].inheritable & capMask) != 0) { 218 try { 219 Os.prctl(OsConstants.PR_CAP_AMBIENT, OsConstants.PR_CAP_AMBIENT_RAISE, i, 0, 220 0); 221 } catch (ErrnoException ex) { 222 // Only log here. Try to run the wrapped application even without this 223 // ambient capability. It may crash after fork, but at least we'll try. 224 Slog.e(RuntimeInit.TAG, "RuntimeInit: Failed to raise ambient capability " 225 + i, ex); 226 } 227 } 228 } 229 } 230 } 231