Androidを支える技術〈Ⅰ〉 ──60fpsを達成するモダンなGUIシステム
![[表紙]Androidを支える技術〈Ⅰ〉 ──60fpsを達成するモダンなGUIシステム [表紙]Androidを支える技術〈Ⅰ〉 ──60fpsを達成するモダンなGUIシステム](/assets/images/cover/2017/9784774187594.jpg)
2017年2月22日発売
有野和真 著
A5判/336ページ
定価(本体3,600円+税)
ISBN 978-4-7741-8759-4
この本の概要
Androidのインターナル解説書。根底に流れるモバイルプラットフォームとしての哲学を丁寧に扱い,最新版(7,N/Nougat)までカバー。
第1巻となる本書では,プラットフォーム戦略の基幹部分を担う「GUIシステム」を主眼に置き,モバイルで主流となったAndroidの中枢を徹底解説。
Androidという巨大ソフトウェアを題材にしつつ,アプリ開発者の方々に身近なテーマの問題設定で,ハードウェアからマルチタッチ/UIスレッド/Handler/Viewツリー/レイアウト/OpenGL ES/バイトコード実行環境まで,ツーランク上のクオリティの製品開発を可能にする技術知識を集約しました。
広くモバイル,Web,デスクトップ,組み込み... 分野ごとの要素技術の壁を越え,さらなるパワーアップをお考えのエンジニアの方々へ,今こそ知っておきたいトピックを凝縮してお届けします。
こんな方におすすめ
- Androidで,ツーランク上のアプリ開発に挑戦したい方
- モバイルプラットフォームの今を本格的に知りたい方
- GUIアプリケーション開発技術を磨きたい方
- Androidのソースコードを読むことになった方
- Androidをテクニカルな観点で押さえたいとお考えのマネージャの方
- 本書について
第1章 AndroidとGUIシステムの基礎知識 ──モバイルプラットフォームの今と基本を知るために
1.1 Androidと最先端のモバイルGUIシステム ……高まり続ける期待と要求
- 1.1.1 GUIシステムに対する要求は年々高まっている
- 解像度の向上によるGUIの複雑化
- ユーザーの期待値が高まった
- 開発者の期待値も高まった
- 1.1.2 AndroidとGUIシステム
- AndroidのスマホはGUIのシステムである
- AndroidのGUIシステムの,アプリ開発者から見た特徴
- ❶マークアップによる記述と動的なツリーの操作
- ❷システムのかなりの部分がJavaで書かれている
- ❸IDEサポート
- ❹豊富なGUI部品と高機能なレイアウト
- ❺解像度非依存な記述
- ❻GPUなどを活かした高速な半透明処理やアニメーション
- 1.1.3 Androidのバージョンの話
- Column 組み込みシステムとGUIのツールキット
- Column Microsoft OfficeはWPFで書かれていない
- Column Honeycomb ……Androidバージョン小話❶
1.2 AndroidのGUIシステムの全体像と変遷 ……最初期からNougatまでの3区分
- 1.2.1 AndroidのGUIシステムの全体像について
- 1.2.2 GUIシステムの基礎Android初期からGBまで
- 1.2.3 ハードウェアアクセラレーションを用いた描画処理 ……HoneycombからICSで完成
- 1.2.4 AOTコンパイルとprofile guidedコンパイル ……LollipopからNougat現在まで
- 1.2.5 描画処理の概要
- Viewツリーとレイアウト
- DisplayListの構築とOpenGL ES呼び出し
- Column デスクトップでのグラフィックスハードウェア活用とWindows Vista
- EGLによるグラフィックスバッファ指定とSurfaceFlingerによる合成
- 描画処理のまとめ
1.3 [速習]本書で登場するAndroidの構成要素のうち,GUIシステム以外の部分 ……Activity,ActivityThread,プロパティ,Binder,システムサービス
- 1.3.1 Activity
- Activityとスタック
- 裏に行ったActivityとkill ……表と裏のActivity
- Activityのライフサイクル
- 1.3.2 ActivityThreadとmainメソッド
- 1.3.3 プロパティによる設定の管理
- 1.3.4 Binderとシステムサービス
- 1.3.5 SystemServerとsystemユーザー
- Column Unixドメインソケットとsocketpair
- 1.3.6 Zygoteによるアプリの開始
- 1.3.7 init.rcから起動されるシステムサービスとデーモン達
- Column fork()システムコールとプロセスの生成
- init.rcファイルの今と昔 ……mount_all
- serviceセクション
- Column Androidの「サービス」 ……4つの「サービス」
- Column Flingerとは何か?
- Zygoteサービス
- installdサービス
- surfaceflingerサービス
- Column CupcakeとG1 Androidバージョン小話❷
1.4 [入門]AndroidのGUIプログラミング ……View周辺の基本とカスタムのView
- 1.4.1 HelloWorld
- レイアウトのリソースを用意
- レイアウトのリソースをsetContentView()で指定
- ボタンがタップされた時の処理を書く
- 1.4.2 カスタムのView
- Column AndroidにUserControlはないの?
- onTouchEvent()でタッチに反応する
- invalidate()とHandlerで内容を動的に変える
- 1.4.3 カスタムの属性を定義する
- 1.4.4 AndroidのGUIプログラミング入門,まとめ
1.5 まとめ
- Column SoCとSnapdragon
第2章 タッチとマルチタッチ ──スマホがスマホであるために
2.1 Androidでのマルチタッチ,基本のしくみ ……LinuxとAndroidの関係
- 2.1.1 ViewのonTouchEvent()メソッドとMotionEvent
- 2.1.2 マルチタッチ概要
- 2.1.3 なぜInputManagerServiceを扱うのか?
- Column epoll()による複数のファイルディスクリプタ待ち
2.2 LinuxのInputサブシステムとinput_event ……入出力機器に共通して使えるフレームワーク
- 2.2.1 LinuxのInputサブシステムについて
- 2.2.2 Linuxの入力関連デバイスドライバとinputモジュール
- シングルタッチの場合
- マルチタッチの場合
- 2.2.3 eventのhandlerとeventファイル
- Column ioctl()システムコール
2.3 Androidフレームワークでの入力イベントの基礎 ……InputManagerService
- 2.3.1 InputManagerServiceとその構成要素
2.4 InputReader ……InputManagerServiceの二大構成要素❶
- 2.4.1 InputReaderの構成要素
- 2.4.2 InputReaderのloopOnce()メソッドとRawEvent
- 2.4.3 EventHubのgetEvents()メソッド
- getEvents()メソッド概要
- 入力デバイスの追加や削除に応じた処理 ……Deviceオブジェクトの作成と削除
- input_eventを読み出した時の処理
- 2.4.4 InputDeviceとInputMapper
- 2.4.5 タッチの処理とMultiTouchInputMapper ……InputMapperの具体例として
- 2.4.6 InputReaderまとめ
2.5 InputDispatcherとInputChannel ……InputManagerServiceの二大構成要素❷と送信相手のクラス
- 2.5.1 InputDispatcher概要
- Column DonutとXperia ……Androidバージョン小話❸
- 2.5.2 ウィンドウとInputChannelの登録
2.6 まとめ
- Column EclairとFroyo ……Androidバージョン小話❹
第3章 UIスレッドとHandler ──LooperとHandlerが見えてくる
3.1 UIスレッド ……UIスレッド周辺の構成要素を知る
- 3.1.1 UIスレッドとは何か ……HandlerとUIスレッドの関わり
- UIスレッドは,GUIシステムの特別なスレッド ……UIスレッドでしか実行できないGUI関連操作がある
- 3.1.2 UIスレッドでしかできないこと ……ラベルの変更やToastの表示など
- UIスレッド以外からUIスレッドでしかできない操作を実行したい場合 ……Handlerを用いたUIスレッドでの実行
- Column 一般的なGUIシステムにおけるUIスレッド
- 3.1.3 UIスレッドではできないこと ……時間のかかる処理
- 3.1.4 メッセージループとUIスレッド ……UIスレッドとLooperの関係
- 3.1.5 AndroidにおけるUIスレッド周辺の構成要素 ……LooperとHandler
3.2 Looper ……UIスレッドを実現するメッセージループ機構
- 3.2.1 Looperの基本的な使い方 ……prepare()とloop()
- Column 「GUIのメッセージループ」以外のLooperの使われ方
- 3.2.2 Looperとスレッドの関連付け ……myLooperとTLS
- Column TLS
- 3.2.3 MessageQueueとnext()メソッド
- MessageQueueへのファイルディスクリプタ登録
- 3.2.4 Looper.loop()では何を行っているのか?❶
3.3 よくわかるHandler ……知っておきたい2つの役割,その実装
- 3.3.1 [再入門]Handler ……2つの役割を分けて考えよう
- 3.3.2 Handlerの使用例
- 3.3.3 メッセージ送り先となるLooperの決定 ……Handlerのコンストラクタによる暗黙の関連付け
- Column 初期の傑作,Gingerbread ……Androidバージョン小話❺
- 3.3.4 Handlerのpost()とMessageのenqueue
- 3.3.5 Looper.loop()では何を行っているのか?❷ ……Handlerのpost()の時の挙動
- 3.3.6 HandlerのdispatchMessage()① ……Runnableが呼ばれるケース
- 3.3.7 HandlerのdispatchMessage()② ……handleMessage()が呼ばれるケース
3.4 まとめ
第4章 Viewのツリーとレイアウト ──GUIシステムの根幹
4.1 Viewツリーの基礎知識 ……GUI部品の親子関係
- 4.1.1 Viewとツリー
- Column ViewツリーのルートとViewRootImpl
- 4.1.2 Viewの担当する領域
- 4.1.3 Viewツリーの使われ方
- 4.1.4 ツリーの再帰的な呼び出し ……タッチのヒット判定の例を元に
4.2 AssetManagerとレイアウトのリソース ……高速なパース,素早い構造の復元
- 4.2.1 Viewツリーの構築とリソースファイル
- 4.2.2 リソースのコンパイルとAssetManager
- 4.2.3 バイナリ化されたリソースとaapt
- 4.2.4 バイナリリソースとXmlResourceParser
- Column 長さの単位 ……dpとspとpx
4.3 LayoutInflater ……メニューやListViewでよく使われるViewツリー生成方法
- 4.3.1 LayoutInflaterを取得する ……ActivityのgetLayoutInflater()の例
- 4.3.2 LayoutInflaterの生成とContext
- 4.3.3 LayoutInflaterとinflate()メソッド
- 4.3.4 LayoutInflaterのonCreateView()メソッドとcreateView()メソッド
- 4.3.5 inflate()メソッドでのViewの生成 ……createView()メソッド
- 呼び出されるViewのコンストラクタ
- 4.3.6 ResXMLParserとAttributeSet
- 4.3.7 スタイルとテーマ入門
- Column SimpleCursorAdapterに見るAndroidのレイアウトリソース哲学
- 4.3.8 スタイル解決 ……obtainStyledAttributes()メソッド
- 4.3.9 LayoutInflaterのまとめ
- Column テーマ関連の公式ドキュメント
4.4 ActivityとDecorView ……ActivityのsetContentView()が作る重要なView
- 4.4.1 setContentView()呼び出しの後のViewの階層 ……DecorViewとContentParentとContentRoot
- 4.4.2 DecorViewとWindow Style
- Column ActivityとPhoneWindow
- Column requestWindowFeature()メソッドとWindow Style
4.5 Viewツリーのmeasureパス ……構築されたViewツリーをレイアウトする❶
- 4.5.1 Viewツリーのレイアウト概要
- Column LinearLayoutのlayout_weight属性
- 4.5.2 measureパスとonMeasure()メソッド
- Column レイアウト可能な場合を考える難しさ
4.6 葉ViewのonMeasure()によるサイズ計算 ……ImageViewを例に
- 4.6.1 葉ノードと内部ノードについて
- 4.6.2 葉のViewの幅の指定いろいろ
- ❶幅がハードコードの場合
- ❷幅がwrap_contentの場合
- ❸幅がmatch_parentの場合
- 4.6.3 いろいろな幅の指定のコードによる表現 ……MeasureSpecとサイズのエンコード
- 4.6.4 onMeasure()の実際の実装 ……ImageViewの場合
- ハードコードされた値の場合 ……EXACTLY
- 最大値指定の範囲内で自由な値を申告して良い場合 ……AT_MOST
- 制約の指定がない場合 ……UNSPECIFIED
4.7 ViewGroupの場合のonMeasure()によるサイズ計算 ……LinearLayoutを例に
- 4.7.1 問題の概要
- 4.7.2 基本ケースのButton B以外のonMeasure()処理
- 4.7.3 Button Bがwrap_contentの場合
- 4.7.4 Button Bがmatch_parentの場合
- 4.7.5 真ん中の子がlayout_weight="1"の場合
4.8 layoutパスとその他の話題 ……構築されたViewツリーをレイアウトする❷
- 4.8.1 layout_で始まる属性達 ……LayoutParamsとViewGroupのgenerateLayoutParams()メソッド
- 4.8.2 layoutパスとgravity
- Column measure()が複数呼ばれるケース
- 4.8.3 タッチの送信とInputChannel
- 4.8.4 onDraw()とCanvasとハードウェアアクセラレーション(第5章に続く)
- Column gravityとlayout_gravity
4.9 まとめ
- Column 第二の傑作,Ice Cream SandwichとNexus 7 ……Androidバージョン小話❻
第5章 OpenGL ESを用いたグラフィックスシステム ──DisplayListとハードウェアアクセラレーション
5.1 なぜOpenGL ESを使ったGUIシステムなのか? ……スピードと電力の問題
- 5.1.1 解像度とゲートの数 ……消費電力とコア数
- 5.1.2 なめらかなアニメーションとViewごとのキャッシュ ……ListViewのスクロールを例に
- 5.1.3 動画の再生と消費電力
- 5.1.4 Androidのグラフィックスシステムのうち,本章で扱う範囲
5.2 Viewのdraw()からOpenGL ES呼び出しまで ……ThreadedRendererとRenderThread
- 5.2.1 誰がdraw()を呼び出し,誰がOpenGL ESを呼び出すのか?
- 5.2.2 ThreadedRendererによるdraw()の呼び出し
- 5.2.3 RenderNodeとDisplayListCanvas
- 5.2.4 drawRenderNode()メソッドとDrawRenderNodeOp
- 5.2.5 nSyncAndDrawFrame()メソッドとRenderThread
- 5.2.6 drawからDisplayListのメソッド呼び出しまで,まとめ
5.3 DisplayList ……「コマンドオブジェクトのリスト」にする効用
- 5.3.1 DisplayListが保持するオペレーション ……DisplayListOp基底クラス
- DisplayListOp::defer()
- DisplayListOp::replay() ……DrawRectOpを例に
- 5.3.2 その他のDrawXXXOpクラス ……DrawBitmapOpとDrawRenderNodeOp
- DrawBitmapOp
- Column AndroidとSkia
- DrawRenderNodeOp ……RenderNodeを描くというコマンド
- 5.3.3 DisplayListを用いた画面の再描画
- ❶再描画,画面の描画内容だけが無効になったケース
- ❸再描画,DisplayListが無効になったケース ……invalidate()メソッド
- ❹再描画,レイアウトが無効になったケース ……requestLayout()メソッド
- ❷DisplayListが有効だが,Surfaceの描画内容が無効なケース ……アニメーション(次節へ続く)
- Column ソフトウェアレンダリングの振る舞い
5.4 ListViewのスクロールに見る,驚異のアニメーション処理 ……60fpsを維持し続ける最重要な応用例
- 5.4.1 スクロール処理の基本処理
- 5.4.2 60fpsを維持するために必要なこと ……VSYNCとChoreographer
- 5.4.3 flingの構造 ……スクロールの特殊処理
- 5.4.4 RenderNode単位の平行移動 ……offsetTopAndBottom()
5.5 まとめ
- Column いまいちなJelly Bean ……Androidバージョン小話❼
第6章 OpenGL ES呼び出しが画面に描かれるまで ──ViewRootImplとSurfaceFlinger
6.1 OpenGL ES呼び出しが画面に描かれるまで ……全体像と一連の流れ
- 6.1.1 本章で登場するクラス達の全体像
- 6.1.2 ハードウェアとAndroidの境界 ……HAL
- 6.1.3 EGL呼び出しでOpenGL ESの描画先を指定する
- 6.1.4 EGLで指定されたSurfaceが,grallocで取得したオフスクリーングラフィックスバッファを更新する
- 6.1.5 SurfaceFlingerが,HWCを用いてグラフィックスバッファを合成して表示
- 6.1.6 ViewRootImplがSurfaceの左上座標を保持し,WindowManagerServiceが複数のViewRootImplを管理
6.2 HALとgralloc ……グラフィックスバッファの確保/解放のインターフェース
- 6.2.1 HALのモジュールの取得 ……hw_get_module()
- 6.2.2 hw_module_t構造体周辺の構造体定義
- 6.2.3 hw_device_tとalloc_device_t
- 6.2.4 alloc_device_tのalloc()関数
- 6.2.5 gralloc_module_tとprivate_module_tの定義
6.3 EGLによるOpenGL ES描画対象の指定 ……OpenGL ESの呼び出しは,どのようにグラフィックス領域に描かれるのか❶
- 6.3.1 EGLによる,OpenGL ESの描き出し先指定
- 6.3.2 EGL,gralloc,OpenGL ESが端末依存である意義
- 6.3.3 アプリのOpenGL ES呼び出しを基に,EGL周辺の構成の意義を考える
- ハードウェアの想定
- 仮に,通常のメモリを介したシンプルなHALであった場合 ……実際とは異なる仮想的なケース
- gralloc,EGL,OpenGL ESといった分け方の場合 ……実際のAndroidのケース
6.4 SurfaceFlingerとHWC ……OpenGL ESの呼び出しが,どのようにグラフィックス領域に描かれるのか❷
- 6.4.1 グラフィックスバッファとSurfaceをつなぐBufferQueue
- 6.4.2 BufferQueueConsumerとしてのSurfaceとOpenGL ES呼び出し
- 6.4.3 SurfaceFlingerシステムサービス ……init.rcのエントリ
- 6.4.4 他のプロセスから見たSurfaceFlingerと画面の描画
- 6.4.5 SurfaceFlingerから見た画面の描画
- 6.4.6 HWC (Hardware Composer) HAL概要
- HWCが専用のハードウェア実装され得る理由
- HWCに要求される基本機能
- 6.4.7 HWCのprepare()メソッド
- 6.4.8 SurfaceFlingerによるグラフィックスバッファの合成
- prepare()メソッドの結果がすべてHWC_OVERLAYのケース
- prepare()の結果にHWC_FRAMEBUFFERが含まれる場合
6.5 ViewRootImpl ……ViewツリーとSurfaceをつなぐ
- 6.5.1 ViewRootImpl概要
- 6.5.2 ViewRootImplの生まれる場所 ……WindowManagerのaddView()
- 6.5.3 IWindowとしてのViewRootImpl ……IWindow概要
- 6.5.4 ViewRootImplでEGL呼び出しが行われる場所 ……ThreadedRendererのinitialize()
- Column WindowManager周辺の複雑さ
- Column BufferQueueProducerの作成はどこで行われるか筆者がソースを読み切れなかった部分について
- 6.5.5 ViewRootImplのperformTraversal()メソッド ……Viewツリーに関わるさまざまな処理
- 6.5.6 ViewRootImplがViewへタッチイベントを届けるまで
6.6 Surfaceをアプリ開発者が使う例 ……「フローティングウィンドウ」「SurfaceViewとMediaCodec」
- 6.6.1 フローティングウィンドウ
- 6.6.2 SurfaceViewとMediaCodec
6.7 まとめ
- Column stagefrightバグとAndroid 7.0 NougatでのMediaFrameworkの改善
第7章 バイトコード実行環境 ──DalvikとART
7.1 Androidのバイトコード実行環境の基礎知識 ……仮想マシンとART
- 7.1.1 スマホにおけるバイトコードの課題
- 厳しいリアルタイム性の要求 ……秒間60フレームを求めて
- 少ないメモリ
- 7.1.2 Androidのバイトコード実行環境の変遷 ……JIT,AOT,そしてprofile guided JITまで
- 最初は,Dalvik VMだった ……最初〜2.1
- 次に,Dalvik VMにJITが入った ……2.2〜4.4
- そして,AOTコンパイルがやってきた ……5.0〜6.X
- AOTコンパイルとJITのハイブリッドに ……7.0〜
- 7.1.3 本章で扱うバイトコード実行環境のバージョンとその方針
7.2 Dalvikバイトコードとdex ……仮想マシンの二大派閥,レジスタ型とスタック型
- 7.2.1 dexファイルができるまで
- 7.2.2 仮想マシンの2つの派閥 ……スタック型とレジスタ型
- Column Jackコンパイラ
- レジスタ型でのaddの呼び出し
- Column その他のレジスタ型仮想マシンシステム ……Elate OSとintent
- スタック型でのaddの呼び出し
- 7.2.3 2つの仮想マシンの比較 ……スタック型とレジスタ型はどちらが良いか?
- 7.2.4 バイトコード比較 ……JavaとDalvik
- 7.2.5 dexフォーマットとその制約
7.3 メモリ節約の工夫とZygote ……バイトコード実行環境をサポートする技術群
- 7.3.1 フラッシュメモリの仕組みとAndroidのスワップ事情
- Column Androidでスワップが行われるのは,どのような時?
- 7.3.2 使用しているメモリの分類
- Column 本当にフラッシュメモリでスワップを使うべきではないか?
- Column mmapとメモリ確保
- 7.3.3 Cleanなメモリとmmap
- 7.3.4 Androidにおける,実メモリを節約する2つの工夫 ……mmapとZygote
- Cleanを増やすためにmmapを有効利用
- Sharedを増やすためにクラスをロードした状態からforkして新プロセス開始
- Column Androidでクラスを列挙するリフレクションが好まれない理由
7.4 これまでのバイトコード実行環境 ……7.0以前の背景から学べること
- 7.4.1 Dalvik VM時代 ……初期〜4.4まで
- Column 最初のバージョンとは何なのか
- 7.4.2 JIT入門 ……トレースJITとメソッドベースのJIT
- トレースJIT
- メソッドベースのJIT
- JITとメモリ
- JITとバッテリー
- JITとリアルタイム性
- JITが有効なケース
- 7.4.3 AOT時代 ……5.0〜6.Xまで
- AOTコンパイルの欠点 ……アップデートが遅い
7.5 Nのバイトコード実行環境 ……Android 7.0 Nougatの進化
- 本節の構成
- 7.5.1 Nのバイトコード実行環境概要
- なぜ一部JITに戻ったのか?
- なぜJITがトレースJITからメソッドベースのJITになったのか?
- 7.5.2 Nのバイトコード実行環境,構成要素
- 7.5.3 ProfileSaverによるプロファイルの保存
- 7.5.4 BackgroundDexOptServiceの起動と処理内容 ……profmanによるプロファイル情報のマージ
- JobSchedulerへの登録と起動条件
- プロファイルのマージとprofile guidedコンパイルの始動 ……profmanとdex2oat呼び出し
- 7.5.5 dex2oatによるprofile guidedコンパイル
- 7.5.6 イメージファイルによる起動の高速化 …….artファイル
- 7.5.7 Nのバイトコード実行環境,まとめ
7.6 まとめ
- Column 次の時代のAndroid,Lollipop ……Androidバージョン小話❽
- おわりに
有野和真(ありのかずま)
新卒でガラケー向けのブラウザ会社に入り組み込み業界で働いた後,2005年にマイクロソフトディベロップメントに移り.NETのサーバーサイド分野であるSharePointの開発に従事。2009年からフリーランスになり,機械学習関連のプロジェクトやスパコンの独自GPGPU開発に携わる傍ら,Androidのお絵描きアプリ「LayerPaint」を共同開発。