2010年12月12日日曜日



f:id:bs-android:20101211200826p:image


アプリ開発者に AndroidMarket に関する変更点の連絡がありましたので、和訳して公開します。


内容


数日中に、Android 1.6以上が稼働しているデバイス上のAndroidマーケットを更新します。あなたのアプリケーションに影響を及ぼすかもしれないことを下記にご案内し、いくつかの変更について警告します:




  • 全てのアプリケーションに対して詳細ページが利用され、アプリの"宣伝画像"が表示されます。まだ画像を用意していないなら、できるだけ早くアプリケーションの"宣伝画像"をアップロードすることをオススメします。

  • ユーザーはコンテンツの等級によって、アプリケーションをフィルタリングすることができるようになります。公開しているアプリの等級がまだ付けられていない場合は、12/15までに公開者サイトで直ちに等級付けを行って下さいー等級付けがされていないアプリやゲームは、"大人向け"として扱われます。

  • 購入後の払い戻しウィンドウは15分に減少します。

  • .apkの最大ファイルサイズを現在の25MBから50MBまで増やします。

  • マーケットはGLテクスチャ圧縮フォーマットのように、画面サイズと解像度に基づくフィルタリングをサポートします。フィルタリングはアプリケーションのマニフェスト中の <compatible-screens> と <uses-gl-texture> 要素に基づきます。

  • アプリケーション中に壁紙かウィジェット*1が含まれる場合、マーケットはマニフェストファイルに基づいて、それらを自動的に新しい "動的" カテゴリに追加します。


原文



Hello,

Over the next several days, we’ll be updating Android Market on devices running Android 1.6 or higher. We’re writing to alert you to several changes being introduced with the update that may affect your applications:

* The details page for every app will now utilize and display the app’s “Promotional Graphic” assets at the top. If you haven’t done so already, we recommend uploading “Promotional Graphic” assets for your apps as soon as possible.
* Users will be able to filter applications by content rating. If you haven’t added a content rating for your published apps, you should do so immediately at the Publisher site by December 15 -- applications or games without a rating will be treated as “Mature”.
* We will be reducing the purchase refund window to 15 minutes.
* We will be increasing the maximum size for .apk files to 50MB, from the current 25MB.
* Market will support filtering based on screen sizes and densities, as well as on GL texture compression formats. Filtering is based on <compatible-screens> and <uses-gl-texture> elements in an app’s manifest.
* If your app includes wallpapers or widgets, Market will automatically add them to new “dynamic” categories, based on their manifest files.

Thanks, and we look forward to continuing to work with you on Android Market.

Regards,
The Android Market Team

〓2010 Google Inc
1600 Amphitheatre Parkway
Mountain View, CA 94043

Email preferences: You have received this mandatory email service announcement to update you about important changes to your Android Market account.





有料アプリの払い戻しの時間が15分に限定されることで、「散々使った挙げ句に払い戻し」のような現象は減りそうですね。また、アプリの最大サイズが増加したことで、古いデバイスにインストールできないアプリも出てきそうです。



文責:技術部 瀬戸 直喜(前・日本Androidの会四国支部長/情報セキュリティスペシャリスト)




*1:正確には "ライブ壁紙(LiveWallpaper)かウィジェット(AppWidget)" でしょうか





数日中にAndroid Marketが変更されます



f:id:bs-android:20101211200826p:image


アプリ開発者に AndroidMarket に関する変更点の連絡がありましたので、和訳して公開します。


内容


数日中に、Android 1.6以上が稼働しているデバイス上のAndroidマーケットを更新します。あなたのアプリケーションに影響を及ぼすかもしれないことを下記にご案内し、いくつかの変更について警告します:




  • 全てのアプリケーションに対して詳細ページが利用され、アプリの"宣伝画像"が表示されます。まだ画像を用意していないなら、できるだけ早くアプリケーションの"宣伝画像"をアップロードすることをオススメします。

  • ユーザーはコンテンツの等級によって、アプリケーションをフィルタリングすることができるようになります。公開しているアプリの等級がまだ付けられていない場合は、12/15までに公開者サイトで直ちに等級付けを行って下さいー等級付けがされていないアプリやゲームは、"大人向け"として扱われます。

  • 購入後の払い戻しウィンドウは15分に減少します。

  • .apkの最大ファイルサイズを現在の25MBから50MBまで増やします。

  • マーケットはGLテクスチャ圧縮フォーマットのように、画面サイズと解像度に基づくフィルタリングをサポートします。フィルタリングはアプリケーションのマニフェスト中の <compatible-screens> と <uses-gl-texture> 要素に基づきます。

  • アプリケーション中に壁紙かウィジェット*1が含まれる場合、マーケットはマニフェストファイルに基づいて、それらを自動的に新しい "動的" カテゴリに追加します。


原文



Hello,

Over the next several days, we’ll be updating Android Market on devices running Android 1.6 or higher. We’re writing to alert you to several changes being introduced with the update that may affect your applications:

* The details page for every app will now utilize and display the app’s “Promotional Graphic” assets at the top. If you haven’t done so already, we recommend uploading “Promotional Graphic” assets for your apps as soon as possible.
* Users will be able to filter applications by content rating. If you haven’t added a content rating for your published apps, you should do so immediately at the Publisher site by December 15 -- applications or games without a rating will be treated as “Mature”.
* We will be reducing the purchase refund window to 15 minutes.
* We will be increasing the maximum size for .apk files to 50MB, from the current 25MB.
* Market will support filtering based on screen sizes and densities, as well as on GL texture compression formats. Filtering is based on <compatible-screens> and <uses-gl-texture> elements in an app’s manifest.
* If your app includes wallpapers or widgets, Market will automatically add them to new “dynamic” categories, based on their manifest files.

Thanks, and we look forward to continuing to work with you on Android Market.

Regards,
The Android Market Team

〓2010 Google Inc
1600 Amphitheatre Parkway
Mountain View, CA 94043

Email preferences: You have received this mandatory email service announcement to update you about important changes to your Android Market account.





有料アプリの払い戻しの時間が15分に限定されることで、「散々使った挙げ句に払い戻し」のような現象は減りそうですね。また、アプリの最大サイズが増加したことで、古いデバイスにインストールできないアプリも出てきそうです。



文責:技術部 瀬戸 直喜(前・日本Androidの会四国支部長/情報セキュリティスペシャリスト)




*1:正確には "ライブ壁紙(LiveWallpaper)かウィジェット(AppWidget)" でしょうか





2010年12月9日木曜日



f:id:bs-android:20101208234559p:image


Android NDK r5の docs/NATIVE-ACTIVITY.HTMLを訳して、まとめてみました。Native Activityの実装方法は2通りあり、その方法はやや難解ですが、ヘルパーライブラリを利用すれば幾分楽に実装ができそうです。


I.概要


Android SDKが提供するヘルパークラスーNativeActivityにより、完全なネイティブアプリケーションを記述することが可能となりました。NativeActivityはAndroidフレームワークとネイティブコードの間のコミュニケーションを処理するので、それらのサブクラスやメソッドをコールする必要はありません。必要なことはAndroidManifest.xmlファイルにネイティブなアプリケーションを宣言し、そのネイティブアプリケーションを作成することです。


ネイティブアクティビティの概念が導入されても、下記の事実に何ら変更はありません。




  • Androidアプリケーションが仮想マシン上で動作すること

  • サンドボックス機構により他のアプリケーションから守られていること


このため、JNIを通じてAndroidフレームワークのAPIにアクセスすることは、これまでと同様に行えます。一方で、センサ・入力イベント、そしてアセットのようなものにアクセスするネイティブなインタフェースも利用可能です。何がサポートされているかに関する詳しい情報は、<ndk_root>/docs/STABLE-APIS.HTMLを参照して下さい。


ネイティブアクティビティを開発するなら今まで通り、Eclipseを用いて、あるいは、"android create project"コマンドによってプロジェクトを生成するべきでしょう。通常のAndroidビルドツールでネイティブアプリケーションのビルドやパッケージを行うと、ビルドシステムは正確な構造を持つAndroidプロジェクトだけをビルドすることができます。androidツールやEclipseを利用することで、それらを確実に行うことができます。


Android NDKはネイティブアクティビティを実装する方法として、2種類の方法を用意しています:




  • native_activity.hを直接利用する方法

  • ヘルパーライブラリを利用する方法


native_activity.hを直接利用する方法

native_activity.h ヘッダはNativeActivityクラスのネイティブバージョンを定義しており、ネイティブアクティビティを生成するのに必要なコールバックインタフェースとデータ構造を有しています。アプリケーションのメインスレッドがコールバックを制御するため、コールバックの実装はブロックされないようにする必要があります。もしこれらがブロックされた場合は、コールバックから戻るまでメインスレッドの応答がなくなるので、ANR(Application Not Responding)エラーを受け取ることになるでしょう。詳細は、<ndk_root>/platforms/android-9/arch-arm/usr/include/android/native_activity.h のコメントを参照下さい。


ヘルパーライブラリを利用する方法

android_native_app_glue.h ファイルは、native_activity.h インタフェース上で構築された静的なヘルパーライブラリを定義しています。コールバックや入力イベントのようなものを処理するために別スレッドを生成します。そのため、種々のコールバックによってメインスレッドがブロックされることを防ぐと共に、コールバックの実装に若干の柔軟性を加えることができるため、このプログラミングモデルは実装が若干簡単に感じられるかもしれません。


<ndk_root>/sources/android/native_app_glue/android_native_app_glue.c のソースも公開されているため、必要であれば実装を修正することも可能です。詳細は、<ndk_root>/sources/android/native_app_glue/android_native_app_glue.h のコメントを参照下さい。


II.native-activity.h インタフェースを使う


完全なネイティブアクティビティを実装するために、native-activity.h インタフェースを利用することができます。このインタフェースを利用すると、メインのUIスレッドがブロックされないようにコールバックを実装することを確実に行わなければなりません。詳細は、<ndk_root>/platforms/android-9/arch-arm/usr/include/android/native_activity.hを参照下さい。


メインUIスレッドとは別のスレッドでイベントループ中のコールバックを制御できる native_app_glue 静的ヘルパーライブラリを利用する方が容易かもしれません。この静的ライブラリの使用方法は、native-activity サンプルアプリケーションを参照下さい。


native-activity.h インタフェースを用いてネイティブアクティビティを実装する方法:




  • 1/ "android create project"コマンドかEclipseからプロジェクトを作成します。プロジェクトのルートディレクトリ中に、jni/ディレクトリを作成します。このディレクトリに全てのネイティブコードを格納します。

  • 2/ AndroidManifest.xml ファイルにネイティブアクティビティを宣言します。記述例は下記の通り:



<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.native_activity"
android:versionCode="1"
android:versionName="1.0">

<uses-sdk android:minSdkVersion="8" />

<application android:label="@string/app_name" android:hasCode="false">

<activity android:name="android.app.NativeActivity"
android:label="@string/app_name"
android:configChanges="orientation|keyboardHidden">

<meta-data android:name="android.app.lib_name"
android:value="native-activity" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>






    • 注意すべき主な点:


      • activityタグの android:name 属性は必ず android.app.NativeActivityに設定します。NativeActivityのサブクラスにすることも可能ですが、そのようにするのであれば、代わりにそのサブクラスの名前を指定します。

      • meta-detaタグの android:name 属性は必ず android.app.lib_name の形式にします。lib_name はlibプリフィックスと.soサフィックスを除いたモジュール名です。




  • 3/ ネイティブアクティビティのためのファイルを生成し、ANativeActivity_onCreate() 関数を実装します。この関数はネイティブアクティビティが開始された際に呼び出されます。この関数はANativeActivity構造体のポインタを受けとり、種々のコールバック実装の関数のポインタを含むように記述する必要があります。ANativeActivity->callbacks に、適切にコールバック関数のポインタをセットします。

  • 4/ ANativeActivity->instance フィールドに、利用したい特定データのインスタンスのアドレスを設定します。

  • 5/ 開始時に実行したいその他の処理を実装します。

  • 6/ ANativeActivity->callbacks に設定したコールバックの残りを実装します。呼ばれるコールバックに関する情報は、SDKドキュメントのアクティビティライフサイクルを参照して下さい。コールバックの実装はブロックされてはならないことを覚えておきましょう。さもなくば、コールバックが戻るまでメインのUIスレッドが待たされることにより、ANRエラーが発生することになるでしょう。

  • 7/ アプリケーションの残りの部分を開発します。

  • 8/ ビルドシステムにネイティブモジュールを宣言するため、プロジェクトのjni/ディレクトリ中にAndroid.mk ファイルを生成します。Android.mkファイルは、本質的にはGNU makeファイルの断片です。例:



LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := my_native_module
LOCAL_SRC_FILES := my_native_code.c
include $(BUILD_SHARED_LIBRARY)






    • Android.mk ファイルの生成と変数の意味に関する情報は、<ndk_root>/docs/ANDROID-MK.TXT ファイルを参照して下さい。


  • 9/ Android.mk ファイルを一度生成したら、"ndk-build"コマンドを使用してネイティブコードをコンパイルします。



cd path/to/project
<ndk_root>/ndk-build




  • 10/ AntかEclipseを使用して、通常どおりAndroidのプロジェクトをビルドし、インストールします。jni/ディレクトリが存在するなら、ビルドでは自動的にネイティブコードが.apkファイルの中にパッケージされます。



文責:技術部 瀬戸 直喜(前・日本Androidの会四国支部長/情報セキュリティスペシャリスト)





Native Activityの実装方法(Native Activities and Applications和訳)



f:id:bs-android:20101208234559p:image


Android NDK r5の docs/NATIVE-ACTIVITY.HTMLを訳して、まとめてみました。Native Activityの実装方法は2通りあり、その方法はやや難解ですが、ヘルパーライブラリを利用すれば幾分楽に実装ができそうです。


I.概要


Android SDKが提供するヘルパークラスーNativeActivityにより、完全なネイティブアプリケーションを記述することが可能となりました。NativeActivityはAndroidフレームワークとネイティブコードの間のコミュニケーションを処理するので、それらのサブクラスやメソッドをコールする必要はありません。必要なことはAndroidManifest.xmlファイルにネイティブなアプリケーションを宣言し、そのネイティブアプリケーションを作成することです。


ネイティブアクティビティの概念が導入されても、下記の事実に何ら変更はありません。




  • Androidアプリケーションが仮想マシン上で動作すること

  • サンドボックス機構により他のアプリケーションから守られていること


このため、JNIを通じてAndroidフレームワークのAPIにアクセスすることは、これまでと同様に行えます。一方で、センサ・入力イベント、そしてアセットのようなものにアクセスするネイティブなインタフェースも利用可能です。何がサポートされているかに関する詳しい情報は、<ndk_root>/docs/STABLE-APIS.HTMLを参照して下さい。


ネイティブアクティビティを開発するなら今まで通り、Eclipseを用いて、あるいは、"android create project"コマンドによってプロジェクトを生成するべきでしょう。通常のAndroidビルドツールでネイティブアプリケーションのビルドやパッケージを行うと、ビルドシステムは正確な構造を持つAndroidプロジェクトだけをビルドすることができます。androidツールやEclipseを利用することで、それらを確実に行うことができます。


Android NDKはネイティブアクティビティを実装する方法として、2種類の方法を用意しています:




  • native_activity.hを直接利用する方法

  • ヘルパーライブラリを利用する方法


native_activity.hを直接利用する方法

native_activity.h ヘッダはNativeActivityクラスのネイティブバージョンを定義しており、ネイティブアクティビティを生成するのに必要なコールバックインタフェースとデータ構造を有しています。アプリケーションのメインスレッドがコールバックを制御するため、コールバックの実装はブロックされないようにする必要があります。もしこれらがブロックされた場合は、コールバックから戻るまでメインスレッドの応答がなくなるので、ANR(Application Not Responding)エラーを受け取ることになるでしょう。詳細は、<ndk_root>/platforms/android-9/arch-arm/usr/include/android/native_activity.h のコメントを参照下さい。


ヘルパーライブラリを利用する方法

android_native_app_glue.h ファイルは、native_activity.h インタフェース上で構築された静的なヘルパーライブラリを定義しています。コールバックや入力イベントのようなものを処理するために別スレッドを生成します。そのため、種々のコールバックによってメインスレッドがブロックされることを防ぐと共に、コールバックの実装に若干の柔軟性を加えることができるため、このプログラミングモデルは実装が若干簡単に感じられるかもしれません。


<ndk_root>/sources/android/native_app_glue/android_native_app_glue.c のソースも公開されているため、必要であれば実装を修正することも可能です。詳細は、<ndk_root>/sources/android/native_app_glue/android_native_app_glue.h のコメントを参照下さい。


II.native-activity.h インタフェースを使う


完全なネイティブアクティビティを実装するために、native-activity.h インタフェースを利用することができます。このインタフェースを利用すると、メインのUIスレッドがブロックされないようにコールバックを実装することを確実に行わなければなりません。詳細は、<ndk_root>/platforms/android-9/arch-arm/usr/include/android/native_activity.hを参照下さい。


メインUIスレッドとは別のスレッドでイベントループ中のコールバックを制御できる native_app_glue 静的ヘルパーライブラリを利用する方が容易かもしれません。この静的ライブラリの使用方法は、native-activity サンプルアプリケーションを参照下さい。


native-activity.h インタフェースを用いてネイティブアクティビティを実装する方法:




  • 1/ "android create project"コマンドかEclipseからプロジェクトを作成します。プロジェクトのルートディレクトリ中に、jni/ディレクトリを作成します。このディレクトリに全てのネイティブコードを格納します。

  • 2/ AndroidManifest.xml ファイルにネイティブアクティビティを宣言します。記述例は下記の通り:



<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.native_activity"
android:versionCode="1"
android:versionName="1.0">

<uses-sdk android:minSdkVersion="8" />

<application android:label="@string/app_name" android:hasCode="false">

<activity android:name="android.app.NativeActivity"
android:label="@string/app_name"
android:configChanges="orientation|keyboardHidden">

<meta-data android:name="android.app.lib_name"
android:value="native-activity" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>






    • 注意すべき主な点:


      • activityタグの android:name 属性は必ず android.app.NativeActivityに設定します。NativeActivityのサブクラスにすることも可能ですが、そのようにするのであれば、代わりにそのサブクラスの名前を指定します。

      • meta-detaタグの android:name 属性は必ず android.app.lib_name の形式にします。lib_name はlibプリフィックスと.soサフィックスを除いたモジュール名です。




  • 3/ ネイティブアクティビティのためのファイルを生成し、ANativeActivity_onCreate() 関数を実装します。この関数はネイティブアクティビティが開始された際に呼び出されます。この関数はANativeActivity構造体のポインタを受けとり、種々のコールバック実装の関数のポインタを含むように記述する必要があります。ANativeActivity->callbacks に、適切にコールバック関数のポインタをセットします。

  • 4/ ANativeActivity->instance フィールドに、利用したい特定データのインスタンスのアドレスを設定します。

  • 5/ 開始時に実行したいその他の処理を実装します。

  • 6/ ANativeActivity->callbacks に設定したコールバックの残りを実装します。呼ばれるコールバックに関する情報は、SDKドキュメントのアクティビティライフサイクルを参照して下さい。コールバックの実装はブロックされてはならないことを覚えておきましょう。さもなくば、コールバックが戻るまでメインのUIスレッドが待たされることにより、ANRエラーが発生することになるでしょう。

  • 7/ アプリケーションの残りの部分を開発します。

  • 8/ ビルドシステムにネイティブモジュールを宣言するため、プロジェクトのjni/ディレクトリ中にAndroid.mk ファイルを生成します。Android.mkファイルは、本質的にはGNU makeファイルの断片です。例:



LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := my_native_module
LOCAL_SRC_FILES := my_native_code.c
include $(BUILD_SHARED_LIBRARY)






    • Android.mk ファイルの生成と変数の意味に関する情報は、<ndk_root>/docs/ANDROID-MK.TXT ファイルを参照して下さい。


  • 9/ Android.mk ファイルを一度生成したら、"ndk-build"コマンドを使用してネイティブコードをコンパイルします。



cd path/to/project
<ndk_root>/ndk-build




  • 10/ AntかEclipseを使用して、通常どおりAndroidのプロジェクトをビルドし、インストールします。jni/ディレクトリが存在するなら、ビルドでは自動的にネイティブコードが.apkファイルの中にパッケージされます。



文責:技術部 瀬戸 直喜(前・日本Androidの会四国支部長/情報セキュリティスペシャリスト)







f:id:bs-android:20101207022545p:image


先日、ADT 8.0.0がリリースされたばかりですが、早速、8.0.1にバージョンアップされました。


変更点は下記の通りです。


依存関係:


ADT 8.0.1 は SDK Tools r8用にデザインされています。まだSDK Tools r8をSDKにインストールしていない場合は、Android SDK and AVD Managerを利用して下さい。


主な変更:




  • これは、ADT 8.0.0 のいくつかのバグを修正した、緊急フォローアップ版です。

  • プロジェクトのコンパイルの失敗とdexエラーの言及について修正しました。

  • リリース版アプリケーションをエクスポートする際の、ProGuardのエラーリポートの改良


8.0.0のリリースノートもあわせてご覧下さい。



文責:技術部 瀬戸 直喜(前・日本Androidの会四国支部長/情報セキュリティスペシャリスト)





ADT 8.0.1 のリリース変更点まとめ



f:id:bs-android:20101207022545p:image


先日、ADT 8.0.0がリリースされたばかりですが、早速、8.0.1にバージョンアップされました。


変更点は下記の通りです。


依存関係:


ADT 8.0.1 は SDK Tools r8用にデザインされています。まだSDK Tools r8をSDKにインストールしていない場合は、Android SDK and AVD Managerを利用して下さい。


主な変更:




  • これは、ADT 8.0.0 のいくつかのバグを修正した、緊急フォローアップ版です。

  • プロジェクトのコンパイルの失敗とdexエラーの言及について修正しました。

  • リリース版アプリケーションをエクスポートする際の、ProGuardのエラーリポートの改良


8.0.0のリリースノートもあわせてご覧下さい。



文責:技術部 瀬戸 直喜(前・日本Androidの会四国支部長/情報セキュリティスペシャリスト)





2010年12月8日水曜日



f:id:bs-android:20101207022545p:image


Android 2.3(Gingerbread) SDKの提供に伴い、Android NDK Revision 5がリリースされました。Rev5では特にゲームのような、よりネイティブコードを使用するアプリ為のサポートが強化されています。


大きな変更点としては、下記のようなものが挙げられます。




  • イベント/オーディオ/グラフィック/ウィンドウマネジメント/アセット/ストレージに対して、直接ネイティブにアクセス可能になったこと

  • ネイティブコード内にAndroidアプリケーションのライフサイクルの概念を導入したこと(NativeActivityクラスの導入)


主なAndroid NDK Rev5の変更点




  • ネイティブコード内でAndroidアプリケーションライフサイクルの実装をサポート

  • 下記をネイティブでサポート


    • 入力サブシステム(キーボード、タッチスクリーン)

    • センサデータへのアクセス(加速計、コンパス、ジャイロなど)

    • 入力やセンサイベントを待ち受けるためのイベントループAPI

    • ウィンドウ及びサーフェイスサブシステム

    • エフェクトの制御を含む、再生及び録音をサポートするOpenSL ES標準のオーディオAPI

    • .apkファイル中にパッケージされたアセットへのアクセス手段



  • 新しいツールチェイン(GCC4.4.3ベース):よりよいコードを生成できる、./configureとmakeでビルドしたい人向けのスタンドアロンのクロスコンパイラ。詳細は docs/STANDALONE-TOOLCHAIN.htmlを参照。GCC4.4.0のバイナリは依然として提供されるが、4.2.1のバイナリは除外された。

  • プリビルドされたスタティック&共有ライブラリのサポートの追加(docs/PREBUILTS.html)

  • サードパーティーモジュールをより簡単に作成&再利用するための、モジュールのインポート・エクスポートのサポート(docs/IMPORT-MODULE.htmlに理由を説明)

  • ヘルパーモジュールとして、STLportベースのデフォルトC++ STL実装の提供。スタティックまたは共有ライブラリとして使用可能(詳細と使用例は sources/android/stlport/README を参照)。STLportのプリビルドバイナリ(スタティックまたは共有)とGNU libstdc++(スタティックのみ)も併せて提供されます。C++例外とRTTIはデフォルトSTL実装では提供されません。さらなる情報は、docs/CPLUSPLUS-SUPPORT.HTMLをご覧下さい。

  • cpufeaturesヘルパーライブラリの改良:CPUタイプのレポートの改良(いくつかのデバイスで実際にはARMv6にもかかわらず、ARMv7のCPUとして報告されている)。マーケットにアップロードする際にはこのライブラリを使用してリビルドすることを推奨。

  • OpenGLのテクスチャー及びサービスを生成・管理するためのEGLライブラリの追加

  • ネイティブアクティビティの記述方法を示した新しいサンプルアプリケーション: native-plasmaとnative-activity

  • 多くのバグフィックスと他の少しの改良。詳細は docs/CHANGES.htmlを参照。



文責:技術部 瀬戸 直喜(前・日本Androidの会四国支部長/情報セキュリティスペシャリスト)





Android NDK rev5 (Gingerbread) の変更点まとめ



f:id:bs-android:20101207022545p:image


Android 2.3(Gingerbread) SDKの提供に伴い、Android NDK Revision 5がリリースされました。Rev5では特にゲームのような、よりネイティブコードを使用するアプリ為のサポートが強化されています。


大きな変更点としては、下記のようなものが挙げられます。




  • イベント/オーディオ/グラフィック/ウィンドウマネジメント/アセット/ストレージに対して、直接ネイティブにアクセス可能になったこと

  • ネイティブコード内にAndroidアプリケーションのライフサイクルの概念を導入したこと(NativeActivityクラスの導入)


主なAndroid NDK Rev5の変更点




  • ネイティブコード内でAndroidアプリケーションライフサイクルの実装をサポート

  • 下記をネイティブでサポート


    • 入力サブシステム(キーボード、タッチスクリーン)

    • センサデータへのアクセス(加速計、コンパス、ジャイロなど)

    • 入力やセンサイベントを待ち受けるためのイベントループAPI

    • ウィンドウ及びサーフェイスサブシステム

    • エフェクトの制御を含む、再生及び録音をサポートするOpenSL ES標準のオーディオAPI

    • .apkファイル中にパッケージされたアセットへのアクセス手段



  • 新しいツールチェイン(GCC4.4.3ベース):よりよいコードを生成できる、./configureとmakeでビルドしたい人向けのスタンドアロンのクロスコンパイラ。詳細は docs/STANDALONE-TOOLCHAIN.htmlを参照。GCC4.4.0のバイナリは依然として提供されるが、4.2.1のバイナリは除外された。

  • プリビルドされたスタティック&共有ライブラリのサポートの追加(docs/PREBUILTS.html)

  • サードパーティーモジュールをより簡単に作成&再利用するための、モジュールのインポート・エクスポートのサポート(docs/IMPORT-MODULE.htmlに理由を説明)

  • ヘルパーモジュールとして、STLportベースのデフォルトC++ STL実装の提供。スタティックまたは共有ライブラリとして使用可能(詳細と使用例は sources/android/stlport/README を参照)。STLportのプリビルドバイナリ(スタティックまたは共有)とGNU libstdc++(スタティックのみ)も併せて提供されます。C++例外とRTTIはデフォルトSTL実装では提供されません。さらなる情報は、docs/CPLUSPLUS-SUPPORT.HTMLをご覧下さい。

  • cpufeaturesヘルパーライブラリの改良:CPUタイプのレポートの改良(いくつかのデバイスで実際にはARMv6にもかかわらず、ARMv7のCPUとして報告されている)。マーケットにアップロードする際にはこのライブラリを使用してリビルドすることを推奨。

  • OpenGLのテクスチャー及びサービスを生成・管理するためのEGLライブラリの追加

  • ネイティブアクティビティの記述方法を示した新しいサンプルアプリケーション: native-plasmaとnative-activity

  • 多くのバグフィックスと他の少しの改良。詳細は docs/CHANGES.htmlを参照。



文責:技術部 瀬戸 直喜(前・日本Androidの会四国支部長/情報セキュリティスペシャリスト)







SDKと共にバージョンアップした「SDK Tools Revision 8」と「ADT 8.0.0」の変更点をまとめました。原文はこちらとこちら。


f:id:bs-android:20101207022545p:image


SDK Tools Revision 8の変更点


依存関係

EclipseのADTを利用して開発している場合、SDK Tools r8は ADT8.0.0以降を対象としてデザインされていることに注意して下さい。SDK Tools r8のインストール後に、ADTプラグインを8.0.0に更新することを強くオススメします。


SDK Tools r7からの更新

SDK Tools r8を以前のバージョンから更新する場合、adbツールの配置場所が <SDK>/tools/adb から <SDK>/platform-tools/adb に変更になったことに注意して下さい。これが意味するところは、パスの設定を新しく追加する必要があることと、カスタムビルドスクリプトのパス参照を修正する必要があるということです。adbの実行ファイルを新しい場所から古い場所へコピーすることはオススメできません。何故なら、SDK Toolsの更新によって、コピーしたadbを削除するかもしれないからです。


主な変更点



  • 全てのSDKプラットフォームがライブラリプロジェクトをサポートします。

  • (本当の意味での)デバッグビルドをサポートします。デベロッパーはマニフェストファイルの<application>タグの属性に、android:debuggableを追記する必要がなくなりましたーこの属性は自動的にツールが付加します。


    • Eclipse/ADTでは、全てのインクリメンタルなビルドはデバッグビルドであると仮定し、android:debuggable="true"としてツールが付加します。署名済みリリースビルドとしてエクスポートした場合は、この属性は付加されません。

    • Antでは、ant debugコマンドを実行した場合に、同様の属性が付加され、ant releaseコマンドを実行した場合は付加されません。手動で android:debuggable="true"を追記した場合は、ant releaseコマンドを実行した場合においても、デバッグビルドとして動作するでしょう。



  • リリースビルドにおいて自動的にProGuardをサポートします。デベロッパーは android ツールを用いてProGuardの設定を生成しますービルドツールがプロジェクトのソースのビルド中にProGuardを走らせます。

  • 新しい上書き可能なAnt javacプロパティ: java.encoding, java.source そして、java.target(デフォルト値は"ascii","1.5")

  • ヒエラルキービューワーツールのための新しいUI


ADT(8.0.0)の変更点(SDK Toolsの変更点と重複する部分を除く)




  • SDK Tools のリビジョン番号に従うように番号体系を変更。メジャーバージョンは常にSDK Toolsのリビジョン番号に一致するようになります。例えば、ADT 8.x は SDK Tools r8といった形です。

  • ビジュアルレイアウトエディターが完全に書き換えられました(この作業はまだ進行中です)。現在含まれるもの:


    • 全てのレイアウトのクラスについて、パレットからドラッグアンドドロップでレイアウトが配置できます。

    • あるレイアウトビューから別のレイアウトビューへ、あるレイアウトファイルから別のレイアウトファイルへ、レイアウトビュー中のウィジェットの移動

    • enum/flagを有するコンテキストメニューの型プロパティ

    • 新しいズームコントロール



  • ヒエラルキービューワープラグインがEclipseに統合されました

  • もはや、Android起動コンフィグレーションは、起動時にワークスペース全体を再コンパイルしません。

  • android.jar ソースとjavadocの配置場所を調整できるようになりました。



文責:技術部 瀬戸 直喜(前・日本Androidの会四国支部長/情報セキュリティスペシャリスト)





SDK Tools Revision 8とADT 8.0.0の変更点まとめ(Gingerbread)



SDKと共にバージョンアップした「SDK Tools Revision 8」と「ADT 8.0.0」の変更点をまとめました。原文はこちらとこちら。


f:id:bs-android:20101207022545p:image


SDK Tools Revision 8の変更点


依存関係

EclipseのADTを利用して開発している場合、SDK Tools r8は ADT8.0.0以降を対象としてデザインされていることに注意して下さい。SDK Tools r8のインストール後に、ADTプラグインを8.0.0に更新することを強くオススメします。


SDK Tools r7からの更新

SDK Tools r8を以前のバージョンから更新する場合、adbツールの配置場所が <SDK>/tools/adb から <SDK>/platform-tools/adb に変更になったことに注意して下さい。これが意味するところは、パスの設定を新しく追加する必要があることと、カスタムビルドスクリプトのパス参照を修正する必要があるということです。adbの実行ファイルを新しい場所から古い場所へコピーすることはオススメできません。何故なら、SDK Toolsの更新によって、コピーしたadbを削除するかもしれないからです。


主な変更点



  • 全てのSDKプラットフォームがライブラリプロジェクトをサポートします。

  • (本当の意味での)デバッグビルドをサポートします。デベロッパーはマニフェストファイルの<application>タグの属性に、android:debuggableを追記する必要がなくなりましたーこの属性は自動的にツールが付加します。


    • Eclipse/ADTでは、全てのインクリメンタルなビルドはデバッグビルドであると仮定し、android:debuggable="true"としてツールが付加します。署名済みリリースビルドとしてエクスポートした場合は、この属性は付加されません。

    • Antでは、ant debugコマンドを実行した場合に、同様の属性が付加され、ant releaseコマンドを実行した場合は付加されません。手動で android:debuggable="true"を追記した場合は、ant releaseコマンドを実行した場合においても、デバッグビルドとして動作するでしょう。



  • リリースビルドにおいて自動的にProGuardをサポートします。デベロッパーは android ツールを用いてProGuardの設定を生成しますービルドツールがプロジェクトのソースのビルド中にProGuardを走らせます。

  • 新しい上書き可能なAnt javacプロパティ: java.encoding, java.source そして、java.target(デフォルト値は"ascii","1.5")

  • ヒエラルキービューワーツールのための新しいUI


ADT(8.0.0)の変更点(SDK Toolsの変更点と重複する部分を除く)




  • SDK Tools のリビジョン番号に従うように番号体系を変更。メジャーバージョンは常にSDK Toolsのリビジョン番号に一致するようになります。例えば、ADT 8.x は SDK Tools r8といった形です。

  • ビジュアルレイアウトエディターが完全に書き換えられました(この作業はまだ進行中です)。現在含まれるもの:


    • 全てのレイアウトのクラスについて、パレットからドラッグアンドドロップでレイアウトが配置できます。

    • あるレイアウトビューから別のレイアウトビューへ、あるレイアウトファイルから別のレイアウトファイルへ、レイアウトビュー中のウィジェットの移動

    • enum/flagを有するコンテキストメニューの型プロパティ

    • 新しいズームコントロール



  • ヒエラルキービューワープラグインがEclipseに統合されました

  • もはや、Android起動コンフィグレーションは、起動時にワークスペース全体を再コンパイルしません。

  • android.jar ソースとjavadocの配置場所を調整できるようになりました。



文責:技術部 瀬戸 直喜(前・日本Androidの会四国支部長/情報セキュリティスペシャリスト)







f:id:bs-android:20101207145216j:image





はじめに

前回の記事ではAntを使う形で、難読化ツールであるProGuardの適用方法を紹介しました。*1


今回は本日(日本時間12/7)リリースされた Android 2.3(Gingerbread)のSDK(正確にはSDK Tools r8とADT8.0.0)に標準で搭載されたProGuardの適用方法について紹介します。





ProGuardとは


詳細は前回の記事を参照頂きたいのですが、ProGuardが初めての方の為に簡単に説明します。ProGuardはソースコードをコンパイルする際に処理を最適化したり、プログラム中の変数やメソッドを意味のない文字列に置き換え、逆コンパイルされた際に処理の中身をわかりにくくする、いわゆる「難読化」を行うツールです。


これまでもAntを使ってProGuardの適用は行えましたが、最新のSDKでは標準搭載され、Eclipse上から簡単に難読化が行えるようになりました。





GoogleがProGuardを標準搭載した理由


他者による解析を難しくさせるツールを標準機能として載せるということは、裏を返せば「Androidのアプリケーションは、リバースエンジニアリングが容易」ということでしょう。Google公式サイトの解説ページに「ProGuardは完全にオプションとして動作するが、適用を"強くおすすめする"」と書かれています。「Androidアプリ開発者はコードレベルで知的財産を守るべき」という、Googleからの静かなるメッセージなのかもしれません。




ProGuardを有効にする方法


それではどのようにProGuardを適用すればよいか、順を追って解説します。


プロジェクトの作成

Android 2.3のSDKを利用してEclipse上でプロジェクトを新規作成すると、ProGuardの設定が記述された「proguard.cfg」ファイルが自動的に生成されます。このファイルには予め、標準的に必要となる設定が記載されていますので、基本的に修正の必要はありません。


default.propertiesの修正

作成したプロジェクトのホーム直下に配置されているdefault.propertiesの最終行に、下記を追記します。



proguard.config = <proguard.cfgの絶対パス> または <proguard.cfgのプロジェクトホームからの相対パス>


以下はプロジェクトのホームにproguard.cfgが配置されている状態での、default.propertiesの設定の例です。



# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "build.properties", and override values to adapt the script to your
# project structure.

# Project target.
target=android-9
proguard.config=proguard.cfg

基本的にはこの設定だけでProGuardが有効になります!*2


ProGuardの設定変更

基本的に前節の設定のみでProGuardが実行されますが、下記のような場合は実行に失敗することがあります。




  • AndroidManifest.xmlファイルのみから参照されているクラス

  • JNIから呼び出されるメソッド

  • 動的参照される変数やメソッド


ProGuardの実行に失敗する場合は、proguard.cfgファイルに -keep オプションを付加した行を追記し、ProGuardの適用を除外する必要があります。



-keep public class <MyClass>


-keepオプションに関する詳しい情報は、前回の記事やProGuardのマニュアルを参照して下さい。





ProGuardを適用する


Antを使う

従来の方法と同様、ant release コマンドでProGuardを適用することが可能です。詳細は前回の記事を参照して下さい。


Eclipseのエクスポート機能を使う

メニューから、ファイル -> エクスポート -> Android -> Export Android application と選択して、アプリケーションへの署名を行い、apkファイルを出力します。

apkファイルの出力と同時に、下記のようなログがEclipseのコンソールビューに出力されているはずです。*3



[2010-12-07 13:05:28 - HelloAndroid] Refreshing resource folders.
[2010-12-07 13:05:28 - HelloAndroid] Starting incremental Pre Compiler: Checking resource changes.
[2010-12-07 13:05:28 - HelloAndroid] Nothing to pre compile!
[2010-12-07 13:05:28 - HelloAndroid] /android-sdk-mac_x86/platform-tools/aapt package -f -v -M /Users/seto/Documents/workspace/HelloAndroid/AndroidManifest.xml -S /Users/seto/Documents/workspace/HelloAndroid/res -A /Users/seto/Documents/workspace/HelloAndroid/assets -I /android-sdk-mac_x86/platforms/android-9/android.jar -F /var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_1153826279934575801.ap_
[2010-12-07 13:05:28 - HelloAndroid] Found 0 custom asset files in /Users/seto/Documents/workspace/HelloAndroid/assets
[2010-12-07 13:05:28 - HelloAndroid] Locale/Vendor pairs:
[2010-12-07 13:05:28 - HelloAndroid] /
[2010-12-07 13:05:28 - HelloAndroid] /
[2010-12-07 13:05:28 - HelloAndroid] /
[2010-12-07 13:05:28 - HelloAndroid] /
[2010-12-07 13:05:28 - HelloAndroid]
[2010-12-07 13:05:28 - HelloAndroid] ファイル:
[2010-12-07 13:05:28 - HelloAndroid] drawable-hdpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/drawable-hdpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] drawable-ldpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/drawable-ldpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] drawable-mdpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/drawable-mdpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] layout/main.xml
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/layout/main.xml
[2010-12-07 13:05:28 - HelloAndroid] values/strings.xml
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/values/strings.xml
[2010-12-07 13:05:28 - HelloAndroid] AndroidManifest.xml
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/AndroidManifest.xml
[2010-12-07 13:05:28 - HelloAndroid] Including resources from package: /android-sdk-mac_x86/platforms/android-9/android.jar
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for drawable
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for layout
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for anim
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for xml
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for raw
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for color
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for menu
[2010-12-07 13:05:28 - HelloAndroid] (processed image /Users/seto/Documents/workspace/HelloAndroid/res/drawable-hdpi/icon.png: 95% size of source)
[2010-12-07 13:05:28 - HelloAndroid] (processed image /Users/seto/Documents/workspace/HelloAndroid/res/drawable-ldpi/icon.png: 89% size of source)
[2010-12-07 13:05:28 - HelloAndroid] (processed image /Users/seto/Documents/workspace/HelloAndroid/res/drawable-mdpi/icon.png: 85% size of source)
[2010-12-07 13:05:28 - HelloAndroid] (new resource id icon from drawable-hdpi/icon.png #generated)
[2010-12-07 13:05:28 - HelloAndroid] (new resource id icon from drawable-hdpi/icon.png #generated)
[2010-12-07 13:05:28 - HelloAndroid] (new resource id icon from drawable-hdpi/icon.png #generated)
[2010-12-07 13:05:28 - HelloAndroid] (new resource id main from /Users/seto/Documents/workspace/HelloAndroid/res/layout/main.xml)
[2010-12-07 13:05:28 - HelloAndroid] Opening '/var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_1153826279934575801.ap_'
[2010-12-07 13:05:28 - HelloAndroid] Writing all files...
[2010-12-07 13:05:28 - HelloAndroid] 'res/layout/main.xml' (compressed 49%)
[2010-12-07 13:05:28 - HelloAndroid] 'AndroidManifest.xml' (compressed 61%)
[2010-12-07 13:05:28 - HelloAndroid] 'resources.arsc' (not compressed)
[2010-12-07 13:05:28 - HelloAndroid] 'res/drawable-hdpi/icon.png' (not compressed)
[2010-12-07 13:05:28 - HelloAndroid] 'res/drawable-ldpi/icon.png' (not compressed)
[2010-12-07 13:05:28 - HelloAndroid] 'res/drawable-mdpi/icon.png' (not compressed)
[2010-12-07 13:05:28 - HelloAndroid] Generated 6 files
[2010-12-07 13:05:28 - HelloAndroid] Included 0 files from jar/zip files.
[2010-12-07 13:05:28 - HelloAndroid] Checking for deleted files
[2010-12-07 13:05:28 - HelloAndroid] 終了!
[2010-12-07 13:05:28 - HelloAndroid] ProGuard, version 4.4
[2010-12-07 13:05:28 - HelloAndroid] Reading input...
[2010-12-07 13:05:28 - HelloAndroid] Reading program jar [/private/var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_16917046672536715.jar]
[2010-12-07 13:05:28 - HelloAndroid] Reading library jar [/android-sdk-mac_x86/platforms/android-9/android.jar]
[2010-12-07 13:05:30 - HelloAndroid] 初期化中...
[2010-12-07 13:05:30 - HelloAndroid] 注: the configuration refers to the unknown class 'com.android.vending.licensing.ILicensingService'
[2010-12-07 13:05:30 - HelloAndroid] 注: there were 1 references to unknown classes.
[2010-12-07 13:05:30 - HelloAndroid] You should check your configuration for typos.
[2010-12-07 13:05:30 - HelloAndroid] Ignoring unused library classes...
[2010-12-07 13:05:30 - HelloAndroid] Original number of library classes: 2750
[2010-12-07 13:05:30 - HelloAndroid] Final number of library classes: 148
[2010-12-07 13:05:30 - HelloAndroid] Printing kept classes, fields, and methods...
[2010-12-07 13:05:30 - HelloAndroid] Shrinking...
[2010-12-07 13:05:30 - HelloAndroid] Printing usage to [/Users/seto/Documents/workspace/HelloAndroid/proguard/usage.txt]...
[2010-12-07 13:05:30 - HelloAndroid] Removing unused program classes and class elements...
[2010-12-07 13:05:30 - HelloAndroid] Original number of program classes: 8
[2010-12-07 13:05:30 - HelloAndroid] Final number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Optimizing...
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized classes: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of vertically merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of horizontally merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of removed write-only fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of staticized methods: 2
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed method parameters: 2
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant parameters: 1
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant return values: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined short method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined unique method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined tail recursion calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of merged code blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of variable peephole optimizations: 1
[2010-12-07 13:05:30 - HelloAndroid] Number of arithmetic peephole optimizations: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of cast peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of field peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of branch peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of simplified instructions: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed instructions: 19
[2010-12-07 13:05:30 - HelloAndroid] Number of removed local variables: 6
[2010-12-07 13:05:30 - HelloAndroid] Number of removed exception blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of optimized local variable frames: 1
[2010-12-07 13:05:30 - HelloAndroid] Shrinking...
[2010-12-07 13:05:30 - HelloAndroid] Removing unused program classes and class elements...
[2010-12-07 13:05:30 - HelloAndroid] Original number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Final number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Optimizing...
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized classes: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of vertically merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of horizontally merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of removed write-only fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of staticized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed method parameters: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant parameters: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant return values: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined short method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined unique method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined tail recursion calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of merged code blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of variable peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of arithmetic peephole optimizations: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of cast peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of field peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of branch peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of simplified instructions: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed instructions: 2
[2010-12-07 13:05:30 - HelloAndroid] Number of removed local variables: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed exception blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of optimized local variable frames: 0
[2010-12-07 13:05:30 - HelloAndroid] Shrinking...
[2010-12-07 13:05:30 - HelloAndroid] Removing unused program classes and class elements...
[2010-12-07 13:05:30 - HelloAndroid] Original number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Final number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Optimizing...
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized classes: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of vertically merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of horizontally merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of removed write-only fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of staticized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed method parameters: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant parameters: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant return values: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined short method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined unique method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined tail recursion calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of merged code blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of variable peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of arithmetic peephole optimizations: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of cast peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of field peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of branch peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of simplified instructions: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed instructions: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed local variables: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed exception blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of optimized local variable frames: 0
[2010-12-07 13:05:30 - HelloAndroid] Obfuscating...
[2010-12-07 13:05:30 - HelloAndroid] Printing mapping to [/Users/seto/Documents/workspace/HelloAndroid/proguard/mapping.txt]...
[2010-12-07 13:05:30 - HelloAndroid] Writing output...
[2010-12-07 13:05:30 - HelloAndroid] Preparing output jar [/private/var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_2607110758288445210.jar]
[2010-12-07 13:05:30 - HelloAndroid] Copying resources from program jar [/private/var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_16917046672536715.jar]
[2010-12-07 13:05:30 - HelloAndroid] Printing classes to [/Users/seto/Documents/workspace/HelloAndroid/proguard/dump.txt]...


下記のように出力されていれば、難読化がされています。



[2010-12-07 13:05:30 - HelloAndroid] Obfuscating...
[2010-12-07 13:05:30 - HelloAndroid] Printing mapping to [/Users/seto/Documents/workspace/HelloAndroid/proguard/mapping.txt]...





ProGuard有効時に出力されるファイル/ディレクトリ

ProGuardが適用されると、<プロジェクトのホーム>/proguard/ にディレクトリが生成され、その中に下記のようなファイルが出力されます。*4




  • dump.txt:.apkファイル中のクラスの内部構造が記載されています。

  • mapping.txt:難読化前と難読化後のクラス、メソッド、変数の対応リスト

  • seed.txt:難読化されていないクラスやメンバのリスト

  • usage.txt:.apkファイルから外されたコードのリスト


特に、mapping.txtは、リリースビルドしたapkから送られる難読化されたバグリポート(スタックトレース)を可読化するために必要となります。





ProGuard利用時の注意点


proguardディレクトリは、リリースビルドの際に上書きされます。これらを失うと、リリース後のバグレポートから原因を調査することが困難になりますので、proguardディレクトリの中身(特にmapping.txtファイル)は、リリースバージョン毎に保存しておく必要があります。


Android開発者サイトでは、保存の方法として下記のようなものが推奨されています。




  • リリース時のバージョンまたはビルド番号を、フォルダやファイル名に追記する

  • バージョン管理システムにファイルを登録する





難読化されたスタックトレースをデコードする方法


ProGuardは難読化において相応の効果を発揮するツールではありますが、反面、デバッグに必要な情報までをも難読化させてしまう欠点があります。そのため、最新のAndroid SDKには、難読化されたスタックトレースを可読化するための、シェルスクリプトが付属されています。<sdk_root>/tools/proguard/ ディレクトリにretrace.sh(Windowsの場合、retrace.bat)が格納されていますので、このスクリプトを使用します。


コマンドの書式:



retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]


使用例:



retrace.sh -verbose mapping.txt obfuscated_trace.txt


例のmapping.txtは、リリース時に保存しておいたファイル、obfuscated_trace.txtは、難読化されたバグリポート中のスタックトレースを記載したファイルです。


ちなみに、スタックトレースを記載したファイルを省略した場合、標準入力からスタックトレースを読み込んで、デコードします。





より簡単に使えるようになったProGuardで、あなたのアプリケーションを守りましょう!



文責:技術部 植物工場研究G 瀬戸 直喜




*1:書いた矢先に標準搭載され、記事の価値が半分になり、ついカッとなって追加記事を書いたりはしていません。


*2:簡単すぎて前回の記事は一体何だったんだと言いたくなります。


*3:ログが出力されない場合は、Eclipseのメニュー->環境設定->Android->ビルドの「ビルド出力」のオプションを「詳細」に設定してみてください。


*4:Antで実行した場合、出力先は<プロジェクトのホーム>/bin/proguard/ となります。





Androidとセキュリティ:Android 2.3(Gingerbread) SDKに標準搭載されたProGuardを試す



f:id:bs-android:20101207145216j:image





はじめに

前回の記事ではAntを使う形で、難読化ツールであるProGuardの適用方法を紹介しました。*1


今回は本日(日本時間12/7)リリースされた Android 2.3(Gingerbread)のSDK(正確にはSDK Tools r8とADT8.0.0)に標準で搭載されたProGuardの適用方法について紹介します。





ProGuardとは


詳細は前回の記事を参照頂きたいのですが、ProGuardが初めての方の為に簡単に説明します。ProGuardはソースコードをコンパイルする際に処理を最適化したり、プログラム中の変数やメソッドを意味のない文字列に置き換え、逆コンパイルされた際に処理の中身をわかりにくくする、いわゆる「難読化」を行うツールです。


これまでもAntを使ってProGuardの適用は行えましたが、最新のSDKでは標準搭載され、Eclipse上から簡単に難読化が行えるようになりました。





GoogleがProGuardを標準搭載した理由


他者による解析を難しくさせるツールを標準機能として載せるということは、裏を返せば「Androidのアプリケーションは、リバースエンジニアリングが容易」ということでしょう。Google公式サイトの解説ページに「ProGuardは完全にオプションとして動作するが、適用を"強くおすすめする"」と書かれています。「Androidアプリ開発者はコードレベルで知的財産を守るべき」という、Googleからの静かなるメッセージなのかもしれません。




ProGuardを有効にする方法


それではどのようにProGuardを適用すればよいか、順を追って解説します。


プロジェクトの作成

Android 2.3のSDKを利用してEclipse上でプロジェクトを新規作成すると、ProGuardの設定が記述された「proguard.cfg」ファイルが自動的に生成されます。このファイルには予め、標準的に必要となる設定が記載されていますので、基本的に修正の必要はありません。


default.propertiesの修正

作成したプロジェクトのホーム直下に配置されているdefault.propertiesの最終行に、下記を追記します。



proguard.config = <proguard.cfgの絶対パス> または <proguard.cfgのプロジェクトホームからの相対パス>


以下はプロジェクトのホームにproguard.cfgが配置されている状態での、default.propertiesの設定の例です。



# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "build.properties", and override values to adapt the script to your
# project structure.

# Project target.
target=android-9
proguard.config=proguard.cfg

基本的にはこの設定だけでProGuardが有効になります!*2


ProGuardの設定変更

基本的に前節の設定のみでProGuardが実行されますが、下記のような場合は実行に失敗することがあります。




  • AndroidManifest.xmlファイルのみから参照されているクラス

  • JNIから呼び出されるメソッド

  • 動的参照される変数やメソッド


ProGuardの実行に失敗する場合は、proguard.cfgファイルに -keep オプションを付加した行を追記し、ProGuardの適用を除外する必要があります。



-keep public class <MyClass>


-keepオプションに関する詳しい情報は、前回の記事やProGuardのマニュアルを参照して下さい。





ProGuardを適用する


Antを使う

従来の方法と同様、ant release コマンドでProGuardを適用することが可能です。詳細は前回の記事を参照して下さい。


Eclipseのエクスポート機能を使う

メニューから、ファイル -> エクスポート -> Android -> Export Android application と選択して、アプリケーションへの署名を行い、apkファイルを出力します。

apkファイルの出力と同時に、下記のようなログがEclipseのコンソールビューに出力されているはずです。*3



[2010-12-07 13:05:28 - HelloAndroid] Refreshing resource folders.
[2010-12-07 13:05:28 - HelloAndroid] Starting incremental Pre Compiler: Checking resource changes.
[2010-12-07 13:05:28 - HelloAndroid] Nothing to pre compile!
[2010-12-07 13:05:28 - HelloAndroid] /android-sdk-mac_x86/platform-tools/aapt package -f -v -M /Users/seto/Documents/workspace/HelloAndroid/AndroidManifest.xml -S /Users/seto/Documents/workspace/HelloAndroid/res -A /Users/seto/Documents/workspace/HelloAndroid/assets -I /android-sdk-mac_x86/platforms/android-9/android.jar -F /var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_1153826279934575801.ap_
[2010-12-07 13:05:28 - HelloAndroid] Found 0 custom asset files in /Users/seto/Documents/workspace/HelloAndroid/assets
[2010-12-07 13:05:28 - HelloAndroid] Locale/Vendor pairs:
[2010-12-07 13:05:28 - HelloAndroid] /
[2010-12-07 13:05:28 - HelloAndroid] /
[2010-12-07 13:05:28 - HelloAndroid] /
[2010-12-07 13:05:28 - HelloAndroid] /
[2010-12-07 13:05:28 - HelloAndroid]
[2010-12-07 13:05:28 - HelloAndroid] ファイル:
[2010-12-07 13:05:28 - HelloAndroid] drawable-hdpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/drawable-hdpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] drawable-ldpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/drawable-ldpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] drawable-mdpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/drawable-mdpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] layout/main.xml
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/layout/main.xml
[2010-12-07 13:05:28 - HelloAndroid] values/strings.xml
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/values/strings.xml
[2010-12-07 13:05:28 - HelloAndroid] AndroidManifest.xml
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/AndroidManifest.xml
[2010-12-07 13:05:28 - HelloAndroid] Including resources from package: /android-sdk-mac_x86/platforms/android-9/android.jar
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for drawable
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for layout
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for anim
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for xml
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for raw
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for color
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for menu
[2010-12-07 13:05:28 - HelloAndroid] (processed image /Users/seto/Documents/workspace/HelloAndroid/res/drawable-hdpi/icon.png: 95% size of source)
[2010-12-07 13:05:28 - HelloAndroid] (processed image /Users/seto/Documents/workspace/HelloAndroid/res/drawable-ldpi/icon.png: 89% size of source)
[2010-12-07 13:05:28 - HelloAndroid] (processed image /Users/seto/Documents/workspace/HelloAndroid/res/drawable-mdpi/icon.png: 85% size of source)
[2010-12-07 13:05:28 - HelloAndroid] (new resource id icon from drawable-hdpi/icon.png #generated)
[2010-12-07 13:05:28 - HelloAndroid] (new resource id icon from drawable-hdpi/icon.png #generated)
[2010-12-07 13:05:28 - HelloAndroid] (new resource id icon from drawable-hdpi/icon.png #generated)
[2010-12-07 13:05:28 - HelloAndroid] (new resource id main from /Users/seto/Documents/workspace/HelloAndroid/res/layout/main.xml)
[2010-12-07 13:05:28 - HelloAndroid] Opening '/var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_1153826279934575801.ap_'
[2010-12-07 13:05:28 - HelloAndroid] Writing all files...
[2010-12-07 13:05:28 - HelloAndroid] 'res/layout/main.xml' (compressed 49%)
[2010-12-07 13:05:28 - HelloAndroid] 'AndroidManifest.xml' (compressed 61%)
[2010-12-07 13:05:28 - HelloAndroid] 'resources.arsc' (not compressed)
[2010-12-07 13:05:28 - HelloAndroid] 'res/drawable-hdpi/icon.png' (not compressed)
[2010-12-07 13:05:28 - HelloAndroid] 'res/drawable-ldpi/icon.png' (not compressed)
[2010-12-07 13:05:28 - HelloAndroid] 'res/drawable-mdpi/icon.png' (not compressed)
[2010-12-07 13:05:28 - HelloAndroid] Generated 6 files
[2010-12-07 13:05:28 - HelloAndroid] Included 0 files from jar/zip files.
[2010-12-07 13:05:28 - HelloAndroid] Checking for deleted files
[2010-12-07 13:05:28 - HelloAndroid] 終了!
[2010-12-07 13:05:28 - HelloAndroid] ProGuard, version 4.4
[2010-12-07 13:05:28 - HelloAndroid] Reading input...
[2010-12-07 13:05:28 - HelloAndroid] Reading program jar [/private/var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_16917046672536715.jar]
[2010-12-07 13:05:28 - HelloAndroid] Reading library jar [/android-sdk-mac_x86/platforms/android-9/android.jar]
[2010-12-07 13:05:30 - HelloAndroid] 初期化中...
[2010-12-07 13:05:30 - HelloAndroid] 注: the configuration refers to the unknown class 'com.android.vending.licensing.ILicensingService'
[2010-12-07 13:05:30 - HelloAndroid] 注: there were 1 references to unknown classes.
[2010-12-07 13:05:30 - HelloAndroid] You should check your configuration for typos.
[2010-12-07 13:05:30 - HelloAndroid] Ignoring unused library classes...
[2010-12-07 13:05:30 - HelloAndroid] Original number of library classes: 2750
[2010-12-07 13:05:30 - HelloAndroid] Final number of library classes: 148
[2010-12-07 13:05:30 - HelloAndroid] Printing kept classes, fields, and methods...
[2010-12-07 13:05:30 - HelloAndroid] Shrinking...
[2010-12-07 13:05:30 - HelloAndroid] Printing usage to [/Users/seto/Documents/workspace/HelloAndroid/proguard/usage.txt]...
[2010-12-07 13:05:30 - HelloAndroid] Removing unused program classes and class elements...
[2010-12-07 13:05:30 - HelloAndroid] Original number of program classes: 8
[2010-12-07 13:05:30 - HelloAndroid] Final number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Optimizing...
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized classes: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of vertically merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of horizontally merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of removed write-only fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of staticized methods: 2
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed method parameters: 2
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant parameters: 1
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant return values: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined short method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined unique method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined tail recursion calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of merged code blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of variable peephole optimizations: 1
[2010-12-07 13:05:30 - HelloAndroid] Number of arithmetic peephole optimizations: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of cast peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of field peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of branch peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of simplified instructions: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed instructions: 19
[2010-12-07 13:05:30 - HelloAndroid] Number of removed local variables: 6
[2010-12-07 13:05:30 - HelloAndroid] Number of removed exception blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of optimized local variable frames: 1
[2010-12-07 13:05:30 - HelloAndroid] Shrinking...
[2010-12-07 13:05:30 - HelloAndroid] Removing unused program classes and class elements...
[2010-12-07 13:05:30 - HelloAndroid] Original number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Final number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Optimizing...
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized classes: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of vertically merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of horizontally merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of removed write-only fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of staticized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed method parameters: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant parameters: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant return values: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined short method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined unique method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined tail recursion calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of merged code blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of variable peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of arithmetic peephole optimizations: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of cast peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of field peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of branch peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of simplified instructions: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed instructions: 2
[2010-12-07 13:05:30 - HelloAndroid] Number of removed local variables: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed exception blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of optimized local variable frames: 0
[2010-12-07 13:05:30 - HelloAndroid] Shrinking...
[2010-12-07 13:05:30 - HelloAndroid] Removing unused program classes and class elements...
[2010-12-07 13:05:30 - HelloAndroid] Original number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Final number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Optimizing...
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized classes: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of vertically merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of horizontally merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of removed write-only fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of staticized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed method parameters: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant parameters: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant return values: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined short method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined unique method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined tail recursion calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of merged code blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of variable peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of arithmetic peephole optimizations: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of cast peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of field peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of branch peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of simplified instructions: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed instructions: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed local variables: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed exception blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of optimized local variable frames: 0
[2010-12-07 13:05:30 - HelloAndroid] Obfuscating...
[2010-12-07 13:05:30 - HelloAndroid] Printing mapping to [/Users/seto/Documents/workspace/HelloAndroid/proguard/mapping.txt]...
[2010-12-07 13:05:30 - HelloAndroid] Writing output...
[2010-12-07 13:05:30 - HelloAndroid] Preparing output jar [/private/var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_2607110758288445210.jar]
[2010-12-07 13:05:30 - HelloAndroid] Copying resources from program jar [/private/var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_16917046672536715.jar]
[2010-12-07 13:05:30 - HelloAndroid] Printing classes to [/Users/seto/Documents/workspace/HelloAndroid/proguard/dump.txt]...


下記のように出力されていれば、難読化がされています。



[2010-12-07 13:05:30 - HelloAndroid] Obfuscating...
[2010-12-07 13:05:30 - HelloAndroid] Printing mapping to [/Users/seto/Documents/workspace/HelloAndroid/proguard/mapping.txt]...





ProGuard有効時に出力されるファイル/ディレクトリ

ProGuardが適用されると、<プロジェクトのホーム>/proguard/ にディレクトリが生成され、その中に下記のようなファイルが出力されます。*4




  • dump.txt:.apkファイル中のクラスの内部構造が記載されています。

  • mapping.txt:難読化前と難読化後のクラス、メソッド、変数の対応リスト

  • seed.txt:難読化されていないクラスやメンバのリスト

  • usage.txt:.apkファイルから外されたコードのリスト


特に、mapping.txtは、リリースビルドしたapkから送られる難読化されたバグリポート(スタックトレース)を可読化するために必要となります。





ProGuard利用時の注意点


proguardディレクトリは、リリースビルドの際に上書きされます。これらを失うと、リリース後のバグレポートから原因を調査することが困難になりますので、proguardディレクトリの中身(特にmapping.txtファイル)は、リリースバージョン毎に保存しておく必要があります。


Android開発者サイトでは、保存の方法として下記のようなものが推奨されています。




  • リリース時のバージョンまたはビルド番号を、フォルダやファイル名に追記する

  • バージョン管理システムにファイルを登録する





難読化されたスタックトレースをデコードする方法


ProGuardは難読化において相応の効果を発揮するツールではありますが、反面、デバッグに必要な情報までをも難読化させてしまう欠点があります。そのため、最新のAndroid SDKには、難読化されたスタックトレースを可読化するための、シェルスクリプトが付属されています。<sdk_root>/tools/proguard/ ディレクトリにretrace.sh(Windowsの場合、retrace.bat)が格納されていますので、このスクリプトを使用します。


コマンドの書式:



retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]


使用例:



retrace.sh -verbose mapping.txt obfuscated_trace.txt


例のmapping.txtは、リリース時に保存しておいたファイル、obfuscated_trace.txtは、難読化されたバグリポート中のスタックトレースを記載したファイルです。


ちなみに、スタックトレースを記載したファイルを省略した場合、標準入力からスタックトレースを読み込んで、デコードします。





より簡単に使えるようになったProGuardで、あなたのアプリケーションを守りましょう!



文責:技術部 植物工場研究G 瀬戸 直喜




*1:書いた矢先に標準搭載され、記事の価値が半分になり、ついカッとなって追加記事を書いたりはしていません。


*2:簡単すぎて前回の記事は一体何だったんだと言いたくなります。


*3:ログが出力されない場合は、Eclipseのメニュー->環境設定->Android->ビルドの「ビルド出力」のオプションを「詳細」に設定してみてください。


*4:Antで実行した場合、出力先は<プロジェクトのホーム>/bin/proguard/ となります。





2010年12月7日火曜日



f:id:bs-android:20101207054850p:image


ついに待ちに待ったAndroid SDK 2.3のGingerBreadがリリースされたので、早速その新機能をまとめてみました。


今回は見た目の変更が多いという噂でしたが、そうでもなかったようです。しかし、今までにないくらい新機能が増えたように思います。


まずは2.3で追加された新APIを見ていきましょう。



Android SDK 2.3からのAPI



SIPベースのVoIP

フレームワークにSIPプロトコルスタックが搭載され、インターネット電話を扱えるようになりました。SIPのサンプルアプリケーションはココにあります。以下は実際にSipDemoを動かしてみたところ。



f:id:bs-android:20101207042542p:image:w160 f:id:bs-android:20101207042551p:image:w160 f:id:bs-android:20101207042801p:image:w160






NFC

NFC(Near Field Communications)のAPIが追加され、ハードウェアが搭載されていれば、FeliCaのように近距離通信を行うことができるようになりました。NFCのサンプルコードはココです。現時点ではまだNFCのハードウェアが搭載されたAndroid 2.3の端末がないため、試せません。エミュレータで実行すると、当然のようにExceptionが発生してしまいました。







ジャイロスコープとその他のセンサー

ジャイロスコープ、回転速度、直線加速、重力、バロメーターのセンサーが増え、センサーAPIから使用できるようになりました。センサーAPIの詳細はココです。







複数のカメラのサポート

アプリケーションから複数のカメラが利用できるようになりました。フロントカメラを利用するサンプルコードはココです。APIDemoのCameraPreviewを試してみましたが、「カメラが一個しか搭載されてないよ!」と怒られてしまいました。



f:id:bs-android:20101207043724p:image:h160






オーディオ効果のミキシング

オーディオにバスブーストやリバーブなどの様々なエフェクトを掛けることのできるAPIが追加されました。オーディオエフェクトのサンプルコードはココです。以下は実際にAPIDemoを動かしてみたところ。



f:id:bs-android:20101207041945p:image:w160






その他のメディア関連の新機能

JPEG画像のEXIF情報の中のaltitude(高度)の値が取得できるようになりました。また、ビデオ撮影中のオリエンテーション情報をsetOrientationHint()メソッドでMediaRecorderに通知することができるようになりました。







ダウンロードマネージャ

DownloadManagerが追加され、長期間動作するHTTPダウンロードをアプリケーションから要求することができるようになりました。







制限モード

StrictModeと呼ばれる制限モードが追加されました。ANRを発生させないために、UIスレッドで時間のかかる処理を使った場合に検知してくれるモードです。検知した場合はHandler、AysncTask、IntentServiceなどを使って回避するようにコードを書き換えることを推奨します。






UIフレームワーク



overscrollのサポート

限界までスクロールしても、余分にスクロールさせることができるようになりました。余分にスクロールさせる量などは制御することができます。




タッチフィルタリング

マルウェアなどから購入ボタンやパーミッション許可を与えるボタンなどを押させることがないように、タッチフィルタリングを使ってセキュリティを強化することができるようになりました。サンプルコードはココです。




イベント管理の改善

InputEventが新しく追加されました。




モーションイベントの改善

MotionEventにポインタIDが追加されました。それによって、アプリケーションから個々の指の動きを捕捉することができるようになりました。




テキスト選択コントロール

setComposingRegionメソッドにより、アプリケーションから編集中のテキスト領域を設定できるようになりました。TextViewに新しい属性も追加されました。




アクティビティの制御

ActivityInfoクラスにアクティビティの向きを管理する定数が追加されました。画面の回転に合わせてすべての向きに画面表示を合わせることが可能になったようです。




ノティファケーションのテキストとアイコンスタイル

ノティファケーションスタイルを管理する新しい属性が追加されました。




WebView

setUseWebViewBackgroundForOverscrollBackground()メソッドを使ってoverscrollの背景を指定することができるようになりました。








超大型スクリーン

タブレットデバイスなどに見られる超大型スクリーンに対応しました。超大型スクリーンの対応方法はココを参照してください。







グラフィック

OpenGL ES 2.0の残りのglDrawElements()、glVertexAttribPointer()メソッドに対応しました。また、YV12の画像フォーマットに対応しました。






コンテントプロバイダ








Location




  • LocationManagerはシステムに管理されたWorkSourceクラスにしたがって、wake locks と wifi locksを要求するアプリケーションを追跡し、バッテリ使用量のパラメータに追加するようになりました。

  • LocationManagerに周期的または1回だけ位置情報を受け取る新しいメソッドが追加されました。







ストレージ

OBB (Opaque Binary Blob)をサポートするStorageManagerが新しく追加されました。2011年の初頭までにAndroid 2.3の開発ツールでOBBファイルを管理することができるようになる予定です。







パッケージマネージャ

PackageInfoクラスにfirstInstallTimeとlastUpdateTimeが追加されました。前者はパッケージのインストール日時で、後者は更新日時です。また、新しいgetProviderInfo()メソッドで独自のコンテントプロバイダクラスの情報も取得できるようになりました。







Telephony

TelephonyManagerにCDMA EVDO Rev BのネットワークタイプのためのNETWORK_TYPE_EVDO_Bの定数が追加されました。また、新しいgetPsc()メソッドを使用してUMTSネットワーク上のスクランブルコードを取得できるようになりました。






アクティビティ、ウインドウのライフサイクルのネイティブアクセス




  • 新しいNativeActivityクラスを使ってネイティブコードにライフサイクルのコールバックを直接実装することができるようになりました。

  • InputQueueクラスのコールバックインターフェースでネイティブコードからイベントキューを管理できるようになりました。

  • SurfaceHolder.Callback2インターフェースでネイティブコードからSurfaceHolderを管理できるようになりました。

  • Windowクラスの新しいメソッドのtakeInputQueueとtakeSurface()メソッドでネイティブコードからイベントとサーフェースを管理できるようになりました。

  • NativeActivityについてはココに詳細があります。






Dalvikランタイム








マニフェストの新しい要素と属性




  • supports-screens要素へのxlargeScreens属性の追加。超大型スクリーンをサポートするための物。

  • <activity>要素へのandroid:screenOrientation属性の値の追加。


    • reverseLandscape


      • アクティビティが通常のランドスケープモードの上下反対の画面を持つ。



    • reversePortait


      • アクティビティが通常のポートレートモードの上下反対の画面を持つ。



    • sensorLandscape


      • アクティビティがランドスケープモード画面を持つが、センサーの検知により、持っている向きに合わせて画面の向きが入れ替わる。



    • sensorPortrait


      • アクティビティがポートレートモード画面を持つが、センサーの検知により、持っている向きに合わせて画面の向きが入れ替わる。



    • fullSensor


      • アクティビティがユーザーが動かした端末の向きに合わせて画面の向きが入れ替わる。










新しいパーミッション




  • com.android.permission.SET_ALARM


    • アプリケーションからSET_ALARMのインテントをbroadcastできるようになる。



  • android.permission.USE_SIP


    • アプリケーションから、SIP APIを使ってインターネット電話を使えるようにする。



  • android.permission.NFC


    • アプリケーションから、NFC APIを使えるようにする。








新機能の定数






APIの新機能をひと通り列挙してみました。かなりの変更量でしたね。


API Level 8からの差分はココにまとまっています。


API以外にも変わっている部分があります。


引き続き、ハイライト編でお伝えします。





Android SDK 2.3(GingerBread)リリースまとめ(API編)



f:id:bs-android:20101207054850p:image


ついに待ちに待ったAndroid SDK 2.3のGingerBreadがリリースされたので、早速その新機能をまとめてみました。


今回は見た目の変更が多いという噂でしたが、そうでもなかったようです。しかし、今までにないくらい新機能が増えたように思います。


まずは2.3で追加された新APIを見ていきましょう。



Android SDK 2.3からのAPI



SIPベースのVoIP

フレームワークにSIPプロトコルスタックが搭載され、インターネット電話を扱えるようになりました。SIPのサンプルアプリケーションはココにあります。以下は実際にSipDemoを動かしてみたところ。



f:id:bs-android:20101207042542p:image:w160 f:id:bs-android:20101207042551p:image:w160 f:id:bs-android:20101207042801p:image:w160






NFC

NFC(Near Field Communications)のAPIが追加され、ハードウェアが搭載されていれば、FeliCaのように近距離通信を行うことができるようになりました。NFCのサンプルコードはココです。現時点ではまだNFCのハードウェアが搭載されたAndroid 2.3の端末がないため、試せません。エミュレータで実行すると、当然のようにExceptionが発生してしまいました。







ジャイロスコープとその他のセンサー

ジャイロスコープ、回転速度、直線加速、重力、バロメーターのセンサーが増え、センサーAPIから使用できるようになりました。センサーAPIの詳細はココです。







複数のカメラのサポート

アプリケーションから複数のカメラが利用できるようになりました。フロントカメラを利用するサンプルコードはココです。APIDemoのCameraPreviewを試してみましたが、「カメラが一個しか搭載されてないよ!」と怒られてしまいました。



f:id:bs-android:20101207043724p:image:h160






オーディオ効果のミキシング

オーディオにバスブーストやリバーブなどの様々なエフェクトを掛けることのできるAPIが追加されました。オーディオエフェクトのサンプルコードはココです。以下は実際にAPIDemoを動かしてみたところ。



f:id:bs-android:20101207041945p:image:w160






その他のメディア関連の新機能

JPEG画像のEXIF情報の中のaltitude(高度)の値が取得できるようになりました。また、ビデオ撮影中のオリエンテーション情報をsetOrientationHint()メソッドでMediaRecorderに通知することができるようになりました。







ダウンロードマネージャ

DownloadManagerが追加され、長期間動作するHTTPダウンロードをアプリケーションから要求することができるようになりました。







制限モード

StrictModeと呼ばれる制限モードが追加されました。ANRを発生させないために、UIスレッドで時間のかかる処理を使った場合に検知してくれるモードです。検知した場合はHandler、AysncTask、IntentServiceなどを使って回避するようにコードを書き換えることを推奨します。






UIフレームワーク



overscrollのサポート

限界までスクロールしても、余分にスクロールさせることができるようになりました。余分にスクロールさせる量などは制御することができます。




タッチフィルタリング

マルウェアなどから購入ボタンやパーミッション許可を与えるボタンなどを押させることがないように、タッチフィルタリングを使ってセキュリティを強化することができるようになりました。サンプルコードはココです。




イベント管理の改善

InputEventが新しく追加されました。




モーションイベントの改善

MotionEventにポインタIDが追加されました。それによって、アプリケーションから個々の指の動きを捕捉することができるようになりました。




テキスト選択コントロール

setComposingRegionメソッドにより、アプリケーションから編集中のテキスト領域を設定できるようになりました。TextViewに新しい属性も追加されました。




アクティビティの制御

ActivityInfoクラスにアクティビティの向きを管理する定数が追加されました。画面の回転に合わせてすべての向きに画面表示を合わせることが可能になったようです。




ノティファケーションのテキストとアイコンスタイル

ノティファケーションスタイルを管理する新しい属性が追加されました。




WebView

setUseWebViewBackgroundForOverscrollBackground()メソッドを使ってoverscrollの背景を指定することができるようになりました。








超大型スクリーン

タブレットデバイスなどに見られる超大型スクリーンに対応しました。超大型スクリーンの対応方法はココを参照してください。







グラフィック

OpenGL ES 2.0の残りのglDrawElements()、glVertexAttribPointer()メソッドに対応しました。また、YV12の画像フォーマットに対応しました。






コンテントプロバイダ








Location




  • LocationManagerはシステムに管理されたWorkSourceクラスにしたがって、wake locks と wifi locksを要求するアプリケーションを追跡し、バッテリ使用量のパラメータに追加するようになりました。

  • LocationManagerに周期的または1回だけ位置情報を受け取る新しいメソッドが追加されました。







ストレージ

OBB (Opaque Binary Blob)をサポートするStorageManagerが新しく追加されました。2011年の初頭までにAndroid 2.3の開発ツールでOBBファイルを管理することができるようになる予定です。







パッケージマネージャ

PackageInfoクラスにfirstInstallTimeとlastUpdateTimeが追加されました。前者はパッケージのインストール日時で、後者は更新日時です。また、新しいgetProviderInfo()メソッドで独自のコンテントプロバイダクラスの情報も取得できるようになりました。







Telephony

TelephonyManagerにCDMA EVDO Rev BのネットワークタイプのためのNETWORK_TYPE_EVDO_Bの定数が追加されました。また、新しいgetPsc()メソッドを使用してUMTSネットワーク上のスクランブルコードを取得できるようになりました。






アクティビティ、ウインドウのライフサイクルのネイティブアクセス




  • 新しいNativeActivityクラスを使ってネイティブコードにライフサイクルのコールバックを直接実装することができるようになりました。

  • InputQueueクラスのコールバックインターフェースでネイティブコードからイベントキューを管理できるようになりました。

  • SurfaceHolder.Callback2インターフェースでネイティブコードからSurfaceHolderを管理できるようになりました。

  • Windowクラスの新しいメソッドのtakeInputQueueとtakeSurface()メソッドでネイティブコードからイベントとサーフェースを管理できるようになりました。

  • NativeActivityについてはココに詳細があります。






Dalvikランタイム








マニフェストの新しい要素と属性




  • supports-screens要素へのxlargeScreens属性の追加。超大型スクリーンをサポートするための物。

  • <activity>要素へのandroid:screenOrientation属性の値の追加。


    • reverseLandscape


      • アクティビティが通常のランドスケープモードの上下反対の画面を持つ。



    • reversePortait


      • アクティビティが通常のポートレートモードの上下反対の画面を持つ。



    • sensorLandscape


      • アクティビティがランドスケープモード画面を持つが、センサーの検知により、持っている向きに合わせて画面の向きが入れ替わる。



    • sensorPortrait


      • アクティビティがポートレートモード画面を持つが、センサーの検知により、持っている向きに合わせて画面の向きが入れ替わる。



    • fullSensor


      • アクティビティがユーザーが動かした端末の向きに合わせて画面の向きが入れ替わる。










新しいパーミッション




  • com.android.permission.SET_ALARM


    • アプリケーションからSET_ALARMのインテントをbroadcastできるようになる。



  • android.permission.USE_SIP


    • アプリケーションから、SIP APIを使ってインターネット電話を使えるようにする。



  • android.permission.NFC


    • アプリケーションから、NFC APIを使えるようにする。








新機能の定数






APIの新機能をひと通り列挙してみました。かなりの変更量でしたね。


API Level 8からの差分はココにまとまっています。


API以外にも変わっている部分があります。


引き続き、ハイライト編でお伝えします。





2010年12月2日木曜日



2010年12月1日~3日までパシフィコ横浜で開催のEmbedded Technology 2010に参加してきました。





スペシャルセッションで講演しました。500人の席が満席でした。ありがとうございます。


f:id:bs-android:20101201221552j:image





「Androidアプリケーション開発を効率化するポイント」日本Androidの会/パナソニックAVCマルチメディアソフト株式会社 第5開発グループ エンジニア 日高 正博 氏


f:id:bs-android:20101201134527j:image





「3Screen + 1Cloudで激変するAndroid家電」日本Androidの会 運営委員/株式会社GClue 代表取締役社長 佐々木 陽 氏


f:id:bs-android:20101201135832j:image





「安い、タダ、Android?魂は安くない!」日本Androidの会 関西支部長/株式会社ブリリアントサービス 代表取締役 杉本 礼彦


f:id:bs-android:20101201144503j:image





ブースで出展中のAndroidで動作のRIC Android君が目を離した隙にOESFのブースのAndroidのセッションを聞きに言ってました。Androidの説明に関心していたようでした。「ヘー、アンドロイドッテソウナッテイルンダ!」と喋っていました。


f:id:bs-android:20101201163126j:image





f:id:bs-android:20101201163319j:image





ETは去年よりも出展者が多く、どこもかしこもAndroidで盛り上がっているようでした。Androidの注目度がすごいですね。





ET2010に参加して来ました



2010年12月1日~3日までパシフィコ横浜で開催のEmbedded Technology 2010に参加してきました。





スペシャルセッションで講演しました。500人の席が満席でした。ありがとうございます。


f:id:bs-android:20101201221552j:image





「Androidアプリケーション開発を効率化するポイント」日本Androidの会/パナソニックAVCマルチメディアソフト株式会社 第5開発グループ エンジニア 日高 正博 氏


f:id:bs-android:20101201134527j:image





「3Screen + 1Cloudで激変するAndroid家電」日本Androidの会 運営委員/株式会社GClue 代表取締役社長 佐々木 陽 氏


f:id:bs-android:20101201135832j:image





「安い、タダ、Android?魂は安くない!」日本Androidの会 関西支部長/株式会社ブリリアントサービス 代表取締役 杉本 礼彦


f:id:bs-android:20101201144503j:image





ブースで出展中のAndroidで動作のRIC Android君が目を離した隙にOESFのブースのAndroidのセッションを聞きに言ってました。Androidの説明に関心していたようでした。「ヘー、アンドロイドッテソウナッテイルンダ!」と喋っていました。


f:id:bs-android:20101201163126j:image





f:id:bs-android:20101201163319j:image





ETは去年よりも出展者が多く、どこもかしこもAndroidで盛り上がっているようでした。Androidの注目度がすごいですね。





2010年11月29日月曜日



f:id:bs-android:20091024120512j:image


はじめに


このエントリでは、Androidアプリという知的財産を守る方法の一つとして、難読化ツールであるProGuardを紹介し、実際にAndroidアプリに組み込む方法を示します。





ソフトウェアの価値


ソフトウェアでは処理の流れ(アルゴリズム)を記述したソースコードが大きな価値を持つため、(特に商用のソフトウェアは)ソースコードを非公開とし、コンピュータで実行可能な必要最小限の中間コードやネイティブコードに限って配布することで、ソフトウェアビジネスを成立させています。つまり、処理の流れを「隠す」ことにより、その会社(あるいは人)にしか解決できないという「情報に対する付加価値」を与え、ソフトウェアビジネスを成立させていると言えます。一方で、何らかの形でこの「隠した部分」が明らかになり白日の下に晒されると、類似したソフトウェアが流通するなど、もはや処理の流れという情報としての「価値」は失われ、ビジネスとして成立しなくなります。


さて、Androidに限らず、最近のソフトウェアは高級言語(Javaなど)を用いて記述され、翻訳(コンパイル)を通じて最終的にはコンピュータが処理可能な「中間コード」や「ネイティブコード」に変換されます。この変換は言語ごとに定められた「文法」によって翻訳されるため、その翻訳ルールさえ判れば逆翻訳(デコンパイルやデアセンブルと言います)が可能です。つまり、「中間コード」や「ネイティブコード」から逆翻訳を行い、人間が理解可能なソースコードを生成することが可能ということです。


このままでは、ちょっとした知識があればソースコードが推測されてしまいます。その為、商用ソフトなどでは難読化を行い、逆翻訳された場合でもソースコードを読みにくくするなどして、簡単に処理の流れが明らかにならないように対策しています。





難読化とは


先に記した通り、難読化とは「ソースコードを読みにくくすること」です。難読化の手法は様々ありますが、下記のような方法によって、翻訳時にソースコードを可能な限り読みにくくします。




  • クラスやメソッド、変数名を省略・無意味化

  • コメントの削除

  • 空白(行)の削除


また、翻訳時に処理パフォーマンスが良くなるように処理の最適化(繰り返し処理の簡略化、関数・メソッドのインライン化等)が行われますが、その結果、人間にとって理解が困難なコードとなることもあります。





Androidの難読化ツール


Androidのビルドプロセスにも適用可能な難読化ツールが存在します。その名も「ProGuard」。


ProGuardは、Javaのクラスファイルの圧縮・難読化・最適化・前検証を行うツールです。使われていないクラス/メソッド/変数を検知・削除したり、バイトコードを最適化したり、クラスやメソッド名を無意味化したりします。ProGuardは一般的なAndroidアプリケーション開発に用いられるEclipseではなく、CUIベースのビルドツール「Ant」に統合される形で利用できます。Antによって、Androidアプリケーションの翻訳や難読化はもちろん、アプリケーションの署名や端末へのインストールも自動化することができます。





ProGuardの概要


f:id:bs-android:20101129144703j:image


引用:http://proguard.sourceforge.net/manual/introduction.html


ProGuardは、jar/war/zip/ディレクトリなどを入力として、次の4つのステップを経て、最終的にjar/war/zip/ディレクトリへ処理結果を出力します。




  • 圧縮ステップ(shrink)

  • 最適化ステップ(optimize)

  • 難読化ステップ(obfuscate)

  • 前検証ステップ(preverify)


圧縮ステップでは、プログラム中の利用されていないクラスやメソッド等を取り除きます。このステップは再帰的に処理されるので、全てのクラス・メソッドが対象となります。


最適化ステップでは、エントリポイントではないクラスやメソッドをprivate/static/final属性に変換、使われていないパラメータは削除され、一部のメソッドはインライン化されます。


難読化ステップでは、エントリポイントではないクラスやメソッドの名前を変更します。エントリポイントとなるクラスやメソッドは、オリジナルの名前でアクセスできるようにするために変更されません。


前検証ステップでは、実行時・ロード時のバイトコードの検証負荷を減らすために、あらかじめ型情報を調査し、その情報をクラスファイル内に添付します。Android(Java6)では使用しません。


開発したプログラムは外部から提供されるライブラリを使用することがありますが、これらはProGuardの処理の対象外となります。





ProGuardの適用


それでは、以下ではAndroidのプロジェクトにProGuardを適用し、難読化&最適化を行う方法について説明しましょう。





システム要件

AndroidのプロジェクトにProGuardを適用する場合、次の条件を満たしている必要があります:




  • Android SDKがインストールされていること

  • Android SDK Toolsがインストールされていて、少なくともリビジョン7以上であること

  • Apache Ant 1.6.5以上(Linux and Mac)/1.7以上(Windows) :Eclipse付属のものを使わず、最新のAntを別途インストールすることが望ましい。


Android SDK Tools Rev.7には、プリコンパイルまたはコンパイル時のユーザー定義処理をサポートするフックを含む、Antビルドルールファイルが同梱されています。





サンプルプロジェクト

今回のサンプルは下記のような比較的シンプルな処理を含みます。ソースコード中には無意味な処理が含まれますが、ProGuardの適用状態が判るようにするためのものです。ここでは処理の内容に注目する必要はありません。


プロジェクトのホームを /HelloAndroidとします。このホームは各自の環境に合わせて読み替えてください。


HelloAndroid/src/test/hello/HelloAndroid.java



package test.hello;

import android.app.Activity;
import android.os.Bundle;

public class HelloAndroid extends Activity
{
public static final class testClass {

testClass() {
methodA(1,"str");
}

private void methodA(int i, String j) {
return;
}
}

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
testMethod1();
new testClass();
}

private void testMethod1()
{
int i,sum;
for( i = 0, sum = 0; i < 10; i++ ) {
sum += i;
}
}
}


リソースファイル等はデフォルトのものをそのまま使用します。





署名キーの用意

ProGuardには直接的に関係無いが、今回はEclipseを使用してビルド・デプロイしないため、ビルド後に自動でデプロイするために予め署名キーを生成しておくと、後が便利です。既に署名キーを用意している場合は、読み飛ばしてもらって構いません。



$ keytool -genkey -v -keystore release.keystore -alias testhello -keyalg RSA -keysize 4096 -validity 10000
キーストアのパスワードを入力してください: <パスワードを入力>
新規パスワードを再入力してください: <もう一度パスワードを入力>
姓名を入力してください。
[Unknown]: Seto Naoki
組織単位名を入力してください。
[Unknown]:
組織名を入力してください。
[Unknown]: Brilliant Service co.,Ltd.
都市名または地域名を入力してください。
[Unknown]: Tokyo
州名または地方名を入力してください。
[Unknown]:
この単位に該当する 2 文字の国番号を入力してください。
[Unknown]: jp
CN=Seto Naoki, OU=Unknown, O=Brilliant Service co.,Ltd., L=Tokyo, ST=Unknown, C=jp でよろしいですか?
[no]: yes

10,000 日間有効な 4,096 ビットの RSA の鍵ペアと自己署名型証明書 (SHA1withRSA) を生成しています
ディレクトリ名: CN=Seto Naoki, OU=Unknown, O="Brilliant Service co.,Ltd.", L=Tokyo, ST=Unknown, C=jp
<testhello> の鍵パスワードを入力してください。
(キーストアのパスワードと同じ場合は RETURN を押してください): <リターンキーを押す>
[release.keystore を格納中]





プロジェクトの更新

下記のコマンドでAntビルドできるようにプロジェクトを更新します。



cd /HelloAndroid/.. (プロジェクトホームの一つ上)
android update project --path ./HelloAndroid


更新すると下記のファイルが作成されているはずです。




  • default.properties

  • local.properties

  • build.properties

  • build.xml





ProGuard用設定ファイルの配置

下記のファイルをプロジェクトのホームに配置します。これらのファイルはオフィシャルブログからもダウンロードできます。




  • add-proguard-release.xml

  • procfg.txt


/HelloAndroid/add-progurad-release.xml




<property name="obfuscate.dir" value="obf" />
<property name="obfuscate.absolute.dir" location="${obfuscate.dir}" />
<property name="android-jar-preobfuscate" value="${obfuscate.absolute.dir}/original.jar" />
<property name="android-jar-postobfuscate" value="${obfuscate.absolute.dir}/postobf.jar" />
<property name="out.dex.input.absolute.dir" value="${android-jar-postobfuscate}" />


<target name="-post-compile" depends="-dex-obfuscate,-dex-no-obfuscate">
</target>

<target name="-dex-no-obfuscate" unless="build.mode.release">
<mkdir dir="${obfuscate.absolute.dir}" />
<jar basedir="${out.classes.dir}" destfile="${android-jar-postobfuscate}" />
</target>


<target name="-dex-obfuscate" if="build.mode.release">
<property name="proguard-jar" value="${proguard.dir}/proguard.jar" />
<property name="proguard-conf.dir" value="" />
<property name="proguard-conf.absolute.dir" location="${proguard-conf.dir}" />
<property name="proguard-conf" value="${proguard-conf.absolute.dir}/procfg.txt" />
<path id="fullclasspath">
<path refid="android.target.classpath"/>
<pathelement path="${external.libs.dir}"/>
</path>
<property name="libraryjarpath" refid="fullclasspath"/>


<taskdef resource="proguard/ant/task.properties" classpath="${proguard-jar}" />

<mkdir dir="${obfuscate.absolute.dir}" />
<delete file="${android-jar-preobfuscate}"/>
<delete file="${android-jar-postobfuscate}"/>
<jar basedir="${out.classes.dir}" destfile="${android-jar-preobfuscate}" />
<proguard>
@${proguard-conf}
-injars ${android-jar-preobfuscate}
-outjars ${android-jar-postobfuscate}
-libraryjars ${libraryjarpath}
-dump ${obfuscate.absolute.dir}/dump.txt
-printseeds ${obfuscate.absolute.dir}/seeds.txt
-printusage ${obfuscate.absolute.dir}/usage.txt
-printmapping ${obfuscate.absolute.dir}/mapping.txt
</proguard>
</target>


このファイルでは、AntでProGuardを使用する際のパラメータ(出力先ディレクトリなど)の定義、ant_rules_r3で定義されるAntのプリコンパイルルールの書き換え、Ant用ProGuardタスクの追加の定義などを行います。


/HelloAndroid/procfg.txt



-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class com.android.vending.licensing.ILicensingService

-keepclasseswithmembernames class * {
native <methods>;
}

-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}

-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}


ここでは最適化の設定や難読化をしない設定(-keep*)を行っています。ビルドエラーが発生する場合、設定を変更する必要があります。この辺りのテクニックは以下のサイトが参考になります。


http://d.hatena.ne.jp/hyoromo/20101120/1290216449





ビルド設定ファイルの修正

build.propertiesとbuild.xmlを改修してProGuardに対応させます。


/HelloAndroid/build.properties


標準の設定ファイルに、下記の設定を追加します。




  • 自動デプロイのオプション設定(12~16行目)

  • 自動署名の設定(18~26行目)

  • ProGuardの有効化(33行目)



01 : # This file is used to override default values used by the Ant build system.
02 : #
03 : # This file must be checked in Version Control Systems, as it is
04 : # integral to the build system of your project.
05 :
06 : # This file is only used by the Ant script.
07 :
08 : # You can use this to override default values such as
09 : # 'source.dir' for the location of your java source folder and
10 : # 'out.dir' for the location of your output folder.
11 :
12 : #-d:device/-e:emulator
13 : adb.device.arg=
14 :
15 : #adb install <option>
16 : adb.install.option=-r
17 :
18 : # You can also use it define how the release builds are signed by declaring
19 : # the following properties:
20 : # 'key.store' for the location of your keystore and
21 : # 'key.alias' for the name of the key to use.
22 : # The password will be asked during the build when you use the 'release' target.
23 : key.store=<キーストアのファイルパス(ファイル名含む)>
24 : key.store.password=<キーストアのパスワード>
25 : key.alias=<キー生成時に指定したエイリアス>
26 : key.alias.password=<エイリアスのパスワード>
27 :
28 : # The name of your application package as defined in the manifest.
29 : # Used by the 'uninstall' rule.
30 : application.package=test.hello
31 :
32 : # For ProGuard
33 : proguard.dir=<ProGuardのlibディレクトリまでのパス>


proguard.dirは<ProGuardのインストール先>\libを指定する必要があります。





/HelloAndroid/build.xml


標準の設定ファイルに、下記の設定を追加します。




  • ProGuard用設定XMLファイルの読み込み(2~6行目)

  • アプリケーションへの自動署名とデプロイタスクの定義(88~103行目)



01 : <?xml version="1.0" encoding="UTF-8"?>
02 : <!DOCTYPE project [
03 : <!ENTITY add-proguard-release SYSTEM "add-proguard-release.xml">
04 : ]>
05 : <project name="HelloAndroid" default="help">
06 : &add-proguard-release;
07 :
08 :
12 : <property file="local.properties" />
13 :
14 :
31 : <property file="build.properties" />
32 :
33 :
37 : <property file="default.properties" />
38 :
39 :
42 : <path id="android.antlibs">
43 : <pathelement path="${sdk.dir}/tools/lib/anttasks.jar" />
44 : <pathelement path="${sdk.dir}/tools/lib/sdklib.jar" />
45 : <pathelement path="${sdk.dir}/tools/lib/androidprefs.jar" />
46 : </path>
47 :
48 : <taskdef name="setup"
49 : classname="com.android.ant.SetupTask"
50 : classpathref="android.antlibs" />
51 :
52 :
54 :
66 :
67 :
68 :
86 : <setup />
87 :
88 :
89 : <macrodef name="install-release-helper">
90 : <sequential>
91 : <echo>Installing ${out.release.file}...</echo>
92 : <exec executable="${adb}" failonerror="true">
93 : <arg line="${adb.device.arg}" />
94 : <arg value="install" />
95 : <arg value="${adb.install.option}" />
96 : <arg path="${out.release.file}" />
97 : </exec>
98 : </sequential>
99 : </macrodef>
101:
101: <target name="deploy" depends="release">
102: <install-release-helper />
103: </target>
104:
105:</project>





ProGuardの適用(ビルド)とデプロイ

ビルドとデプロイは簡単です。アプリを配置したいデバイスを接続し(または、abdコマンドでシミュレータ上にデバイスを作成しておいて)、下記のコマンドを実行します。



$ ant deploy


これまでに示した定義ファイルの記述が正しければ、ProGuardが適用された状態でビルドされ、アプリへの自動署名が行われて端末にアプリがインストールされます。



Buildfile: C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\build.xml
[setup] Android SDK Tools Revision 7
[setup] Project Target: Google APIs
[setup] Vendor: Google Inc.
[setup] Platform Version: 1.5
[setup] API level: 3
[setup]
[setup] ------------------
[setup] Resolving library dependencies:
[setup] ------------------
[setup] Ordered libraries:
[setup] ------------------
[setup]
[setup] WARNING: No minSdkVersion value set. Application will install on all Android versions.
[setup]
[setup] Importing rules file: tools\ant\ant_rules_r3.xml

-set-release-mode:

-dirs:
[echo] Creating output directories if needed...
[mkdir] Created dir: C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\bin
[mkdir] Created dir: C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\gen
[mkdir] Created dir: C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\bin\classes

-pre-build:

-resource-src:
[echo] Generating R.java / Manifest.java from the resources...

-aidl:
[echo] Compiling aidl files into Java classes...

-pre-compile:

compile:
[javac] C:\android-sdk-windows\tools\ant\ant_rules_r3.xml:336: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
[javac] Compiling 2 source files to C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\bin\classes

-dex-obfuscate:
[mkdir] Created dir: C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\obf
[jar] Building jar: C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\obf\original.jar
[proguard] ProGuard, version 4.5.1
[proguard] Reading input...
[proguard] Reading program jar [C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\obf\original.jar]
[proguard] Reading library jar [C:\android-sdk-windows\platforms\android-3\android.jar]
[proguard] Reading library jar [C:\android-sdk-windows\add-ons\addon_google_apis_google_inc_3\libs\maps.jar]
[proguard] Reading library directory [C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\libs]
[proguard] Initializing...
[proguard] Note: the configuration refers to the unknown class 'com.android.vending.licensing.ILicensingService'
[proguard] Note: there were 1 references to unknown classes.
[proguard] You should check your configuration for typos.
[proguard] Ignoring unused library classes...
[proguard] Original number of library classes: 2398
[proguard] Final number of library classes: 92
[proguard] Printing kept classes, fields, and methods...
[proguard] Shrinking...
[proguard] Printing usage to [C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\obf\usage.txt]...
[proguard] Removing unused program classes and class elements...
[proguard] Original number of program classes: 6
[proguard] Final number of program classes: 2
[proguard] Optimizing...
[proguard] Number of finalized classes: 0
[proguard] Number of vertically merged classes: 0 (disabled)
[proguard] Number of horizontally merged classes: 0 (disabled)
[proguard] Number of removed write-only fields: 0 (disabled)
[proguard] Number of privatized fields: 0 (disabled)
[proguard] Number of inlined constant fields: 0 (disabled)
[proguard] Number of privatized methods: 0
[proguard] Number of staticized methods: 2
[proguard] Number of finalized methods: 0
[proguard] Number of removed method parameters: 2
[proguard] Number of inlined constant parameters: 1
[proguard] Number of inlined constant return values: 0
[proguard] Number of inlined short method calls: 0
[proguard] Number of inlined unique method calls: 0
[proguard] Number of inlined tail recursion calls: 0
[proguard] Number of merged code blocks: 0
[proguard] Number of variable peephole optimizations: 0
[proguard] Number of arithmetic peephole optimizations: 0 (disabled)
[proguard] Number of cast peephole optimizations: 0
[proguard] Number of field peephole optimizations: 0
[proguard] Number of branch peephole optimizations: 0
[proguard] Number of simplified instructions: 0
[proguard] Number of removed instructions: 21
[proguard] Number of removed local variables: 0
[proguard] Number of removed exception blocks: 0
[proguard] Number of optimized local variable frames: 0
[proguard] Shrinking...
[proguard] Removing unused program classes and class elements...
[proguard] Original number of program classes: 2
[proguard] Final number of program classes: 2
[proguard] Optimizing...
[proguard] Number of finalized classes: 0
[proguard] Number of vertically merged classes: 0 (disabled)
[proguard] Number of horizontally merged classes: 0 (disabled)
[proguard] Number of removed write-only fields: 0 (disabled)
[proguard] Number of privatized fields: 0 (disabled)
[proguard] Number of inlined constant fields: 0 (disabled)
[proguard] Number of privatized methods: 0
[proguard] Number of staticized methods: 0
[proguard] Number of finalized methods: 0
[proguard] Number of removed method parameters: 0
[proguard] Number of inlined constant parameters: 0
[proguard] Number of inlined constant return values: 0
[proguard] Number of inlined short method calls: 0
[proguard] Number of inlined unique method calls: 0
[proguard] Number of inlined tail recursion calls: 0
[proguard] Number of merged code blocks: 0
[proguard] Number of variable peephole optimizations: 0
[proguard] Number of arithmetic peephole optimizations: 0 (disabled)
[proguard] Number of cast peephole optimizations: 0
[proguard] Number of field peephole optimizations: 0
[proguard] Number of branch peephole optimizations: 0
[proguard] Number of simplified instructions: 0
[proguard] Number of removed instructions: 0
[proguard] Number of removed local variables: 0
[proguard] Number of removed exception blocks: 0
[proguard] Number of optimized local variable frames: 0
[proguard] Obfuscating...
[proguard] Printing mapping to [C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\obf\mapping.txt]...
[proguard] Writing output...
[proguard] Preparing output jar [C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\obf\postobf.jar]
[proguard] Copying resources from program jar [C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\obf\original.jar]
[proguard] Printing classes to [C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\obf\dump.txt]...

-dex-no-obfuscate:

-post-compile:

-dex:
[echo] Converting compiled files and external libraries into C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\bin\classes.dex...

-package-resources:
[echo] Packaging resources
[aapt] Creating full resource package...

-package-release:
[apkbuilder] Creating HelloAndroid-unsigned.apk for release...

-release-prompt-for-password:

-release-nosign:

release:
[echo] Signing final apk...
[signjar] Signing JAR: C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\bin\HelloAndroid-unsigned.apk to C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\bin\HelloAndroid-unaligned.apk as ky
[signjar] キーストアのパスワードを入力してください:
[echo] Running zip align on final apk...
[echo] Release Package: C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\bin\HelloAndroid-release.apk

deploy:
[echo] Installing C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\bin\HelloAndroid-release.apk...
[exec] pkg: /data/local/tmp/HelloAndroid-release.apk
[exec] Success
[exec] 72 KB/s (4211 bytes in 0.057s)

BUILD SUCCESSFUL
Total time: 8 seconds


-dex-obfuscate:のフェーズで[proguard]のログが出力されていれば、ProGuardが適用されています。ログを詳しく見ると、下記のように圧縮、最適化、難読化が行われていることが分かります。




  • [proguard] Shrinking...

  • [proguard] Optimizing...

  • [proguard] Obfuscating...





ProGuard適用前と適用後を比較してみる


実際にProGuardの処理結果を比較して確認してみましょう。





apktoolによるデコンパイル

リエンジニアリングツールであるandroid-apktoolを使って、.apkファイルをデコンパイルし、アプリ内のクラス構成や処理内容を可視化します。





apktoolのシステム要件



  • JRE 1.6 (Java Runtime Environment)

  • 実行パスにaaptコマンドが設定されていること





apktoolのダウンロード

apktoolのダウンロードページから、OSに対応したファイルをダウンロードして下さい。





apktoolのインストール



  1. apktool-install-windows-* ファイルのダウンロード(Windowsの場合)

  2. apktool-* ファイルのダウンロード

  3. 以上の2つのファイルを適当なディレクトリに展開します。





デコンパイルの実行


$ cd <プロジェクトディレクトリ>/bin/
$ apktool d HelloAndroid-release.apk


デコンパイルの結果、HelloAndroid-release.apkのディレクトリ以下に、HelloAndroid-releaseディレクトリが生成され、下記のようなファイルが生成されます。




  • AndroidManifest.xml:アプリのマニフェストファイル

  • apktool.yml:apktoolの処理結果

  • resディレクトリ:アプリに含まれるリソースファイル

  • smaliディレクトリ:アプリの処理手順の解析結果





smaliファイルの比較

最適化や難読化がなされているかどうかは、smaliディレクトリをProGuardを適用しない場合と適用した場合とで見比べてみることで判ります。


ProGuard適用前


ファイル構成:




  • HelloAndroid.smali

  • HelloAndroid$testClass.smali

  • R.smali

  • R$attr.smali

  • R$layout.smali

  • R$string.smali


HelloAndroid.smaliの内容:



.class public Ltest/hello/HelloAndroid;
.super Landroid/app/Activity;
.source "HelloAndroid.java"

# annotations
.annotation system Ldalvik/annotation/MemberClasses;
value = {
Ltest/hello/HelloAndroid$testClass;
}
.end annotation

# direct methods
.method public constructor <init>()V
.locals 0

.prologue
.line 6
invoke-direct {p0}, Landroid/app/Activity;-><init>()V

.line 8
return-void
.end method

.method private testMethod1()V
.locals 3

.prologue
.line 32
const/4 v0, 0x0

.local v0, i:I
const/4 v1, 0x0

.local v1, sum:I
const/16 v2, 0xa

if-ge v0, v2, :cond_0

.line 33
add-int/2addr v1, v0

.line 32
add-int/lit8 v0, v0, 0x1

goto :goto_0

.line 35
return-void
.end method

# virtual methods
.method public onCreate(Landroid/os/Bundle;)V
.locals 1
.parameter "savedInstanceState"

.prologue
.line 23
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V

.line 24
const/high16 v0, 0x7f02

invoke-virtual {p0, v0}, Ltest/hello/HelloAndroid;->setContentView(I)V

.line 25
invoke-direct {p0}, Ltest/hello/HelloAndroid;->testMethod1()V

.line 26
new-instance v0, Ltest/hello/HelloAndroid$testClass;

invoke-direct {v0}, Ltest/hello/HelloAndroid$testClass;-><init>()V

.line 27
return-void
.end method


ProGuard適用しない場合、アプリのファイル構成がそのまま解析結果として出力され、クラス・メソッドの構成、コールシーケンスが丸見えになります。また、内部で使用しているクラス(内部クラスを含む)やメソッド名も判るため、何の処理をしているのかが予測しやすい状態です。





ProGuard適用後


ファイル構成:




  • a.smali

  • HelloAndroid.smali


HelloAndroid.smaliの内容:



.class public Ltest/hello/HelloAndroid;
.super Landroid/app/Activity;

# direct methods
.method public constructor <init>()V
.locals 0

invoke-direct {p0}, Landroid/app/Activity;-><init>()V

return-void
.end method

# virtual methods
.method public onCreate(Landroid/os/Bundle;)V
.locals 1

invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V

const/high16 v0, 0x7f02

invoke-virtual {p0, v0}, Ltest/hello/HelloAndroid;->setContentView(I)V

new-instance v0, Ltest/hello/a;

invoke-direct {v0}, Ltest/hello/a;-><init>()V

return-void
.end method


a.smaliの内容:



.class final Ltest/hello/a;
.super Ljava/lang/Object;

# direct methods
.method constructor <init>()V
.locals 0

invoke-direct {p0}, Ljava/lang/Object;-><init>()V

return-void
.end method


ProGuardを適用すると、ファイル構成は「エントリポイントとなるクラスファイル」と「難読化されたクラスファイル」だけとなっており、実際のファイル構成とは異なっています。また、クラスやメソッドの解析に失敗しており、この結果から処理を予測することが難しくなっています。





まとめ


以上のようにProGuardを利用すると簡単な手順で実効性のある難読化を行い、Androidのアプリという知的財産を守ることができます。一方で、JNI経由でネイティブメソッドなどを利用している場合、ProGuardでのビルドに失敗するなど、適用に関わる工数が著しく増大することがあります(いわゆる「ハマる」可能性があるということ)。とはいえ、アプリ中のアルゴリズムや手順、利用している技術が特殊であればあるほど、ProGuardを適用する意味は大きいでしょう。何らかの形でアプリ中の知的財産を守る必要がある場合は、ProGuardの利用を検討してみてはいかがでしょうか。


文責:技術部 植物工場研究G 瀬戸 直喜





Androidとセキュリティ:プログラム難読化ツール - ProGuard



f:id:bs-android:20091024120512j:image


はじめに


このエントリでは、Androidアプリという知的財産を守る方法の一つとして、難読化ツールであるProGuardを紹介し、実際にAndroidアプリに組み込む方法を示します。





ソフトウェアの価値


ソフトウェアでは処理の流れ(アルゴリズム)を記述したソースコードが大きな価値を持つため、(特に商用のソフトウェアは)ソースコードを非公開とし、コンピュータで実行可能な必要最小限の中間コードやネイティブコードに限って配布することで、ソフトウェアビジネスを成立させています。つまり、処理の流れを「隠す」ことにより、その会社(あるいは人)にしか解決できないという「情報に対する付加価値」を与え、ソフトウェアビジネスを成立させていると言えます。一方で、何らかの形でこの「隠した部分」が明らかになり白日の下に晒されると、類似したソフトウェアが流通するなど、もはや処理の流れという情報としての「価値」は失われ、ビジネスとして成立しなくなります。


さて、Androidに限らず、最近のソフトウェアは高級言語(Javaなど)を用いて記述され、翻訳(コンパイル)を通じて最終的にはコンピュータが処理可能な「中間コード」や「ネイティブコード」に変換されます。この変換は言語ごとに定められた「文法」によって翻訳されるため、その翻訳ルールさえ判れば逆翻訳(デコンパイルやデアセンブルと言います)が可能です。つまり、「中間コード」や「ネイティブコード」から逆翻訳を行い、人間が理解可能なソースコードを生成することが可能ということです。


このままでは、ちょっとした知識があればソースコードが推測されてしまいます。その為、商用ソフトなどでは難読化を行い、逆翻訳された場合でもソースコードを読みにくくするなどして、簡単に処理の流れが明らかにならないように対策しています。





難読化とは


先に記した通り、難読化とは「ソースコードを読みにくくすること」です。難読化の手法は様々ありますが、下記のような方法によって、翻訳時にソースコードを可能な限り読みにくくします。




  • クラスやメソッド、変数名を省略・無意味化

  • コメントの削除

  • 空白(行)の削除


また、翻訳時に処理パフォーマンスが良くなるように処理の最適化(繰り返し処理の簡略化、関数・メソッドのインライン化等)が行われますが、その結果、人間にとって理解が困難なコードとなることもあります。





Androidの難読化ツール


Androidのビルドプロセスにも適用可能な難読化ツールが存在します。その名も「ProGuard」。


ProGuardは、Javaのクラスファイルの圧縮・難読化・最適化・前検証を行うツールです。使われていないクラス/メソッド/変数を検知・削除したり、バイトコードを最適化したり、クラスやメソッド名を無意味化したりします。ProGuardは一般的なAndroidアプリケーション開発に用いられるEclipseではなく、CUIベースのビルドツール「Ant」に統合される形で利用できます。Antによって、Androidアプリケーションの翻訳や難読化はもちろん、アプリケーションの署名や端末へのインストールも自動化することができます。





ProGuardの概要


f:id:bs-android:20101129144703j:image


引用:http://proguard.sourceforge.net/manual/introduction.html


ProGuardは、jar/war/zip/ディレクトリなどを入力として、次の4つのステップを経て、最終的にjar/war/zip/ディレクトリへ処理結果を出力します。




  • 圧縮ステップ(shrink)

  • 最適化ステップ(optimize)

  • 難読化ステップ(obfuscate)

  • 前検証ステップ(preverify)


圧縮ステップでは、プログラム中の利用されていないクラスやメソッド等を取り除きます。このステップは再帰的に処理されるので、全てのクラス・メソッドが対象となります。


最適化ステップでは、エントリポイントではないクラスやメソッドをprivate/static/final属性に変換、使われていないパラメータは削除され、一部のメソッドはインライン化されます。


難読化ステップでは、エントリポイントではないクラスやメソッドの名前を変更します。エントリポイントとなるクラスやメソッドは、オリジナルの名前でアクセスできるようにするために変更されません。


前検証ステップでは、実行時・ロード時のバイトコードの検証負荷を減らすために、あらかじめ型情報を調査し、その情報をクラスファイル内に添付します。Android(Java6)では使用しません。


開発したプログラムは外部から提供されるライブラリを使用することがありますが、これらはProGuardの処理の対象外となります。





ProGuardの適用


それでは、以下ではAndroidのプロジェクトにProGuardを適用し、難読化&最適化を行う方法について説明しましょう。





システム要件

AndroidのプロジェクトにProGuardを適用する場合、次の条件を満たしている必要があります:




  • Android SDKがインストールされていること

  • Android SDK Toolsがインストールされていて、少なくともリビジョン7以上であること

  • Apache Ant 1.6.5以上(Linux and Mac)/1.7以上(Windows) :Eclipse付属のものを使わず、最新のAntを別途インストールすることが望ましい。


Android SDK Tools Rev.7には、プリコンパイルまたはコンパイル時のユーザー定義処理をサポートするフックを含む、Antビルドルールファイルが同梱されています。





サンプルプロジェクト

今回のサンプルは下記のような比較的シンプルな処理を含みます。ソースコード中には無意味な処理が含まれますが、ProGuardの適用状態が判るようにするためのものです。ここでは処理の内容に注目する必要はありません。


プロジェクトのホームを /HelloAndroidとします。このホームは各自の環境に合わせて読み替えてください。


HelloAndroid/src/test/hello/HelloAndroid.java



package test.hello;

import android.app.Activity;
import android.os.Bundle;

public class HelloAndroid extends Activity
{
public static final class testClass {

testClass() {
methodA(1,"str");
}

private void methodA(int i, String j) {
return;
}
}

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
testMethod1();
new testClass();
}

private void testMethod1()
{
int i,sum;
for( i = 0, sum = 0; i < 10; i++ ) {
sum += i;
}
}
}


リソースファイル等はデフォルトのものをそのまま使用します。





署名キーの用意

ProGuardには直接的に関係無いが、今回はEclipseを使用してビルド・デプロイしないため、ビルド後に自動でデプロイするために予め署名キーを生成しておくと、後が便利です。既に署名キーを用意している場合は、読み飛ばしてもらって構いません。



$ keytool -genkey -v -keystore release.keystore -alias testhello -keyalg RSA -keysize 4096 -validity 10000
キーストアのパスワードを入力してください: <パスワードを入力>
新規パスワードを再入力してください: <もう一度パスワードを入力>
姓名を入力してください。
[Unknown]: Seto Naoki
組織単位名を入力してください。
[Unknown]:
組織名を入力してください。
[Unknown]: Brilliant Service co.,Ltd.
都市名または地域名を入力してください。
[Unknown]: Tokyo
州名または地方名を入力してください。
[Unknown]:
この単位に該当する 2 文字の国番号を入力してください。
[Unknown]: jp
CN=Seto Naoki, OU=Unknown, O=Brilliant Service co.,Ltd., L=Tokyo, ST=Unknown, C=jp でよろしいですか?
[no]: yes

10,000 日間有効な 4,096 ビットの RSA の鍵ペアと自己署名型証明書 (SHA1withRSA) を生成しています
ディレクトリ名: CN=Seto Naoki, OU=Unknown, O="Brilliant Service co.,Ltd.", L=Tokyo, ST=Unknown, C=jp
<testhello> の鍵パスワードを入力してください。
(キーストアのパスワードと同じ場合は RETURN を押してください): <リターンキーを押す>
[release.keystore を格納中]





プロジェクトの更新

下記のコマンドでAntビルドできるようにプロジェクトを更新します。



cd /HelloAndroid/.. (プロジェクトホームの一つ上)
android update project --path ./HelloAndroid


更新すると下記のファイルが作成されているはずです。




  • default.properties

  • local.properties

  • build.properties

  • build.xml





ProGuard用設定ファイルの配置

下記のファイルをプロジェクトのホームに配置します。これらのファイルはオフィシャルブログからもダウンロードできます。




  • add-proguard-release.xml

  • procfg.txt


/HelloAndroid/add-progurad-release.xml




<property name="obfuscate.dir" value="obf" />
<property name="obfuscate.absolute.dir" location="${obfuscate.dir}" />
<property name="android-jar-preobfuscate" value="${obfuscate.absolute.dir}/original.jar" />
<property name="android-jar-postobfuscate" value="${obfuscate.absolute.dir}/postobf.jar" />
<property name="out.dex.input.absolute.dir" value="${android-jar-postobfuscate}" />


<target name="-post-compile" depends="-dex-obfuscate,-dex-no-obfuscate">
</target>

<target name="-dex-no-obfuscate" unless="build.mode.release">
<mkdir dir="${obfuscate.absolute.dir}" />
<jar basedir="${out.classes.dir}" destfile="${android-jar-postobfuscate}" />
</target>


<target name="-dex-obfuscate" if="build.mode.release">
<property name="proguard-jar" value="${proguard.dir}/proguard.jar" />
<property name="proguard-conf.dir" value="" />
<property name="proguard-conf.absolute.dir" location="${proguard-conf.dir}" />
<property name="proguard-conf" value="${proguard-conf.absolute.dir}/procfg.txt" />
<path id="fullclasspath">
<path refid="android.target.classpath"/>
<pathelement path="${external.libs.dir}"/>
</path>
<property name="libraryjarpath" refid="fullclasspath"/>


<taskdef resource="proguard/ant/task.properties" classpath="${proguard-jar}" />

<mkdir dir="${obfuscate.absolute.dir}" />
<delete file="${android-jar-preobfuscate}"/>
<delete file="${android-jar-postobfuscate}"/>
<jar basedir="${out.classes.dir}" destfile="${android-jar-preobfuscate}" />
<proguard>
@${proguard-conf}
-injars ${android-jar-preobfuscate}
-outjars ${android-jar-postobfuscate}
-libraryjars ${libraryjarpath}
-dump ${obfuscate.absolute.dir}/dump.txt
-printseeds ${obfuscate.absolute.dir}/seeds.txt
-printusage ${obfuscate.absolute.dir}/usage.txt
-printmapping ${obfuscate.absolute.dir}/mapping.txt
</proguard>
</target>


このファイルでは、AntでProGuardを使用する際のパラメータ(出力先ディレクトリなど)の定義、ant_rules_r3で定義されるAntのプリコンパイルルールの書き換え、Ant用ProGuardタスクの追加の定義などを行います。


/HelloAndroid/procfg.txt



-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class com.android.vending.licensing.ILicensingService

-keepclasseswithmembernames class * {
native <methods>;
}

-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}

-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}


ここでは最適化の設定や難読化をしない設定(-keep*)を行っています。ビルドエラーが発生する場合、設定を変更する必要があります。この辺りのテクニックは以下のサイトが参考になります。


http://d.hatena.ne.jp/hyoromo/20101120/1290216449





ビルド設定ファイルの修正

build.propertiesとbuild.xmlを改修してProGuardに対応させます。


/HelloAndroid/build.properties


標準の設定ファイルに、下記の設定を追加します。




  • 自動デプロイのオプション設定(12~16行目)

  • 自動署名の設定(18~26行目)

  • ProGuardの有効化(33行目)



01 : # This file is used to override default values used by the Ant build system.
02 : #
03 : # This file must be checked in Version Control Systems, as it is
04 : # integral to the build system of your project.
05 :
06 : # This file is only used by the Ant script.
07 :
08 : # You can use this to override default values such as
09 : # 'source.dir' for the location of your java source folder and
10 : # 'out.dir' for the location of your output folder.
11 :
12 : #-d:device/-e:emulator
13 : adb.device.arg=
14 :
15 : #adb install <option>
16 : adb.install.option=-r
17 :
18 : # You can also use it define how the release builds are signed by declaring
19 : # the following properties:
20 : # 'key.store' for the location of your keystore and
21 : # 'key.alias' for the name of the key to use.
22 : # The password will be asked during the build when you use the 'release' target.
23 : key.store=<キーストアのファイルパス(ファイル名含む)>
24 : key.store.password=<キーストアのパスワード>
25 : key.alias=<キー生成時に指定したエイリアス>
26 : key.alias.password=<エイリアスのパスワード>
27 :
28 : # The name of your application package as defined in the manifest.
29 : # Used by the 'uninstall' rule.
30 : application.package=test.hello
31 :
32 : # For ProGuard
33 : proguard.dir=<ProGuardのlibディレクトリまでのパス>


proguard.dirは<ProGuardのインストール先>\libを指定する必要があります。





/HelloAndroid/build.xml


標準の設定ファイルに、下記の設定を追加します。




  • ProGuard用設定XMLファイルの読み込み(2~6行目)

  • アプリケーションへの自動署名とデプロイタスクの定義(88~103行目)



01 : <?xml version="1.0" encoding="UTF-8"?>
02 : <!DOCTYPE project [
03 : <!ENTITY add-proguard-release SYSTEM "add-proguard-release.xml">
04 : ]>
05 : <project name="HelloAndroid" default="help">
06 : &add-proguard-release;
07 :
08 :
12 : <property file="local.properties" />
13 :
14 :
31 : <property file="build.properties" />
32 :
33 :
37 : <property file="default.properties" />
38 :
39 :
42 : <path id="android.antlibs">
43 : <pathelement path="${sdk.dir}/tools/lib/anttasks.jar" />
44 : <pathelement path="${sdk.dir}/tools/lib/sdklib.jar" />
45 : <pathelement path="${sdk.dir}/tools/lib/androidprefs.jar" />
46 : </path>
47 :
48 : <taskdef name="setup"
49 : classname="com.android.ant.SetupTask"
50 : classpathref="android.antlibs" />
51 :
52 :
54 :
66 :
67 :
68 :
86 : <setup />
87 :
88 :
89 : <macrodef name="install-release-helper">
90 : <sequential>
91 : <echo>Installing ${out.release.file}...</echo>
92 : <exec executable="${adb}" failonerror="true">
93 : <arg line="${adb.device.arg}" />
94 : <arg value="install" />
95 : <arg value="${adb.install.option}" />
96 : <arg path="${out.release.file}" />
97 : </exec>
98 : </sequential>
99 : </macrodef>
101:
101: <target name="deploy" depends="release">
102: <install-release-helper />
103: </target>
104:
105:</project>





ProGuardの適用(ビルド)とデプロイ

ビルドとデプロイは簡単です。アプリを配置したいデバイスを接続し(または、abdコマンドでシミュレータ上にデバイスを作成しておいて)、下記のコマンドを実行します。



$ ant deploy


これまでに示した定義ファイルの記述が正しければ、ProGuardが適用された状態でビルドされ、アプリへの自動署名が行われて端末にアプリがインストールされます。



Buildfile: C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\build.xml
[setup] Android SDK Tools Revision 7
[setup] Project Target: Google APIs
[setup] Vendor: Google Inc.
[setup] Platform Version: 1.5
[setup] API level: 3
[setup]
[setup] ------------------
[setup] Resolving library dependencies:
[setup] ------------------
[setup] Ordered libraries:
[setup] ------------------
[setup]
[setup] WARNING: No minSdkVersion value set. Application will install on all Android versions.
[setup]
[setup] Importing rules file: tools\ant\ant_rules_r3.xml

-set-release-mode:

-dirs:
[echo] Creating output directories if needed...
[mkdir] Created dir: C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\bin
[mkdir] Created dir: C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\gen
[mkdir] Created dir: C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\bin\classes

-pre-build:

-resource-src:
[echo] Generating R.java / Manifest.java from the resources...

-aidl:
[echo] Compiling aidl files into Java classes...

-pre-compile:

compile:
[javac] C:\android-sdk-windows\tools\ant\ant_rules_r3.xml:336: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
[javac] Compiling 2 source files to C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\bin\classes

-dex-obfuscate:
[mkdir] Created dir: C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\obf
[jar] Building jar: C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\obf\original.jar
[proguard] ProGuard, version 4.5.1
[proguard] Reading input...
[proguard] Reading program jar [C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\obf\original.jar]
[proguard] Reading library jar [C:\android-sdk-windows\platforms\android-3\android.jar]
[proguard] Reading library jar [C:\android-sdk-windows\add-ons\addon_google_apis_google_inc_3\libs\maps.jar]
[proguard] Reading library directory [C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\libs]
[proguard] Initializing...
[proguard] Note: the configuration refers to the unknown class 'com.android.vending.licensing.ILicensingService'
[proguard] Note: there were 1 references to unknown classes.
[proguard] You should check your configuration for typos.
[proguard] Ignoring unused library classes...
[proguard] Original number of library classes: 2398
[proguard] Final number of library classes: 92
[proguard] Printing kept classes, fields, and methods...
[proguard] Shrinking...
[proguard] Printing usage to [C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\obf\usage.txt]...
[proguard] Removing unused program classes and class elements...
[proguard] Original number of program classes: 6
[proguard] Final number of program classes: 2
[proguard] Optimizing...
[proguard] Number of finalized classes: 0
[proguard] Number of vertically merged classes: 0 (disabled)
[proguard] Number of horizontally merged classes: 0 (disabled)
[proguard] Number of removed write-only fields: 0 (disabled)
[proguard] Number of privatized fields: 0 (disabled)
[proguard] Number of inlined constant fields: 0 (disabled)
[proguard] Number of privatized methods: 0
[proguard] Number of staticized methods: 2
[proguard] Number of finalized methods: 0
[proguard] Number of removed method parameters: 2
[proguard] Number of inlined constant parameters: 1
[proguard] Number of inlined constant return values: 0
[proguard] Number of inlined short method calls: 0
[proguard] Number of inlined unique method calls: 0
[proguard] Number of inlined tail recursion calls: 0
[proguard] Number of merged code blocks: 0
[proguard] Number of variable peephole optimizations: 0
[proguard] Number of arithmetic peephole optimizations: 0 (disabled)
[proguard] Number of cast peephole optimizations: 0
[proguard] Number of field peephole optimizations: 0
[proguard] Number of branch peephole optimizations: 0
[proguard] Number of simplified instructions: 0
[proguard] Number of removed instructions: 21
[proguard] Number of removed local variables: 0
[proguard] Number of removed exception blocks: 0
[proguard] Number of optimized local variable frames: 0
[proguard] Shrinking...
[proguard] Removing unused program classes and class elements...
[proguard] Original number of program classes: 2
[proguard] Final number of program classes: 2
[proguard] Optimizing...
[proguard] Number of finalized classes: 0
[proguard] Number of vertically merged classes: 0 (disabled)
[proguard] Number of horizontally merged classes: 0 (disabled)
[proguard] Number of removed write-only fields: 0 (disabled)
[proguard] Number of privatized fields: 0 (disabled)
[proguard] Number of inlined constant fields: 0 (disabled)
[proguard] Number of privatized methods: 0
[proguard] Number of staticized methods: 0
[proguard] Number of finalized methods: 0
[proguard] Number of removed method parameters: 0
[proguard] Number of inlined constant parameters: 0
[proguard] Number of inlined constant return values: 0
[proguard] Number of inlined short method calls: 0
[proguard] Number of inlined unique method calls: 0
[proguard] Number of inlined tail recursion calls: 0
[proguard] Number of merged code blocks: 0
[proguard] Number of variable peephole optimizations: 0
[proguard] Number of arithmetic peephole optimizations: 0 (disabled)
[proguard] Number of cast peephole optimizations: 0
[proguard] Number of field peephole optimizations: 0
[proguard] Number of branch peephole optimizations: 0
[proguard] Number of simplified instructions: 0
[proguard] Number of removed instructions: 0
[proguard] Number of removed local variables: 0
[proguard] Number of removed exception blocks: 0
[proguard] Number of optimized local variable frames: 0
[proguard] Obfuscating...
[proguard] Printing mapping to [C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\obf\mapping.txt]...
[proguard] Writing output...
[proguard] Preparing output jar [C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\obf\postobf.jar]
[proguard] Copying resources from program jar [C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\obf\original.jar]
[proguard] Printing classes to [C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\obf\dump.txt]...

-dex-no-obfuscate:

-post-compile:

-dex:
[echo] Converting compiled files and external libraries into C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\bin\classes.dex...

-package-resources:
[echo] Packaging resources
[aapt] Creating full resource package...

-package-release:
[apkbuilder] Creating HelloAndroid-unsigned.apk for release...

-release-prompt-for-password:

-release-nosign:

release:
[echo] Signing final apk...
[signjar] Signing JAR: C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\bin\HelloAndroid-unsigned.apk to C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\bin\HelloAndroid-unaligned.apk as ky
[signjar] キーストアのパスワードを入力してください:
[echo] Running zip align on final apk...
[echo] Release Package: C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\bin\HelloAndroid-release.apk

deploy:
[echo] Installing C:\Users\brilliantservice.brilliant_vaio\anttest\HelloAndroid\bin\HelloAndroid-release.apk...
[exec] pkg: /data/local/tmp/HelloAndroid-release.apk
[exec] Success
[exec] 72 KB/s (4211 bytes in 0.057s)

BUILD SUCCESSFUL
Total time: 8 seconds


-dex-obfuscate:のフェーズで[proguard]のログが出力されていれば、ProGuardが適用されています。ログを詳しく見ると、下記のように圧縮、最適化、難読化が行われていることが分かります。




  • [proguard] Shrinking...

  • [proguard] Optimizing...

  • [proguard] Obfuscating...





ProGuard適用前と適用後を比較してみる


実際にProGuardの処理結果を比較して確認してみましょう。





apktoolによるデコンパイル

リエンジニアリングツールであるandroid-apktoolを使って、.apkファイルをデコンパイルし、アプリ内のクラス構成や処理内容を可視化します。





apktoolのシステム要件



  • JRE 1.6 (Java Runtime Environment)

  • 実行パスにaaptコマンドが設定されていること





apktoolのダウンロード

apktoolのダウンロードページから、OSに対応したファイルをダウンロードして下さい。





apktoolのインストール



  1. apktool-install-windows-* ファイルのダウンロード(Windowsの場合)

  2. apktool-* ファイルのダウンロード

  3. 以上の2つのファイルを適当なディレクトリに展開します。





デコンパイルの実行


$ cd <プロジェクトディレクトリ>/bin/
$ apktool d HelloAndroid-release.apk


デコンパイルの結果、HelloAndroid-release.apkのディレクトリ以下に、HelloAndroid-releaseディレクトリが生成され、下記のようなファイルが生成されます。




  • AndroidManifest.xml:アプリのマニフェストファイル

  • apktool.yml:apktoolの処理結果

  • resディレクトリ:アプリに含まれるリソースファイル

  • smaliディレクトリ:アプリの処理手順の解析結果





smaliファイルの比較

最適化や難読化がなされているかどうかは、smaliディレクトリをProGuardを適用しない場合と適用した場合とで見比べてみることで判ります。


ProGuard適用前


ファイル構成:




  • HelloAndroid.smali

  • HelloAndroid$testClass.smali

  • R.smali

  • R$attr.smali

  • R$layout.smali

  • R$string.smali


HelloAndroid.smaliの内容:



.class public Ltest/hello/HelloAndroid;
.super Landroid/app/Activity;
.source "HelloAndroid.java"

# annotations
.annotation system Ldalvik/annotation/MemberClasses;
value = {
Ltest/hello/HelloAndroid$testClass;
}
.end annotation

# direct methods
.method public constructor <init>()V
.locals 0

.prologue
.line 6
invoke-direct {p0}, Landroid/app/Activity;-><init>()V

.line 8
return-void
.end method

.method private testMethod1()V
.locals 3

.prologue
.line 32
const/4 v0, 0x0

.local v0, i:I
const/4 v1, 0x0

.local v1, sum:I
const/16 v2, 0xa

if-ge v0, v2, :cond_0

.line 33
add-int/2addr v1, v0

.line 32
add-int/lit8 v0, v0, 0x1

goto :goto_0

.line 35
return-void
.end method

# virtual methods
.method public onCreate(Landroid/os/Bundle;)V
.locals 1
.parameter "savedInstanceState"

.prologue
.line 23
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V

.line 24
const/high16 v0, 0x7f02

invoke-virtual {p0, v0}, Ltest/hello/HelloAndroid;->setContentView(I)V

.line 25
invoke-direct {p0}, Ltest/hello/HelloAndroid;->testMethod1()V

.line 26
new-instance v0, Ltest/hello/HelloAndroid$testClass;

invoke-direct {v0}, Ltest/hello/HelloAndroid$testClass;-><init>()V

.line 27
return-void
.end method


ProGuard適用しない場合、アプリのファイル構成がそのまま解析結果として出力され、クラス・メソッドの構成、コールシーケンスが丸見えになります。また、内部で使用しているクラス(内部クラスを含む)やメソッド名も判るため、何の処理をしているのかが予測しやすい状態です。





ProGuard適用後


ファイル構成:




  • a.smali

  • HelloAndroid.smali


HelloAndroid.smaliの内容:



.class public Ltest/hello/HelloAndroid;
.super Landroid/app/Activity;

# direct methods
.method public constructor <init>()V
.locals 0

invoke-direct {p0}, Landroid/app/Activity;-><init>()V

return-void
.end method

# virtual methods
.method public onCreate(Landroid/os/Bundle;)V
.locals 1

invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V

const/high16 v0, 0x7f02

invoke-virtual {p0, v0}, Ltest/hello/HelloAndroid;->setContentView(I)V

new-instance v0, Ltest/hello/a;

invoke-direct {v0}, Ltest/hello/a;-><init>()V

return-void
.end method


a.smaliの内容:



.class final Ltest/hello/a;
.super Ljava/lang/Object;

# direct methods
.method constructor <init>()V
.locals 0

invoke-direct {p0}, Ljava/lang/Object;-><init>()V

return-void
.end method


ProGuardを適用すると、ファイル構成は「エントリポイントとなるクラスファイル」と「難読化されたクラスファイル」だけとなっており、実際のファイル構成とは異なっています。また、クラスやメソッドの解析に失敗しており、この結果から処理を予測することが難しくなっています。





まとめ


以上のようにProGuardを利用すると簡単な手順で実効性のある難読化を行い、Androidのアプリという知的財産を守ることができます。一方で、JNI経由でネイティブメソッドなどを利用している場合、ProGuardでのビルドに失敗するなど、適用に関わる工数が著しく増大することがあります(いわゆる「ハマる」可能性があるということ)。とはいえ、アプリ中のアルゴリズムや手順、利用している技術が特殊であればあるほど、ProGuardを適用する意味は大きいでしょう。何らかの形でアプリ中の知的財産を守る必要がある場合は、ProGuardの利用を検討してみてはいかがでしょうか。


文責:技術部 植物工場研究G 瀬戸 直喜





Related Posts Plugin for WordPress, Blogger...