Posted at

AndroidのVM情報を取得する

More than 5 years have passed since last update.

LからAndroidのRuntimeはARTになるけど,KitKatに載ってるARTだとDalvikとの互換がまだ不十分でDalvikだと通るコードがARTで落ちるとかはままある。

なので,落ちた例外とVM情報を抱き合わせで送信したいとかいう場合。


ARTかDalvikかを判定する

公式ドキュメントをみると,System.getProperty("java.vm.name")でDalvikが返ってくるというのでてっきりこれでいけると思ったら,ART環境下でもDalvikが返ってくる…。System.getProperty("java.vm.specification.name")も同様。

困ったのでAndroid Developersを読んでいくと,


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.


とある。System.getProperty("java.vm.version")の値が2.0.0以上であればARTと判定しろとの事だ。マジか…と思いつつ気を取り直して判定メソッドを書いてみる。

public static boolean IsArtInUse() {

final String versionName = System.getProperty("java.vm.version");
final int version = Integer.parseInt(versionName.substring(0, 1));
return version > 1;
}

大分苦しいが,1文字目を数値に変換して1より大きければARTと判定できる。

StackOverFlowには下記の様なコードも載っていた。

private boolean getIsArtInUse() {

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

もう1つのやり方としては,リフレクションを使って内部でロードしているsoファイルを見に行くやり方があるらしい。

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

DalvikとARTとART debg buildという3つの状態が取得できるのは面白いが,ART debg buildが何なのか分からないのとリフレクションを使っているので柔軟性は低い。

System.getProperty("java.vm.version")した値が2.0.0以上かを判定する方法がシンプルで良さそう。