2017/10/16

Android Performance. UI Rendering

レイアウトXMLはどのようなプロセスを経てピクセル情報に変換され, 画面に描画されるのでしょうか?
Androidのパフォーマンスを改善するには, UIレンダリングの仕組みを理解しておく必要があります.

Android Performance. Dropped frameでは画面のアップデートが16ms毎に行われ, これが遅延するとユーザ体験を悪くしてしまうことについて触れました.

アプリが60fpsを維持するためにはMainThreadでの処理を軽くし, 16msごとのリフレッシュレートを逃さないようにしなければなりません.
60fpsを維持できなくする理由はたくさんありますが, 今回はViewの更新とレンダリングパイプラインについて見ていきます.

Layout & Draw

レイアウトXMLがパースされるとレイアウトツリー(ビューヒエラルキー)が作成されます. 描画はルートノードから始まり, ツリーを渡り歩きながらレイアウトと描画が行われます.
複数のビューを持つ親ビュー(ビューグループ)の場合は, 子ビューにいくつかの制約や制限をつけて描画を要求します. 描画の順序は親ビューが先で子ビューが後になるので, 親が子より奥に描画され, 子ビューが親に重なる形で描画されることになります.

ビューのレイアウトにはメジャーとレイアウトのプロセスがあります. 親ビューは子ビューのサイズに依存するので, まずは子ビューのサイズを計測します. 計測が終わると親ビューが全ての子ビューを計算されたサイズで配置していきます. これはビューツリーからトップダウントラバーサルで処理されるため, ビュー階層が浅いほどパフォーマンスが良くなります. ビューのレイアウトが終わるとこれを描画します.

Rasterization

Viewをディスプレイに描画するには, ボタンやテキストをピクセルに変換する必要があります. 例えば, ラスタ形式(ビットマップ, etc.)ではない文字列やボタン, ベクタードロワブルのようなオブジェクトはラスタライズと呼ばれるプロセスでピクセル形式に変換されてから画面に出力されます.
Android3.0以降, レンダリングパイプラインはハードウェアアクセラレーションをサポートしました. ラスタライズはとても時間のかかるプロセスなので, 専用にデザインされたハードウェアユニット(アクセラレータ)で高速に処理されます. これがGPU(Graphics Processing Unit)です.

GPUはポリゴンやテクスチャといったいわゆる画像などのために設計されたハードウェアユニットです. CPUはそういった画像をGPUに供給する役割を果たします. この操作には OpenGL ES のAPIを使って行われています.

ボタンなどのUIオブジェクトを描画したい場合, まずはCPUでポリゴンやテクスチャ情報に変換し, これをGPUに送ってラスタライズします. CPUでポリゴンやテクスチャ情報に変換したり, GPUにこれを入力する処理は高速ではありません.

パフォーマンスのために, これらのオブジェクトに変換する回数を減らすことは効果があります. OpenGL ES のAPIはGPUに入力したオブジェクトをGPU上にそのままキャッシュさせることが可能です. 同じボタンやUIコンポーネントを使う場合は, 単にGPU上に残ったキャッシュを参照すればよいので, 余計なオーバーヘッドが起こりません. レンダリングの性能を最適化するには, GPU上にあるキャッシュを可能な限り長時間保持して, これを再利用するようにすることです.

Display list

標準UIコンポーネントのドロワブルなどはあらかじめGPUに入力されており, これらの描画は効率的に動きます.
しかし, 実際のUIは複雑で, 例えば背景画像といったビットマップはCPUが画像をメモリにロードしてGPUに転送されます. また, ベクタードロワブルはパスを繋げてポリゴンを描画する必要があります.
テキストにいたってはCPUで文字グリフをテクスチャにラスタライズしたあとGPUにこれを入力し, GPUメモリにグリフを参照する領域を描画します.
アニメーションリソースはもっと複雑で, ビジュアルが変わればGPUリソースを1コマ, 1コマ何度も更新しなければなりません.

ハードウェアアクセラレーションが有効である場合, ディスプレイリストを使った新しい描画モデルで描画されます. ディスプレイリストにはGPUレンダリングに必要な情報アセットとOpenGLコマンドリストが格納されていて, 無駄なオーバーヘッドを抑えて効率的に描画することができます.

Draw Phase

ビューが実際にレンダリングされる前に, まずGPUに適した形式に変換するDrawフェーズがあります. これはJavaによるonDrawコマンドで行われますが, Canvasを使ってテッセレートされた複雑なオブジェクトかもしれません.
この変換が終わると, システムによって結果がディスプレイリストとしてキャッシュされます.

Androidではその都度画面全体を再描画することはせず, 更新が必要な領域に絞って描画します. しかし, 多数のビューが無効化(invalidate())されるとDrawフェーズに多くの時間を費やします. あるいはonDrawで非常に複雑なロジックを抱えているかもしれません.

Execute Phase

作成されたディスプレイリストは2Dレンダラーによって実行されます. ディスプレイリストはOpenGL ES APIを使ってドローされます. これによってGPUにデータが送られ, 最終的にピクセルを画面に送ります.
複雑な描画をするカスタムビューでは, OpenGLが描画できるようにコマンドも複雑になる必要があります. 複雑なビューを描画することは2DレンダラーのExecuteフェーズに多くの時間を費やす原因になります.

画面上でUIオブジェクトの位置が変わった場合は, 同じディスプレイリストをもう1度Executeフェーズを実行するだけです. しかし, 画像のビジュアルが変化すると過去のディスプレイリストが無効になるかもしれません. その場合はDrawフェーズでディスプレイリストを再作成して, 再び実行する必要があります. 画像の描画内容が変わるたびにこのプロセスが繰り返されます. このパフォーマンスは画像の複雑さによって変わるため不正確です.

Process

DrawフェーズとExecuteフェーズが終わるとCPUはフレームのレンダリングが完了したことをGPU/グラフィックドライバーに伝えます. このアクションはブロッキングコールであるため, GPUがコマンドを受け付けたことの応答をCPUは待つことになります.
GPUからのコマンド応答が長くなると, このプロセスも長くなります. プロセスが長くなるのは大抵GPUが多くの仕事をしていることが多いです. 多数の複雑なビューの結果, 多くのOpenGLレンダリングコマンドが必要になりGPUの仕事が増えるのです.

16ms / Frame

16msの間に起こるレンダリングパイプラインは次の通りです.

  1. Input(ユーザからの入力)
  2. Animation(アニメーション)
  3. Measure&Layout
  4. Drawing(Draw Phase)
  5. Sync/Upload
  6. Issuing Commands(Execute Phase)
  7. Processing(Process)
  8. Misc

これらの時間はProfile GPU Renderingツールで見ることができます. 下図はフレームごとのレンダリングに要した時間を並べたもので, 緑色の水平線が16msを示すラインです. これを超えるとDropped Frameが発生します.


実際にアプリケーションを作成すると, 16ms/フレーム・60fpsを維持することが大変であることを実感できるでしょう. パフォーマンスを改善するには計測して問題のある箇所を特定することを繰り返すことが重要です.

前回と合わせて, 最低限必要な知識は揃いましたので, アプリのパフォーマンスを悪くしている箇所を特定し, それを改善するアプローチについて次回以降に書きたいと思います.

次回に続く…

2017/10/13

Android Performance. Dropped frame

SystemEvents, Input Events, Application, Service, Alarm, UI Drawingといった多くの処理はMain Thread(UI Thread) で実行されます.
重要なポイントは, 画面は16ミリ秒の間隔で再描画されているということです.

Why 16ms, Why 60fps?

人間は繋がりのある複数枚の絵が十分な速さで連続していると, それがあたかもアニメーションしているかのように錯覚します. パラパラ漫画やアニメGifの原理です.
アニメーションをスムーズに見せるために, どれだけ素早く画像を表示できるかという点が重要で, 滑らかで流れるようなアニメーションには必要不可欠な要素です.

人間の脳がアニメーションしているように感じるためには, 最低でも12fps程度の速度が必要です. これよりも遅いとパラパラ漫画のようなぎこちない見た目になります. 12fpsという速度はアニメーションには見えてもあまりスムーズには映りません.
24fpsは流れるようなアニメーションに見えますが, これはモーションブラーやビジュアルエフェクトの効果によるものです.
60fpsはモーションブラーやエフェクトなしでスムーズに映ります. これ以上のfpsはほぼ感知できない領域です.

注意すべきは人間の目の明敏さで, フレームレートが60fpsから24fpsに落ちると, 途端にアニメーションのスムーズさを欠いたように感じ, よくない印象を与えることになります.

VSYNC

スムーズなアニメーションを実現するためにも, Androidがどのようにして60fpsを実現しているのかを理解しておきましょう. それには2つの用語を理解しておく必要があります.

リフレッシュレート

1秒間に画面を何回リフレッシュできるかの値で, ハードウェアが定めた一定間隔で実行されます.
単位はHz(ヘルツ)で, 例えば60Hzであれば1秒間に60回のリフレッシュが可能です.

フレームレート

GPUが一秒間で幾つのフレームを描画できるかの値です.
単位はfpsで, 例えば60fpsであれば一秒間に60フレームの描画が可能です.

Synchronized

GPUが画像データを出力し, ハードウェアがそれを画面に表示します.
スクリーンの描画は, これを何度も繰り返しているので, GPUとハードウェアはできる限り一緒に働くことが望ましいのですが, リフレッシュレートとフレームレートは同じ頻度で起こることが保証されていません.

フレームレートがリフレッシュレートより早いと, ティアリングという現象が発生します.
これは, GPUが新しいフレームをメモリに上書きしている最中に, 画面がリフレッシュされてしまい, まだ更新中の画像を描画してしまうことで, 画像が崩れる(部分的に古いフレームが残る)現象です. これを解決するのがダブルバッファリングです.

ダブルバッファリングでは, GPUがバックバッファにフレームを描画し, それが終わるとフレームバッファーと呼ばれる領域にコピーします. 画面をリフレッシュするときはこのフレームバッファから取り出してリフレッシュするわけです. これによって古いフレームへの上書きが行われないので, 中途半端に上書きされた状態にはなりません.

ここで注意しないといけないことのは, 画面のリフレッシュ中にバックバッファからフレームバッファへのコピー作業が発生しないようにすることです. そうしないと, 同じ問題が起こります. ここで登場するのがVSYNC(Vertical Synchronization)です.

通常はフレームレートがリフレッシュレートよりも高いことが望ましいです. なぜなら, 画面を読み込むよりもGPUのリフレッシュの方が早くなるからです.
GPUはフレームをバックバッファに載せると, VSYNCによって次の画面リフレッシュまで処理を待つことになります.

しかし, 反対にフレームレートがリフレッシュレートよりも低い場合, 例えば30fpsに対して60Hzのディスプレイであった場合, フレームバッファのリフレッシュ作業には, 画面リフレッシュの倍の時間を要するため, 同じフレーム内容で2回ずつリフレッシュすることになります.
問題は, これが断続的に起こった場合です.

十分に早いフレームレートで動作しても, 突然フレームレートが落ちると, ユーザはスムーズなアニメーションに続いて, ぶつ切りになったものを見ることになります.
これらの事象は一般的に ラグ, ジャンク, ヒッチング, スタッター と呼ばれます.

アプリの開発者はこれらの事象を避けなければなりません.
人間の目は明敏で, フレームレートが落ちると, 途端にアニメーションのスムーズさを欠いたように感じ, よくない印象を与えてしまうことを思い出してください.

アプリ開発者が目指すところは 常に60fpsのパフォーマンスを維持すること です.

1000ms / 60frames = 16.666ms/frame

MainThreadでは16msの間隔でUI Drawingイベントが発生します. 60fpsの滑らかなアニメーションを実現するためには16ms間隔の描画が必要になります.

Main Thread(UI Thread)

単一スレッドの処理は逐次実行されるため, 順番に処理されていきます. MainThreadも例外ではありません. UI DrawingイベントもMainThreadで実行されるので, もしあなたの処理が長引くとUI Drawingイベントが遅延し, 次のリフレッシュレートのタイミングを逃してしまい, アニメーションで描画されるはずであったフレームが抜け落ちる ドロップフレーム が発生します.
あなたが書いた処理の後には, 常にUI Drawingイベントが待ち構えていることを忘れないでください.

次回に続きます…

2017/10/10

aapt:attr でリソースファイル数を節約する

layer-listselector など, リソースがまた別のリソースを参照する場合があります.

<selector ...>
  <item android:drawable="@drawable/image01" />
  <item android:drawable="@drawable/image02" />

image01image02 がベクタードロワブルの場合は, 新たに image01.xml, image02.xml と2つのドロワブルリソースを用意する必要があります.

  • selectorlayer-list の定義ファイル
  • image01.xml
  • image02.xml

image01image02 が他リソースでも使われている共通化されたリソースであれば良いのですが, 他では使われず, ここでしか参照されない場合は1つのリソースファイルとしてまとめて定義できた方が管理が楽です.

そうした場合は aapt:attr タグが使えます.

<?xml version="1.0" encoding="utf-8"?>
<selector
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:aapt="http://schemas.android.com/aapt">
  <item>
    <aapt:attr name="android:drawable">
      <vector ... >
        <path ... />
      </vector>
    </aapt:attr>
  </item>
</selector>

<aapt:attr> タグで指定したリソースは, aaptによってリソースファイルとして抽出・生成され, name属性名の値は, 親タグの同属性に指定のリソースを設定する動作となります.
この機能は全てのAndroidバージョンで利用できます.

以上です.

2017/10/09

DevFest2017

Android1.5~8.0 Walkthrough のセッションに登壇した際のスライドとスピーカーノートメモ、あと喋った内容の文字起こし.

はじまり。

2017年8月に最新のOS Android8.0 コードネーム Oreoがリリースされました.

アプリを Oreo に最適化するには TargetSdkVersion を 26 に上げる必要があります。
TargetSdkVersion を上げることで、Oreoの新機能を十分に活かすことができます。

ここ数年のアップデートでは システムリソースの消費を抑える DozeやAppStandby、バックグラウンド動作制限などがリリースされています。

これによって、ユーザは端末やアプリを使っていないときの バッテリー消費 を抑えることができます。
その一方で, 開発者は OSの仕様変更に対応する必要があります。

バックグラウンド活動のデザイン原則というものがあります。

  • バックグラウンドの活動を減らすことができないのか?
  • デバイスが充電中の状態になるまで活動を遅らせることができないのか?
  • 他の活動とまとめることができないのか?

といったことを考える必要があります。

8.0で バックグラウンド活動が厳格化されたことで 開発者はこれらと “まじめに” 向き合っていく必要があります。

これらの機能を搭載したOSが市場にどれぐらい流通しているのかをグラフにしました。
一番左のグラフは、下から青がAndroid ヌガー, 緑がマシュマロ, 黄色がロリポップ, 赤がキットカット のシェア率を積み上げたものです。

Dozeは マシュマロ以降のOSに搭載されていますので 市場端末の およそ50% がこれを搭載しています。
Android ヌガーでリリースされた, 一部のBroadcastを無効にするProjectSvelteは 18% です。

この割合は DevelopersサイトのDashboardで公開されている 10月時点でのWorldWideなOSバージョンシェアの数字になります。国内に限定したり、ターゲットユーザ層やminSdkでそもそもサポートしていないOSがあると思いますので、みなさんのサービスと同じ数字にはならない点にご注意ください。

本日は、こういった仕様変更や動作制限の移り変わりを Android 1.5~8.0まで 振り返ります。
時間の都合上、厳選してピックアップしている点はご了承ください。

まず初めは2009年4月リリースのOS1.5 CUPCAKEです.

2009年といえば バラク・オバマ氏が アメリカ合衆国大統領に就任した年 になりますね。
その頃Androidは スクリーンキーボードのサポートやアプリウィジェットプロバイダーをリリースしていました。

リリース:2009年4月 Android1.5 - Api Lv.3

3rd party keyboards… サードパーティ製のキーボードはこの頃からサポート.
Bluetooth A2DP… BluetoothプロファイルのA2DPがサポートされました. 当然まだBLEはサポートされていません.
AppWidgetProvider… アプリウィジェット機能のAPIがリリースされ, 開発者はアプリウィジェットを作成することができるようになりました.

次にリリースされたのが 2009年9月 OS1.6 DONUT です。
Cupcakeでは 320ピクセル x 480ピクセル の解像度のみをサポートしていましたが、Donutからは複数の解像度を扱えるようになりました。
また、バッテリー問題が今よりも はるかに深刻だった時代で, アプリ毎のバッテリー使用量をユーザが確認できる機能などが追加されました。

リリース:2009年9月 Android1.6 - Api Lv.4

Battery usage indicator… アプリごとの消費電力がわかる画面を搭載
当時は電力消費問題が深刻で朝満充電にしても夕方前にはバッテリー切れという状態.

New Android Market UI… 現Google PlayのUIが大幅刷新.
当時のAndroidアプリは簡素なものが多かっただけに, Android Marketの多彩な表現は開発者の目をひくものだった

Text-to-speech engine… 多言語の音声合成エンジンでテキスト読み上げをサポート. ただし日本語は含まれていなかった.

2009年10月 Donutリリースから わずか1ヶ月後には OS2.0 Eclair がリリースされました。
この頃はOSバージョンアップが 今よりも頻繁にあった時代です。
ここでサービス周りのアップデートがありましたので詳しくみてみます。

リリース:2009年10月 Android2.0~2.1 - Api Lv.5~7

Service.setForeground deprecated… Service.setForegroundが非推奨に.
代わりにService.startForegroundを使う必要がある. さらにフォアグラウンドで動作していることをユーザに伝えるためにOngoing Notificationの登録が必須化された.

Key events executed on Key-up… Android2.0はHOMEやBackといったバーチャルキーをサポートするため, ユーザが誤ってキーダウンしてもドラッグすることでキーイベントをキャンセルすることができるように, キーアップでイベント発火されるように変更された.

Multi-touch… マルチタッチがサポートされて, キーボードで素早く文字入力しても抜けることが少なくなりました

その他… Live WallpaperのAPIリリースもこの時.

まず、2.0のタイミングでService.setForegroundメソッドが非推奨になりました。
2.0未満のOSでは フォアグラウンドサービスを開始するのに 通知アイコン が不要でした。

通知アイコンが必須になったのは2.0からで、これによって、ユーザがバックグラウンドで活動しているアプリの存在に気づき、
無用なアプリを停止させることができるようになりました。

また、当時はバックグラウンドの活動に対する制限が緩かったので、バックグラウンドにいるアプリプロセスを片っ端からKillしていくタスクキラー系アプリが バッテリー寿命に効くということで流行りました。
アプリ開発者はそうしたキラー系アプリとも戦っていた時代です。

8.0ではサービスの在り方が大きく変わりました。原則、バックグラウンド状態から新しくサービスを起動できなくなったり、startForegroundServiceで起動する場合には5秒以内にフォアグラウンドへ昇格させないとANRが発生するなど厳格化されました。

バックグラウンド活動まわりで使えるAPIに、ロリポップでリリースされたJobScheduler APIがあります。
これの互換性ライブラリとして FirebaseJobDispatcherが API Lv.9から利用可能です。カバー率はほぼ100%です。
JobSchedulerは ロリポップ から使えるAPIなので 78% の端末で使うことができます。

2010年5月にはOS2.2 Froyoがリリースされました。
音声操作機能や、テザリング機能、GCMの前身にあたる C2DM がリリースされたのもこの時です。

リリース:2010年5月 Android2.2 - Api Lv.8

Install on external storage… アプリのインストール領域に外部ストレージを指定可能になった.

Backup Manager, C2DM… 新しい端末に乗換えした時に便利なアプリデータをクラウドへバックアップ/リストアを実現するAPI Backup Managerがリリース.
アプリはBackup agentを実装することでこれを実現することができる. 現在のバックアップの仕組みとは少し異なる. またGCMやFCMの前身にあたるC2DMもこのOSからサポートされています. C2DMはGCMにリプレースされた時点で非推奨になっています.

JIT compiler… JITコンパイラサポートにより2~5倍高速化. マニフェストに vmSafeMode=false を指定することでJITコンパイラによる最適化を無効化することができます. このオプションは後々AOTコンパイラを無効化するオプションに置きかわります.

その他… PlayServiceはこれ以前のバージョンでは対応していない.

2010年12月には OS2.3 Gingerbreadがリリースされました。
電池が何に使われたかを計測するバッテリー管理機能などが強化されています。

Androidのイースターエッグが搭載されたのもGingerbreadからです。
Gingerbreadでは ゾンビ ジンジャーブレッドマン の絵がイースターエッグで表示されます。
実際、ジンジャーブレッドは ゾンビ な状態になります。

スマホ向けOSの最新版としての期間が長かったことと、スマホブームが重なったこともあって 一時期は全体の60%を超えるシェアにまでGingerbreadは普及しました。
その後は、2015年にマシュマロがリリースされて、ようやくGingerbreadのシェアが10%を切ったぐらいに ”ゾンビ” な状態でした。

リリース:2010年12月 Android2.3 - Api Lv.9/10

2010年… 東北新幹線全線開業した年.

1touch word selection & copy/paste… テキストのロングプレスで単語が選択されフリー選択モードに移行するようになった.

Improved Power management… アプリがバックグラウンドで消費したCPUタイムをユーザが見られるようになるなどバッテリー管理機能が強化された.

その他… StrictMode搭載. Apache Harmony 6.0ベース化. システムアプリやシステムUIの刷新. Google PlayServiceのサポートはここから.

ここで、パフォーマンスに関する仕様変更についてみてみます。
OS5.0から実行環境がARTに置き換わりましたが、それまではDalvikでした。

OS2.2でJITコンパイラが搭載されたことで CPU使用率の高いコードのパフォーマンスが 最大で5倍改善されました。
OS2.3ではコンカレントGCが採用され、いわゆる”Stop the world”が改善されています。
OS5.0でランタイムがARTに置き換わり、OS7.0ではARTにJITコンパイラが採用されています。

JITコンパイラの採用によってDEXを ジャストインタイム方式で 実行形式にコンバートすればよくなるので、
アプリのインストールやアップデート、OSバージョンアップの時間が大幅に短縮されています。

ランタイムやコンパイラやGCアルゴリズムの違いによってパフォーマンスに差がでる場合もありますので、
ランタイムの違いぐらいは覚えておいて損はないと思います。

ARTはキットカットでも利用できますが オプショナルです。
標準搭載されたのはロリポップ以降ですので 78% の端末に搭載されています。

2011年 2月には OS3.0 Honeycomb がリリースされました。
なかには 黒歴史 という人もいるハニカムですが、重要なアップデートが多くあった OS です。

ActionBar, Fragment, Loader, ハードウェアアクセラレーション, ホログラフィックUIがリリースされています。
ホログラフィックUIはこのスライドデザインのように 黒背景に水色のアクセントカラーをもつテーマで、白背景もバリエーションとしてありましたが、
黒背景が印象的なUIでした。ハニカムは大画面向けのOSで、スマホ向けには配信されていません。

リリース:2011年2月 Android3.0 - Api Lv.11/12/13

New UI design for tablets… Android3.0はタブレットデバイスのような大画面向けのアップデートですが, その内容は後々スマホ向けにも展開され非常に重要なアップデート内容が多く含まれている.

ActionBar, Fragment, Loader… アプリのUI要素にActionBarが導入されました. ActionBarにはMenuキーをエミュレートするオーバーフローメニューが導入されました. また, ActivityをFragmentというサブコンポーネントに分割してMaster-Detail Flowのような柔軟な画面デザインを提供することができる. 開発者は画面の大きさが異なるスマートフォンとタブレット両方で動作するアプリケーションを効率よく作成できるようになります. またActivityやFragmentからの非同期ロードをサポートするLoaderも追加.

Holographic UI… システム全体に新しいUIテーマが適用され, デザインが一新されました. アプリはTheme.Holoを指定することでこれを適用できるようになります. Notificationの表現がリッチになり始めたのもこの頃です.

その他… クリップボードへのコピー&ペースト対応. ハードウェアアクセラレーションサポート.

2011年10月には OS4.0 IceCreamSandwichがリリースされました。
ハニカムの大画面向けUI Frameworkがスマホ向けにも移植され、統一UIフレームワークとなりました。
また、ハードウェアにMenuキーを搭載することが必須でなくなったのもこのタイミングからです。

リリース:2011年10月 Android4.0 - Api Lv.14/15

Unified UI framework… Honeycombで追加されたタブレット向け要素がスマートフォン向けにも引き継がれた. スマホでは画面が小さいことからアクションアイテムがActionBarに収まらない場合, 上下に分割するSplit ActionBarの実装もここから始まります.
ただし, SplitActionBarは現在では非推奨となっています.

MENUボタンがハードウェアに搭載されることは必須ではなくなり, オプションメニューを提供する場合はActionBarにオーバーフローメニューを配置する必要が出てきたのもこのバージョンからです.

2012年 6月には OS4.1 JellyBean がリリースされました。
16ms毎のvsyncやトリプルバッファリングによって、アニメーションやスクロールがより滑らかになりました。
Unicode6対応によって Unicode絵文字にも対応し、また, Google Play Service v1がリリースされたのもこの年です。

リリース:2012年6月 Android4.1~4.3 - Api Lv.16/17/18

Project Butter… 16ms毎のvsyncやグラフィクスのトリプルバッファリングにより, より早く, よりスムーズなユーザ体験を得られるようになりアニメーションやスクロール操作がより滑らかになりました. デバッグツールのsystraceがリリースされたのもこのタイミングです.

Unicode6.0… Unicode6.0絵文字がサポートされたのがこのOSからです. それまでの絵文字はキャリア絵文字でそれぞれ独自の文字コードが割り当てられていましたが, Unicode6.0絵文字がサポートされたことでキャリアを問わず絵文字が使えるようになりました.

Notification styles, GCM … NotificationにBigStyle/InBoxStyle/PictureStyleのスタイルが加わったのがこのバージョン. まだC2DMはGCMにリプレースされた.

その他… 2012年はAndroidMarketがGooglePlayに改名され, Androidアプリ以外のビデオや音楽も扱うストアサービスとして登場した.
GooglePlayServiceライブラリもこの頃にリリースされた. API.18でBluetooth GATTプロファイルに対応も対応した.

Unicode6対応で うれしいことは Unicode絵文字が使えるようになったことですね。
プッシュ文言にUnicode絵文字を使うサービスも増えてきましたが、Unicode絵文字が使えるのはOS4.3からで、それ以前のOSでは文字化けするものがあります。
また, 絵文字に色がついてカラフルになったのはOS4.4からです。

OS5.0では、人間に関わる絵文字はスライドにあるような黄色いキャラクターのグリフに差し替えられました。
OS6.0でUnicode 7と8をサポートし、また「お父さんの絵文字+お母さんの絵文字+子供の絵文字」を
Zero Width Joiner の文字コードで連結すると「家族」の絵文字、1文字に置き換わる仕様にも対応しています。

OS7.0ではUnicode9に対応し、5.0で対応されたnonhuman shapeのキャラクターが”人間”の見た目に戻りました。
絵文字には国や宗教、人種、思想に配慮した仕様になっていて複雑ですが、「human shape」な絵文字と Skin toneの文字コードを繋げることで
絵文字の肌の色を変えることができるようになり、絵文字のバリエーションがグッと増えました。

一応、国内キャリア端末は標準絵文字グリフをキャリア絵文字のグリフで上書きしているので、
OSが同じでもキャリアによって絵文字の見た目に違いがでる問題があることも, ここに付け加えておきます。

それぞれのUnicodeバージョンを搭載している端末の割合はこちらの通りで、
Unicode6が 94%、Unicode 7&8が 50%、Unicode 9が 18%です。

2013年 10月にはOS4.4 Kitkatがリリースされました。
エントリーレベルのデバイスでも動作できるように設計されたOSでストレージアクセスフレームワークが搭載されたのもここからです。
WebViewのアップデートもありましたが そちらは後ほどお話しします。

リリース:2013年10月 Android4.4 - Api Lv.19

Support 512MB RAM device… エントリーレベルのデバイスであっても動作するように設計されたOSで, アプリもActivityManager.isLowRamDevice() APIを使うことで低スペックデバイス向けのコンフィグレーションが可能になりました.

Storage Access Framework… これまで端末内のファイルをユーザに選択させたり, 保存場所を指定させる場合に使われるファイルエクスプローラはOSから提供されていませんでした. ストレージアクセスフレームワークを使うことでユーザに一貫したファイルシステムへの参照方法を提供できるようになりました.

Chromium WebView… WebKitがChromiumベースに差し代わりました. これよりChrome Dev Toolsによるリモートデバッグもサポートされるようになった.

その他… RTLサポートが強化されました. それまではテキストの対応しかなく, リソースを重複して持つ必要がありました.

Android4.4からは, バッテリー消費を抑えるためにアラームの発火タイミングが不正確になります。
4.4以降、どうしても正確なアラームが欲しい場合は AlarmManager の setWindow() か setExact() を使うことになります。

Android6.0は Dozeによるデバイスアイドル状態では アラームの発火が保留されます。
アイドル状態でもアラームを正確に発火させたい場合は setAndAllowWhileIdle() か setExactAndAllowWhileIdle() を使うことになります。

ちなみに、アラームはアプリごとに9分間に1回以上発火はされない仕様です。

2014年10月にはOS5.0 Lollipop がリリースされました。
マテリアルデザインによってUI/UXが大きく変更され、ベクタードロワブル や マルチユーザのサポート、
ARTの標準搭載、CPUの64bitアーキテクチャサポートなど、幅広いアップデート内容になっています。

リリース:2014年10月 Android5.0 - Api Lv.21/22

Material Design, Project Volta… マテリアルデザインの導入でUI/UXが大きく刷新された. RecyclerViewやZ軸, シャドウの概念もここから.
また, バッテリー消費を抑えて電池持ちを改善するプロジェクトProject Voltaが明らかにされました. ジョブスケジューラの機能が提供されたことにより, アプリの動作が最適化されバッテリー消費を抑えることに貢献しています.

Overview, Notification, Multi-user… OverviewはこれまでRecentsと呼ばれていた”最近使ったアプリーケション一覧”の機能に相当するものです.
従来は使ったアプリケーションのリストが並ぶだけでしたが, ここに複数のActivityをドキュメントとして追加することができるようになり, マルチタスクにも使えるようになりました. また, Notificationにはプライオリティやカテゴリの概念が追加され, 重要な通知がヘッドアップ表示されるようになったのもこの頃です.

64bit, ART… また, パフォーマンス改善も行われ, ARTランタイム対応や64bit対応もここから始まりました.

その他… Chromium WebViewがPlayStoreからアップデートできるようになった. AndroidHttpClientのメンテナンスが終了・廃止されURLConnectionの使用が必須に. API Lv20はAndroid Wear向けのAPI Lvとして割り当てられた. またディベロッパープレビュー版という提供方法が始まったのもここから.

WebView周りの変更についてみてみると、4.3までのWebViewは WebKit上で動作していましたが, 4.4以降はChromium上で動作します。
5.0では Google Play経由で アップデート可能になり、WebViewのセキュリティパッチが素早くユーザに届けられるようになりました。
WebViewに依存したアプリの開発者は WebViewのアップデート頻度が高くなったので注意する必要があります。

7.0 以降は Chrome APKから WebViewを提供する機能が搭載されています。これによって、メモリ消費が改善されました。
8.0では アプリのWebView がマルチプロセスモードで実行されます。ウェブコンテンツはアプリのプロセスとは別の独立したプロセスで処理されるので、
セキュリティが強化されています。

また、ここに記載していませんが Chrome custom Tab の機能がOS4.1以降で利用できるようになっています。

Chromium版は 93%の端末 に搭載されていて, WebViewを個別にアップデート可能な端末は 78% です。

2015年 10月にはOS6.0 マシュマロがリリースされました。
このあたりからアプリの挙動を変えるアップデートが目立つようになりました。
RuntimePermission, Doze, AppStandbyなどです。

リリース:2015年10月 Android6.0 - Api Lv.23

RuntimePermission… パーミッションモデルに大きな変更が入りました. ユーザはアプリのパーミッションを管理できるようになり, 好きなタイミングで権限を付与/剥奪できるようになります. また, アプリインストール時にパーミッション許可を求めることはせず, アプリの任意のタイミングでユーザにパーミッション付与を求めるようになります.

Doze, App Standby… 電源に接続していない状態で, 一定時間端末を画面オフで放置していた場合にスリープ状態を維持するDozeや, アプリが長時間アイドル状態であった場合にアプリのネットワークアクセスが無効になり, 同期とジョブが保留されるようになりました.

AutoBackup, Do not disturb… アプリデータが自動でGoogle Driveへバックアップできるようになりました. 追加のコードは必要ありません. バックアップを無効にする場合はマニフェストに1行無効にするフラグを定義します. また, Do not disturbモードもこのバージョンからです.

その他… Apache HTTP clientが削除. OpenSSLからBoringSSLに移行. TextSelectionもそれまでの編集モードからpopup windowでアクションを選択するUIに変更されました.

6.0のDoze機能は, 画面OFF かつ 充電中ではない場合 かつ 端末をほとんど動かさない静止状態 にし続けると、
CPU と ネットワーク通信 を一時保留して バッテリーの寿命を延ばす 省電力機能が働きます。

7.0ではDoze状態になる条件が緩和されて、端末が静止していなくてもDoze状態に入ります。
これによって、ポケットにスマホを入れて持ち歩いているような状況でも バッテリー消費を抑えることができるようになりました。

Dozeがリリースされたのは Android マシュマロ以降なので 50%の端末 がこれを搭載しています。

2016年8月には OS7.0 Nougat がリリースされました。
マルチウィンドウやRAMの使用量を削減するProject Svelteによって一部のブロードキャストが廃止されました。
また、ランチャーアイコンにまつわる変更もあります。

リリース:2016年8月 Android7.0/71 - Api Lv.24/25

Multi-window, Screen zoom… スマートフォンやタブレットで画面を分割して2つのアプリを並べて利用できるようになり, AndroidTVではピクチャーインピクチャーがサポートがサポートされました. また視力が低いユーザ向けの補助機能としてスクリーンズームが搭載され, 端末の画面密度設定が変更可能になりました.

Doze2, File security… 従来はDozeモードに突入するためには端末が静止状態である必要がありましたが, Doze2ではこの制限がなくなりました.
また, プライベートディレクトリのアクセス権限が厳格化され, 他アプリにファイルを直接読み書きさせることができなくなりました. これに伴いfileスキームのURIを含むIntentを共有しようとするとセキュリティ例外が投げられるようになっています.

Project Svelte… アプリのバックグラウンド実行を最適化することでRAMの使用量を削減する取り組み. CONNECTIVITY_ACTION、ACTION_NEW_PICTURE、ACTION_NEW_VIDEOの暗黙的なブロードキャストが削除されました. これらのブロードキャストは複数のアプリが同時に起動するため, メモリが逼迫しシステムのパフォーマンスを低下させる要因になるためです.

その他… 3DレンダリングAPIのvulkanがプラットフォームに統合, データセーバ機能の搭載, WebViewがChrome APKから提供される, VRサポート, App Shortcutなど. またこのタイミングでApache HarmonyベースからOpenJDKベースに移行された.

OS4.3 では 一般的なサイズよりも大きく アプリアイコンを表示するランチャーアプリに対応するため,
端末の抽象解像度ではなく、リクエストされたサイズに応じてリソースを返す mipmapリソースがサポートされました。

OS7.1では アプリアイコンを丸く表示するランチャーアプリが増えたため, アプリから丸いアイコンを提供するRound Iconリソースが追加されています。
OS8.0では さらに元のデザインを崩すことなく、自由にアプリアイコンの形を変えることができるAdaptive Iconがサポートされています。

そして 2017年8月の Android8.0 現在に至ります。

リリース:2017年8月 Android8.0 - Api Lv.26

Background execution limits… バックグランドによる動作が大きく制限されました。サービスを開始してもアプリがバックグラウンドに遷移するとサービスは自動で停止されます。
バックグランドからサービス開始したい場合はContext.startForegroundServiceメソッドをコールし, 5秒以内にフォアグラウンドサービスに昇格させる必要があります。
また、暗黙的なブロードキャストも制限されはじめ、JobShcedulerへの移行が推奨されています。

Notification dots, XML font… アプリの通知がランチャーアイコンにドットで表現されるようになったり, フォントをリソースとして扱えるXMLフォントの機能が導入されました。

Alert windows… システムウィンドウより上にアラートウィンドウを表示できなくなりました。アプリはTYPE_APPLICATION_OVERLAYウィンドウを使うことができます。

その他… HttpsURLConnectionが古いTSLバージョンへフォールバックする動作をやめる, WebViewのマルチプロセスモード実行, ANDROID-IDの処理方法変更, クリッカブルなViewがデフォルトでフォーカス可能に変更, スマホ/タブレットでのピクチャーインピクチャーモード対応, AppShortcutの改善, アダプティブアイコン, 最大アスペクト比, マルティディスプレイ, JobScheduler改善など

Android8.0 ではバックグラウンドで実行する動作を制限していますが、多くの場合 ジョブスケジューラに置き換えることができます。

これは ディベロッパーサイトの Intelligent Job-Scheduling というページからの引用で、
 ジョブを賢くスケジューリングすることで、バッテリ寿命といったシステム状態とともに、アプリのパフォーマンスも向上できます。
と書かれています。

バッテリー寿命というのは、モバイルユーザ体験の重要なポイントです。

Android を よりスマートで、より早く、よりパワフルなプラットフォームに仕上げるには、OSのバージョンアップだけではなく、
アプリの最適化によるバージョンアップも必要不可欠です。

OSに最適化する作業は大変ですが、プラットフォームにも デバイスにも また, ユーザにも優しいアプリ開発を心がけたいものです。

発表は以上ですが、本日紹介した内容は時間の都合上、細かな内容は省いています。
みなさんのサービスに関わる部分で気になるものがありましたら、これらのページを参考にしてみてください。