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