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