インテル® プロセッサー・ベースのプラットフォームにおけるサードパーティー Android* アプリケーションのデバッグ・リファレンス – パート 2

同カテゴリーの次の記事

Havok Vision Engine* を Android* プラットフォームへ移行する

この記事は、インテル® デベロッパー・ゾーンに掲載されている「Third-Party Android* Application Debug Reference on Intel® Processor-based Platforms Part 2」の日本語参考訳です。


目次


サードパーティー・ベンダー・アプリケーションのデバッグ

Java* アプリケーションのデバッグ
アプリケーションの x86 ネイティブ・ライブラリーのデバッグ

アプリケーションの問題 – 重要項目

アプリケーション利用の前提条件
アプリケーションのインストールに失敗する
アプリケーションに ARM の ABI やアーキテクチャーのプロパティーなどに依存するコードが含まれている
アプリケーションが OEM のフレームワークに依存している
アプリケーションがインテル® プロセッサー・ベースのプラットフォームに含まれていないネイティブ・ライブラリーに依存している
アプリケーションにパーミッションがない
データベースの構造が異なる
アプリケーションが AndroidManifest.xml の <uses-library android:name=”xxx_feature” /> のような ISV 関数パッケージファイルに依存している
有料アプリケーションに関連する com.google.android.vending.licensing.LicenseValidator.verify 問題
リソースを apk ファイルへ追加する方法
Google* Play ストアフィルターの詳細

サードパーティー・ベンダー・アプリケーションのデバッグ

Android* 市場には数多くのサードパーティー・アプリケーションがあります。モバイル・プラットフォームで成功するためには、それらのアプリケーションをモバイル・プラットフォームで確実に実行できるようにすることが重要です。では、これらのサードパーティー・ベンダー・アプリケーションに利用可能なソースコードがなく、一部のモバイル・プラットフォームで正常に動作しない場合、どうすればその原因を特定できるでしょうか。

Java* アプリケーションのデバッグ

Android* Java* アプリケーションに対応するデバッグ用ツールを利用することで、開発者は Android* アプリケーションを迅速かつ容易にデバッグすることができます。

Android* デバッグツールの使い方とダウンロードのリンクを以下に示します。

  1. baksmali: odex / dex ファイルを解析して smali ファイルにします。ファイルは同じ作業ディレクトリーの /system/framework に配置する必要があります。
    コマンド: java -jar baksmali.jar -x file.odex
    ダウンロード・リンク: http://code.google.com/p/smali/downloads/list

  2. smali: smali ファイルを make して classes.dex ファイルにします。
    コマンド: java -Xmx512M -jar smali.jar out -o classes.dex

  3. keytool: apk 証明書を作成します。
    keytool -genkey -v -alias CERT -keyalg RSA -keysize 2048 -validity 10000 -keystore CERT.keystore

  4. jarsigner: apk に署名します。
    jarsigner -verbose -keystore CERT.keystore to_sign.apk CERT

  5. dex2jar: classes.dex ファイルを jar ファイルに逆コンパイルします。
    ダウンロード・リンク: http://code.google.com/p/dex2jar/downloads/list

  6. JD-GUI: jar ファイルの Java* ソースを確認します。

  7. apktool: apk からリソース /xml/smali ファイルを逆コンパイルします。smali を使用して apk ファイルをコンパイルすることもできます。
    ダウンロード・リンク: http://code.google.com/p/android-apktool/downloads/list

  8. AXMLPrinter: apk の xml ファイルを読み込み可能なファイルにします。
    ダウンロード・リンク: http://code.google.com/p/android4me/downloads/list

  9. zipalign: apk ファイルのサイズを最適化します。
    コマンド: zipalign -v 4 unaligned.apk aligned.apk

smali のデバッグ

Google* は、Dalvik* dex を smali コード (Dalvik* バイトコード) に逆コンパイルする apktool を提供しています。

apktool を使用した後、アプリケーション dex のすべての smali ファイルが smali ディレクトリーに配置されます。

smali オペコードについては、次のリンクを参照してください。
http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html

smali ファイルの一般的な形式は次のとおりです。

     .class <パーミッション> [修飾ワード] <クラス名>
     .super <親クラス>
     .source <ソースコードのファイル名>

次に例を示します。
MainActivity.smali を開くと、最初の 3 行は次のようになっています。

     .class public Lcom/droider/crackme0502/MainActivity;
     .super Landroid/app/Activity;
     .source “MainActivity.java”

     1 行目 – クラス名は MainActivity で、 パッケージは com.droider.crackme0502 です。
     2 行目 – MainActivity のスーパークラスは android.app.Activity です。
     3 行目 – ソースコードの名前は MainActivity.java です。

クラスは、さまざまなフィールドとメソッドから構成されます。smali では、フィールドは「.field」命令で宣言されます。形式は次のとおりです。

     .field <パーミッション> static [修飾キーワード] <フィールド名>:<フィールドタイプ>

smali の static フィールドでは、smali のアノテーションは # で始まります。
instance フィールドおよび形式は次のとおりです。

     # instance fields
     .field <パーミッション> static [修飾キーワード] <フィールド名>:<フィールドタイプ>

次に例を示します。

     # instance fields
     .field private btnAnno:Landroid/widget/Button;

     1 行目 – baksmali による注釈。
     2 行目 – フィールド btnAnno は android.widget.Button です。

クラスにメソッドがある場合、メソッドの smali コードは「.method」命令で始まります。
ダイレクトメソッドと仮想メソッドがあります。

     # direct methods
     .method <パーミッション> [修飾キーワード] <プロトタイプ>
     <.locals>
     [.parameter]
     [.prologue]
     [.line]
     <smali コード>
     .end method

仮想メソッドはダイレクトメソッドに似ています。

インターフェイスは「.implements」命令で始まります。

     # interfaces
     .implements <インターフェイス名>

アノテーションは「.annotation」で始まります。

     # annotations
     .annotation [プロパティー] <クラス名>
    [フィールド = 値]
     .end annotation
     # instance fields
     .field public sayWhat:Ljava/lang/String;
         .annotation runtime Lcom/droider/anno/MyAnnoField;
             info = “Hello my friend”
         .end annotation
     .end field

ヒント:

smali コードをどのように迅速に記述できるでしょうか?
それは Eclipse* を利用することです。Eclipse* で Android* プロジェクトを作成した後、Java* で必要なコードを記述し、dex で apk ファイルを作成します。最後に、apktool で関数の smali コードをコピーして、それを使用する場所に貼り付けます。

例: Java* コードの Log.x API を smali に逆コンパイルした後、メッセージ出力をデバッグするアプリケーションの smali コードに貼り付けます。

     invoke-static {v11, v12}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I

アプリケーションをデバッグするとき、次の 2 つのいずれかの方法を使用できます。

  1. smali コードにログを追加します。

    1. 「.local」変数にレジスターを追加します (例えば、v11、v12)。

    2. ログを出力する smali コードを追加します。
          const-string v11, “@@@@”
          const-string v12, “interceptPowerKeyDown enter”
          invoke-static {v11, v12}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I

          レジスターが v28 および v29 の場合、次のコードを使用します。
          invoke-static/range {v28 .. v29}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I

  2. smali のコールスタックを出力します。

    1. 「.local」変数にレジスターを追加します (例えば、v11)。

    2. コールスタックを出力する smali コードを追加します。
          new-instance v11 Ljava/lang/Exception;
          invoke-direct {v11, Ljava/lang/Exception;-><init>()V
          invoke-virtual {v11, Ljava/lang/Exception;->printStackTrace()V

smali コードのトラブルシューティング

デバッグの後、ランタイムエラーを解決するため smali コードの変更が必要になることがあります。smali コードのランタイムエラーを調べるには、次のコマンドを実行します。

     adb logcat | grep dalvikvm
     adb logcat | grep VFY

VFY の情報には、smali エラーファイル、ルーチンおよびエラーの原因が含まれます。dalvikvm の情報には、コールスタック、コンテキスト、その他が含まれます。

一般的なランタイムエラー:

  1. 変数リストが宣言と一致しない。

  2. ルーチンの呼び出しタイプが正しくない。
    例えば、public/package ルーチンには invoke-virtual を使用し、private ルーチンには invoke-director を使用します。

  3. apk が適切に署名されていない。
    adb logcat | grep mismatch を実行して署名が正しくないパッケージを調べます。

smali のデバッグのトラブルシューティング

smali コードを変更した後、「apktool b」を実行してパッケージにする必要があります。通常、次のようなエラーメッセージが表示されます。

  1. res/values/styles.xml:166: No resource found that matches the given name ‘@*android:style/Widget.Button error. You need to change styles.xml 166 line ‘@*android:style/Widget.Button  into  @android:style/Widget.Button

  2. 多くのエラー行は :\apktool\apk\res\values\public.xml:3847: error: Public symbol xxxxx The declaration is not defined. のように表示されます。

    これらのエラーの最初の数字に注目します。
    res/values/strings.xml:242: error: Multiple substitutions specified in non-positional format. Did you mean to add the formatted=”false” attribute?string.xml
    strings.xml ファイルの 242 行目を確認して問題の文字列を修正します。

  3. 関数呼び出し (invoke-virtual などの命令) では引数として v0~v15 レジスターのみ使用できるため、v16 などを使用するとエラーになります。この問題を修正する方法は 2 つあります。

    1. invoke-virtual/range {p1 .. p1} 命令を使用する。

    2. move-object/from16 v0, v18 命令を追加する。

  4. pN は等しい変数番号 + N と同じです。例えば、「.local」が 16 で宣言されている場合、レジスター v0~v15 を使用できます。p0 は v16 と同じで、p1 は v17 と同じです。

  5. Jump label conflict (ジャンプラベルの競合)
    同じジャンプラベルが 2 つある場合、このメッセージが表示されます。例えば、cond_11 が 2 つあるとコンパイルに失敗します。1 つのラベルを ABCD_XXXX のような別の名前に変更することで競合を解決できます。

  6. Use no-definition variable (未定義変数の使用)
    「.local」命令で宣言されている変数を使用できます。例えば、.local 30 shows this routine は v0 から v29 のみを使うため、v39 を使うとエラーになります。

アプリケーションの x86 ネイティブ・ライブラリーのデバッグ

例えば、apk に x86 ネイティブ・ライブラリー libcmplayer_14.so が含まれている場合、インテル® プロセッサー・ベースのプラットフォームでアプリケーションを実行すると、libcmplayer_14.so でクラッシュしたことを示す tombstone が含まれます。インテル® プロセッサー・ベースのプラットフォームへの libcmplayer_14.so API 呼び出しを確認して潜在的な問題を推測する方法を次に示します。

ステップ 1: readelf を用いて libcmplayer_14.so で使用されるインテル® プロセッサー・ベースのプラットフォームのライブラリーを確認すると、問題に関連すると思われるコンポーネントが分かります。

     readelf -d libcmplayer_14.so

オフセット 0xd8b8 のダイナミック・セクションには 33 のエントリーが含まれています。

タグタイプ名前/値
0x00000001 (NEEDED) 共有ライブラリー: [libdl.so]
0x00000001 (NEEDED) 共有ライブラリー: [liblog.so]
0x00000001 (NEEDED) 共有ライブラリー: [libz.so]
0x00000001 (NEEDED) 共有ライブラリー: [libui.so]
0x00000001 (NEEDED) 共有ライブラリー: [libmedia.so]
0x00000001 (NEEDED) 共有ライブラリー: [libbinder.so]
0x00000001 (NEEDED) 共有ライブラリー: [libutils.so]
0x00000001 (NEEDED) 共有ライブラリー: [libstdc++.so]
0x00000001 (NEEDED) 共有ライブラリー: [libgui.so]
0x00000001 (NEEDED) 共有ライブラリー: [libandroid.so]
0x00000001 (NEEDED) 共有ライブラリー: [libsurfaceflinger_client.so]
0x00000001 (NEEDED) 共有ライブラリー: [libm.so]
0x00000001 (NEEDED) 共有ライブラリー: [libc.so]
0x0000000e (SONAME) ライブラリー soname: [libcmplayer.so]
0x00000010 (SYMBOLIC) 0x0
0x00000019 (INIT_ARRAY) 0xe89c
0x0000001b (INIT_ARRAYSZ) 16 (バイト)
0x0000001a (FINI_ARRAY) 0xe8ac
0x0000001c (FINI_ARRAYSZ) 12 (バイト)
0x00000004 (HASH) 0xd4
0x00000005 (STRTAB) 0x8f0
0x00000006 (SYMTAB) 0x350
0x0000000a (STRSZ) 2409 (バイト)
0x0000000b (SYMENT) 16 (バイト)
0x00000003 (PLTGOT) 0xe9f4
0x00000002 (PLTRELSZ) 496 (バイト)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x12a4
0x00000011 (REL) 0x125c
0x00000012 (RELSZ) 72 (バイト)
0x00000013 (RELENT) 8 (バイト)
0x6ffffffa (RELCOUNT) 6
0x00000000 (NULL) 0x0

ステップ 2: objdump ツールを利用して libcmplayer_14.so で使用された UND API 呼び出しを調べ、潜在的な問題となる API 名を見つけます。

     objdump -T libcmplayer_14.so | grep UND
     00000000      DF *UND*    00000000 _ZNK7android7RefBase9incStrongEPKv
     00000000      DF *UND*    00000000 rewind
     00000000      DF *UND*    00000000 pthread_attr_setschedparam
     00000000      DF *UND*    00000000 fwrite
     00000000      DO *UND*   00000000 __sF
     00000000      DF *UND*    00000000 usleep
     00000000      DF *UND*    00000000 memcpy
     00000000      DF *UND*    00000000 realloc
     00000000      DF *UND*    00000000 pthread_mutex_init
     00000000      DF *UND*    00000000 pthread_attr_init
     00000000      DF *UND*    00000000 strcat
     00000000  w  DF *UND*    00000000 __deregister_frame_info_bases
     00000000      DF *UND*    00000000 _ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionE
     00000000      DF *UND*    00000000 __cxa_finalize
     00000000      DF *UND*    00000000 sched_get_priority_max
     00000000      DF *UND*    00000000 malloc
     00000000      DF *UND*    00000000 dlsym
     00000000      DF *UND*    00000000 strlen
     00000000      DF *UND*    00000000 pthread_mutex_lock
     00000000      DF *UND*    00000000 __cxa_atexit
     00000000      DF *UND*    00000000 sched_get_priority_min
     00000000      DF *UND*    00000000 snprintf
     00000000      DF *UND*    00000000 __android_log_print
     00000000      DF *UND*    00000000 dlerror
     00000000      DF *UND*    00000000 setjmp
     00000000      DF *UND*    00000000 pthread_mutex_destroy
     00000000      DF *UND*    00000000 fclose
     00000000      DF *UND*    00000000 fread
     00000000      DF *UND*    00000000 fopen
     00000000      DF *UND*    00000000 __stack_chk_fail
     00000000      DF *UND*    00000000 time
     00000000      DF *UND*    00000000 strtok
     00000000      DF *UND*    00000000 pthread_create
     00000000      DF *UND*    00000000 _ZNK7android7RefBase9decStrongEPKv
     00000000  w  DF *UND*    00000000 __register_frame_info_bases
     00000000      DF *UND*    00000000 _ZN7android10AudioTrack5startEv
     00000000      DF *UND*    00000000 pthread_cond_signal
     00000000      DF *UND*    00000000 pthread_mutexattr_init
     00000000      DF *UND*    00000000 sscanf
     00000000      DF *UND*    00000000 pthread_cond_timedwait
     00000000      DF *UND*    00000000 pthread_cond_init
     00000000      DF *UND*    00000000 _ZN7android10AudioTrack5writeEPKvj
     00000000      DF *UND*    00000000 pthread_attr_setschedpolicy
     00000000      DF *UND*    00000000 memset
     00000000      DF *UND*    00000000 sprintf
     00000000      DF *UND*    00000000 fseek
     00000000      DF *UND*    00000000 pthread_mutex_unlock
     00000000      DF *UND*    00000000 pthread_cond_destroy
     00000000      DF *UND*    00000000 strstr
     00000000      DF *UND*    00000000 ftell
     00000000      DF *UND*    00000000 free
     00000000      DF *UND*    00000000 atoi
     00000000      DF *UND*    00000000 strchr
     00000000      DF *UND*    00000000 printf
     00000000      DF *UND*    00000000 _ZN7android10AudioTrack5pauseEv
     00000000      DF *UND*    00000000 pthread_cond_wait
     00000000      DF *UND*    00000000 strdup
     00000000      DF *UND*    00000000 puts
     00000000      DF *UND*    00000000 dlopen
     00000000      DF *UND*    00000000 _ZN7android10AudioTrack4stopEv
     00000000      DF *UND*    00000000 _ZN7android10AudioTrack5flushEv
     00000000      DF *UND*    00000000 strcpy
     00000000      DF *UND*    00000000 pthread_join

ステップ 3: libcmplayer_14.so で使用されるインテル® プロセッサー・ベースのライブラリーおよび API に対するログを追加するか、別のデバッグ方法によりクラッシュしている場所を特定します。

GDB によるコアダンプのチェック

gdb.sh

  1. 次のコマンドを実行してコアダンプ・ファイルを調べます。
    adb shell cat /logs/history_event
    #V1.0 CURRENTUPTIME   0001:05:08
    #EVENT  ID                                       DATE                      TYPE
    REBOOT  8a41fa9bc91dc23cc5a2   1982-01-01/00:04:40  SWUPDATE         0000:00:00
    STATE   e4fd39f21a9630bf4187        1982-01-01/00:04:40  DECRYPTED      
    CRASH   4be805a6b721775813d6    2013-02-06/09:16:00  TOMBSTONE /mnt/sdcard/logs/crashlog0
    CRASH   00526c3de09fd880c454      2013-02-06/09:16:16  APCOREDUMP /mnt/sdcard/logs/crashlog1

    コアダンプ・ファイルは /mnt/sdcard/logs/crashlog1 にあります。

  2. コアダンプ・ファイルおよびアプリケーションのネイティブ x86 ライブラリーを取得します。次に例を示します。
    adb pull /mnt/sdcard/logs/crashlog1
    adb pull /data/app-lib/com.zeptolab.ctr.ads-1/libctr-jni.so

  3. アプリケーションのネイティブ x86 ライブラリーをプロジェクト・シンボル・ライブラリー・パスにコピーします。次に例を示します。
    cp libctr-jni.so ~/JB/ target/product/blackbay/symbols/system/lib

  4. 添付の gdb.sh により (ホストの gdb.sh スクリプトのパスの変更が必要になることがあります) gdb を実行し、コアダンプを解析します。次に例を示します。
    cd ~/JB/
    gdb.sh app_process out/target/product/blackbay
    core ~/temp/crashlog1/1360114650_app_process_5145.core

これで、gdb コマンドによりコアダンプ・ファイルを解析できるようになりました。例えば、bt コマンドでコール・バック・トレースを取得します。

objdump によるネイティブ・ライブラリーのチェック

上記と同じ例:

  1. バグに関連するコードを取得します。

  2. バグのコードをビルドします。
  3. cd <aosp>/out/target/product/<プラットフォーム>/symbols/system/lib でライブラリーのシンボルが含まれるディレクトリーに移動します。

  4. objdump -d libjni_latinime.so > tmp.log でライブラリーを逆コンパイルします。

  5. tmp.log を開いて eip 880b を検索します。tmp.log で逆コンパイルしたルーチン名のエラーコード位置を調べることができます。
    例えば、c++filt を使って _ZN8latinimeL30latinime_BinaryDictionary_openEP7_JNIEnvP8_jobjectP8_jstringxxiiii を読み込み可能な関数名にすることができます。
         c++filt _ZN8latinimeL30latinime_BinaryDictionary_openEP7_JNIEnvP8_jobjectP8_jstringxxiiii
         latinime::latinime_BinaryDictionary_open(_JNIEnv*, _jobject*, _jstring*, long long, long long, int, int, int, int)

GDB によるアセンブリー・コードのデバッグ

ターゲットデバイス:

     gdbserver :port – -attach ID

ホスト PC:

                adb forward tcp:1234 tcp: 1234
                     gdb.sh app_process <シンボルパス>
                #target remot :1234
     b *0x80123432 // アドレス 0x80123432 でブレーク
     x/64xw 0x80123432
// アドレス 0x80123432 からメモリーの内容を 4 バイト単位 (16 進形式) で 64 個表示
     x/s 0x80123432 // アドレス 0x80123432 から文字列を表示
     info register // すべてのレジスター値を確認
     info symbol 0x80123432 // アドレス 0x80123432 からシンボル情報を取得
     nexti // 次のアセンブリー命令を実行
     display $eax // 式の値を追加
     p expression // 式の値を表示
     disassemble _ZN14ProfileManager18WriteTrophiesStateEP7__sFILERKN13PlayerProfile21ProfileActiveTrophiesE
// 関数のアセンブリー・コードを表示

c++filt ツールを用いて関数名をデマングルします。

     _ZN14ProfileManager18WriteTrophiesStateEP7__sFILERKN13PlayerProfile21ProfileActiveTrophiesE
     ProfileManager::WriteTrophiesState(__sFILE*, PlayerProfile::ProfileActiveTrophies const&)

apk インストール・ディレクトリー

JB 以降、Google* Play ストアから有料アプリケーションをダウンロードしてインストールする場合、インストール・パスは /data/app-asec で形式は .asec です。

apk を逆コンパイルする場合は、ICS プラットフォームでダウンロードしてインストールする必要があります。

Android* のバージョン インストール・パス デバイス上のファイル形式
ICS /data/app .apk
JB /data/app-asec .asec

JB で有料アプリケーションをインストールする場合、/mnt/asec ディレクトリーにインストールされたパッケージを調べることができます。

例えば、「モダンコンバット 2」の場合は次のようになります。

     /mnt/asec/com.gameloft.android.ANMP.GloftBPHM.ML-1/pkg.apk は apk インストール・パッケージです。

ダウンロードしたアプリケーション・データは次の場所に含まれます (find –name * GloftBPHM* で検索できます)。

     /mnt/shell/emulated/0/Android/data/com.gameloft.android.ANMP.GloftBPHM.ML
     /data/media/0/Android/data/com.gameloft.android.ANMP.GloftBPHM.ML
     /storage/sdcard0/Android/data/com.gameloft.android.ANMP.GloftBPHM.ML <-/storage
     このディレクトリーのデータの多くはアプリケーションを起動したときに作成されます。

x86 デバッグケース

AnTuTu の tombstone 問題 [BZ 107342]

  1. DUT 暗号化の後で 3D ベンチテストを実行すると、tombstone 問題が発生します。x86 エミュレーターでも同じ問題が発生するため、アプリケーションでこの問題を解決します。

  2. cat /logs/his* を実行して tombstone コアダンプ・ファイルを検索します。AnTuTu ライブラリー 3drating.5 および libabenchmark.so を out/target/platform/redhookbay/symbols/system/lib にコピーします。

  3. 「GDB によるコアダンプのチェック」の手順に従ってコアダンプ・ファイルを開きます。bt コマンドでコールスタックを表示します。

    #0  0x5e361ef5 in native_window_set_buffers_format (format=4, window=0x0) at system/core/include/system/window.h:749

    #1  ANativeWindow_setBuffersGeometry (window=0x0, width=0, height=0, format=4) at frameworks/base/native/android/native_window.cpp:63

    #2  0x60f4be20 in Ogre::AndroidEGLWindow::_createInternalResources(ANativeWindow*, AConfiguration*) () from /home/zwang/r4_2_stable/out/target/product/redhookbay/symbols/system/lib/3drating.5

    #3  0x60f4c4dd in Ogre::AndroidEGLWindow::create(std::string const&, unsigned int, unsigned int, bool, std::map<std::string, std::string, std::less<std::string>, Ogre::STLAllocator<std::pair<std::string const, std::string>, Ogre::CategorisedAllocPolicy<(Ogre::MemoryCategory)0> > > const*) () from /home/zwang/r4_2_stable/out/target/product/redhookbay/symbols/system/lib/3drating.5

    #4  0x60f4af8e in Ogre::AndroidEGLSupport::newWindow(std::string const&, unsigned int, unsigned int, bool, std::map<std::string, std::string, std::less<std::string>, Ogre::STLAllocator<std::pair<std::string const, std::string>, Ogre::CategorisedAllocPolicy<(Ogre::MemoryCategory)0> > > const*) () from /home/zwang/r4_2_stable/out/target/product/redhookbay/symbols/system/lib/3drating.5

    #5  0x60f428eb in Ogre::GLES2RenderSystem::_createRenderWindow(std::string const&, unsigned int, unsigned int, bool, std::map<std::string, std::string, std::less<std::string>, Ogre::STLAllocator<std::pair<std::string const, std::string>, Ogre::CategorisedAllocPolicy<(Ogre::MemoryCategory)0> > > const*) () from /home/zwang/r4_2_stable/out/target/product/redhookbay/symbols/system/lib/3drating.5

    #6  0x61095091 in Ogre::Root::createRenderWindow(std::string const&, unsigned int, unsigned int, bool, std::map<std::string, std::string, std::less<std::string>, Ogre::STLAllocator<std::pair<std::string const, std::string>, Ogre::CategorisedAllocPolicy<(Ogre::MemoryCategory)0> > > const*) () from /home/zwang/r4_2_stable/out/target/product/redhookbay/symbols/system/lib/3drating.5

    #7  0x60ecaf05 in OgreAndroidBaseFramework::initRenderWindow(unsigned int, unsigned int, unsigned int) () from /home/zwang/r4_2_stable/out/target/product/redhookbay/symbols/system/lib/3drating.5

    #8  0x60ec2b71 in ogre3d_initWindow () from /home/zwang/r4_2_stable/out/target/product/redhookbay/symbols/system/lib/3drating.5

    #9  0x5f09e271 in Java_com_antutu_ABenchMark_Test3D_OgreActivity_initWindow () from /home/zwang/r4_2_stable/out/target/product/redhookbay/symbols/system/lib/libabenchmark.so

    #10 0x40dce170 in dvmPlatformInvoke () at dalvik/vm/arch/x86/Call386ABI.S:128

    #11 0x40e27a68 in dvmCallJNIMethod (args=0x57941df8, pResult=0x8000cf10, method=0x57c11e10, self=0x8000cf00) at dalvik/vm/Jni.cpp:1174

    #12 0x40df197b in dvmCheckCallJNIMethod (args=0x57941df8, pResult=0x8000cf10, method=0x57c11e10, self=0x8000cf00) at dalvik/vm/CheckJni.cpp:145

    #13 0x40e2da5d in dvmResolveNativeMethod (args=0x57941df8, pResult=0x8000cf10, method=0x57c11e10, self=0x8000cf00) at dalvik/vm/Native.cpp:135

    #14 0x40f2ec8d in common_invokeMethodNoRange () from /home/zwang/r4_2_stable/out/target/product/redhookbay/symbols/system/lib/libdvm.so

    #15 0x57941df8 in ?? ()

    #16 0x40de1626 in dvmMterpStd (self=0x8000cf00) at dalvik/vm/mterp/Mterp.cpp:105

    #17 0x40ddefc4 in dvmInterpret (self=0x8000cf00, method=0x579e0b68, pResult=0xbffff604) at dalvik/vm/interp/Interp.cpp:1954

    #18 0x40e590ec in dvmInvokeMethod (obj=0x0, method=0x579e0b68, argList=0x4207c260, params=0x4207c170, returnType=0x417e42d0, noAccessCheck=false) at dalvik/vm/interp/Stack.cp37

    #19 0x40e6cf67 in Dalvik_java_lang_reflect_Method_invokeNative (args=0x57941f00, pResult=0x8000cf10) at dalvik/vm/native/java_lang_reflect_Method.cpp:101

    #20 0x40f2ec8d in common_invokeMethodNoRange () from /home/zwang/r4_2_stable/out/target/product/redhookbay/symbols/system/lib/libdvm.so

    #21 0x57941f00 in ?? ()

    #22 0x40de1626 in dvmMterpStd (self=0x8000cf00) at dalvik/vm/mterp/Mterp.cpp:105

    #23 0x40ddefc4 in dvmInterpret (self=0x8000cf00, method=0x579d63c0, pResult=0xbffff8c8) at dalvik/vm/interp/Interp.cpp:1954

    #24 0x40e57e1c in dvmCallMethodV (self=0x8000cf00, method=0x579d63c0, obj=0x0, fromJni=true, pResult=0xbffff8c8, args=<optimized out>) at dalvik/vm/interp/Stack.cpp:526

    #25 0x40e1ba6e in CallStaticVoidMethodV (env=0x8000a020, jclazz=0x1d400015, methodID=0x579d63c0, args=0xbffff97c “\t”) at dalvik/vm/Jni.cpp:2111

    #26 0x40dfb440 in Check_CallStaticVoidMethodV (env=0x8000a020, clazz=0x1d400015, methodID=0x579d63c0, args=0xbffff97c “\t”) at dalvik/vm/CheckJni.cpp:1679

    #27 0x402685ba in _JNIEnv::CallStaticVoidMethod (this=0x8000a020, clazz=0x1d400015, methodID=0x579d63c0) at libnativehelper/include/nativehelper/jni.h:793

    #28 0x40269e71 in android::AndroidRuntime::start (this=0xbffffa50, className=0x80001208 “com.android.internal.os.ZygoteInit”, options=<optimized out>) at frameworks/base/core/jni/AndroidRuntime.cpp:1005

    #29 0x80000fd0 in main (argc=4, argv=0xbffffaf8) at frameworks/base/cmds/app_process/app_main.cpp:190

  4. フレームワーク API からデバッグすると、次のことが分かります。
    android_view_Surface_getNativeWindow: get surface = 0x802fbbc8 は有効な ANativeWindow* を返しています。
    ANativeWindow_setBuffersGeometry の入力引数は ANativeWindow* = null です。
    このため、上記の 2 つの API 間で何かが起こり、tombstone 問題が発生していると考えられます。

  5. AnTuTu は、コールスタックに ORGE レンダリング・エンジンを使用しています。ORGE レンダリング・エンジンのソースコードは次のリンクから入手できます。
    http://code.metager.de/source/xref/ogre/RenderSystems/GLES/src/EGL/Android/OgreAndroidEGLWindow.cpp

    コードを見ると、ANativeWindow* ポイント値が void AndroidEGLWindow::create で変更されていることが分かりました。このため、mWindow が NULL 値になり、tombstone 問題が発生していたのです。

    void AndroidEGLWindow::create(const String& name, uint width, uint height, bool fullScreen, const NameValuePairList *miscParams) {
    
    ...
    	mWindow = (ANativeWindow*)(Ogre::StringConverter::parseInt(opt->second));
    ...
    	_createInternalResources(mWindow, config);
    ...
    }
    

  6. インテル® プロセッサー・ベースのプラットフォームでは、ANativeWindow* のようなメモリーポイントが 0x80000000 よりも高くなる (ARM プラットフォームでは 0x80000000 よりも低くなる) ため、unsigned int -> int -> string -> int の変換問題が発生します。この問題は ARM プラットフォームでは発生しません。

    上記の AnTuTu の例では、opt->second に格納されている ANativeWindow* は unsigned int として使用すべきですが、parseInte で 0 が返されるため、tombstone 問題が発生します。

アプリケーションの問題 – 重要項目

アプリケーション利用の前提条件

エラーの症状:

アプリケーションに問題がないのに実行できない場合、テスト担当者やエンドユーザーによってアプリケーションを利用する前提条件が無視されたことが原因で問題が発生している可能性があります。いくつかの一般的な前提条件を示します。

  1. SIM カードのエリアの違い (例えば、米国、中国、フランスの SIM カードでは 3G エリアが異なります)。

  2. Wi-Fi*/3G インターネット接続の違い。一部のアプリケーションは、Wi-Fi*/3G 接続を行う際に特定の位置や要件を満たす必要があります。

  3. Wi-Fi*/3G 接続不良。接続不良の場合、一部のアプリケーションはインターネットへの接続を何度も繰り返してクラッシュすることがあります。

  4. 画面の解像度/dpi による制限。多くのアプリケーションは動作する画面解像度/dpi に制限があります。

  5. GMS サービス。Google* Play サービス、Google* サービス・フレームワーク、その他がオフ。多くの GMS アプリケーションは基本的な GMS サービスに依存して動作しています。

解決方法:

使用するアプリケーションが上記の前提条件をすべて満たしていることを確認します。

アプリケーションのインストールに失敗する

エラーの症状:

Play ストアからダウンロードしたアプリケーションがデバイスへのインストールに失敗する、あるいは adb インストールで apk のインストールに失敗する。

解決方法:

USB/SD カードへの書き込みに問題がないことを確認します。また、PMS の Houdini フックが適切に動作していることを確認します。

アプリケーションに ARM のアプリケーション・バイナリー・インターフェイスやアーキテクチャーのプロパティーなどに依存するコードが含まれている

エラーの症状:

アプリケーションを実行したときに Dalvik* がネイティブ・ライブラリーのデバイスへのコピーに失敗するため、ARM ライブラリーへのリンクを解決できない、あるいはネイティブメソッド実装を見つけることができない。

主要なアプリケーションの関数チェックに失敗する、など。

解決方法:

smali コードを変更してアプリケーションのハード・コード・チェックを削除するか、アプリケーション ISV に修正を依頼します。

アプリケーションが OEM のフレームワークに依存している

エラーの症状:

フィールド、メソッド、クラスが見つからない。

解決方法:

smali コードを変更して関連するフィールド/メソッド/クラスの使用をマスクします。

関連するフレームワーク・クラスをデバイスにコピーします。

アプリケーションがインテル® プロセッサー・ベースのプラットフォームに含まれていないネイティブ・ライブラリーに依存している

エラーの症状:

含まれていないライブラリー名の UnSatisfiedException 例外が発生する。

解決方法:

アプリケーション・ライブラリーの依存関係を確認して、関連するライブラリーをデバイスにコピーします。

アプリケーションにパーミッションがない

エラーの症状:

パーミッションがない。

解決方法:

<user-permision /> を AndroidMenifest.xml に追加します。

データベースの構造が異なる

エラーの症状:

フィールドまたは型が一致しない。

解決方法:

apk を逆コンパイルし、smali コードを確認して SQL 関連文字列 (例: create table … ) を見つけ、SQL 文字列をデータベースに合うように編集し、apk に再パッケージします。

アプリケーションが AndroidManifest.xml の <uses-library android:name=”xxx_feature” /> のような ISV 関数パッケージファイルに依存している

エラーの症状:

アプリケーションを起動するときに一部の機能へアクセスするパーミッションがない。

解決方法:

AndroidManifest.xml を変更してこれらの <uses-library> タグを削除するか、これらの機能の jar パッケージをほかのモバイル・プラットフォームからターゲットデバイスにコピーします。

有料アプリケーションに関連する com.google.android.vending.licensing.LicenseValidator.verify 問題

この問題が発生した場合は、次の手順で repo コマンドを実行できます。

エラーの症状:

次のようなログが出力される。

     E/AndroidRuntime(27088): FATAL EXCEPTION: background thread
     E/AndroidRuntime(27088): java.lang.NullPointerException
     E/AndroidRuntime(27088): at com.google.android.vending.licensing.LicenseValidator.verify(LicenseValidator.java:99)
     E/AndroidRuntime(27088): at com.google.android.vending.licensing.LicenseChecker$ResultListener$2.run(LicenseChecker.java:228)

repo 手順:

(a) apk をインストールします。

(b) デバイス上の Google* アカウントを削除します。

(c) このアプリケーションを起動します。

リソースを apk ファイルへ追加する方法

例えば、1 つの文字列リソースを追加する場合、values/strings.xml に追加する必要があります。

     <string name=”newstring”>content</string>
                values ディレクトリーの public.xml には、public なリソース id が含まれます。
                最新の <public type=”string” …> 要素を見つけて、<public type=”string”
                name=”newstring” id=”0x7f0700a0″ /> を追加します。
                新しい文字列リソースを使用するように smali ファイルを変更します。
invoke-virtual {p0}, Lcom/sini/SfsdfsActivity;->getResources()Landroid/content/res/Resources;
move-result-object v0
const v1, 0x7f0700a0
invoke-virtual {v0, v1}, Landroid/content/res/Resources;->getString(I)Ljava/lang/String;

Google* Play ストアフィルターの詳細

Google* フィルターのリンク: http://developer.android.com/google/play/filters.html

  • デバイス DPI フィルター

    Google* の標準 DPI は、320、240 (HDPI)、160 (MDPI)、および 120 (LDPI) です。
    デバイスの DPI が異なる場合、Play ストアのアプリケーションの多くは利用できません。

  • デバイス機能フィルター
    Google* Play ストアは、API PackageManager.getSystemAvailableFeatures および hasSystemFeature を呼び出してデバイスのすべての機能を取得し、デバイスで利用可能な機能によってアプリケーションをフィルターします。

  • MFLD PR Phone JB 4.1 の例

    API PackageManager.getSystemAvailableFeatures および hasSystemFeature の戻り値でカメラ関連機能が利用できない場合、MFLD PR Phone は Smart Compass、WeChat、その他のカメラ機能が必要なアプリケーションを見つけられません。

    これらの戻り値でカメラ関連機能が利用できる場合、MFLD PR Phone は Smart Compass、WeChat、その他のカメラ機能が必要なアプリケーションを見つけることができます。

    注:
    ターゲットデバイスで機能の変更を有効にするには、Google* Play サービスおよび Google* Play ストアのデータとキャッシュをクリアする必要があります。

  • MFLD PR Phone で利用可能な機能は次のとおりです。

    root@android:/ # pm list features
    feature:reqGlEsVersion=0x20000
    feature:android.hardware.bluetooth
    feature:android.hardware.camera
    feature:android.hardware.camera.autofocus
    feature:android.hardware.camera.flash
    feature:android.hardware.camera.front
    feature:android.hardware.faketouch
    feature:android.hardware.location
    feature:android.hardware.location.gps
    feature:android.hardware.location.network
    feature:android.hardware.microphone
    feature:android.hardware.nfc
    feature:android.hardware.screen.landscape
    feature:android.hardware.screen.portrait
    feature:android.hardware.sensor.accelerometer
    feature:android.hardware.sensor.barometer
    feature:android.hardware.sensor.compass
    feature:android.hardware.sensor.gyroscope
    feature:android.hardware.sensor.light
    feature:android.hardware.sensor.proximity
    feature:android.hardware.telephony
    feature:android.hardware.telephony.gsm
    feature:android.hardware.touchscreen
    feature:android.hardware.touchscreen.multitouch
    feature:android.hardware.touchscreen.multitouch.distinct
    feature:android.hardware.touchscreen.multitouch.jazzhand
    feature:android.hardware.usb.accessory
    feature:android.hardware.usb.host
    feature:android.hardware.wifi
    feature:android.software.live_wallpaper
    feature:android.software.sip
    feature:android.software.sip.voip

コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。

関連記事