RuntimeInit.java revision 16f5f5cc9d4c480fac3dc7f176f3f1edfbd256f4
1/* 2 * Copyright (C) 2006 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 17package com.android.internal.os; 18 19import android.app.ActivityManagerNative; 20import android.app.ApplicationErrorReport; 21import android.os.Build; 22import android.os.Debug; 23import android.os.IBinder; 24import android.os.Process; 25import android.os.SystemProperties; 26import android.util.Log; 27import android.util.Slog; 28import com.android.internal.logging.AndroidConfig; 29import com.android.server.NetworkManagementSocketTagger; 30import dalvik.system.VMRuntime; 31import java.lang.reflect.Method; 32import java.lang.reflect.Modifier; 33import java.util.TimeZone; 34import java.util.logging.LogManager; 35import org.apache.harmony.luni.internal.util.TimezoneGetter; 36 37/** 38 * Main entry point for runtime initialization. Not for 39 * public consumption. 40 * @hide 41 */ 42public class RuntimeInit { 43 private final static String TAG = "AndroidRuntime"; 44 private final static boolean DEBUG = false; 45 46 /** true if commonInit() has been called */ 47 private static boolean initialized; 48 49 private static IBinder mApplicationObject; 50 51 private static volatile boolean mCrashing = false; 52 53 private static final native void nativeZygoteInit(); 54 private static final native void nativeFinishInit(); 55 56 /** 57 * Use this to log a message when a thread exits due to an uncaught 58 * exception. The framework catches these for the main threads, so 59 * this should only matter for threads created by applications. 60 */ 61 private static class UncaughtHandler implements Thread.UncaughtExceptionHandler { 62 public void uncaughtException(Thread t, Throwable e) { 63 try { 64 // Don't re-enter -- avoid infinite loops if crash-reporting crashes. 65 if (mCrashing) return; 66 mCrashing = true; 67 68 if (mApplicationObject == null) { 69 Slog.e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e); 70 } else { 71 Slog.e(TAG, "FATAL EXCEPTION: " + t.getName(), e); 72 } 73 74 // Bring up crash dialog, wait for it to be dismissed 75 ActivityManagerNative.getDefault().handleApplicationCrash( 76 mApplicationObject, new ApplicationErrorReport.CrashInfo(e)); 77 } catch (Throwable t2) { 78 try { 79 Slog.e(TAG, "Error reporting crash", t2); 80 } catch (Throwable t3) { 81 // Even Slog.e() fails! Oh well. 82 } 83 } finally { 84 // Try everything to make sure this process goes away. 85 Process.killProcess(Process.myPid()); 86 System.exit(10); 87 } 88 } 89 } 90 91 private static final void commonInit() { 92 if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!"); 93 94 /* set default handler; this applies to all threads in the VM */ 95 Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler()); 96 97 /* 98 * Install a TimezoneGetter subclass for ZoneInfo.db 99 */ 100 TimezoneGetter.setInstance(new TimezoneGetter() { 101 @Override 102 public String getId() { 103 return SystemProperties.get("persist.sys.timezone"); 104 } 105 }); 106 TimeZone.setDefault(null); 107 108 /* 109 * Sets handler for java.util.logging to use Android log facilities. 110 * The odd "new instance-and-then-throw-away" is a mirror of how 111 * the "java.util.logging.config.class" system property works. We 112 * can't use the system property here since the logger has almost 113 * certainly already been initialized. 114 */ 115 LogManager.getLogManager().reset(); 116 new AndroidConfig(); 117 118 /* 119 * Sets the default HTTP User-Agent used by HttpURLConnection. 120 */ 121 String userAgent = getDefaultUserAgent(); 122 System.setProperty("http.agent", userAgent); 123 124 /* 125 * Wire socket tagging to traffic stats. 126 */ 127 NetworkManagementSocketTagger.install(); 128 129 /* 130 * If we're running in an emulator launched with "-trace", put the 131 * VM into emulator trace profiling mode so that the user can hit 132 * F9/F10 at any time to capture traces. This has performance 133 * consequences, so it's not something you want to do always. 134 */ 135 String trace = SystemProperties.get("ro.kernel.android.tracing"); 136 if (trace.equals("1")) { 137 Slog.i(TAG, "NOTE: emulator trace profiling enabled"); 138 Debug.enableEmulatorTraceOutput(); 139 } 140 141 initialized = true; 142 } 143 144 /** 145 * Returns an HTTP user agent of the form 146 * "Dalvik/1.1.0 (Linux; U; Android Eclair Build/MASTER)". 147 */ 148 private static String getDefaultUserAgent() { 149 StringBuilder result = new StringBuilder(64); 150 result.append("Dalvik/"); 151 result.append(System.getProperty("java.vm.version")); // such as 1.1.0 152 result.append(" (Linux; U; Android "); 153 154 String version = Build.VERSION.RELEASE; // "1.0" or "3.4b5" 155 result.append(version.length() > 0 ? version : "1.0"); 156 157 // add the model for the release build 158 if ("REL".equals(Build.VERSION.CODENAME)) { 159 String model = Build.MODEL; 160 if (model.length() > 0) { 161 result.append("; "); 162 result.append(model); 163 } 164 } 165 String id = Build.ID; // "MASTER" or "M4-rc20" 166 if (id.length() > 0) { 167 result.append(" Build/"); 168 result.append(id); 169 } 170 result.append(")"); 171 return result.toString(); 172 } 173 174 /** 175 * Invokes a static "main(argv[]) method on class "className". 176 * Converts various failing exceptions into RuntimeExceptions, with 177 * the assumption that they will then cause the VM instance to exit. 178 * 179 * @param className Fully-qualified class name 180 * @param argv Argument vector for main() 181 */ 182 private static void invokeStaticMain(String className, String[] argv) 183 throws ZygoteInit.MethodAndArgsCaller { 184 Class<?> cl; 185 186 try { 187 cl = Class.forName(className); 188 } catch (ClassNotFoundException ex) { 189 throw new RuntimeException( 190 "Missing class when invoking static main " + className, 191 ex); 192 } 193 194 Method m; 195 try { 196 m = cl.getMethod("main", new Class[] { String[].class }); 197 } catch (NoSuchMethodException ex) { 198 throw new RuntimeException( 199 "Missing static main on " + className, ex); 200 } catch (SecurityException ex) { 201 throw new RuntimeException( 202 "Problem getting static main on " + className, ex); 203 } 204 205 int modifiers = m.getModifiers(); 206 if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) { 207 throw new RuntimeException( 208 "Main method is not public and static on " + className); 209 } 210 211 /* 212 * This throw gets caught in ZygoteInit.main(), which responds 213 * by invoking the exception's run() method. This arrangement 214 * clears up all the stack frames that were required in setting 215 * up the process. 216 */ 217 throw new ZygoteInit.MethodAndArgsCaller(m, argv); 218 } 219 220 public static final void main(String[] argv) { 221 if (argv.length == 2 && argv[1].equals("application")) { 222 if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application"); 223 redirectLogStreams(); 224 } else { 225 if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool"); 226 } 227 228 commonInit(); 229 230 /* 231 * Now that we're running in interpreted code, call back into native code 232 * to run the system. 233 */ 234 nativeFinishInit(); 235 236 if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!"); 237 } 238 239 /** 240 * The main function called when started through the zygote process. This 241 * could be unified with main(), if the native code in nativeFinishInit() 242 * were rationalized with Zygote startup.<p> 243 * 244 * Current recognized args: 245 * <ul> 246 * <li> <code> [--] <start class name> <args> 247 * </ul> 248 * 249 * @param targetSdkVersion target SDK version 250 * @param argv arg strings 251 */ 252 public static final void zygoteInit(int targetSdkVersion, String[] argv) 253 throws ZygoteInit.MethodAndArgsCaller { 254 if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote"); 255 256 redirectLogStreams(); 257 258 commonInit(); 259 nativeZygoteInit(); 260 261 applicationInit(targetSdkVersion, argv); 262 } 263 264 /** 265 * The main function called when an application is started through a 266 * wrapper process. 267 * 268 * When the wrapper starts, the runtime starts {@link RuntimeInit#main} 269 * which calls {@link WrapperInit#main} which then calls this method. 270 * So we don't need to call commonInit() here. 271 * 272 * @param targetSdkVersion target SDK version 273 * @param argv arg strings 274 */ 275 public static void wrapperInit(int targetSdkVersion, String[] argv) 276 throws ZygoteInit.MethodAndArgsCaller { 277 if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from wrapper"); 278 279 applicationInit(targetSdkVersion, argv); 280 } 281 282 private static void applicationInit(int targetSdkVersion, String[] argv) 283 throws ZygoteInit.MethodAndArgsCaller { 284 // We want to be fairly aggressive about heap utilization, to avoid 285 // holding on to a lot of memory that isn't needed. 286 VMRuntime.getRuntime().setTargetHeapUtilization(0.75f); 287 VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); 288 289 final Arguments args; 290 try { 291 args = new Arguments(argv); 292 } catch (IllegalArgumentException ex) { 293 Slog.e(TAG, ex.getMessage()); 294 // let the process exit 295 return; 296 } 297 298 // Remaining arguments are passed to the start class's static main 299 invokeStaticMain(args.startClass, args.startArgs); 300 } 301 302 /** 303 * Redirect System.out and System.err to the Android log. 304 */ 305 public static void redirectLogStreams() { 306 System.out.close(); 307 System.setOut(new AndroidPrintStream(Log.INFO, "System.out")); 308 System.err.close(); 309 System.setErr(new AndroidPrintStream(Log.WARN, "System.err")); 310 } 311 312 /** 313 * Report a serious error in the current process. May or may not cause 314 * the process to terminate (depends on system settings). 315 * 316 * @param tag to record with the error 317 * @param t exception describing the error site and conditions 318 */ 319 public static void wtf(String tag, Throwable t) { 320 try { 321 if (ActivityManagerNative.getDefault().handleApplicationWtf( 322 mApplicationObject, tag, new ApplicationErrorReport.CrashInfo(t))) { 323 // The Activity Manager has already written us off -- now exit. 324 Process.killProcess(Process.myPid()); 325 System.exit(10); 326 } 327 } catch (Throwable t2) { 328 Slog.e(TAG, "Error reporting WTF", t2); 329 } 330 } 331 332 /** 333 * Set the object identifying this application/process, for reporting VM 334 * errors. 335 */ 336 public static final void setApplicationObject(IBinder app) { 337 mApplicationObject = app; 338 } 339 340 public static final IBinder getApplicationObject() { 341 return mApplicationObject; 342 } 343 344 /** 345 * Enable debugging features. 346 */ 347 static { 348 // Register handlers for DDM messages. 349 android.ddm.DdmRegister.registerHandlers(); 350 } 351 352 /** 353 * Handles argument parsing for args related to the runtime. 354 * 355 * Current recognized args: 356 * <ul> 357 * <li> <code> [--] <start class name> <args> 358 * </ul> 359 */ 360 static class Arguments { 361 /** first non-option argument */ 362 String startClass; 363 364 /** all following arguments */ 365 String[] startArgs; 366 367 /** 368 * Constructs instance and parses args 369 * @param args runtime command-line args 370 * @throws IllegalArgumentException 371 */ 372 Arguments(String args[]) throws IllegalArgumentException { 373 parseArgs(args); 374 } 375 376 /** 377 * Parses the commandline arguments intended for the Runtime. 378 */ 379 private void parseArgs(String args[]) 380 throws IllegalArgumentException { 381 int curArg = 0; 382 for (; curArg < args.length; curArg++) { 383 String arg = args[curArg]; 384 385 if (arg.equals("--")) { 386 curArg++; 387 break; 388 } else if (!arg.startsWith("--")) { 389 break; 390 } 391 } 392 393 if (curArg == args.length) { 394 throw new IllegalArgumentException("Missing classname argument to RuntimeInit!"); 395 } 396 397 startClass = args[curArg++]; 398 startArgs = new String[args.length - curArg]; 399 System.arraycopy(args, curArg, startArgs, 0, startArgs.length); 400 } 401 } 402} 403