Runtime.java revision 498e6e60b7c9180b6d58818fe49fd72ad0209a65
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.VMDebug; 36import dalvik.system.VMStack; 37import java.io.ByteArrayOutputStream; 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.io.PipedInputStream; 45import java.io.PipedOutputStream; 46import java.io.Reader; 47import java.io.UnsupportedEncodingException; 48import java.io.Writer; 49import java.nio.charset.Charsets; 50import java.util.ArrayList; 51import java.util.List; 52import java.util.StringTokenizer; 53 54/** 55 * Allows Java applications to interface with the environment in which they are 56 * running. Applications can not create an instance of this class, but they can 57 * get a singleton instance by invoking {@link #getRuntime()}. 58 * 59 * @see System 60 */ 61public class Runtime { 62 63 /** 64 * Holds the Singleton global instance of Runtime. 65 */ 66 private static final Runtime mRuntime = new Runtime(); 67 68 /** 69 * Holds the library paths, used for native library lookup. 70 */ 71 private final String[] mLibPaths; 72 73 /** 74 * Holds the list of threads to run when the VM terminates 75 */ 76 private List<Thread> shutdownHooks = new ArrayList<Thread>(); 77 78 /** 79 * Reflects whether finalization should be run for all objects 80 * when the VM terminates. 81 */ 82 private static boolean finalizeOnExit; 83 84 /** 85 * Reflects whether we are already shutting down the VM. 86 */ 87 private boolean shuttingDown; 88 89 /** 90 * Reflects whether we are tracing method calls. 91 */ 92 private boolean tracingMethods; 93 94 /** 95 * Prevent this class from being instantiated. 96 */ 97 private Runtime(){ 98 String pathList = System.getProperty("java.library.path", "."); 99 String pathSep = System.getProperty("path.separator", ":"); 100 String fileSep = System.getProperty("file.separator", "/"); 101 102 mLibPaths = pathList.split(pathSep); 103 104 int i; 105 106 if (false) 107 System.out.println("Runtime paths:"); 108 109 // Add a '/' to the end so we don't have to do the property lookup 110 // and concatenation later. 111 for (i = 0; i < mLibPaths.length; i++) { 112 if (!mLibPaths[i].endsWith(fileSep)) 113 mLibPaths[i] += fileSep; 114 if (false) 115 System.out.println(" " + mLibPaths[i]); 116 } 117 } 118 119 /** 120 * Executes the specified command and its arguments in a separate native 121 * process. The new process inherits the environment of the caller. Calling 122 * this method is equivalent to calling {@code exec(progArray, null, null)}. 123 * 124 * @param progArray 125 * the array containing the program to execute as well as any 126 * arguments to the program. 127 * @return the new {@code Process} object that represents the native 128 * process. 129 * @throws IOException 130 * if the requested program can not be executed. 131 * @throws SecurityException 132 * if the current {@code SecurityManager} disallows program 133 * execution. 134 * @see SecurityManager#checkExec 135 */ 136 public Process exec(String[] progArray) throws java.io.IOException { 137 return exec(progArray, null, null); 138 } 139 140 /** 141 * Executes the specified command and its arguments in a separate native 142 * process. The new process uses the environment provided in {@code envp}. 143 * Calling this method is equivalent to calling 144 * {@code exec(progArray, envp, null)}. 145 * 146 * @param progArray 147 * the array containing the program to execute as well as any 148 * arguments to the program. 149 * @param envp 150 * the array containing the environment to start the new process 151 * in. 152 * @return the new {@code Process} object that represents the native 153 * process. 154 * @throws IOException 155 * if the requested program can not be executed. 156 * @throws SecurityException 157 * if the current {@code SecurityManager} disallows program 158 * execution. 159 * @see SecurityManager#checkExec 160 */ 161 public Process exec(String[] progArray, String[] envp) throws java.io.IOException { 162 return exec(progArray, envp, null); 163 } 164 165 /** 166 * Executes the specified command and its arguments in a separate native 167 * process. The new process uses the environment provided in {@code envp} 168 * and the working directory specified by {@code directory}. 169 * 170 * @param progArray 171 * the array containing the program to execute as well as any 172 * arguments to the program. 173 * @param envp 174 * the array containing the environment to start the new process 175 * in. 176 * @param directory 177 * the directory in which to execute the program. If {@code null}, 178 * execute if in the same directory as the parent process. 179 * @return the new {@code Process} object that represents the native 180 * process. 181 * @throws IOException 182 * if the requested program can not be executed. 183 * @throws SecurityException 184 * if the current {@code SecurityManager} disallows program 185 * execution. 186 * @see SecurityManager#checkExec 187 */ 188 public Process exec(String[] progArray, String[] envp, File directory) throws IOException { 189 // BEGIN android-changed: push responsibility for argument checking into ProcessManager 190 return ProcessManager.getInstance().exec(progArray, envp, directory, false); 191 // END android-changed 192 } 193 194 /** 195 * Executes the specified program in a separate native process. The new 196 * process inherits the environment of the caller. Calling this method is 197 * equivalent to calling {@code exec(prog, null, null)}. 198 * 199 * @param prog 200 * the name of the program to execute. 201 * @return the new {@code Process} object that represents the native 202 * process. 203 * @throws IOException 204 * if the requested program can not be executed. 205 * @throws SecurityException 206 * if the current {@code SecurityManager} disallows program 207 * execution. 208 * @see SecurityManager#checkExec 209 */ 210 public Process exec(String prog) throws java.io.IOException { 211 return exec(prog, null, null); 212 } 213 214 /** 215 * Executes the specified program in a separate native process. The new 216 * process uses the environment provided in {@code envp}. Calling this 217 * method is equivalent to calling {@code exec(prog, envp, null)}. 218 * 219 * @param prog 220 * the name of the program to execute. 221 * @param envp 222 * the array containing the environment to start the new process 223 * in. 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 * @throws SecurityException 229 * if the current {@code SecurityManager} disallows program 230 * execution. 231 * @see SecurityManager#checkExec 232 */ 233 public Process exec(String prog, String[] envp) throws java.io.IOException { 234 return exec(prog, envp, null); 235 } 236 237 /** 238 * Executes the specified program in a separate native process. The new 239 * process uses the environment provided in {@code envp} and the working 240 * directory specified by {@code directory}. 241 * 242 * @param prog 243 * the name of the program to execute. 244 * @param envp 245 * the array containing the environment to start the new process 246 * in. 247 * @param directory 248 * the directory in which to execute the program. If {@code null}, 249 * execute if in the same directory as the parent process. 250 * @return the new {@code Process} object that represents the native 251 * process. 252 * @throws IOException 253 * if the requested program can not be executed. 254 * @throws SecurityException 255 * if the current {@code SecurityManager} disallows program 256 * execution. 257 * @see SecurityManager#checkExec 258 */ 259 public Process exec(String prog, String[] envp, File directory) throws java.io.IOException { 260 // Sanity checks 261 if (prog == null) { 262 throw new NullPointerException(); 263 } else if (prog.length() == 0) { 264 throw new IllegalArgumentException(); 265 } 266 267 // Break down into tokens, as described in Java docs 268 StringTokenizer tokenizer = new StringTokenizer(prog); 269 int length = tokenizer.countTokens(); 270 String[] progArray = new String[length]; 271 for (int i = 0; i < length; i++) { 272 progArray[i] = tokenizer.nextToken(); 273 } 274 275 // Delegate 276 return exec(progArray, envp, directory); 277 } 278 279 /** 280 * Causes the virtual machine to stop running and the program to exit. If 281 * {@link #runFinalizersOnExit(boolean)} has been previously invoked with a 282 * {@code true} argument, then all objects will be properly 283 * garbage-collected and finalized first. 284 * 285 * @param code 286 * the return code. By convention, non-zero return codes indicate 287 * abnormal terminations. 288 * @throws SecurityException 289 * if the current {@code SecurityManager} does not allow the 290 * running thread to terminate the virtual machine. 291 * @see SecurityManager#checkExit 292 */ 293 public void exit(int code) { 294 // Security checks 295 SecurityManager smgr = System.getSecurityManager(); 296 if (smgr != null) { 297 smgr.checkExit(code); 298 } 299 300 // Make sure we don't try this several times 301 synchronized(this) { 302 if (!shuttingDown) { 303 shuttingDown = true; 304 305 Thread[] hooks; 306 synchronized (shutdownHooks) { 307 // create a copy of the hooks 308 hooks = new Thread[shutdownHooks.size()]; 309 shutdownHooks.toArray(hooks); 310 } 311 312 // Start all shutdown hooks concurrently 313 for (int i = 0; i < hooks.length; i++) { 314 hooks[i].start(); 315 } 316 317 // Wait for all shutdown hooks to finish 318 for (Thread hook : hooks) { 319 try { 320 hook.join(); 321 } catch (InterruptedException ex) { 322 // Ignore, since we are at VM shutdown. 323 } 324 } 325 326 // Ensure finalization on exit, if requested 327 if (finalizeOnExit) { 328 runFinalization(true); 329 } 330 331 // Get out of here finally... 332 nativeExit(code, true); 333 } 334 } 335 } 336 337 /** 338 * Returns the amount of free memory resources which are available to the 339 * running program. 340 * 341 * @return the approximate amount of free memory, measured in bytes. 342 */ 343 public native long freeMemory(); 344 345 /** 346 * Indicates to the virtual machine that it would be a good time to run the 347 * garbage collector. Note that this is a hint only. There is no guarantee 348 * that the garbage collector will actually be run. 349 */ 350 public native void gc(); 351 352 /** 353 * Returns the single {@code Runtime} instance. 354 * 355 * @return the {@code Runtime} object for the current application. 356 */ 357 public static Runtime getRuntime() { 358 return mRuntime; 359 } 360 361 /** 362 * Loads and links the dynamic library that is identified through the 363 * specified path. This method is similar to {@link #loadLibrary(String)}, 364 * but it accepts a full path specification whereas {@code loadLibrary} just 365 * accepts the name of the library to load. 366 * 367 * @param pathName 368 * the absolute (platform dependent) path to the library to load. 369 * @throws UnsatisfiedLinkError 370 * if the library can not be loaded. 371 * @throws SecurityException 372 * if the current {@code SecurityManager} does not allow to load 373 * the library. 374 * @see SecurityManager#checkLink 375 */ 376 public void load(String pathName) { 377 // Security checks 378 SecurityManager smgr = System.getSecurityManager(); 379 if (smgr != null) { 380 smgr.checkLink(pathName); 381 } 382 383 load(pathName, VMStack.getCallingClassLoader()); 384 } 385 386 /* 387 * Loads and links a library without security checks. 388 */ 389 void load(String filename, ClassLoader loader) { 390 if (filename == null) { 391 throw new NullPointerException("library path was null."); 392 } 393 if (!nativeLoad(filename, loader)) { 394 throw new UnsatisfiedLinkError( 395 "Library " + filename + " not found"); 396 } 397 } 398 399 /** 400 * Loads and links the library with the specified name. The mapping of the 401 * specified library name to the full path for loading the library is 402 * implementation-dependent. 403 * 404 * @param libName 405 * the name of the library to load. 406 * @throws UnsatisfiedLinkError 407 * if the library can not be loaded. 408 * @throws SecurityException 409 * if the current {@code SecurityManager} does not allow to load 410 * the library. 411 * @see SecurityManager#checkLink 412 */ 413 public void loadLibrary(String libName) { 414 // Security checks 415 SecurityManager smgr = System.getSecurityManager(); 416 if (smgr != null) { 417 smgr.checkLink(libName); 418 } 419 420 loadLibrary(libName, VMStack.getCallingClassLoader()); 421 } 422 423 /* 424 * Loads and links a library without security checks. 425 */ 426 void loadLibrary(String libname, ClassLoader loader) { 427 String filename; 428 int i; 429 430 if (loader != null) { 431 filename = loader.findLibrary(libname); 432 if (filename != null && nativeLoad(filename, loader)) 433 return; 434 // else fall through to exception 435 } else { 436 filename = System.mapLibraryName(libname); 437 for (i = 0; i < mLibPaths.length; i++) { 438 if (false) 439 System.out.println("Trying " + mLibPaths[i] + filename); 440 if (nativeLoad(mLibPaths[i] + filename, loader)) 441 return; 442 } 443 } 444 445 throw new UnsatisfiedLinkError("Library " + libname + " not found"); 446 } 447 448 private static native void nativeExit(int code, boolean isExit); 449 450 private static native boolean nativeLoad(String filename, 451 ClassLoader loader); 452 453 /** 454 * Requests proper finalization for all Objects on the heap. 455 * 456 * @param forced Decides whether the VM really needs to do this (true) 457 * or if this is just a suggestion that can safely be ignored 458 * (false). 459 */ 460 private native void runFinalization(boolean forced); 461 462 /** 463 * Provides a hint to the virtual machine that it would be useful to attempt 464 * to perform any outstanding object finalizations. 465 * 466 */ 467 public void runFinalization() { 468 runFinalization(false); 469 } 470 471 /** 472 * Sets the flag that indicates whether all objects are finalized when the 473 * virtual machine is about to exit. Note that all finalization which occurs 474 * when the system is exiting is performed after all running threads have 475 * been terminated. 476 * 477 * @param run 478 * {@code true} to enable finalization on exit, {@code false} to 479 * disable it. 480 * @deprecated This method is unsafe. 481 */ 482 @Deprecated 483 public static void runFinalizersOnExit(boolean run) { 484 SecurityManager smgr = System.getSecurityManager(); 485 if (smgr != null) { 486 smgr.checkExit(0); 487 } 488 finalizeOnExit = run; 489 } 490 491 /** 492 * Returns the total amount of memory which is available to the running 493 * program. 494 * 495 * @return the total amount of memory, measured in bytes. 496 */ 497 public native long totalMemory(); 498 499 /** 500 * Switches the output of debug information for instructions on or off. 501 * On Android, this method does nothing. 502 * 503 * @param enable 504 * {@code true} to switch tracing on, {@code false} to switch it 505 * off. 506 */ 507 public void traceInstructions(boolean enable) { 508 // TODO(Google) Provide some implementation for this. 509 return; 510 } 511 512 /** 513 * Switches the output of debug information for methods on or off. 514 * 515 * @param enable 516 * {@code true} to switch tracing on, {@code false} to switch it 517 * off. 518 */ 519 public void traceMethodCalls(boolean enable) { 520 if (enable != tracingMethods) { 521 if (enable) { 522 VMDebug.startMethodTracing(); 523 } else { 524 VMDebug.stopMethodTracing(); 525 } 526 tracingMethods = enable; 527 } 528 } 529 530 /** 531 * Returns the localized version of the specified input stream. The input 532 * stream that is returned automatically converts all characters from the 533 * local character set to Unicode after reading them from the underlying 534 * stream. 535 * 536 * @param stream 537 * the input stream to localize. 538 * @return the localized input stream. 539 * @deprecated Use {@link InputStreamReader}. 540 */ 541 @Deprecated 542 public InputStream getLocalizedInputStream(InputStream stream) { 543 String encoding = System.getProperty("file.encoding", "UTF-8"); 544 if (!encoding.equals("UTF-8")) { 545 throw new UnsupportedOperationException("Cannot localize " + encoding); 546 } 547 return stream; 548 } 549 550 /** 551 * Returns the localized version of the specified output stream. The output 552 * stream that is returned automatically converts all characters from 553 * Unicode to the local character set before writing them to the underlying 554 * stream. 555 * 556 * @param stream 557 * the output stream to localize. 558 * @return the localized output stream. 559 * @deprecated Use {@link OutputStreamWriter}. 560 */ 561 @Deprecated 562 public OutputStream getLocalizedOutputStream(OutputStream stream) { 563 String encoding = System.getProperty("file.encoding", "UTF-8"); 564 if (!encoding.equals("UTF-8")) { 565 throw new UnsupportedOperationException("Cannot localize " + encoding); 566 } 567 return stream; 568 } 569 570 /** 571 * Registers a virtual-machine shutdown hook. A shutdown hook is a 572 * {@code Thread} that is ready to run, but has not yet been started. All 573 * registered shutdown hooks will be executed once the virtual machine shuts 574 * down properly. A proper shutdown happens when either the 575 * {@link #exit(int)} method is called or the surrounding system decides to 576 * terminate the application, for example in response to a {@code CTRL-C} or 577 * a system-wide shutdown. A termination of the virtual machine due to the 578 * {@link #halt(int)} method, an {@link Error} or a {@code SIGKILL}, in 579 * contrast, is not considered a proper shutdown. In these cases the 580 * shutdown hooks will not be run. 581 * <p> 582 * Shutdown hooks are run concurrently and in an unspecified order. Hooks 583 * failing due to an unhandled exception are not a problem, but the stack 584 * trace might be printed to the console. Once initiated, the whole shutdown 585 * process can only be terminated by calling {@code halt()}. 586 * <p> 587 * If {@link #runFinalizersOnExit(boolean)} has been called with a {@code 588 * true} argument, garbage collection and finalization will take place after 589 * all hooks are either finished or have failed. Then the virtual machine 590 * terminates. 591 * <p> 592 * It is recommended that shutdown hooks do not do any time-consuming 593 * activities, in order to not hold up the shutdown process longer than 594 * necessary. 595 * 596 * @param hook 597 * the shutdown hook to register. 598 * @throws IllegalArgumentException 599 * if the hook has already been started or if it has already 600 * been registered. 601 * @throws IllegalStateException 602 * if the virtual machine is already shutting down. 603 * @throws SecurityException 604 * if a SecurityManager is registered and the calling code 605 * doesn't have the RuntimePermission("shutdownHooks"). 606 */ 607 public void addShutdownHook(Thread hook) { 608 // Sanity checks 609 if (hook == null) { 610 throw new NullPointerException("Hook may not be null."); 611 } 612 613 if (shuttingDown) { 614 throw new IllegalStateException("VM already shutting down"); 615 } 616 617 if (hook.hasBeenStarted) { 618 throw new IllegalArgumentException("Hook has already been started"); 619 } 620 621 SecurityManager sm = System.getSecurityManager(); 622 if (sm != null) { 623 sm.checkPermission(new RuntimePermission("shutdownHooks")); 624 } 625 626 synchronized (shutdownHooks) { 627 if (shutdownHooks.contains(hook)) { 628 throw new IllegalArgumentException("Hook already registered."); 629 } 630 631 shutdownHooks.add(hook); 632 } 633 } 634 635 /** 636 * Unregisters a previously registered virtual machine shutdown hook. 637 * 638 * @param hook 639 * the shutdown hook to remove. 640 * @return {@code true} if the hook has been removed successfully; {@code 641 * false} otherwise. 642 * @throws IllegalStateException 643 * if the virtual machine is already shutting down. 644 * @throws SecurityException 645 * if a SecurityManager is registered and the calling code 646 * doesn't have the RuntimePermission("shutdownHooks"). 647 */ 648 public boolean removeShutdownHook(Thread hook) { 649 // Sanity checks 650 if (hook == null) { 651 throw new NullPointerException("Hook may not be null."); 652 } 653 654 if (shuttingDown) { 655 throw new IllegalStateException("VM already shutting down"); 656 } 657 658 SecurityManager sm = System.getSecurityManager(); 659 if (sm != null) { 660 sm.checkPermission(new RuntimePermission("shutdownHooks")); 661 } 662 663 synchronized (shutdownHooks) { 664 return shutdownHooks.remove(hook); 665 } 666 } 667 668 /** 669 * Causes the virtual machine to stop running, and the program to exit. 670 * Neither shutdown hooks nor finalizers are run before. 671 * 672 * @param code 673 * the return code. By convention, non-zero return codes indicate 674 * abnormal terminations. 675 * @throws SecurityException 676 * if the current {@code SecurityManager} does not allow the 677 * running thread to terminate the virtual machine. 678 * @see SecurityManager#checkExit 679 * @see #addShutdownHook(Thread) 680 * @see #removeShutdownHook(Thread) 681 * @see #runFinalizersOnExit(boolean) 682 */ 683 public void halt(int code) { 684 // Security checks 685 SecurityManager smgr = System.getSecurityManager(); 686 if (smgr != null) { 687 smgr.checkExit(code); 688 } 689 690 // Get out of here... 691 nativeExit(code, false); 692 } 693 694 695 /** 696 * Returns the number of processors available to the virtual machine. 697 * 698 * @return the number of available processors, at least 1. 699 */ 700 public native int availableProcessors(); 701 702 /** 703 * Returns the maximum amount of memory that may be used by the virtual 704 * machine, or {@code Long.MAX_VALUE} if there is no such limit. 705 * 706 * @return the maximum amount of memory that the virtual machine will try to 707 * allocate, measured in bytes. 708 */ 709 public native long maxMemory(); 710 711}