如何检测 Android 运行时(Dalvik 或 ART)?

Posted

技术标签:

【中文标题】如何检测 Android 运行时(Dalvik 或 ART)?【英文标题】:How can I detect the Android runtime (Dalvik or ART)? 【发布时间】:2013-11-18 18:25:52 【问题描述】:

Google 在 android 4.4 中添加了一个新的 ART 运行时。如何确定当前运行时是 ART 还是 Dalvik?

【问题讨论】:

你为什么想知道它?与开发 POV 有什么区别吗? 我的应用在 ART 下运行时遇到问题,但在 Dalvik 下运行良好。因此,我正在寻找一种方法来通知用户他们正在运行实验性运行时,并在我有机会查看它们之前预计会出现稳定性问题。 在 ART 下运行的应用问题可以按照本页的指南和提示进行验证:developer.android.com/guide/practices/verifying-apps-art.html 【参考方案1】:

更新

至少,早在 2014 年 6 月,Google 就在 how to correctly verify the current runtime in use 上发布了官方文档:

您可以通过调用 System.getProperty("java.vm.version") 来验证正在使用的运行时。如果使用 ART,则属性值为“2.0.0”或更高。

这样,现在就不需要再去反射了,直接检查对应的系统属性即可:

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


一种可能的方法是通过反射读取相应的SystemProperty

示例:

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";
        
    

希望这会有所帮助。

【讨论】:

像魅力一样工作!谢谢。 请注意——属性名称不能保证保持不变。它已经改变了:android.googlesource.com/platform/frameworks/base/+/… 这个问题的其他答案似乎更可取:它们都更容易实现,更少hacky并且容易破坏。 @DCKing ,在发布此答案时(2013 年 11 月),没有提及如何在开发人员文档中验证当前运行时(因此,反射:)。感谢您的提醒,帖子已相应更新。【参考方案2】:

对于任何需要 JNI 版本的人:

#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;

或者,如果您想遵循更接近鞋鼠发布的代码路径,

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;

【讨论】:

【参考方案3】:

Android docs其实给出了如下建议:

您可以通过调用 System.getProperty("java.vm.version") 来验证正在使用的运行时。如果使用 ART,则属性值为“2.0.0”或更高。

这在我启用了 ART 的 Nexus 4 上似乎是准确的(运行 Android 4.4.4)。 Dalvik 上的 Nexus 5 返回了1.6.0

【讨论】:

【参考方案4】:

一个简单的解决方案:

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

在我的 Android 8.0 (API 26) 手机上,它返回 Dalvik 2.1.0。

【讨论】:

【参考方案5】:

我认为您应该能够使用System.getProperty 和java.vm.name 作为键。 在 JavaDoc 中,它的值为 Dalvik,我们希望在使用 runtime 时它是 ArtART。值得一试...

【讨论】:

运行 ART 时:System.getProperty("java.vm.name") 返回DalvikSystem.getProperty("java.specification.name") 返回Dalvik Core Library。 :( 嗯,这将是查询它的最简单方法。也许他们没有改变它,因为 ART 还没有发布... 发布与否,即使是开发版也需要检测。即使他们将来更新它,它也永远不会被认为是可靠的。【参考方案6】:

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

然后将vm与“libdvm.so”或“libart.so”进行比较,判断是Dalvik还是ART。

参考:https://gitorious.org/cyandreamproject/android_frameworks_base/commit/4c3f1e9e30948113b47068152027676172743eb1

【讨论】:

以上是关于如何检测 Android 运行时(Dalvik 或 ART)?的主要内容,如果未能解决你的问题,请参考以下文章

Android ART 运行时是不是具有与 Dalvik 相同的方法限制限制?

将 Dalvik 字节码动态生成到正在运行的 Dalvik/Android 应用程序中

Android ART运行时与Dalvik虚拟机

Android:如何在运行时增加堆大小?

Android中的Dalvik和ART的区别

ART和Dalvik的比较