1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package dalvik.system;
18
19import dalvik.annotation.optimization.FastNative;
20import java.lang.ref.FinalizerReference;
21import java.util.HashMap;
22import java.util.Map;
23import java.util.function.Consumer;
24
25/**
26 * Provides an interface to VM-global, Dalvik-specific features.
27 * An application cannot create its own Runtime instance, and must obtain
28 * one from the getRuntime method.
29 *
30 * @hide
31 */
32public final class VMRuntime {
33
34    /**
35     * Holds the VMRuntime singleton.
36     */
37    private static final VMRuntime THE_ONE = new VMRuntime();
38
39    // Note: Instruction set names are used to construct the names of some
40    // system properties. To be sure that the properties stay valid the
41    // instruction set name should not exceed 7 characters. See installd
42    // and the package manager for the actual propeties.
43    private static final Map<String, String> ABI_TO_INSTRUCTION_SET_MAP
44            = new HashMap<String, String>(16);
45    static {
46        ABI_TO_INSTRUCTION_SET_MAP.put("armeabi", "arm");
47        ABI_TO_INSTRUCTION_SET_MAP.put("armeabi-v7a", "arm");
48        ABI_TO_INSTRUCTION_SET_MAP.put("mips", "mips");
49        ABI_TO_INSTRUCTION_SET_MAP.put("mips64", "mips64");
50        ABI_TO_INSTRUCTION_SET_MAP.put("x86", "x86");
51        ABI_TO_INSTRUCTION_SET_MAP.put("x86_64", "x86_64");
52        ABI_TO_INSTRUCTION_SET_MAP.put("arm64-v8a", "arm64");
53    }
54
55    /**
56     * Magic version number for a current development build, which has not
57     * yet turned into an official release. This number must be larger than
58     * any released version in {@code android.os.Build.VERSION_CODES}.
59     * @hide
60     */
61    public static final int SDK_VERSION_CUR_DEVELOPMENT = 10000;
62
63    private static Consumer<String> nonSdkApiUsageConsumer = null;
64
65    private int targetSdkVersion = SDK_VERSION_CUR_DEVELOPMENT;
66
67    /**
68     * Prevents this class from being instantiated.
69     */
70    private VMRuntime() {
71    }
72
73    /**
74     * Returns the object that represents the VM instance's Dalvik-specific
75     * runtime environment.
76     *
77     * @return the runtime object
78     */
79    public static VMRuntime getRuntime() {
80        return THE_ONE;
81    }
82
83    /**
84     * Returns a copy of the VM's command-line property settings.
85     * These are in the form "name=value" rather than "-Dname=value".
86     */
87    public native String[] properties();
88
89    /**
90     * Returns the VM's boot class path.
91     */
92    public native String bootClassPath();
93
94    /**
95     * Returns the VM's class path.
96     */
97    public native String classPath();
98
99    /**
100     * Returns the VM's version.
101     */
102    public native String vmVersion();
103
104    /**
105     * Returns the name of the shared library providing the VM implementation.
106     */
107    public native String vmLibrary();
108
109    /**
110     * Returns the VM's instruction set.
111     */
112    public native String vmInstructionSet();
113
114    /**
115     * Returns whether the VM is running in 64-bit mode.
116     */
117    @FastNative
118    public native boolean is64Bit();
119
120    /**
121     * Returns whether the VM is running with JNI checking enabled.
122     */
123    @FastNative
124    public native boolean isCheckJniEnabled();
125
126    /**
127     * Gets the current ideal heap utilization, represented as a number
128     * between zero and one.  After a GC happens, the Dalvik heap may
129     * be resized so that (size of live objects) / (size of heap) is
130     * equal to this number.
131     *
132     * @return the current ideal heap utilization
133     */
134    public native float getTargetHeapUtilization();
135
136    /**
137     * Sets the current ideal heap utilization, represented as a number
138     * between zero and one.  After a GC happens, the Dalvik heap may
139     * be resized so that (size of live objects) / (size of heap) is
140     * equal to this number.
141     *
142     * <p>This is only a hint to the garbage collector and may be ignored.
143     *
144     * @param newTarget the new suggested ideal heap utilization.
145     *                  This value may be adjusted internally.
146     * @return the previous ideal heap utilization
147     * @throws IllegalArgumentException if newTarget is &lt;= 0.0 or &gt;= 1.0
148     */
149    public float setTargetHeapUtilization(float newTarget) {
150        if (newTarget <= 0.0f || newTarget >= 1.0f) {
151            throw new IllegalArgumentException(newTarget +
152                    " out of range (0,1)");
153        }
154        /* Synchronize to make sure that only one thread gets
155         * a given "old" value if both update at the same time.
156         * Allows for reliable save-and-restore semantics.
157         */
158        synchronized (this) {
159            float oldTarget = getTargetHeapUtilization();
160            nativeSetTargetHeapUtilization(newTarget);
161            return oldTarget;
162        }
163    }
164
165    /**
166     * Sets the target SDK version. Should only be called before the
167     * app starts to run, because it may change the VM's behavior in
168     * dangerous ways. Defaults to {@link #SDK_VERSION_CUR_DEVELOPMENT}.
169     */
170    public synchronized void setTargetSdkVersion(int targetSdkVersion) {
171        this.targetSdkVersion = targetSdkVersion;
172        setTargetSdkVersionNative(this.targetSdkVersion);
173    }
174
175    /**
176     * Gets the target SDK version. See {@link #setTargetSdkVersion} for
177     * special values.
178     */
179    public synchronized int getTargetSdkVersion() {
180        return targetSdkVersion;
181    }
182
183    private native void setTargetSdkVersionNative(int targetSdkVersion);
184
185    /**
186     * This method exists for binary compatibility.  It was part of a
187     * heap sizing API which was removed in Android 3.0 (Honeycomb).
188     */
189    @Deprecated
190    public long getMinimumHeapSize() {
191        return 0;
192    }
193
194    /**
195     * This method exists for binary compatibility.  It was part of a
196     * heap sizing API which was removed in Android 3.0 (Honeycomb).
197     */
198    @Deprecated
199    public long setMinimumHeapSize(long size) {
200        return 0;
201    }
202
203    /**
204     * This method exists for binary compatibility.  It used to
205     * perform a garbage collection that cleared SoftReferences.
206     */
207    @Deprecated
208    public void gcSoftReferences() {}
209
210    /**
211     * This method exists for binary compatibility.  It is equivalent
212     * to {@link System#runFinalization}.
213     */
214    @Deprecated
215    public void runFinalizationSync() {
216        System.runFinalization();
217    }
218
219    /**
220     * Implements setTargetHeapUtilization().
221     *
222     * @param newTarget the new suggested ideal heap utilization.
223     *                  This value may be adjusted internally.
224     */
225    private native void nativeSetTargetHeapUtilization(float newTarget);
226
227    /**
228     * This method exists for binary compatibility.  It was part of
229     * the external allocation API which was removed in Android 3.0 (Honeycomb).
230     */
231    @Deprecated
232    public boolean trackExternalAllocation(long size) {
233        return true;
234    }
235
236    /**
237     * This method exists for binary compatibility.  It was part of
238     * the external allocation API which was removed in Android 3.0 (Honeycomb).
239     */
240    @Deprecated
241    public void trackExternalFree(long size) {}
242
243    /**
244     * This method exists for binary compatibility.  It was part of
245     * the external allocation API which was removed in Android 3.0 (Honeycomb).
246     */
247    @Deprecated
248    public long getExternalBytesAllocated() {
249        return 0;
250    }
251
252    /**
253     * Tells the VM to enable the JIT compiler. If the VM does not have a JIT
254     * implementation, calling this method should have no effect.
255     */
256    public native void startJitCompilation();
257
258    /**
259     * Tells the VM to disable the JIT compiler. If the VM does not have a JIT
260     * implementation, calling this method should have no effect.
261     */
262    public native void disableJitCompilation();
263
264    /**
265     * Returns true if the app has accessed a hidden API. This does not include
266     * attempts which have been blocked.
267     */
268    public native boolean hasUsedHiddenApi();
269
270    /**
271     * Sets the list of exemptions from hidden API access enforcement.
272     *
273     * @param signaturePrefixes
274     *         A list of signature prefixes. Each item in the list is a prefix match on the type
275     *         signature of a blacklisted API. All matching APIs are treated as if they were on
276     *         the whitelist: access permitted, and no logging..
277     */
278    public native void setHiddenApiExemptions(String[] signaturePrefixes);
279
280    /**
281     * Sets the log sampling rate of hidden API accesses written to the event log.
282     *
283     * @param rate Proportion of hidden API accesses that will be logged; an integer between
284     *                0 and 0x10000 inclusive.
285     */
286    public native void setHiddenApiAccessLogSamplingRate(int rate);
287
288    /**
289     * Returns an array allocated in an area of the Java heap where it will never be moved.
290     * This is used to implement native allocations on the Java heap, such as DirectByteBuffers
291     * and Bitmaps.
292     */
293    @FastNative
294    public native Object newNonMovableArray(Class<?> componentType, int length);
295
296    /**
297     * Returns an array of at least minLength, but potentially larger. The increased size comes from
298     * avoiding any padding after the array. The amount of padding varies depending on the
299     * componentType and the memory allocator implementation.
300     */
301    @FastNative
302    public native Object newUnpaddedArray(Class<?> componentType, int minLength);
303
304    /**
305     * Returns the address of array[0]. This differs from using JNI in that JNI might lie and
306     * give you the address of a copy of the array when in forcecopy mode.
307     */
308    @FastNative
309    public native long addressOf(Object array);
310
311    /**
312     * Removes any growth limits, allowing the application to allocate
313     * up to the maximum heap size.
314     */
315    public native void clearGrowthLimit();
316
317    /**
318     * Make the current growth limit the new non growth limit capacity by releasing pages which
319     * are after the growth limit but before the non growth limit capacity.
320     */
321    public native void clampGrowthLimit();
322
323    /**
324     * Returns true if either a Java debugger or native debugger is active.
325     */
326    @FastNative
327    public native boolean isDebuggerActive();
328
329    /**
330     * Returns true if native debugging is on.
331     */
332    @FastNative
333    public native boolean isNativeDebuggable();
334
335    /**
336     * Returns true if Java debugging is enabled.
337     */
338    public native boolean isJavaDebuggable();
339
340    /**
341     * Registers a native allocation so that the heap knows about it and performs GC as required.
342     * If the number of native allocated bytes exceeds the native allocation watermark, the
343     * function requests a concurrent GC. If the native bytes allocated exceeds a second higher
344     * watermark, it is determined that the application is registering native allocations at an
345     * unusually high rate and a GC is performed inside of the function to prevent memory usage
346     * from excessively increasing.
347     */
348    public native void registerNativeAllocation(int bytes);
349
350    /**
351     * Registers a native free by reducing the number of native bytes accounted for.
352     */
353    public native void registerNativeFree(int bytes);
354
355    /**
356     * Wait for objects to be finalized.
357     *
358     * If finalization takes longer than timeout, then the function returns before all objects are
359     * finalized.
360     *
361     * @param timeout
362     *            timeout in nanoseconds of the maximum time to wait until all pending finalizers
363     *            are run. If timeout is 0, then there is no timeout. Note that the timeout does
364     *            not stop the finalization process, it merely stops the wait.
365     *
366     * @see #Runtime.runFinalization()
367     * @see #wait(long,int)
368     */
369    public static void runFinalization(long timeout) {
370        try {
371            FinalizerReference.finalizeAllEnqueued(timeout);
372        } catch (InterruptedException e) {
373            // Interrupt the current thread without actually throwing the InterruptionException
374            // for the caller.
375            Thread.currentThread().interrupt();
376        }
377    }
378
379    public native void requestConcurrentGC();
380    public native void concurrentGC();
381    public native void requestHeapTrim();
382    public native void trimHeap();
383    public native void startHeapTaskProcessor();
384    public native void stopHeapTaskProcessor();
385    public native void runHeapTasks();
386
387    /**
388     * Let the heap know of the new process state. This can change allocation and garbage collection
389     * behavior regarding trimming and compaction.
390     */
391    public native void updateProcessState(int state);
392
393    /**
394     * Fill in dex caches with classes, fields, and methods that are
395     * already loaded. Typically used after Zygote preloading.
396     */
397    public native void preloadDexCaches();
398
399    /**
400     * Register application info.
401     * @param profileFile the path of the file where the profile information should be stored.
402     * @param codePaths the code paths that should be profiled.
403     */
404    public static native void registerAppInfo(String profileFile, String[] codePaths);
405
406    /**
407     * Returns the runtime instruction set corresponding to a given ABI. Multiple
408     * compatible ABIs might map to the same instruction set. For example
409     * {@code armeabi-v7a} and {@code armeabi} might map to the instruction set {@code arm}.
410     *
411     * This influences the compilation of the applications classes.
412     */
413    public static String getInstructionSet(String abi) {
414        final String instructionSet = ABI_TO_INSTRUCTION_SET_MAP.get(abi);
415        if (instructionSet == null) {
416            throw new IllegalArgumentException("Unsupported ABI: " + abi);
417        }
418
419        return instructionSet;
420    }
421
422    public static boolean is64BitInstructionSet(String instructionSet) {
423        return "arm64".equals(instructionSet) ||
424                "x86_64".equals(instructionSet) ||
425                "mips64".equals(instructionSet);
426    }
427
428    public static boolean is64BitAbi(String abi) {
429        return is64BitInstructionSet(getInstructionSet(abi));
430    }
431
432    /**
433     * Return false if the boot class path for the given instruction
434     * set mapped from disk storage, versus being interpretted from
435     * dirty pages in memory.
436     */
437    public static native boolean isBootClassPathOnDisk(String instructionSet);
438
439    /**
440     * Returns the instruction set of the current runtime.
441     */
442    public static native String getCurrentInstructionSet();
443
444    /**
445     * Return true if the dalvik cache was pruned when booting. This may have happened for
446     * various reasons, e.g., after an OTA. The return value is for the current instruction
447     * set.
448     */
449    public static native boolean didPruneDalvikCache();
450
451    /**
452     * Register the current execution thread to the runtime as sensitive thread.
453     * Should be called just once. Subsequent calls are ignored.
454     */
455    public static native void registerSensitiveThread();
456
457    /**
458     * Sets up the priority of the system daemon thread (caller).
459     */
460    public static native void setSystemDaemonThreadPriority();
461
462    /**
463     * Sets a callback that the runtime can call whenever a usage of a non SDK API is detected.
464     */
465    public static void setNonSdkApiUsageConsumer(Consumer<String> consumer) {
466        nonSdkApiUsageConsumer = consumer;
467    }
468
469    /**
470     * Sets whether or not the runtime should dedupe detection and warnings for hidden API usage.
471     * If deduping is enabled, only the first usage of each API will be detected. The default
472     * behaviour is to dedupe.
473     */
474    public static native void setDedupeHiddenApiWarnings(boolean dedupe);
475
476    /**
477     * Sets the package name of the app running in this process.
478     */
479    public static native void setProcessPackageName(String packageName);
480}
481