• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.shadows;
2 
3 import static android.os.Build.VERSION_CODES.LOLLIPOP;
4 import static android.os.Build.VERSION_CODES.Q;
5 
6 import android.annotation.TargetApi;
7 import dalvik.system.VMRuntime;
8 import java.lang.ref.WeakReference;
9 import java.lang.reflect.Array;
10 import javax.annotation.Nullable;
11 import org.robolectric.annotation.Implementation;
12 import org.robolectric.annotation.Implements;
13 import org.robolectric.annotation.Resetter;
14 import org.robolectric.res.android.NativeObjRegistry;
15 
16 @Implements(value = VMRuntime.class, isInAndroidSdk = false)
17 public class ShadowVMRuntime {
18 
19   private final NativeObjRegistry<WeakReference<Object>> nativeObjRegistry =
20       new NativeObjRegistry<>("VRRuntime.nativeObjectRegistry");
21   // There actually isn't any android JNI code to call through to in Robolectric due to
22   // cross-platform compatibility issues. We default to a reasonable value that reflects the devices
23   // that would commonly run this code.
24   private static boolean is64Bit = true;
25 
26   @Nullable private static String currentInstructionSet = null;
27 
28   @Implementation
newUnpaddedArray(Class<?> klass, int size)29   public Object newUnpaddedArray(Class<?> klass, int size) {
30     return Array.newInstance(klass, size);
31   }
32 
33   @Implementation
newNonMovableArray(Class<?> type, int size)34   public Object newNonMovableArray(Class<?> type, int size) {
35     if (type.equals(int.class)) {
36       return new int[size];
37     }
38     return null;
39   }
40 
41   /**
42    * Returns a unique identifier of the object instead of a 'native' address.
43    */
44   @Implementation
addressOf(Object obj)45   public long addressOf(Object obj) {
46     return nativeObjRegistry.register(new WeakReference<>(obj));
47   }
48 
49   /**
50    * Returns the object previously registered with {@link #addressOf(Object)}.
51    */
52   public @Nullable
getObjectForAddress(long address)53   Object getObjectForAddress(long address) {
54     return nativeObjRegistry.getNativeObject(address).get();
55   }
56 
57   /**
58    * Returns whether the VM is running in 64-bit mode. Available in Android L+. Defaults to true.
59    */
60   @Implementation
is64Bit()61   protected boolean is64Bit() {
62     return ShadowVMRuntime.is64Bit;
63   }
64 
65   /** Sets whether the VM is running in 64-bit mode. */
66   @TargetApi(LOLLIPOP)
setIs64Bit(boolean is64Bit)67   public static void setIs64Bit(boolean is64Bit) {
68     ShadowVMRuntime.is64Bit = is64Bit;
69   }
70 
71   /** Returns the instruction set of the current runtime. */
72   @Implementation
getCurrentInstructionSet()73   protected static String getCurrentInstructionSet() {
74     return currentInstructionSet;
75   }
76 
77   /** Sets the instruction set of the current runtime. */
78   @TargetApi(LOLLIPOP)
setCurrentInstructionSet(@ullable String currentInstructionSet)79   public static void setCurrentInstructionSet(@Nullable String currentInstructionSet) {
80     ShadowVMRuntime.currentInstructionSet = currentInstructionSet;
81   }
82 
83   @Resetter
reset()84   public static void reset() {
85     ShadowVMRuntime.is64Bit = true;
86     ShadowVMRuntime.currentInstructionSet = null;
87   }
88 
89   @Implementation(minSdk = Q)
getNotifyNativeInterval()90   protected static int getNotifyNativeInterval() {
91     // The value '384' is from
92     // https://cs.android.com/android/platform/superproject/+/android-12.0.0_r18:art/runtime/gc/heap.h;l=172
93     // Note that value returned is irrelevant for the JVM, it just has to be greater than zero to
94     // avoid a divide-by-zero error in VMRuntime.notifyNativeAllocation.
95     return 384; // must be greater than 0
96   }
97 }
98