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