AND OR  

このページではAndroidアプリ開発関連のメモを書いています。

エミュレータ関連

エミュレータ操作のためのショートカットキー

Emulated Device KeyKeyboard Key
HomeHOME (Mac: fn + left key)
Menu (left softkey)F2 or Page-up button
Star (right softkey)Shift-F2 or Page Down
BackESC
Call/dial buttonF3
Hangup/end call buttonF4
SearchF5
Power buttonF7
Audio volume up buttonKEYPAD_PLUS, Ctrl-F5
Audio volume down buttonKEYPAD_MINUS, Ctrl-F6
Camera buttonCtrl-KEYPAD_5, Ctrl-F3
Switch to previous layout orientation (for example, portrait, landscape)KEYPAD_7, Ctrl-F11
Switch to next layout orientation (for example, portrait, landscape)KEYPAD_9, Ctrl-F12
Toggle cell networking on/offF8
Toggle code profilingF9 (only with -trace startup option)
Toggle fullscreen modeAlt-Enter
Toggle trackball modeF6
Enter trackball mode temporarily (while key is pressed)Delete
DPad left/up/right/downKEYPAD_4/8/6/2
DPad center clickKEYPAD_5
Onion alpha increase/decreaseKEYPAD_MULTIPLY(*) / KEYPAD_DIVIDE(/)

ネットワークアドレス

10.0.2.1Router/gateway address
10.0.2.2Special alias to your host loopback interface (i.e., 127.0.0.1 on your development machine)
10.0.2.3First DNS server
10.0.2.4 / 10.0.2.5 / 10.0.2.6Optional second, third and fourth DNS server (if any)
10.0.2.15The emulated device's own network/ethernet interface
127.0.0.1The emulated device's own loopback interface

エミュレータを動作させている開発環境とネットワーク通信を行いたい場合は上記の通り''10.0.2.2''を参照すれば良いです。

NDK(JNI)関連

JNIHelp

JNIで呼び出される関数名はパッケージ名、クラス名、メソッド名を連結した名前を付ける必要があり可読性を著しく損なう原因となっています。そこで、JNIから呼び出される関数をパッケージ単位で登録できる ''jniRegisterNativeMethods'' 関数を使うと便利です(以下抜粋)。

最適化

コンパイル時に指定できる最適化関連のオプション

$ arm-linux-androideabi-g++  --target-help
The following options are target specific:
 -mabi=                      Specify an ABI
 -mabort-on-noreturn         Generate a call to abort if a noreturn function
                             returns
 -mandroid                   Generate code for the Android platform.
 -mapcs-float                Pass FP arguments in FP registers
 -mapcs-frame                Generate APCS conformant stack frames
 -mapcs-reentrant            Generate re-entrant, PIC code
 -march=                     Specify the name of the target architecture
 -mbig-endian                Assume target CPU is configured as big endian
 -mbionic                    Use Bionic C library
 -mcallee-super-interworking Thumb: Assume non-static functions may be called
                             from ARM code
 -mcaller-super-interworking Thumb: Assume function pointers may go to non-
                             Thumb aware code
 -mcirrus-fix-invalid-insns  Cirrus: Place NOPs to avoid invalid instruction
                             combinations
 -mcpu=                      Specify the name of the target CPU
 -mfix-cortex-m3-ldrd        Avoid overlapping destination and address
                             registers on LDRD instructions that may trigger
                             Cortex-M3 errata.
 -mfloat-abi=                Specify if floating point hardware should be used
 -mfp16-format=              Specify the __fp16 floating-point format
 -mfpu=                      Specify the name of the target floating point
                             hardware/format
 -mglibc                     Use GNU C library
 -mhard-float                Alias for -mfloat-abi=hard
 -mlittle-endian             Assume target CPU is configured as little endian
 -mlong-calls                Generate call insns as indirect calls, if
                             necessary
 -mpic-register=             Specify the register to be used for PIC addressing
 -mpoke-function-name        Store function names in object code
 -msched-prolog              Permit scheduling of a function's prologue
                             sequence
 -msingle-pic-base           Do not load the PIC register in function prologues
 -msoft-float                Alias for -mfloat-abi=soft
 -mstructure-size-boundary=  Specify the minimum bit alignment of structures
 -mthumb                     Compile for the Thumb not the ARM
 -mthumb-interwork           Support calls between Thumb and ARM instruction
                             sets
 -mtp=                       Specify how to access the thread pointer
 -mtpcs-frame                Thumb: Generate (non-leaf) stack frames even if
                             not needed
 -mtpcs-leaf-frame           Thumb: Generate (leaf) stack frames even if not
                             needed
 -mtune=                     Tune code for the given processor
 -muclibc                    Use uClibc C library
 -mvectorize-with-neon-quad  Use Neon quad-word (rather than double-word)
                             registers for vectorization
 -mword-relocations          Only generate absolute relocations on word sized
                             values.
 -mwords-little-endian       Assume big endian bytes, little endian words

 Known ARM CPUs (for use with the -mcpu= and -mtune= options):
   cortex-m0, cortex-m1, cortex-m3, cortex-m4, cortex-r4f, cortex-r4,
   cortex-a15, cortex-a9, cortex-a8, cortex-a5, arm1156t2f-s, arm1156t2-s,
   mpcore, mpcorenovfp, arm1176jzf-s, arm1176jz-s, arm1136jf-s, arm1136j-s,
   arm1026ej-s, arm926ej-s, fa726te, fmp626, fa626te, fa606te, iwmmxt2, iwmmxt,
   xscale, arm1022e, arm1020e, arm10e, arm968e-s, arm966e-s, arm946e-s, arm9e,
   arm1020t, arm10tdmi, ep9312, arm940t, arm922t, arm920t, arm920, arm9tdmi,
   arm9, arm740t, arm720t, arm710t, arm7tdmi-s, arm7tdmi, fa626, fa526,
   strongarm1110, strongarm1100, strongarm110, strongarm, arm810, arm8,
   arm7dmi, arm7dm, arm7m, arm7500fe, arm7500, arm7100, arm710c, arm720,
   arm710, arm700i, arm700, arm70, arm7di, arm7d, arm7, arm620, arm610, arm600,
   arm60, arm6, arm3, arm250, arm2

 Known ARM architectures (for use with the -march= option):
   iwmmxt2, iwmmxt, ep9312, armv7e-m, armv7-m, armv7-r, armv7-a, armv7,
   armv6-m, armv6t2, armv6zk, armv6z, armv6k, armv6j, armv6, armv5te, armv5e,
   armv5t, armv5, armv4t, armv4, armv3m, armv3, armv2a, armv2
Assembler options
=================

Use "-Wa,OPTION" to pass "OPTION" to the assembler.

ARM-specific assembler options:
 -k                      generate PIC code
 -mthumb                 assemble Thumb code
 -mthumb-interwork       support ARM/Thumb interworking
 -mapcs-32               code uses 32-bit program counter
 -mapcs-26               code uses 26-bit program counter
 -mapcs-float            floating point args are in fp regs
 -mapcs-reentrant        re-entrant code
 -matpcs                 code is ATPCS conformant
 -mbig-endian            assemble for big-endian
 -mlittle-endian         assemble for little-endian
 -mapcs-frame            use frame pointer
 -mapcs-stack-check      use stack size checking
 -mno-warn-deprecated    do not warn on use of deprecated feature
 -mcpu=<cpu name>        assemble for CPU <cpu name>
 -march=<arch name>      assemble for architecture <arch name>
 -mfpu=<fpu name>        assemble for FPU architecture <fpu name>
 -mfloat-abi=<abi>       assemble for floating point ABI <abi>
 -meabi=<ver>            assemble for eabi version <ver>
 -mimplicit-it=<mode>    controls implicit insertion of IT instructions
 -EB                     assemble code for a big-endian cpu
 -EL                     assemble code for a little-endian cpu
 --fix-v4bx              Allow BX in ARMv4 code

FPU(浮動小数点演算ユニット)関連のオプション

VFP/NEON関連のオプションです。

  • ''ハードウェアFPUを利用''
    mfloat-abi オプションで指定します。
    -mfloat-abi=softfp
    を指定してコンパイルすると
    .fpu vfp
    
    ...
    fmsr s15, r3 @int
    fsitos s0, s15
    このようにVFP(Vector Floating-Point, ARMv6)命令を使います。
  • ''FPUの指定''
    mfpu オプションで利用するFPUを指定できます。
    -mfloat-abi=softfp -mfpu=vfpv3-d16
    このようにFPU名を明示します。
    .fpu vfpv3-d16
     
    ...
    fmsr s15, r3 @int
    fsitos s0, s15
  • ''NEONを利用したベクトル化''
    ベクトル化のオプションを追加指定します。
    -mfloat-abi=softfp -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad
    mfpu オプションでNEONを指定し、ftree-vectorize オプションでループのベクトル化を、mvectorize-with-neon-quad オプションでQレジスタ(128bitレジスタ)を利用するように指定します。
    .fpu neon
    
    ...
    vmla.i32  q8, q10, q9
    vst1.32 {q8}, [ip]!
    これでNEON(ARMv7)命令を使うようになります。-mfloat-abi=softfp は値の名前で勘違いしそうですが、浮動小数点演算をエミュレーション実行しているわけではなくハードウェア(FPU)で演算してくれます。このオプションはABI(Application Binary Interface)を指定するもので、関数呼び出し時のレジスタの使われ方が異なります。FPUがない(soft)場合との互換性が取れるように、ハードウェアFPUで関数によって演算が実行される場合でも浮動小数点引数は整数レジスタ(r)に渡されます。
    参考: ハードウェア VFP 命令の使用

数学演算関連のオプション

  • ffast-math オプション
    これはAndroid特有のものではなくGCC一般の最適化オプションです。このオプションを指定すると次のオプションを一度に指定したことになります。
    -fno-math-errno
    -funsafe-math-optimizations
    -fno-trapping-math
    -ffinite-math-only
    -fno-signaling-nans
    実行速度最適化のためANSIやIEEEの規則や仕様を破ることをGCCに許します。例えば、sqrt 関数の引数が負にならないと仮定したりとか。結果として浮動小数点演算の精度が変わってしまうような最適化でも行うようになります。精度を重視する場合は指定しないようにしましょう。O3オプションを併せて指定されることが多いです。

ndk-buildコマンド

ndk-buildをコマンドラインから実行する際にコンパイルオプションなどを標準出力で確認したい場合は

$ ndk-build V=1

のように Vオプション を指定すれば確認できます。

開発での注意点、SDKバグ関連

XMLパーサー

Android 4.0 (Ice Cream Sandwich) から''XmlPullParser''のコア部分が変更となったため(バグの多いExpatPullParserが削除されKXmlParserに統一)、Android 3.2以前のプロジェクトで動作していたXMLを扱うプログラムが4.0以降では動作しなくなる可能性があります。

参考: Watch out for XmlPullParser.nextText()

画像処理/カメラ関連

画像処理を行うAndroidアプリ開発はメモリとの戦いです。とにかく OutOfMemory エラーが多発します。。

  • android.graphics.BitmapFactory 画像のデコードに合計32KBしか使えない模様。ただし、tempStorage の方は任意に指定できる(?
  • カメラデバイスオープン時の注意点
    カメラデバイスを開くときに(android.hardware.Camera#open)、API Level 11(Android 3.0)未満ではカメラ処理の種類を明示的に指定(android.view.SurfaceHolder#setType)しておかないとアプリが落ちてしまいます。

SURFACE_TYPE_PUSH_BUFFERS を指定すると「バッファに入れられた画像を画面表示する(カメラプレビュー)」という処理になります。

OpenCV for Android

OpenCV for Androidについては別ページに。

Androidソースコードリーディング

まだ殴り書きのメモ段階です、コードリーディングを進めながら整理していきます

Androidのソースコードリーディングを進めています。
Welcome to Android

  • 構成 platform
    bionic         glibc互換 Cライブラリ
    bootable       ブート関連
    build          ビルドツール
    cts            互換性確認ツール
    dalvik         仮想マシン(DalvikVM)
    development    開発ツール(エミュレータとか)
    device         デバイス関連ファイル
    external       外部で開発されたソフトなど
    frameworks     Android フレームワーク
    hardware       ハードウェア制御ライブラリ
    ndk            Native Development Kit
    packages       標準インストールアプリ
    prebuilt       ビルドツール(ビルド済)
    sdk            Android SDK
    system         デバイスドライバのソース
  • 名前の由来
    「GoogleのDan Bornsteinが自作の仮想マシンに付けたDalvikという名前は、祖先がむかし住んでいたアイスランドの漁村の名に由来している。」 とのこと。
  • きっかけ
    主にNDK(JNI)を用いた開発中、スタックトレースに見慣れない単語(Zygoteなど)が頻発するため中身を知りたいと思ったから。
    at com.android.internal.os.ZygoteInit.main
    at dalvik.system.NativeStart.main
    とか、あとは画像処理アプリを作っているときはよくメモリが足りなくてつまづくことが多いです。
    ERROR/dalvikvm-heap(187): 2457600-byte external allocation too large for this process.
    ERROR/(187): VM won't let us allocate 2457600 bytes…
    ERROR/AndroidRuntime(187): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
    などのエラー

Zygote

Androidアプリケーションはマルチタスクで実行することができますが、ここではその仕組みを調べます。

Androidを起動すると、まずZygote(ザイゴウト)というプロセスが立ち上がります(いわゆるinitプロセス)。このZygoteはすべてのAndroidアプリケーションの親プロセスになっています。アプリケーションを起動するには下図のようにZygoteから fork して子プロセスを作ります。

zygote.png

Zygoteは多くのライブラリを含んでいるため起動には時間がかかりますが、その後の子プロセス生成は非常に高速に行うことができます。また、子プロセスは親プロセスとメモリ領域を共有するためメモリ消費量も節約できます。

ここで、Zygoteプロセス起動からのフローを整理します。

  • init.rc
    service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    initでサービスを起動します。エントリーポイントは以下のようになっています。
  • frameworks/base/cmds/app_process/app_main.cpp Zygoteを起動する AppRuntime#start の中身は以下のようになっています。JNI経由でJava側の static void main(String[] args) を呼び出しています。
  • frameworks/base/core/jni/AndroidRuntime.cpp 続きは調べつつ書きます。

ashmem (Anonymouse Shared memory Subsystem)

Androidにおける共有メモリ用デバイスで、Linuxカーネルに組み込まれています。ashmem からメモリを確保するには /dev/ashmem をオープンして mmap を使います。mmap を行うと ashmem デバイスを通じて最終的に tmpfs からデータを取得します。

ashmem.png

ashmem API

ashmemの機能は libcutils.so に含まれています。

  • system/core/include/cutils/ashmem.h
    ashmemの提供するAPIは以下の5つ。内部では ioctl でデバイスドライバに情報を渡しているだけ。 共有メモリ領域生成には以下のように ashmem_create_region で返ってくるファイルディスクリプタを mmap に渡します。 他のプロセスから共有メモリを使うには binder (Android独自のデバイスドライバ)経由で使うようです。要調査。

Android SDKではJavaから ashmem を利用するために、''android.os.MemoryFile'' クラスが提供されています。アプリケーションキャッシュなどに利用すると良いです。また、 ashmem はグラフィックメモリのバッファなどでも利用されているとのことです。

binder

プロセス間通信
atodekaku

bionic

bionic はAndroidのCライブラリです。 glibc は組み込み向けには大きすぎるため BSD libc をAndroid向けに改良したライブラリが用いられています。

dlmalloc

(ここではv2.8.6を対象としています)
bionic にはDoug Leaという方が作った通称 dlmalloc と呼ばれるメモリ確保機構が含まれています。dlmalloc は速度と空間効率を両立したアルゴリズムを採用しており、フラグメンテーションの問題を最小限にします。スマートフォンデバイスのような組み込み環境に適しているとのことです。

  • platform/bionic/libc/upstream-dlmalloc 以下のようにメモリ確保関数を #define して使うことができます。 まず create_mspace() で指定したサイズ(capacity, 0ならデフォルトの粒度)の領域をあらかじめ確保し、そこから必要なサイズの領域を mspace_malloc() で取得します。デフォルトで確保される領域については以下の通りです。 フリーリストは''循環双方向リンクリスト''あるいは''トライ木(trie)''(内部では bin と呼ばれている)で管理されています。チャンク(リストのノード)のサイズは、フリーチャンクの最後の4バイトにも記録されています。これを活用して隣接するフリーチャンクを結合してメモリの断片化を避けています。各binはサイズ別にチャンクを管理しており、求めるサイズのチャンクをすばやく探せるようになっています。チャンクを解放するとき、可能であれば隣り合うフリーチャンクと結合させます(断片化防止)。解放するチャンクの直前または直後に位置するチャンクがフリーであれば、そのフリーチャンクはbinから外され、解放しようとしているチャンクと結合して適切なbinに配置されます。チャンクの構造は以下のようになっています。 実は glibc malloc は dlmalloc から派生したもの、歴史はとても古いのです。シンプルな仕組みなのに効率が良く、現在でも広く利用されています。詳細は本家サイトにて、図付きでわかりやすいです。
    A Memory Allocator

DEXファイルフォーマット

Androidアプリは、それぞれが独自のLinuxプロセス内で実行され、それらのプロセスが個々にDalvik VMのインスタンスをホストしています。Dalvikは、デバイスが複数の仮想マシンを同時に効率よく実行できるように設計されています。効率が良い理由は、主にDalvikがDEX(Dalvik Executable)ベースのファイルを実行するからです。DEXはメモリの占有を最小限に抑えるよう最適化されたフォーマットです。
.dex — Dalvik Executable Format

データ型

DEXファイルフォーマットで扱えるデータ型は以下の11種類です。また、バイトオーダーはリトルエンディアンとなっています。

NameDescription
byte8ビット符号付き整数
ubyte8ビット符号無し整数
short16ビット符号付き整数
ushort16ビット符号無し整数
int32ビット符号付き整数
uint32ビット符号無し整数
long64ビット符号付き整数
ulong64ビット符号無し整数
sleb128符号付きLEB128 (後述)
uleb128符号無しLEB128 (後述)
uleb128p1符号無しLEB128 + 1

LEB128(Little-Endian Base 128)では可変長整数を扱います。これは DWARF3 フォーマットを参考にしたもので以下のような構造(2バイトの場合)になっています。

| Bitwise diagram of a two-byte LEB128 value                                                                  |
| First byte                                         | Second byte                                            |
| 1 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 0 | bit13 | bit12 | bit11 | bit10 | bit9 | bit8 | bit7 |

各バイトの7ビットがデータで最上位ビットを使ってデータの終端を示しています。上の例だと2バイト目の最上位ビットが落ちているため、ここでこのデータは終了ということになります。値の大きさによってデータ長も変化するので、小さな整数値だとデータ長も短くなります。LEB128のような可変長整数の扱い方は特に珍しくはなく、バイナリネットワークプロトコルだとよく見かけます(thriftとか)。

ファイルレイアウト

内部のセクションは以下のようになっています。

headerヘッダ
string_ids文字列(UTF-16)を格納
type_idsデータ型を格納
proto_idsメソッドのプロトタイプ情報(戻り値の型とか)を格納
field_idsクラスのフィールド情報を格納
method_idsクラスのメソッド情報を格納
class_defsクラス情報(継承関係とか)を格納
dataデータを格納、アノテーション情報も含む
link_data静的リンクされたファイルのデータを格納

型のシグネチャはJNIを利用するときにもよく目にします。以下にシグネチャと型の対応を載せます。

Vvoid; only valid for return types
Zboolean
Bbyte
Sshort
Cchar
Iint
Jlong
Ffloat
Ddouble
Lfully/qualified/Name;the class fully.qualified.Name
[descriptorarray of descriptor, usable recursively for arrays-of-arrays, though it is invalid to have more than 255 dimensions.

最後の配列型は例えば "[I" ならint型配列、"[D" ならdouble型配列を表します。

''Dalvik VMはJavaバイトコードを実行しません。''コンパイルされたJavaのクラスファイル(.class)をDEXファイル(.dex)に変換して生成されたバイトコードが実行されます。

  • ''dx''
    classファイルをdexファイルに変換できるコマンド。Android SDKに入っています。
    $ dx
    usage:
     dx --dex [--debug] [--verbose] [--positions=<style>] [--no-locals]
     [--no-optimize] [--statistics] [--[no-]optimize-list=<file>] [--no-strict]
     [--keep-classes] [--output=<file>] [--dump-to=<file>] [--dump-width=<n>]
     [--dump-method=<name>[*]] [--verbose-dump] [--no-files] [--core-library]
     [--num-threads=<n>] [--incremental] [--force-jumbo]
     [<file>.class | <file>.{zip,jar,apk} | <directory>] ...
       Convert a set of classfiles into a dex file, optionally embedded in a
       jar/zip. Output name must end with one of: .dex .jar .zip .apk. Positions
       options: none, important, lines.
     dx --annotool --annotation=<class> [--element=<element types>]
     [--print=<print types>]
     dx --dump [--debug] [--strict] [--bytes] [--optimize]
     [--basic-blocks | --rop-blocks | --ssa-blocks | --dot] [--ssa-step=<step>]
     [--width=<n>] [<file>.class | <file>.txt] ...
       Dump classfiles, or transformations thereof, in a human-oriented format.
     dx --find-usages <file.dex> <declaring type> <member>
       Find references and declarations to a field or method.
       declaring type: a class name in internal form, like Ljava/lang/Object;
       member: a field or method name, like hashCode
     dx -J<option> ... <arguments, in one of the above forms>
       Pass VM-specific options to the virtual machine that runs dx.
     dx --version
       Print the version of this tool (1.7).
     dx --help
       Print this message.
    実際にAndroidプロジェクトディレクトリで以下のようにコマンドを実行してみます。--output オプションで出力ファイル名を指定し、その後に変換対象のclassファイルを含んだディレクトリを指定します。
    $ dx --dex --verbose --output=classes.dex bin/classes
    ignored resource bin/classes/./.DS_Store
    ignored resource bin/classes/./com/.DS_Store
    ignored resource bin/classes/./com/example/.DS_Store
    processing bin/classes/./com/example/hellojni/BuildConfig.class...
    processing bin/classes/./com/example/hellojni/MainActivity$1.class...
    processing bin/classes/./com/example/hellojni/MainActivity$2.class...
    processing bin/classes/./com/example/hellojni/MainActivity.class...
    processing bin/classes/./com/example/hellojni/R$attr.class...
    processing bin/classes/./com/example/hellojni/R$drawable.class...
    processing bin/classes/./com/example/hellojni/R$id.class...
    processing bin/classes/./com/example/hellojni/R$layout.class...
    processing bin/classes/./com/example/hellojni/R$menu.class...
    processing bin/classes/./com/example/hellojni/R$string.class...
    processing bin/classes/./com/example/hellojni/R$style.class...
    processing bin/classes/./com/example/hellojni/R.class...
    カレントディレクトリに classes.dex ファイルが生成されていたら成功です。このdexファイルは後述の dexdump コマンドで中身を覗くことができます。

Dalvik VMバイトコード

Dalvik VMは''レジスタマシン''として実装されています(JVMはスタックマシン)。Dalvik VMバイトコードの特徴を整理します。

  • オペコードは8ビットで、これに必要な分だけオペランドが追加される
  • 命令は16ビット単位でアライメントされる(16-bit code units)
  • 各命令毎に指定できるレジスタ番号の異なり、4/8/16ビットの範囲の番号で指定する

Dalvik VMで実行されるバイトコードについて、以下の公式リファレンスを見ながら dexdump コマンドを使って整理していきます。
Bytecode for the Dalvik VM

  • ''dexdump''
    Unix系OSでELFバイナリを読むときに使う objdump のようなもの。 前述の dx コマンドと同様にこれもAndroid SDKに入っています。
    $ dexdump
    dexdump: no file specified
    Copyright (C) 2007 The Android Open Source Project
    
    dexdump: [-c] [-d] [-f] [-h] [-i] [-l layout] [-m] [-t tempfile] dexfile...
    
     -c : verify checksum and exit
     -d : disassemble code sections
     -f : display summary information from file header
     -h : display file header details
     -i : ignore checksum failures
     -l : output layout, either 'plain' or 'xml'
     -m : dump register maps (and nothing else)
     -t : temp file name (defaults to /sdcard/dex-temp-*)
    以下のような簡単なJavaコードをコンパイルしてclassファイルを作り、それを dx コマンドでdexファイルに変換。 dexdump コマンドを使ってその中身を覗いてみます。

コードをディスアセンブルするには -d オプションを付けて実行します。

Helloworldクラスでは単純な演算命令しか使っていないのでバイトコードを読むのも楽だと思います。

/dalvik/vm/mterp/out 以下にアーキテクチャ毎のバイトコードインタプリタのコードが入っています。

$ ls dalvik/vm/mterp
InterpAsm-allstubs.S     InterpAsm-armv7-a-neon.S  InterpAsm-x86.S          InterpC-armv5te.cpp       InterpC-mips.cpp
InterpAsm-armv5te-vfp.S  InterpAsm-armv7-a.S       InterpC-allstubs.cpp     InterpC-armv7-a-neon.cpp  InterpC-portable.cpp
InterpAsm-armv5te.S      InterpAsm-mips.S          InterpC-armv5te-vfp.cpp  InterpC-armv7-a.cpp       InterpC-x86.cpp

ガベージコレクション

Dalvik VMのGCには''Mark & Sweep(ビットマップマーキング)''アルゴリズムを採用しています。通常のMark & Sweep方式はLinuxのCopy On Write(データの書き換えが発生した時にコピーを行う)と相性が悪いです。Mark & Sweepは生きているオブジェクトのヘッダにマークビットを立てますが、これを行うと本来は必要のないコピーが行われてしまうからです。なので、Dalvik VMではビットマップマーキングという手法を併用してこの問題に対処しています。この手法は各オブジェクトのマークビットだけを集めたテーブル(ビットマップテーブル)を用意し、オブジェクトとは別の場所で管理する手法です。

  • dalvik/vm/alloc
    $ ls
    Alloc.cpp      Copying.cpp   DlMalloc.h      HeapBitmap.h         HeapInternal.h  MarkSweep.h  Visit.cpp
    Alloc.h        DdmHeap.cpp   Heap.cpp        HeapBitmapInlines.h  HeapSource.cpp  TEST/        Visit.h
    CardTable.cpp  DdmHeap.h     Heap.h          HeapDebug.cpp        HeapSource.h    Verify.cpp   VisitInlines.h
    CardTable.h    DlMalloc.cpp  HeapBitmap.cpp  HeapDebug.h          MarkSweep.cpp   Verify.h     WriteBarrier.h
    $ du -sh *.cpp
    12K     Alloc.cpp
    16K     CardTable.cpp
    72K     Copying.cpp
    16K     DdmHeap.cpp
    4.0K    DlMalloc.cpp
    24K     Heap.cpp
    8.0K    HeapBitmap.cpp
    4.0K    HeapDebug.cpp
    40K     HeapSource.cpp
    28K     MarkSweep.cpp
    4.0K    Verify.cpp
    12K     Visit.cpp

Dalvik VMのヒープ

Dalvik VMのオブジェクトは専用のヒープに保持されます。これには2種類あり、1つは前述の Zygote 用のヒープ、もう1つはAndroidアプリケーションで使用するヒープです。ヒープの中身は以下のようになっています。

  • dalvik/vm/alloc/HeapSource.cpp 前述の dlmalloc の項で紹介した mspace をメンバとして持っています。オブジェクトはこの中にアロケーションされます。
  • dalvik/vm/alloc/HeapBitmap.h
    マーキングで用いるビットマップは以下のように定義されています。実態は unsigned long の配列のようです。 処理の詳細については調べながら追記していきます。