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}