Android のカメラ ハードウェア抽象化レイヤ(HAL)は、Camera 2 の高レベルのカメラ フレームワーク API を、基盤となるカメラのドライバとハードウェアに接続します。カメラのサブシステムには、カメラ パイプライン内のコンポーネントの実装が含まれています。一方、カメラ用 HAL は、これらのコンポーネントの各バージョンの実装に使用するインターフェースを備えています。
アーキテクチャ
次の図とリストでは、HAL コンポーネントについて説明しています。
図 1. カメラのアーキテクチャ
- アプリのフレームワーク
- アプリ フレームワーク レベルには、Camera 2 API を利用してカメラ ハードウェアと通信するアプリコードがあります。このコードは、対応する Binder インターフェースを内部で呼び出して、カメラと通信するネイティブ コードにアクセスします。
- AIDL
CameraServiceに関連付けられた Binder インターフェースは frameworks/av/camera/aidl/android/hardware にあります。生成されたコードは下位レベルのネイティブ コードを呼び出すことで物理カメラへのアクセス権を取得して、CameraDeviceを生成し、最終的にフレームワーク レベルでのCameraCaptureSessionオブジェクトを生成するために使用するデータを返します。- ネイティブ フレームワーク
frameworks/av/に存在するこのフレームワークには、CameraDeviceクラスとCameraCaptureSessionクラスに相当するネイティブ クラスが用意されています。NDK camera2 のリファレンスもご覧ください。- binder IPC インターフェース
- binder IPC インターフェースは、プロセスの境界を越えた通信を容易にします。
frameworks/av/camera/camera/aidl/android/hardwareディレクトリには、カメラサービスへの呼び出しを行う複数の camera binder クラスがあります。ICameraServiceはカメラサービスへのインターフェースです。ICameraDeviceUserはオープンになっている特定のカメラデバイスへのインターフェースです。ICameraServiceListenerとICameraDeviceCallbacksはそれぞれ、アプリケーション フレームワークへのCameraServiceコールバックとCameraDeviceコールバックです。 - カメラサービス
frameworks/av/services/camera/libcameraservice/CameraService.cppに配置されているカメラサービスは、HAL と通信する実際のコードです。- HAL
- ハードウェア抽象化レイヤは、カメラサービスの呼び出し先となり、カメラ ハードウェアを正しく機能させるために実装する必要がある標準インターフェースを定義します。
HAL の実装
HAL は、カメラドライバと上位レベルの Android フレームワークの間にあり、アプリがカメラ ハードウェアを正しく操作できるようにするために実装する必要があるインターフェースを定義します。Camera HAL の HIDL インターフェースは、hardware/interfaces/camera で定義されます。
バインドされた一般的な HAL では、次の HIDL インターフェースを実装する必要があります。
ICameraProvider: 個別のデバイスを列挙し、それらのステータスを管理します。ICameraDevice: カメラデバイスのインターフェースです。ICameraDeviceSession: アクティブなカメラデバイス セッションのインターフェースです。
リファレンス HIDL の実装は、CameraProvider.cpp、CameraDevice.cpp、および CameraDeviceSession.cpp に使用できます。この実装では、レガシー API を現在も使用する古い HAL がラップされます。Android 8.0 以降、Camera HAL の実装には HIDL API を使用する必要があります。レガシー インターフェースの使用はサポートされていません。
入力検証
HAL はカメラサービスとは異なるリソースにアクセスできるため、この 2 つの境界はセキュリティ境界として扱われます。つまり、カメラサービスから渡されたパラメータは信頼できない、サニタイズされていないものであると判断されます。攻撃者が権限を昇格させる、またはアクセスすることを想定されていないデータにアクセスするセキュリティ上の脆弱性を回避するため、カメラ HAL でカメラサービスから HAL に渡されたパラメータを検証する必要があります。これには、バッファ長の値が許容範囲内にあることを確認し、使用前およびハードウェアまたはカーネルのドライバに渡す前にパラメータをサニタイズすることが含まれます。
レガシー HAL コンポーネント
このセクションでは、レガシー HAL コンポーネントのアーキテクチャと HAL の実装方法について説明します。Android 8.0 以降での Camera HAL の実装には、代わりに上記の HIDL API を使用する必要があります。
アーキテクチャ(レガシー)
次の図とリストでは、レガシー Camera HAL コンポーネントについて説明しています。
図 2. レガシー カメラ アーキテクチャ
- アプリのフレームワーク
- アプリ フレームワーク レベルには、
android.hardware.CameraAPI を利用してカメラ ハードウェアと通信するアプリコードがあります。このコードは対応する JNI グルークラスを内部で呼び出して、カメラと通信するネイティブ コードにアクセスします。 - JNI
android.hardware.Cameraに関連付けられた JNI コードはframeworks/base/core/jni/android_hardware_Camera.cppにあります。このコードは下位レベルのネイティブ コードを呼び出すことで物理カメラへのアクセス権を取得し、フレームワーク レベルでのandroid.hardware.Cameraオブジェクトの生成に使用するデータを返します。- ネイティブ フレームワーク
frameworks/av/camera/Camera.cppで定義されたネイティブ フレームワークには、android.hardware.Cameraクラスに相当するネイティブ クラスが用意されています。このクラスは IPC バインダ プロキシを呼び出すことで、カメラサービスへのアクセス権を取得します。- バインダ IPC プロキシ
- IPC バインダ プロキシは、プロセスの境界を越えた通信を容易にします。カメラサービスを呼び出す
frameworks/av/cameraディレクトリには、3 つのカメラバインダ クラスがあります。ICameraServiceはカメラサービスへのインターフェースです。ICameraはオープンになっている特定のカメラデバイスへのインターフェースです。ICameraClientはアプリのフレームワークにコールバックを行うデバイスのインターフェースです。 - カメラサービス
frameworks/av/services/camera/libcameraservice/CameraService.cppに配置されているカメラサービスは、HAL と通信する実際のコードです。- HAL
- ハードウェア抽象化レイヤは、カメラサービスの呼び出し先となり、カメラ ハードウェアを正しく機能させるために実装する必要がある標準インターフェースを定義します。
- カーネル ドライバ
- カメラのドライバは、実際のカメラ ハードウェアおよび実装されている HAL と通信します。カメラとドライバは、ディスプレイでのカメラ画像のプレビューと動画の録画をサポートするために YV12 と NV21 の画像形式に対応している必要があります。
HAL(レガシー)の実装
HAL は、カメラドライバと上位レベルの Android フレームワークの間にあり、アプリがカメラ ハードウェアを正しく操作できるようにするために実装する必要があるインターフェースを定義します。HAL インターフェースは、hardware/libhardware/include/hardware/camera.h ヘッダーファイルと hardware/libhardware/include/hardware/camera_common.h ヘッダーファイルで定義されます。
camera_common.h は camera_module を定義します。これはカメラ ID やすべてのカメラに共通するプロパティ(カメラが前面カメラまたは背面カメラのいずれであるか)など、カメラの一般的な情報を取得するための標準的な仕組みです。
camera.h には android.hardware.Camera に対応するコードが含まれています。このヘッダーファイルは camera_device 構造体を宣言し、この構造体は HAL インターフェースを実装する関数へのポインタを持つ camera_device_ops 構造体を含みます。デベロッパーが設定できるカメラ パラメータに関するドキュメントについては、frameworks/av/include/camera/CameraParameters.h を参照してください。これらのパラメータは、HAL の int
(*set_parameters)(struct camera_device *, const char *parms) によってポイントされる関数で設定されます。
HAL 実装の例については、hardware/ti/omap4xxx/camera の Galaxy Nexus HAL の実装を参照してください。
共有ライブラリの設定
Android ビルドシステムを設定し、Android.mk ファイルの作成によって HAL 実装を共有ライブラリに正しくパッケージ化して、適切な場所にその共有ライブラリをコピーします。
- ライブラリのソースファイルを格納する
device/<company_name>/<device_name>/cameraディレクトリを作成します。 Android.mkファイルを作成して、共有ライブラリをビルドします。makefile に次の行が含まれていることを確認します。LOCAL_MODULE := camera.<device_name> LOCAL_MODULE_RELATIVE_PATH := hw
Android でライブラリを正しくロードできるように、ライブラリの名前は
camera.<device_name>とします(.soは自動的に付加されます)。例については、hardware/ti/omap4xxx/Android.mkにある Galaxy Nexus カメラの makefile を参照してください。- デバイスにカメラ機能があることを指定するには、デバイスの makefile を使用して必要となる機能 XML ファイルを
frameworks/native/data/etcディレクトリにコピーします。たとえば、デバイスにカメラ フラッシュと自動フォーカス機能があることを指定するには、デバイスの<device>/<company_name>/<device_name>/device.mkmakefile に次の行を追加します。PRODUCT_COPY_FILES := \ ... PRODUCT_COPY_FILES += \ frameworks/native/data/etc/android.hardware.camera.flash-autofocus.xml:system/etc/permissions/android.hardware.camera.flash-autofocus.xml \
デバイスの makefile の例については、
device/samsung/tuna/device.mkを参照してください。 - カメラのメディア コーデック、フォーマット、解像度を
device/<company_name>/<device_name>/media_profiles.xmlXML ファイルとdevice/<company_name>/<device_name>/media_codecs.xmlXML ファイルで宣言します。詳細については、フレームワークにコーデックを公開するをご覧ください。 - デバイスの
device/<company_name>/<device_name>/device.mkmakefile に次の行を追加して、media_profiles.xmlファイルとmedia_codecs.xmlファイルを適切な場所にコピーします。# media config xml file PRODUCT_COPY_FILES += \ <device>/<company>/<device>/media_profiles.xml:system/etc/media_profiles.xml # media codec config xml file PRODUCT_COPY_FILES += \ <device>/<company>/<device>/media_codecs.xml:system/etc/media_codecs.xml - デバイスの
device/<company>/<device>/device.mkmakefile のPRODUCT_PACKAGES変数でカメラアプリを指定して、デバイスのシステム イメージにカメラアプリを含めます。PRODUCT_PACKAGES := \ Gallery2 \ ...