読者です 読者をやめる 読者になる 読者になる

Happy My Life

日常とか技術とか

NDKの後継開発キット-GDK

Android

Android Advent Calendar 2012 12月11日(表)のエントリーです。裏は、@currycatgtiさんです。おいらのエントリーでネタを期待している人はいないでしょうから技術話で。

ここではAndroid NDKの後継開発ツールとして開発が進められているらしいGDK(もちろん未発表)について、推測も交えていろいろ話していこうかと。まあ、正式な発表があったわけでもなく、推測も織り交ぜて書いてあるので、話半分で読むのが丁度良いかなと。

Android4.1で出現したGDKフォルダ

事の発端は、AOSP(Androidの公開されているソースコード)のAndorid4.1から追加されたGDKフォルダを調査したことから。AOSPに含まれている「なんとかDK」フォルダはAOSPにいくつかあるが、これらフォルダはすべて開発キットが格納されている。AOSPのトップにあるフォルダは、それぞれ、SDK=Software Development Kit、NDK=Native Development Kit、PDK=Porting Development Kitとなっている。

そんな流れで「このGDKフォルダも新しい開発キットだろうなあ」とは予想できたけど、このフォルダ名だけじゃ何かよくわからず、ドキュメントも一切ない。なので、GDKフォルダ内のソースコードなどを読んで調べてみた。たどり着いた結果が、「Android NDKのtoolchainをLLVM/clangに置き換えた開発キット」だとわかってきた。

ちなみに、このGDKという名称は「General Development Kit」(汎用開発キット)の略称かなーと予想している(最初見たときはGame Development Kitかと思った)

LLVM/clang

GDKに触れる前に、そのコア技術であるLLVM(Low Level Virtual Machine)とclangについて解説していく。LLVMは、コンパイル時、リンク時、実行時を考慮して設計されたコンパイラ基盤。DalvikVMなどと違って実行環境だけではなく生成されるコード生成の支援もLLVMは行う。で、LLVMとDalvikVMの一番の違いは、プログラミング言語、CPUアーキテクチャから独立している点がある(JavaVMやDalvikVMは、JavaScalaなどのJavaVMで動作するコードが前提となっている)

そして、LLVM上でソフトウェアを動作させるには以下のソフトウェアが必要となる。

  1. 特定のプログラミング言語からLLVMへ中間コードを渡すフロントエンド
  2. LLVMから特定CPU(ARM、x86など)で実行するためのバックエンド

RetargetableCompiler

引用元www.aosabook.org/en/llvm.html

clangは、さっきのうち(1)に相当するLLVM向けのC,C++,Objective-C向けのコンパイラのフロントエンドのこと(gccと互換性がある)

つまりclangを利用することで、既存のC,C++のコードがLLVMで動作させることができる。ちなみにLLVMのバックエンド側は、ARM、x86MIPSなどAndroidが動作しているCPUアーキテクチャには既に対応している。

もっと詳しいことを知りたい方はWikipediaや本家サイトのllvm.orgを見てもらったほうが早いかと。

GDKで開発するメリット

GDKを利用することでAndroid NDKにはなかったメリットがいくつかある。

  • CPUアーキテクチャの区別が不要
  • コードがシンプルになる
  • アプリが高速動作させやすくなる(はず)

これらを順に解説していく。

CPUアーキテクチャの区別が不要

これはLLVMの一番のメリットである。Android NDKを利用した場合は、生成されたファイルが直接CPU上で動作するものであるため、ARM,x86,MIPSなどのCPU上で直接動作するファイルとして生成される。つまり、ARM向け、x86向け、MIPS向けのファイルを用意することになり、その結果、ARM、x86MIPSといったCPUアーキテクチャに対応させた場合は、実行ファイルそのものが大きくなってしまう。

しかしGDK(LLVM)を使って出力したファイルは、CPUアーキテクチャとは独立している(実行時にCPUアーキテクチャに合わせたコードに変換される)ため、CPUに関係なくファイルが1つだけとなる。

app_ndk_gdk

コードがシンプルになる

これは、gdk/samples以下にあるサンプルコードを読むとよく分かる。

Android NDKを利用した場合、JavaからCのコードを呼び出す際には、JNI(Java Native Interface)を利用する必要がある。JNIは全般的に「JavaVMの仕様にC/C++のコードが歩み寄れ」という仕様になっているので、JNIを使ったC/C++のコードは、Javaの規約に従った書き方をする必要がある。

例えば2つの値を加算するコードをJNI & C言語で作成すると、以下のようなコードとなる。

#include 

jint
Java_com_example_HelloLLVM_addValues( JNIEnv* env,
                                      jobject thiz, 
                                      jint a, jint b )
{
    return a + b;
}

このコードには、Javaの仕様に歩み寄るために

  • 変数宣言は、JNIで定義された型(jint型など)を指定する
  • Javaから直接コールされる関数の名前は、クラスの完全修飾名(FQCN)とメソッド名を含ませる
  • 関数の引数には、JNIEnv型などJNI特有の引数を最初に定義する

といった点が変更がされている。正直言って読みにくい…。

しかし、GDKでは、先のコードが以下のコードとなる。

int addValues(int a, int b){
    return a+b;
}

見ての通り、素直にC言語で書かれたコードそのままで、Javaから呼び出せる。

また、呼び出す側のJavaコードは、NDK、GDKともに同じ書き方になる。

public class HelloLLVM extends Activity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        TextView  tv = new TextView(this);
        int val = addValues(1,2);
        tv.setText("HelloLLVM! : val="+val);
        setContentView(tv);
    }

    public native int addValues(int a, int b); // ← nativeをつける

    static {
        System.loadLibrary("hello_llvm");  // ← モジュールをロードしてる
    }
}

これらを見てわかる通り、GDKを利用することで「JavaVMの仕様をC/C++での変則的な実装によってカバーする」から「JavaのコードとC/C++のコードを対等に扱う」というコーディングに変化する。これは読みやすく、理解しやすい。そしてコードのtypoなどでハマりにくくなる。

アプリが高速動作しやすくなる(はず)

このGDKを利用したメリットは、コードの見た目だけではなくアプリの動作にも影響を与える。おそらく、Android NDKで作成した場合に比べて実行パフォーマンスの改善も予想される。これは、LLVM自身にJITやAOTが搭載されている点も理由の一つなのだが、もうひとつ、アプリケーション内部の処理の流れがNDKとGDKでは変化するためというのもある。

まずJavaからJNIを通してC/C++のコードを呼び出した場合は、JavaからCのコードを呼び出す場合は、必ずJNIを通す必要がある。そしてJNIの内部では、様々な変換が自動的に行われる場合も多く、変数の型によってはオーバーヘッドが大きくなる場合がある(例えば配列など)

そのため、JNIを利用したソフトウェアで実行パフォーマンスを向上させたい場合は、JNIの内部での動きを熟知した上で、JNI内部で処理負荷がかかりそうな処理を想定して回避することもある。

jni01

GDKを利用した場合は、JNIによる影響は小さくなる。実装はJava向けのリフレクションAPIを通してLLVMのコードにアクセスすると予想している(既にLLVMを利用しているRenderScriptの実装がそうだから) これによって、JNIよりは実行パフォーマンスが向上するのではないかと。まあ、実際のところはベンチマークを取ってみないと分からないが。

gdk01

GDKがアプリケーション開発で利用できるのはいつ?

当分先ではないかと予想している。

というのは、Android NDKがAndroid自身の開発で十分使われた(ある程度枯れた状態にした)後にアプリケーション開発用として公開された過去があるので、GDKに関しても、まずはAndroid自身の開発でGDKを利用したコードにある程度置き換えられた後に正式に公開となるのではないかと。まあ、開発キットの大きな転換点なのでアプリケーション開発向けに正式リリース前にはGoogle I/Oで言及があるはず。もちろん、GDKがボツとなる可能性も無きにしもあらず。

Androidの開発環境は日々進化していますねー。ということで今回の話は終わり。