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