android起動周りのノウハウ

2013年10月19日

チャンスラボ株式会社 水野善文
自己紹介
■水野善文
Chancelab株式会社 に 2000年に入社
組込業務経験 13年
-μITRON上でのドライバ開発
-メモリーカードドライバ開発
等々行ってきました。

android は、約3年間関わっています。
-1.5 Cupcake から 4.1.x/4.2.x Jelly Bean 迄
-USBドライバ開発がメインです。
→ Gadget/Host ドライバ、UsbService等々

Chance Lab. Corp.

2
会社紹介
■チャンスラボ株式会社
http://www.chancelab.jp/
1982年6月設立

コンピューターソフトウェアの開発および販売、
インターネットを利用した各種情報提供サービス業を展開
・OSSコンソーシアム(理事会員)

自社サービス
・http://chanceapp.net/

・http://github.com/chancelab/columbus

Chance Lab. Corp.

3
講習の概要と目的
本日は、androidの起動シーケンスを学んでいただき、
android platformに対する知識を深めていただくことを
目的としています。
OESFで今年の5月から始まる「androidプラットホーム技
術者認定試験ベーシック」に向けた勉強の一環としていただ
いても良いかと思います。
http://www.oesf.jp/modules/training/index.php?content_id=2

Chance Lab. Corp.

4
アジェンダ
■androidのplatform概要
• レイヤー構成
• コード取得
• ビルド方法
• 解析ツールの紹介

■androidのinit
・initシーケンスの流れ
・android init処理について

・init.rc(init.xxx.rc)について
・JAVA層(system_server)起動処理

Chance Lab. Corp.

5
androidのplatform概要

androidのplatform概要

Chance Lab. Corp.

6
androidのplatform概要 |

Chance Lab. Corp.

レイヤー構成

7
androidのplatform概要 |

Chance Lab. Corp.

レイヤー構成

8
androidのplatform概要 |

レイヤー構成

■Applications

一般ユーザが直接アクセスする層
androidアプリと呼ばれるものは、すべてこの層に属する。

全てのアプリケーションはJava
C/C++で書かれることもある。(NDK)

主要アプリケーションが付属
ホーム(待ち受け画面)、ブラウザ、連絡先(アドレス帳)、メー
ルなど。

Chance Lab. Corp.

9
androidのplatform概要 |

Chance Lab. Corp.

レイヤー構成

10
androidのplatform概要 |

レイヤー構成

■Application Framework

アプリケーションを管理している層
アプリケーションにAPIを提供し管理する。

フレームワークAPIにフルアクセスが可能
開発者はコアアプリケーションと同じようにフレームワークAPI
にフルアクセスが可能。
開発者がライブラリにアクセスする場合には、必ずフレームワー
クAPIを介する必要がある。

Chance Lab. Corp.

11
androidのplatform概要 |

Chance Lab. Corp.

レイヤー構成

12
androidのplatform概要 |

レイヤー構成

■Library

Application Frameworkに使用されるライブラリ群
グラフィック、マルチメディアコーディック、DBなどの様々なラ
イブラリを提供する。

様々なコンポーネントでC/C++ライブラリを利用
androidアプリは、フレームワークを介して、ライブラリにアクセ
スする。

Chance Lab. Corp.

13
androidのplatform概要 |

Chance Lab. Corp.

レイヤー構成

14
androidのplatform概要 |

レイヤー構成

■Android Runtime
コアライブラリとDalvikで構成される。

Core Libraries(コア ライブラリ)
Javaの大半のライブラリをサポートする。
android専用ライブラリ、各種サードパーティのライブラリも含む。

Dalvik Virtual Machine(Dalvik仮想マシン)
低メモリ向けに最適化された仮想マシン。

Chance Lab. Corp.

15
androidのplatform概要 |

Chance Lab. Corp.

レイヤー構成

16
androidのplatform概要 |

レイヤー構成

■HAL(Hardware Abstraction Layer)

ハードウェアとApplication Frameworkを結ぶ
ハードウェアの違いを吸収する役割をしている。

■Linux Kernel

androidはLinuxベース
セキュリティ、メモリ管理、プロセス管理、ネットワークスタッ
ク、ドライバモデルなどのコアシステムサービスを提供する。

Chance Lab. Corp.

17
androidのplatform概要 |

コードの取得

■Windows環境

【手順】
1.Cygwinのインストール(Git+curlのインストール)
2.Repoのインストール
3.Repoの初期化
4.ソースコードの取得

■Linux環境

【手順】
1.Git+curlのインストール
2.Repoのインストール
3.Repoの初期化
4.ソースコードの取得
Chance Lab. Corp.

18
androidのplatform概要 |

ビルド方法

■環境構築

必要なパッケージのインストール
$ sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev ¥
libc6-dev lib32ncurses5-dev ia32-libs x11proto-core-dev libx11-dev lib32readline5-dev ¥
lib32readline-gplv2-dev lib32z-dev libgl1-mesa-dev g++-multilib mingw32 tofrodos ¥
python-markdown libxml2-utils

Java(JDK)のインストール

※Java(JDK)1.6以上が必要です。

■ビルド
$ cd ~/【ソースコードをダウロードしたフォルダ】
$ make

makeコマンドに-jオプションをつけてスレッド数を指定することでビルドを高速にする
ことが可能です。
$ make -j 8

Chance Lab. Corp.

19
androidのplatform概要 |

必要なパッケージ

■必要なパッケージ

apt-get installに使用したパッケージの一覧
git-core

gnupg

flex

bison

gperf

build-essential

zip

curl

zlib1g-dev

libc6-dev

lib32ncurses5-dev

ia32-libs

x11proto-core-dev

libx11-dev

lib32readline5-dev

lib32readline-gplv2-dev

lib32z-dev

libgl1-mesa-dev

g++-multilib

mingw32

tofrodos

python-markdown

libxml2-utils

Chance Lab. Corp.

20
androidのplatform概要 |

解析ツールの紹介

解析ツールの紹介

■gnu global

■vim
■OpenGrok

Chance Lab. Corp.

21
androidのplatform概要 |

解析ツールの紹介

■gnu global

コード解析ツール
一般的にはタグツールと呼ばれる。

Ctagsより優秀。

対象の定義箇所と使用箇所の相互検索が可能
Linux, android等のコード検索に便利。
巨大なプロジェクトのコード検索に役立つ。

Chance Lab. Corp.

22
androidのplatform概要 |

解析ツールの紹介

■gnu global

Chance Lab. Corp.

23
androidのplatform概要 |

解析ツールの紹介

■vim

viの拡張版
CUIエディタviを拡張したエディタ。

globalやgitなどのプラグインが豊富
各種プラグインで、コード解析が楽に。

Chance Lab. Corp.

24
androidのplatform概要 |

解析ツールの紹介

■vim

Chance Lab. Corp.

25
androidのplatform概要 |

解析ツールの紹介

■OpenGrok

webソース閲覧ツール
CTAGSを利用し、javaで実装された検索機能付き閲覧ツール。

android検索ページ
OESFでは、OpenGrokを使用してandroidの検索ページを公開し
ている。

社内プロジェクトでも使用可能
JavaアプリケーションサーバとLAN環境だけで社内プロジェクト
で使用可能。

Chance Lab. Corp.

26
androidのplatform概要 |

解析ツールの紹介

■OpenGrok

Chance Lab. Corp.

27
androidのinit

androidのinit

Chance Lab. Corp.

28
androidのinit |

initシーケンスの流れ

■全体の流れ

Bootloader
メインRAMと特定の周辺機器の初期化
Kernelに渡すパラメータの設定

Kernel
Linuxカーネルと各デバイスの初期化

Android
Init.cとinit.rcを元にandroidシステムの初期化

Chance Lab. Corp.

29
androidのinit |

initシーケンスの流れ

■Bootloader

Bootloader

Kernel

Bootloaderとは
android端末の起動直後に動作しOS(LinuxKernel)
を読込んで起動するプログラム。

Bootloaderのinit
メインRAM、周辺機器の初期化を行う。
Kernelへ渡すためのブートパラメータの準備(メモ
リ上への配置)が完了したら、Kernelを起動する。

Android
Chance Lab. Corp.

30
androidのinit |

initシーケンスの流れ

■Kernel

Bootloader

Kernel

Android

Kernelとは
androidはOSとしてLinuxカーネルを採用している。

Linuxカーネルは、メモリーやプロセスの管理、ファ
イル・システム、セキュリティといった基本機能に加
え、各種ドライバを提供する。

Kernelのinit
Bootloaderから渡されブートパラメータを解析し、
KernelCore(割り込み管理、メモリ管理等)の初期
化、各ドライバの初期化を行う。
最後にandroidのinitプロセスを実行する。

Chance Lab. Corp.

31
androidのinit |

initシーケンスの流れ

■Android

Bootloader

Kernel

Androidのinit
initプロセスがinit.rcという設定ファイルを読込み、
初期化が実行される。
初期化が完了すると仮想マシン起動後、Android
Frameworkの各Serviceが起動し、ユーザーが操作
できる状態となる。

Android
Chance Lab. Corp.

32
androidのinit |

android init 処理について

■android init シーケンス
initは「ブート処理部」と「デーモン処理部」に大きく分類される。
int main(int argc, char **argv)
{
/* ブート処理部

*/

デーモン処理部

}
return 0;
}

Chance Lab. Corp.

起動時に一度だけ呼ばれる。
システムに必要なフォルダの生成、
init.rcの読込みと解析を行う。

for(;;) {
/*

ブート処理部

*/

また、実行するアクションの登録な
ども行う。

デーモン処理部
androidの電源が落ちるまで処理が
ループされる。アクションやサービ
スの実行とシステムの監視を行う。
33
androidのinit |

android init 処理について

■該当コード(system/core/init/init.c)

ブート処理部

android 4.2.0より抜粋

mkdir("/dev", 0755);
mkdir("/proc", 0755);
mkdir("/sys", 0755);

➊

mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
mount("proc", "/proc", "proc", 0, NULL);
mount("sysfs", "/sys", "sysfs", 0, NULL);
・・・・・中略・・・・・

INFO("reading config file¥n");
init_parse_config_file("/init.rc");
action_for_each_trigger("early-init", action_add_queue_tail);
queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
queue_builtin_action(keychord_init_action, "keychord_init");
queue_builtin_action(console_init_action, "console_init");

➋
➌

/* execute all the boot actions to get us started */
action_for_each_trigger("init", action_add_queue_tail);
・・・・・後略・・・・・

Chance Lab. Corp.

34
androidのinit |

android init 処理について

■該当コード(system/core/init/init.c)

ブート処理部

android 4.2.0より抜粋

mkdir("/dev", 0755);
mkdir("/proc", 0755);
mkdir("/sys", 0755);

➊

mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
mount("proc", "/proc", "proc", 0, NULL);
mount("sysfs", "/sys", "sysfs", 0, NULL);

・androidシステムに必要なフォルダの生成と初期化処理を行う。

Chance Lab. Corp.

35
androidのinit |

android init 処理について

■該当コード(system/core/init/init.c)

ブート処理部
INFO("reading config file¥n");

android 4.2.0より抜粋

➋

init_parse_config_file("/init.rc");

・init.rcを読込み、解析を行う。

Chance Lab. Corp.

36
androidのinit |

android init 処理について

■該当コード(system/core/init/init.c)

ブート処理部

android 4.2.0より抜粋

action_for_each_trigger("early-init", action_add_queue_tail);

➌

queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
queue_builtin_action(keychord_init_action, "keychord_init");
queue_builtin_action(console_init_action, "console_init");
/* execute all the boot actions to get us started */
action_for_each_trigger("init", action_add_queue_tail);
・・・・・後略・・・・・

・action_for_each_trigger関数は引数のアクションを実行するよう
に実行キューへの登録を行う。
・queue_builtin_action関数は引数を実行キューに追加を行う。

Chance Lab. Corp.

37
androidのinit |

android init 処理について

■該当コード(system/core/init/init.c)

デーモン処理部

android 4.2.0より抜粋

for(;;) {
int nr, i, timeout = -1;
execute_one_command();
restart_processes();
・・・・・中略・・・・・
for (i = 0; i < fd_count; i++) {
if (ufds[i].revents == POLLIN) {
if (ufds[i].fd == get_property_set_fd())
handle_property_set_fd();
else if (ufds[i].fd == get_keychord_fd())
handle_keychord();
else if (ufds[i].fd == get_signal_fd())
handle_signal();
}
}

➊
➋

}
return 0;
}
Chance Lab. Corp.

38
androidのinit |

android init 処理について

■該当コード(system/core/init/init.c)

デーモン処理部

android 4.2.0より抜粋

execute_one_command();
restart_processes();

➊

・execute_one_command関数
実行キューに登録されたアクションを実行する。
・restart_processes関数
init.rcで定義されているサービスを実行する。
ループ処理の中でアクションとサービスを順次実行する。

Chance Lab. Corp.

39
androidのinit |

android init 処理について

■該当コード(system/core/init/init.c)

デーモン処理部
for (i = 0; i < fd_count; i++) {
if (ufds[i].revents == POLLIN) {
if (ufds[i].fd == get_property_set_fd())
handle_property_set_fd();
else if (ufds[i].fd == get_keychord_fd())
handle_keychord();
else if (ufds[i].fd == get_signal_fd())
handle_signal();
}
}

android 4.2.0より抜粋

➋

・property_set_fd システムプロパティの書込み監視処理を行う。
・keychord_fd 複数のキー入力監視を行い、それに対応したサービ
スを実行する。
・signal_fd 子プロセスの終了の監視と、登録されているサービス情
報にともない再起動の監視を行う。
Chance Lab. Corp.

40
androidのinit |

android init 処理について

■init.rc(init.xxx.rc)について

種類
init.rc

init.usb.rc
init.${ro.hardware}.rc
init.trace.rc

記載内容
アクションとサービスの定義により各種設定が行われる。
init.rc内で importコマンドを用いて、他のrcファイルを取り込む。

ソースツリーのsystem/core/init/readme.txtに記載。

Chance Lab. Corp.

41
androidのinit |

android init 処理について

■init.rc(init.xxx.rc)について

詳細(アクション)
アクションにはトリガーが設定されており、トリガーに一致したイベ
ントが発生した場合にコマンドが順次実行されていく。

書式
on <トリガー>
<コマンド>
<コマンド>
<コマンド>

Chance Lab. Corp.

42
androidのinit |

android init 処理について

■init.rc(init.xxx.rc)について

主なトリガー一覧
名称

概要

boot

initスタート時に、最初のトリガーとなる

<name>=<value>

プロパティの<name>に<value>が設定されたときに
トリガーとなる

"device-added-<path>
device-removed-<path>"

デバイスノードに追加、削除されたときにトリガーとなる

service-exited-<name>

特定のサービスが終了したときにトリガーとなる

Early-init

Ueventd実行時のトリガーとなる

init

環境変数の設定、ディレクトリの設定時のトリガーとなる

Chance Lab. Corp.

43
androidのinit |

android init 処理について

■init.rc(init.xxx.rc)について

主なコマンド一覧
名称
exec <path> [ <argument> ]*
export <name> <value>
ifup <interface>
import <filename>
hostname <name>
chdir <directory>
chmod <octal-mode> <path>
chown <owner> <group> <path>
class_start <serviceclass>
class_stop <serviceclass>
domainname <name>
insmod <path>
mkdir <path>
mount <type> <device> <dir>
[<mountoption> ]*
setprop <name> <value>
setrlimit <resource> <cur> <max>
start <service>
stop <service>
symlink <target> <path>
sysclktz <mins_west_of_gmt>
trigger <event>
write <path> <string> [ <string> ]*
Chance Lab. Corp.

概要
プログラムをフォークして実行する
環境変数を設定する
ネットワークインターフェースを有効にする
init設定ファイルを今の設定に取り込む
ホスト名を設定する
カレントディレクトリを変更する
<path>のアクセス権限を設定する
<path>のオーナーとグループを変更する
まだ起動していない場合、指定したクラスの全てのサービスを起動する
起動中の場合、指定したクラスの全てのサービスを停止する
ドメイン名を設定する
<path>にあるモジュールをインストールする
<pathのディレクトリ>を作成する
<dir>と<device>ディレクトリのデバイスをマウントする
システムプロパティとして<name>に<value>を指定する
リソースのためにrlimitを指定する
そのサービスが起動していなかったら、サービスを起動する
サービスがまだ起動していたら、サービスを終了する
シンボリックリンクを作成する
システムクロックベースを設定する
イベントを起動(Trigger)させる
<path>にあるファイルを開き、文字列を書き込む

44
androidのinit |

android init 処理について

■init.rc(init.xxx.rc)について

アクション使用例1
on boot
export PATH /system/lib
mkdir /proc
mount proc proc /proc
ifup lo
hostname localhost

1.
2.
3.
4.
5.

環境変数PATHに/system/libを設定する。
/procディレクトリを作成する。
procデバイスを/procディレクトリにマウントする。
ネットワークインターフェースloを有効にする。
ホスト名をlocalhostに設定する。

Chance Lab. Corp.

45
androidのinit |

android init 処理について

■init.rc(init.xxx.rc)について

アクション使用例2
on property:vold.decrypt=trigger_restart_framework
class_start main
class_start late_start

vold.decryptプロパティにtrigger_restart_frameworkが設定
されたときに実行されるアクション。
1. mainクラスの全てのサービスを起動する。
2. Late_startクラスの全てのサービスを起動する。

Chance Lab. Corp.

46
androidのinit |

android init 処理について

■init.rc(init.xxx.rc)について

詳細(サービス)
サービスの実行条件が定義されている。

実行ファイルに対して引数の設定やオプションを付けることで起動条
件を定義することが出来る。

詳細(オプション)
サービス起動時の条件を指定することが出来る。

書式
service <名称> <パス名> [ <引数> ]*
<オプション>
<オプション>

Chance Lab. Corp.

47
androidのinit |

android init 処理について

■init.rc(init.xxx.rc)について

主なオプション一覧
名称
critical

概要
デバイスクリティカルなサービス。もし4分間に4回以上終了した
場合そのデバイスはリカバリーモードで再起動する

setenv <name> <value>

このサービスはクラス指定では自動的に起動しない。名前指定
によって起動する
起動時に、環境変数nameにvalueを設定する

socket <name> <type> <perm>
[ <user> [ <group> ] ]

/dev/socket/<name> というunixドメインソケットを生成
する

user <username>

アプリケーションを実行する前にユーザーネームを変更する。初
期値はroot

disabled

group <groupname> [
<groupname> ]*
oneshot

サービスの起動時にグループを変更する。初期値はroot
アプリケーションが終了しても再起動させない

class <name>

サービスにクラス名をつけることができ、サービスをグループ化
することができる。初期値には"default"が設定されており、こ
れとは別の名前を変更したいときに付ける

onrestart

サービスが再起動したときにコマンドを実行する

Chance Lab. Corp.

48
androidのinit |

android init 処理について

■init.rc(init.xxx.rc)について

サービス/オプション使用例1
service serfaceflinger /system/bin/ serfaceflinger
class main
user system
group graphics drmrpc
onrestart restart zygote

Serfaceflingerは画面描画の実行、管理を行うサービス。
1. Mainクラスにグループ化する。
2. ユーザネームをsystemに変更する。
3. グループをgraphics、補助グループをdrmrpcに変更する。
4. サービスが再起動したときにzygoteサービスを再起動する。

Chance Lab. Corp.

49
androidのinit |

android init 処理について

■init.rc(init.xxx.rc)について

サービス/オプション使用例2
service bootanim /system/bin/bootanimation
class main
user graphics
group graphics
disabled
oneshot

bootanimは起動時のブートアニメーションを表示するサービス。
1. Mainクラスにグループ化する。
2. ユーザネームをgraphicsに変更する。
3. グループをgraphicsに変更する。
4. 自動的に起動せず、外部から指定され起動する。
5. 再起動しない。

Chance Lab. Corp.

50
androidのinit |

android init 処理について

■Java層(system_server)起動処理

Chance Lab. Corp.

51
androidのinit |

android init 処理について

■Java層(system_server)起動処理
zygote 起動 ~ Java層 SystemServer 起動

Zygote
Zygoteプロセスはandroidシステムブート時にDalvik VMと必要なダ
イナミックリンクライブラリ、Javaのクラスライブラリをロードした
状態で待機する。アプリケーションの実行要求があった場合はZygote
プロセスが自身をforkすることで子プロセスを生成して、その子プロ
セスがアプリケーションを実行する。

Dalvik VM(Dalvik仮想マシン)
全てのアプリケーションはDalvik VM上で動作する。
Dalvik VMは少ないメモリでも動作するよう最適化されており、アー
キテクチャはレジスタベースになっているのが特徴。
Chance Lab. Corp.

52
androidのinit |

android init 処理について

■Java層(system_server)起動処理

Chance Lab. Corp.

53
androidのinit |

android init 処理について

■Java層(system_server)起動処理
zygote 起動 ~ Java層 SystemServer 起動
service zygote /system/bin/app_process -Xzygote
/system/bin --zygote --start-system-server
init.rc

main(int argc, const char* const argv[])
app_main.cpp
AndroidRuntime::start(const char* className, const char*
options)

AndroidRuntime.cpp

main(String argv[])
startSystemServer()
ZygoteInit.java
SystemServer.java
Chance Lab. Corp.

54
androidのinit |

android init 処理について

■Java層(system_server)起動処理
android frameworks各種サービス起動 ~
android.intent.action.BOOT_COMPLETED送信まで

System Server
起動時に各サービスをシステムに登録して、中心となるActivity
ManagerやWindow Manager、Battery Service、Mount Serviceな
どの各サービスを起動する。

Activity Manager
各アプリケーション、サービスのアクティビティのライフサイクルを
管理する。
また、システムの起動完了時にACTION_BOOT_COMPLETEDをブ
ロードキャストする。
Chance Lab. Corp.

55
androidのinit |

android init 処理について

■Java層(system_server)起動処理
android frameworks各種サービス起動 ~
android.intent.action.BOOT_COMPLETED送信まで
main(String[] args)
SystemServer.java

以下のサービスを起動
・SurfaceFlinger
・SensorService

android_server_SystemServer_init1
(JNIEnv* env, jobject clazz)
com_android_server_SystemServer.cpp
system_init()

・ActivityManager
・WindowManager
・BatteryService
・PowerManagerService
・PackageManager
:

system_init.cpp

init2()

run()
SystemServer.java

Chance Lab. Corp.

56
androidのinit |

android init 処理について

■Java層(system_server)起動処理
android frameworks各種サービス起動 ~
android.intent.action.BOOT_COMPLETED送信まで
ActivityManagerService.self().systemReady(new Runnable()
{ ... })

SystemServer.java

systemReady(final Runnable goingCallback)
ActivityManagerService.java
resumeTopActivityLocked(ActivityRecord prev, Bundle
options)

ActivityStack.java

startHomeActivityLocked(int userId)
ensureBootCompleted()

finishBooting()
ActivityManagerService.java
Chance Lab. Corp.

57
最後に
■version差分に関して
基本的な処理シーケンスに関しては大幅な変更はないが、セキュリティ
関連の視点や機能拡張により変更点が多く見られた。

■initシーケンス
Platform開発において起動シーケンスは直接的には関わらない事も多い
が、新たな機能の追加等のカスタマイズを概要レベル以上は知っておく
必要があるでしょう。

■Android以外のinitシーケンス
スマートフォン向けモバイルOSである、Firefox OS やTizenなどの同
じようにLinux上で動作するPlatformのinitシーケンスなども調査して
みるとそれぞれの違いや機能移植を前提においた開発も検討可能となる
でしょう。
Chance Lab. Corp.

58
まとめ

android platformの知識を深めよう
ありがとうございました
解析ツールを使い効率化を図ろう

Chance Lab. Corp.

59
参考文献
■書籍
「組み込みAndroidエキスパートテクニックブック」
出村成和 著
横浜Androidプラットフォーム部 監修
株式会社 シーアンドアール研究所 発行

■Web
電脳羊(Android Dream)

http://xiangcai.at.webry.info/

Hermit4

http://blog.hermit4.info/

Yokohama Android Platform Club
Developer Collaboration Project
KMC Staff Blog

Chance Lab. Corp.

http://www.yokohama.android-pf.org/

https://sites.google.com/site/devcollaboration/
http://blog.kmckk.com/

60

Android起動周りのノウハウ