39

Google added a new ART runtime with Android 4.4. How can I determine whether ART or Dalvik is the current runtime?

Charles
  • 50,943
  • 13
  • 104
  • 142
Chris Lacy
  • 4,222
  • 3
  • 35
  • 33
  • 2
    Why do you want to know it? Is there any difference from dev POV? – korro Nov 07 '13 at 20:12
  • 5
    My app experiences issues running under ART but works fine with Dalvik. As such, I'm after a way to inform users they are running an experimental runtime and to expect stability issues until I get the chance to look at them. – Chris Lacy Nov 07 '13 at 23:28
  • 1
    The app issues running under ART can be verified by following the guidelines and tips on this page: https://developer.android.com/guide/practices/verifying-apps-art.html – rwong Jun 19 '14 at 19:57

6 Answers6

33

Update

At least, as early as June 2014 Google has released an official documentation on how to correctly verify the current runtime in use:

You can verify which runtime is in use by calling System.getProperty("java.vm.version"). If ART is in use, the property's value is "2.0.0" or higher.

With that, now there is no need to go through reflection and simply check the corresponding system property:

private boolean getIsArtInUse() {
    final String vmVersion = System.getProperty("java.vm.version");
    return vmVersion != null && vmVersion.startsWith("2");
}

One possible way is to read the respective SystemProperty through reflection.

Sample:

package com.example.getcurrentruntimevalue;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MainActivity extends Activity {
    private static final String SELECT_RUNTIME_PROPERTY = "persist.sys.dalvik.vm.lib";
    private static final String LIB_DALVIK = "libdvm.so";
    private static final String LIB_ART = "libart.so";
    private static final String LIB_ART_D = "libartd.so";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView tv = (TextView)findViewById(R.id.current_runtime_value);
        tv.setText(getCurrentRuntimeValue());
    }

    private CharSequence getCurrentRuntimeValue() {
        try {
            Class<?> systemProperties = Class.forName("android.os.SystemProperties");
            try {
                Method get = systemProperties.getMethod("get",
                   String.class, String.class);
                if (get == null) {
                    return "WTF?!";
                }
                try {
                    final String value = (String)get.invoke(
                        systemProperties, SELECT_RUNTIME_PROPERTY,
                        /* Assuming default is */"Dalvik");
                    if (LIB_DALVIK.equals(value)) {
                        return "Dalvik";
                    } else if (LIB_ART.equals(value)) {
                        return "ART";
                    } else if (LIB_ART_D.equals(value)) {
                        return "ART debug build";
                    }

                    return value;
                } catch (IllegalAccessException e) {
                    return "IllegalAccessException";
                } catch (IllegalArgumentException e) {
                    return "IllegalArgumentException";
                } catch (InvocationTargetException e) {
                    return "InvocationTargetException";
                }
            } catch (NoSuchMethodException e) {
                return "SystemProperties.get(String key, String def) method is not found";
            }
        } catch (ClassNotFoundException e) {
            return "SystemProperties class is not found";
        }
    }
}

Hope this helps.

ozbek
  • 20,955
  • 5
  • 61
  • 84
  • Be careful though -- the property name is not guaranteed to remain the same. It has already changed: https://android.googlesource.com/platform/frameworks/base/+/c6c633608ad4cd77ed21227b0bdb11eb79797c31 – fadden Feb 28 '14 at 01:50
  • The other answers to this question appear be preferable: they are both easier to implement and less hacky and prone to breaking. – DCKing Jul 24 '14 at 09:46
  • 1
    @DCKing , at the time when this answer was posted (Nov 2013) there was no mention of how to verify the current runtime in Developer Docs (hence, the reflection:). Thanks for the heads up, the post is updated accordingly. – ozbek Jul 24 '14 at 21:47
4

For anyone needing a JNI version:

#include <sys/system_properties.h>

static bool isArtEnabled() {
    char buf[PROP_VALUE_MAX] = {};
    __system_property_get("persist.sys.dalvik.vm.lib.2", buf);
    // This allows libartd.so to be detected as well.
    return strncmp("libart", buf, 6) == 0;
}

Or if you want to follow a code path closer to what shoe rat posted,

static bool isArtEnabled(JNIEnv *env)
{
    // Per https://developer.android.com/guide/practices/verifying-apps-art.html
    // if the result of System.getProperty("java.vm.version") starts with 2,
    // ART is enabled.

    jclass systemClass = env->FindClass("java/lang/System");

    if (systemClass == NULL) {
        LOGD("Could not find java.lang.System.");
        return false;
    }

    jmethodID getProperty = env->GetStaticMethodID(systemClass,
        "getProperty", "(Ljava/lang/String;)Ljava/lang/String;");

    if (getProperty == NULL) {
        LOGD("Could not find java.lang.System.getProperty(String).");
        return false;
    }

    jstring propertyName = env->NewStringUTF("java.vm.version");

    jstring jversion = (jstring)env->CallStaticObjectMethod(
        systemClass, getProperty, propertyName);

    if (jversion == NULL) {
        LOGD("java.lang.System.getProperty('java.vm.version') did not return a value.");
        return false;
    }

    const char *version = env->GetStringUTFChars(jversion, JNI_FALSE);

    // Lets flip that check around to better bullet proof us.
    // Consider any version which starts with "1." to be Dalvik,
    // and all others to be ART.
    bool isArtEnabled = !(strlen(version) < 2 ||
        strncmp("1.", version, 2) == 0);

    LOGD("Is ART enabled? %d (%s)", isArtEnabled, version);

    env->ReleaseStringUTFChars(jversion, version);

    return isArtEnabled;
}
Joseph Lennox
  • 3,202
  • 1
  • 27
  • 25
3

The Android docs actually give the following suggestion:

You can verify which runtime is in use by calling System.getProperty("java.vm.version"). If ART is in use, the property's value is "2.0.0" or higher.

This seems accurate on my Nexus 4 w/ ART enabled (running Android 4.4.4). Nexus 5 on Dalvik returned 1.6.0.

wsanville
  • 37,158
  • 8
  • 76
  • 101
2

A simple solution :

String vm = System.getProperty("java.vm.name") + " " + System.getProperty("java.vm.version");

On my Android 8.0 (API 26) phone, it returns Dalvik 2.1.0 .

Domenico
  • 1,331
  • 18
  • 22
1

I think you should be able to use System.getProperty with java.vm.name as the key. In the JavaDoc its value is Dalvik, which let's hope it is Art or ART when using that runtime. It's worth a try...

tilpner
  • 4,351
  • 2
  • 22
  • 45
  • 1
    When running ART: `System.getProperty("java.vm.name")` returns `Dalvik`. `System.getProperty("java.specification.name")` returns `Dalvik Core Library`. :( – Chris Lacy Nov 07 '13 at 10:35
  • 1
    Hm, that would have been the easiest way to query it. Maybe they didn't change it because ART isn't *released* yet... – tilpner Nov 07 '13 at 14:25
  • Released or not, it needs to be detected even if it's a development version. Even if they update this in the future it can never be considered reliable. – Joseph Lennox Aug 01 '14 at 12:50
0

final String vm = VMRuntime.getRuntime().vmLibrary();

and then compare vm with "libdvm.so" or "libart.so" to check if it is Dalvik or ART.

Reference: https://gitorious.org/cyandreamproject/android_frameworks_base/commit/4c3f1e9e30948113b47068152027676172743eb1

Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
Yong
  • 1,529
  • 12
  • 21