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