Runtime.java revision 99b4489d0555c6e0e5df941cbfad4cf250c8f0b8
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17/* 18 * Copyright (C) 2008 The Android Open Source Project 19 * 20 * Licensed under the Apache License, Version 2.0 (the "License"); 21 * you may not use this file except in compliance with the License. 22 * You may obtain a copy of the License at 23 * 24 * http://www.apache.org/licenses/LICENSE-2.0 25 * 26 * Unless required by applicable law or agreed to in writing, software 27 * distributed under the License is distributed on an "AS IS" BASIS, 28 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 29 * See the License for the specific language governing permissions and 30 * limitations under the License. 31 */ 32 33package java.lang; 34 35import dalvik.system.BaseDexClassLoader; 36import dalvik.system.VMDebug; 37import dalvik.system.VMStack; 38import java.io.File; 39import java.io.IOException; 40import java.io.InputStream; 41import java.io.InputStreamReader; 42import java.io.OutputStream; 43import java.io.OutputStreamWriter; 44import java.lang.ref.FinalizerReference; 45import java.util.ArrayList; 46import java.util.List; 47import java.util.StringTokenizer; 48import libcore.io.IoUtils; 49import libcore.io.Libcore; 50import libcore.util.EmptyArray; 51import static libcore.io.OsConstants._SC_NPROCESSORS_CONF; 52 53/** 54 * Allows Java applications to interface with the environment in which they are 55 * running. Applications can not create an instance of this class, but they can 56 * get a singleton instance by invoking {@link #getRuntime()}. 57 * 58 * @see System 59 */ 60public class Runtime { 61 62 /** 63 * Holds the Singleton global instance of Runtime. 64 */ 65 private static final Runtime mRuntime = new Runtime(); 66 67 /** 68 * Holds the library paths, used for native library lookup. 69 */ 70 private final String[] mLibPaths = initLibPaths(); 71 72 private static String[] initLibPaths() { 73 String javaLibraryPath = System.getProperty("java.library.path"); 74 if (javaLibraryPath == null) { 75 return EmptyArray.STRING; 76 } 77 String[] paths = javaLibraryPath.split(":"); 78 // Add a '/' to the end of each directory so we don't have to do it every time. 79 for (int i = 0; i < paths.length; ++i) { 80 if (!paths[i].endsWith("/")) { 81 paths[i] += "/"; 82 } 83 } 84 return paths; 85 } 86 87 /** 88 * Holds the list of threads to run when the VM terminates 89 */ 90 private List<Thread> shutdownHooks = new ArrayList<Thread>(); 91 92 /** 93 * Reflects whether finalization should be run for all objects 94 * when the VM terminates. 95 */ 96 private static boolean finalizeOnExit; 97 98 /** 99 * Reflects whether we are already shutting down the VM. 100 */ 101 private boolean shuttingDown; 102 103 /** 104 * Reflects whether we are tracing method calls. 105 */ 106 private boolean tracingMethods; 107 108 /** 109 * Prevent this class from being instantiated. 110 */ 111 private Runtime() { 112 } 113 114 /** 115 * Executes the specified command and its arguments in a separate native 116 * process. The new process inherits the environment of the caller. Calling 117 * this method is equivalent to calling {@code exec(progArray, null, null)}. 118 * 119 * @param progArray 120 * the array containing the program to execute as well as any 121 * arguments to the program. 122 * @return the new {@code Process} object that represents the native 123 * process. 124 * @throws IOException 125 * if the requested program can not be executed. 126 */ 127 public Process exec(String[] progArray) throws java.io.IOException { 128 return exec(progArray, null, null); 129 } 130 131 /** 132 * Executes the specified command and its arguments in a separate native 133 * process. The new process uses the environment provided in {@code envp}. 134 * Calling this method is equivalent to calling 135 * {@code exec(progArray, envp, null)}. 136 * 137 * @param progArray 138 * the array containing the program to execute as well as any 139 * arguments to the program. 140 * @param envp 141 * the array containing the environment to start the new process 142 * in. 143 * @return the new {@code Process} object that represents the native 144 * process. 145 * @throws IOException 146 * if the requested program can not be executed. 147 */ 148 public Process exec(String[] progArray, String[] envp) throws java.io.IOException { 149 return exec(progArray, envp, null); 150 } 151 152 /** 153 * Executes the specified command and its arguments in a separate native 154 * process. The new process uses the environment provided in {@code envp} 155 * and the working directory specified by {@code directory}. 156 * 157 * @param progArray 158 * the array containing the program to execute as well as any 159 * arguments to the program. 160 * @param envp 161 * the array containing the environment to start the new process 162 * in. 163 * @param directory 164 * the directory in which to execute the program. If {@code null}, 165 * execute if in the same directory as the parent process. 166 * @return the new {@code Process} object that represents the native 167 * process. 168 * @throws IOException 169 * if the requested program can not be executed. 170 */ 171 public Process exec(String[] progArray, String[] envp, File directory) throws IOException { 172 // ProcessManager is responsible for all argument checking. 173 return ProcessManager.getInstance().exec(progArray, envp, directory, false); 174 } 175 176 /** 177 * Executes the specified program in a separate native process. The new 178 * process inherits the environment of the caller. Calling this method is 179 * equivalent to calling {@code exec(prog, null, null)}. 180 * 181 * @param prog 182 * the name of the program to execute. 183 * @return the new {@code Process} object that represents the native 184 * process. 185 * @throws IOException 186 * if the requested program can not be executed. 187 */ 188 public Process exec(String prog) throws java.io.IOException { 189 return exec(prog, null, null); 190 } 191 192 /** 193 * Executes the specified program in a separate native process. The new 194 * process uses the environment provided in {@code envp}. Calling this 195 * method is equivalent to calling {@code exec(prog, envp, null)}. 196 * 197 * @param prog 198 * the name of the program to execute. 199 * @param envp 200 * the array containing the environment to start the new process 201 * in. 202 * @return the new {@code Process} object that represents the native 203 * process. 204 * @throws IOException 205 * if the requested program can not be executed. 206 */ 207 public Process exec(String prog, String[] envp) throws java.io.IOException { 208 return exec(prog, envp, null); 209 } 210 211 /** 212 * Executes the specified program in a separate native process. The new 213 * process uses the environment provided in {@code envp} and the working 214 * directory specified by {@code directory}. 215 * 216 * @param prog 217 * the name of the program to execute. 218 * @param envp 219 * the array containing the environment to start the new process 220 * in. 221 * @param directory 222 * the directory in which to execute the program. If {@code null}, 223 * execute if in the same directory as the parent process. 224 * @return the new {@code Process} object that represents the native 225 * process. 226 * @throws IOException 227 * if the requested program can not be executed. 228 */ 229 public Process exec(String prog, String[] envp, File directory) throws java.io.IOException { 230 // Sanity checks 231 if (prog == null) { 232 throw new NullPointerException("prog == null"); 233 } else if (prog.isEmpty()) { 234 throw new IllegalArgumentException("prog is empty"); 235 } 236 237 // Break down into tokens, as described in Java docs 238 StringTokenizer tokenizer = new StringTokenizer(prog); 239 int length = tokenizer.countTokens(); 240 String[] progArray = new String[length]; 241 for (int i = 0; i < length; i++) { 242 progArray[i] = tokenizer.nextToken(); 243 } 244 245 // Delegate 246 return exec(progArray, envp, directory); 247 } 248 249 /** 250 * Causes the VM to stop running and the program to exit. 251 * If {@link #runFinalizersOnExit(boolean)} has been previously invoked with a 252 * {@code true} argument, then all objects will be properly 253 * garbage-collected and finalized first. 254 * Use 0 to signal success to the calling process and 1 to signal failure. 255 * This method is unlikely to be useful to an Android application. 256 */ 257 public void exit(int code) { 258 // Make sure we don't try this several times 259 synchronized(this) { 260 if (!shuttingDown) { 261 shuttingDown = true; 262 263 Thread[] hooks; 264 synchronized (shutdownHooks) { 265 // create a copy of the hooks 266 hooks = new Thread[shutdownHooks.size()]; 267 shutdownHooks.toArray(hooks); 268 } 269 270 // Start all shutdown hooks concurrently 271 for (Thread hook : hooks) { 272 hook.start(); 273 } 274 275 // Wait for all shutdown hooks to finish 276 for (Thread hook : hooks) { 277 try { 278 hook.join(); 279 } catch (InterruptedException ex) { 280 // Ignore, since we are at VM shutdown. 281 } 282 } 283 284 // Ensure finalization on exit, if requested 285 if (finalizeOnExit) { 286 runFinalization(); 287 } 288 289 // Get out of here finally... 290 nativeExit(code); 291 } 292 } 293 } 294 295 /** 296 * Indicates to the VM that it would be a good time to run the 297 * garbage collector. Note that this is a hint only. There is no guarantee 298 * that the garbage collector will actually be run. 299 */ 300 public native void gc(); 301 302 /** 303 * Returns the single {@code Runtime} instance for the current application. 304 */ 305 public static Runtime getRuntime() { 306 return mRuntime; 307 } 308 309 /** 310 * Loads and links the dynamic library that is identified through the 311 * specified path. This method is similar to {@link #loadLibrary(String)}, 312 * but it accepts a full path specification whereas {@code loadLibrary} just 313 * accepts the name of the library to load. 314 * 315 * @param pathName 316 * the absolute (platform dependent) path to the library to load. 317 * @throws UnsatisfiedLinkError 318 * if the library can not be loaded. 319 */ 320 public void load(String pathName) { 321 load(pathName, VMStack.getCallingClassLoader()); 322 } 323 324 /* 325 * Loads and links the given library without security checks. 326 */ 327 void load(String pathName, ClassLoader loader) { 328 if (pathName == null) { 329 throw new NullPointerException("pathName == null"); 330 } 331 String error = doLoad(pathName, loader); 332 if (error != null) { 333 throw new UnsatisfiedLinkError(error); 334 } 335 } 336 337 /** 338 * Loads and links the library with the specified name. The mapping of the 339 * specified library name to the full path for loading the library is 340 * implementation-dependent. 341 * 342 * @param libName 343 * the name of the library to load. 344 * @throws UnsatisfiedLinkError 345 * if the library can not be loaded. 346 */ 347 public void loadLibrary(String libName) { 348 loadLibrary(libName, VMStack.getCallingClassLoader()); 349 } 350 351 /* 352 * Searches for a library, then loads and links it without security checks. 353 */ 354 void loadLibrary(String libraryName, ClassLoader loader) { 355 if (loader != null) { 356 String filename = loader.findLibrary(libraryName); 357 if (filename == null) { 358 throw new UnsatisfiedLinkError("Couldn't load " + libraryName + 359 " from loader " + loader + 360 ": findLibrary returned null"); 361 } 362 String error = doLoad(filename, loader); 363 if (error != null) { 364 throw new UnsatisfiedLinkError(error); 365 } 366 return; 367 } 368 369 String filename = System.mapLibraryName(libraryName); 370 List<String> candidates = new ArrayList<String>(); 371 String lastError = null; 372 for (String directory : mLibPaths) { 373 String candidate = directory + filename; 374 candidates.add(candidate); 375 376 if (IoUtils.canOpenReadOnly(candidate)) { 377 String error = doLoad(candidate, loader); 378 if (error == null) { 379 return; // We successfully loaded the library. Job done. 380 } 381 lastError = error; 382 } 383 } 384 385 if (lastError != null) { 386 throw new UnsatisfiedLinkError(lastError); 387 } 388 throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates); 389 } 390 391 private static native void nativeExit(int code); 392 393 private String doLoad(String name, ClassLoader loader) { 394 // Android apps are forked from the zygote, so they can't have a custom LD_LIBRARY_PATH, 395 // which means that by default an app's shared library directory isn't on LD_LIBRARY_PATH. 396 397 // The PathClassLoader set up by frameworks/base knows the appropriate path, so we can load 398 // libraries with no dependencies just fine, but an app that has multiple libraries that 399 // depend on each other needed to load them in most-dependent-first order. 400 401 // We added API to Android's dynamic linker so we can update the library path used for 402 // the currently-running process. We pull the desired path out of the ClassLoader here 403 // and pass it to nativeLoad so that it can call the private dynamic linker API. 404 405 // We didn't just change frameworks/base to update the LD_LIBRARY_PATH once at the 406 // beginning because multiple apks can run in the same process and third party code can 407 // use its own BaseDexClassLoader. 408 409 // We didn't just add a dlopen_with_custom_LD_LIBRARY_PATH call because we wanted any 410 // dlopen(3) calls made from a .so's JNI_OnLoad to work too. 411 412 // So, find out what the native library search path is for the ClassLoader in question... 413 String ldLibraryPath = null; 414 if (loader != null && loader instanceof BaseDexClassLoader) { 415 ldLibraryPath = ((BaseDexClassLoader) loader).getLdLibraryPath(); 416 } 417 // nativeLoad should be synchronized so there's only one LD_LIBRARY_PATH in use regardless 418 // of how many ClassLoaders are in the system, but dalvik doesn't support synchronized 419 // internal natives. 420 synchronized (this) { 421 return nativeLoad(name, loader, ldLibraryPath); 422 } 423 } 424 425 // TODO: should be synchronized, but dalvik doesn't support synchronized internal natives. 426 private static native String nativeLoad(String filename, ClassLoader loader, String ldLibraryPath); 427 428 /** 429 * Provides a hint to the VM that it would be useful to attempt 430 * to perform any outstanding object finalization. 431 */ 432 public void runFinalization() { 433 try { 434 FinalizerReference.finalizeAllEnqueued(); 435 } catch (InterruptedException e) { 436 Thread.currentThread().interrupt(); 437 } 438 } 439 440 /** 441 * Sets the flag that indicates whether all objects are finalized when the 442 * VM is about to exit. Note that all finalization which occurs 443 * when the system is exiting is performed after all running threads have 444 * been terminated. 445 * 446 * @param run 447 * {@code true} to enable finalization on exit, {@code false} to 448 * disable it. 449 * @deprecated This method is unsafe. 450 */ 451 @Deprecated 452 public static void runFinalizersOnExit(boolean run) { 453 finalizeOnExit = run; 454 } 455 456 /** 457 * Switches the output of debug information for instructions on or off. 458 * On Android, this method does nothing. 459 */ 460 public void traceInstructions(boolean enable) { 461 } 462 463 /** 464 * Switches the output of debug information for methods on or off. 465 */ 466 public void traceMethodCalls(boolean enable) { 467 if (enable != tracingMethods) { 468 if (enable) { 469 VMDebug.startMethodTracing(); 470 } else { 471 VMDebug.stopMethodTracing(); 472 } 473 tracingMethods = enable; 474 } 475 } 476 477 /** 478 * Returns the localized version of the specified input stream. The input 479 * stream that is returned automatically converts all characters from the 480 * local character set to Unicode after reading them from the underlying 481 * stream. 482 * 483 * @param stream 484 * the input stream to localize. 485 * @return the localized input stream. 486 * @deprecated Use {@link InputStreamReader} instead. 487 */ 488 @Deprecated 489 public InputStream getLocalizedInputStream(InputStream stream) { 490 String encoding = System.getProperty("file.encoding", "UTF-8"); 491 if (!encoding.equals("UTF-8")) { 492 throw new UnsupportedOperationException("Cannot localize " + encoding); 493 } 494 return stream; 495 } 496 497 /** 498 * Returns the localized version of the specified output stream. The output 499 * stream that is returned automatically converts all characters from 500 * Unicode to the local character set before writing them to the underlying 501 * stream. 502 * 503 * @param stream 504 * the output stream to localize. 505 * @return the localized output stream. 506 * @deprecated Use {@link OutputStreamWriter} instead. 507 */ 508 @Deprecated 509 public OutputStream getLocalizedOutputStream(OutputStream stream) { 510 String encoding = System.getProperty("file.encoding", "UTF-8"); 511 if (!encoding.equals("UTF-8")) { 512 throw new UnsupportedOperationException("Cannot localize " + encoding); 513 } 514 return stream; 515 } 516 517 /** 518 * Registers a VM shutdown hook. A shutdown hook is a 519 * {@code Thread} that is ready to run, but has not yet been started. All 520 * registered shutdown hooks will be executed when the VM 521 * terminates normally (typically when the {@link #exit(int)} method is called). 522 * 523 * <p><i>Note that on Android, the application lifecycle does not include VM termination, 524 * so calling this method will not ensure that your code is run</i>. Instead, you should 525 * use the most appropriate lifecycle notification ({@code Activity.onPause}, say). 526 * 527 * <p>Shutdown hooks are run concurrently and in an unspecified order. Hooks 528 * failing due to an unhandled exception are not a problem, but the stack 529 * trace might be printed to the console. Once initiated, the whole shutdown 530 * process can only be terminated by calling {@code halt()}. 531 * 532 * <p>If {@link #runFinalizersOnExit(boolean)} has been called with a {@code 533 * true} argument, garbage collection and finalization will take place after 534 * all hooks are either finished or have failed. Then the VM 535 * terminates. 536 * 537 * <p>It is recommended that shutdown hooks do not do any time-consuming 538 * activities, in order to not hold up the shutdown process longer than 539 * necessary. 540 * 541 * @param hook 542 * the shutdown hook to register. 543 * @throws IllegalArgumentException 544 * if the hook has already been started or if it has already 545 * been registered. 546 * @throws IllegalStateException 547 * if the VM is already shutting down. 548 */ 549 public void addShutdownHook(Thread hook) { 550 // Sanity checks 551 if (hook == null) { 552 throw new NullPointerException("hook == null"); 553 } 554 555 if (shuttingDown) { 556 throw new IllegalStateException("VM already shutting down"); 557 } 558 559 if (hook.hasBeenStarted) { 560 throw new IllegalArgumentException("Hook has already been started"); 561 } 562 563 synchronized (shutdownHooks) { 564 if (shutdownHooks.contains(hook)) { 565 throw new IllegalArgumentException("Hook already registered."); 566 } 567 568 shutdownHooks.add(hook); 569 } 570 } 571 572 /** 573 * Unregisters a previously registered VM shutdown hook. 574 * 575 * @param hook 576 * the shutdown hook to remove. 577 * @return {@code true} if the hook has been removed successfully; {@code 578 * false} otherwise. 579 * @throws IllegalStateException 580 * if the VM is already shutting down. 581 */ 582 public boolean removeShutdownHook(Thread hook) { 583 // Sanity checks 584 if (hook == null) { 585 throw new NullPointerException("hook == null"); 586 } 587 588 if (shuttingDown) { 589 throw new IllegalStateException("VM already shutting down"); 590 } 591 592 synchronized (shutdownHooks) { 593 return shutdownHooks.remove(hook); 594 } 595 } 596 597 /** 598 * Causes the VM to stop running, and the program to exit with the given return code. 599 * Use 0 to signal success to the calling process and 1 to signal failure. 600 * Neither shutdown hooks nor finalizers are run before exiting. 601 * This method is unlikely to be useful to an Android application. 602 */ 603 public void halt(int code) { 604 // Get out of here... 605 nativeExit(code); 606 } 607 608 /** 609 * Returns the number of processor cores available to the VM, at least 1. 610 * Traditionally this returned the number currently online, 611 * but many mobile devices are able to take unused cores offline to 612 * save power, so releases newer than Android 4.2 (Jelly Bean) return the maximum number of 613 * cores that could be made available if there were no power or heat 614 * constraints. 615 */ 616 public int availableProcessors() { 617 return (int) Libcore.os.sysconf(_SC_NPROCESSORS_CONF); 618 } 619 620 /** 621 * Returns the number of bytes currently available on the heap without expanding the heap. See 622 * {@link #totalMemory} for the heap's current size. When these bytes are exhausted, the heap 623 * may expand. See {@link #maxMemory} for that limit. 624 */ 625 public native long freeMemory(); 626 627 /** 628 * Returns the number of bytes taken by the heap at its current size. The heap may expand or 629 * contract over time, as the number of live objects increases or decreases. See 630 * {@link #maxMemory} for the maximum heap size, and {@link #freeMemory} for an idea of how much 631 * the heap could currently contract. 632 */ 633 public native long totalMemory(); 634 635 /** 636 * Returns the maximum number of bytes the heap can expand to. See {@link #totalMemory} for the 637 * current number of bytes taken by the heap, and {@link #freeMemory} for the current number of 638 * those bytes actually used by live objects. 639 */ 640 public native long maxMemory(); 641} 642