PCRescuroidの設計は、以下の2つの層に分けて行います。
| 分類 | 内容 | 
|---|---|
| アプリ層 | 一般的なAndroidアプリとして実現する機能 | 
| フレームワーク依存処理層 | フレームワーク内の非公開APIを呼び出す機能 | 
| 表4 2つの層に分けて設計 | |
本稿では、フレームワーク依存処理層について、その設計概要を紹介します。
フレームワーク内の非公開APIの呼び出しは、先述の通り、リフレクションを使用することにしました。とはいえ、アプリの実装内に、リフレクションのためのソースコードを記述していくのは骨が折れますし、アプリとフレームワーク依存部分との境界が見えにくくなり、結果的に保守性の悪いソースコードが出来上がることになります。
そこで今回、アプリ層とフレームワーク依存処理層の境界をしっかりと分けるために、図3のような設計としました。
本設計では、フレームワーク依存処理層のインタフェース(MountService)を定義し、PCRescuroidのアプリは、このインタフェースを通してAndroidアプリケーションフレームワーク層の処理を呼び出すことにしています。
インタフェース実装部分については、一般的に、個々のAPIに対応するリフレクション処理をインタフェース実装クラスで定義することになります。しかし、今回は、Javaに標準で組み込まれているProxyクラスを使用することで実装コストを低減することにしました。
Proxyクラスは、「インタフェース」と「実現方法」を分離し、それらをつなげる代理人としての機能を提供しています。Webサービスの呼び出しでよく見掛けるものですが、この場合の実現方法は、「ネットワーク越しのサービスを呼び出す」です。今回、「リフレクション処理でフレームワークの非公開APIを呼び出す」ことになるので、そのためのハンドラをProxyのnewInstance()メソッドに渡すだけで済みます。ハンドラの具体的な実装内容は以下の通りであり、2行のリフレクション処理だけで全てのMountServiceのインタフェースを実現できます。
| クラス | private static class MountServiceInvocationHandler implements InvocationHandler | 
|---|---|
| メソッド | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable | 
| 概要 | 引数で渡されてくるmethodとargsからMountServiceのメソッド呼び出しを行う | 
| 対象コード | 以下、ソースコード1 | 
//MountServiceのメソッドを取得する //引数で渡されてくるmethodは、アプリが実行したMountServiceインタフェースのメソッドであり、 // MountService(フレームワーク)のメソッドと同じシグネチャである Method serviceMethod = mountService.getClass().getMethod(method.getName(), method.getParameterTypes()); //取得したメソッドを実行する。引数には、MountServiceのオブジェクト(mountService※)とメソッド引数(args)を渡す return serviceMethod.invoke(mountService, args); //(※)mountServiceは、事前にServiceManagerを通して取得しておく
Androidアプリケーションフレームワーク層の改造内容は、先述の通り、MountServiceクラスのNotificationの設定として、タップ時に起動するアプリを「クラスオブジェクト(UsbStorageActivity)」から「クラス名の文字列(PCRescuroid)」に変更するだけです。以下に改造箇所を示します。
| クラス | MountService | 
|---|---|
| メソッド | void updateUsbMassStorageNotification(boolean suppressIfConnected, boolean sound) | 
| 概要 | 本メソッドは、MountServiceがUSBマスストレージの状態の変更を通知する場合に呼び出すものであり、タップ時に起動するアプリをPCRescuroidに変更する | 
| 対象コード | 以下、ソースコード2 | 
// 通知により起動するフレームワーク標準のcom.android.internal.app.UsbStorageActivityを // PCRescuroidのjp.co.esm.etec.usbgadget.FormatChooseActivityに変更する intent.setClassName(mContext, "jp.co.esm.etec.usbgadget.FormatChooseActivity");
今回作成したPCRescuroidとAndroidアプリケーションフレームワーク層の改造部分のプログラム構成、および、その配置先を以下に示します(注4)。
| アプリのプログラム配置場所 | |
|---|---|
| https://github.com/esminc/qemu/tree/master/PCRescuroid/src/jp/co/esm/etec/usbgadget | |
| 概要 | 対象ファイル | |
|---|---|---|
| 画面 | 初期画面 | FormatChooseActivity.java | 
| SDマウント画面 | SDCardMounter.java | |
| ISOマウント画面 | ISOFileMounter.java | |
| サービス選択画面 | ServiceChooseActivity.java | |
| CDイメージ検索画面 | FileViewerActivity.java | |
| コントローラ | フレームワークとのインタフェース | MountService.java | 
| フレームワーク依存処理機能実装 | MountServiceUtil.java | |
| フレームワーク改造対象となるプログラムの配置場所 | |
|---|---|
| https://github.com/esminc/qemu/tree/master/android/platform_frameworks /base/services/java/com/android/server | |
| 修正概要 | 対象ファイル | |
|---|---|---|
| MountServiceのアプリ依存部分の改造 | MountService.java | |
今回は、Androidアプリケーションフレームワークに強く依存するアプリの開発において、開発効率を向上させるための手法を紹介しました。
以上で、PCRescuroidのアプリ側の開発はほぼ終了です。ただし、現時点では、ISOイメージファイルをマウントするためのドライバが、Androidカーネル内に存在しないため、全機能の実現には至っていません。そこで次回は、AndroidカーネルにCD-ROMドライバを追加するための方法を模索した結果を紹介したいと思います。ご期待ください! (次回に続く)
Copyright © ITmedia, Inc. All Rights Reserved.
組み込み開発の記事ランキング
コーナーリンク