この記事について
これは、 JavaソースコードなしでAndroidアプリケーションをデバッグすることに関する昨日の私の記事の続きです (誰かがそれを読んでいないなら、それから始めることを強くお勧めします)。 昨日、ApkツールバンドルとNetBeansを設定して使用を開始する方法について順を追って説明しました。 そこの最後の2つのポイントは、次のようなものでした。
13.関心のある命令にブレークポイントを設定します...何とか何とか...
14.ブレークポイントが機能するように、アプリケーションで何かを行います。 その後、段階的なデバッグを実行したり、フィールドや変数の値を表示したりできます。
さらに、落とし穴のセクションでは、アプリケーションを開始するアクティビティの
onCreate(...)
メソッドの命令にブレークポイントを設定するなど、最初からアプリケーションのデバッグを開始できない理由について説明しました。
この記事では、最初からJavaソースコードなしでアプリケーションのデバッグを開始する方法を示します。 この記事も初心者向けではありません。 少なくともSmaliアセンブラーの構文を理解し、ペンで.smaliファイルにパッチを当て、そこにコードを正しく入力できる必要があります。
ツール
再びApk-tool 1.4.1とNetBeans 6.8が必要です -これらはこれまでで最も古いバージョンです。 新しいバージョンでは、デバッグを機能させることができません。 そして、私だけでなく、テーマ別フォーラムでの議論によって判断します。
昨日の記事ですでにApkツールとNetBeansのインストールについて説明しましたが、それでも繰り返します。 NetBeansはデフォルトでインストールされます。インストールウィザードで[次へ]、[次へ]、[次へ]の順にクリックするだけです。 Apk-toolsのインストールは、
apktool.jar
ファイルをアーカイブから任意のフォルダーに抽出する
apktool.jar
です。
アプリケーションの最初にブレークポイントを置く方法
アイデアは一般的にシンプルです。 最初にアプリケーションで開始するアクティビティを見つけ、このアクティビティの
onCreate(...)
メソッドの開始時に無限ループに入る必要があります。 アプリケーションが起動し、このアクティビティのコンストラクターを呼び出した直後に、
onCreate(...)
メソッドが呼び出されます。 その結果、制御は無限のサイクルに陥ります。 そこでループが回転している間、実行中のアプリケーションにデバッガーをゆっくりとアタッチし、無限ループの直後にブレークポイントを配置してから、デバッガーの機能を利用して、制御をこのループから抜けさせます。 そしてすぐにブレークポイントに到達しました。 ご覧のとおり、すべてが基本です。
このセクションでは、手順を追って説明します。 この指示はWindows用に書かれていますが、ほとんどの場合、LinuxおよびMac OSで動作します。
指示に正確に従ってください-これは重要です!
- Apkツールを使用して、.apkファイルを
temp
ディレクトリにデコードします。-d
オプションを使用しないでください 。
java -jar apktool.jar d my.app.apk temp
その結果、temp/smali
ディレクトリに多数の.smaliファイルが作成されます。
-
temp/AndroidManifest.xml
ファイルで、アクティビティを見つけます
<intent -filter="-filter"> <action android:name="android.intent.action.MAIN"> <category android:name="android.intent.category.LAUNCHER"> </intent>
これは、アプリケーションで最初に開始されるアクティビティです。
- 最初にアプリケーションで開始するアクティビティを見つけましたか? ここで、このアクティビティのクラス(通常は
android.app.Activity
クラスの子孫)を実装する.smaliファイルを見つけます。temp/smali
深く見てください。 - このクラスで、呼び出しの直後に
onCreate(...)
メソッドを見つけます(通常、この呼び出しは最初から始まります)
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
onCreate(...)
で次のコードを記述します。
:debug sget v0, Lmy/activity/class/MyActivity;->debugFlag:I if-nez v0, :debug
気配りのある読者は、おそらく、このコードが前に説明した無限ループであることをすでに推測していました。 当然、MyActivity
代わりに実名アクティビティを使用する必要があり、v0
代わりに適切なローカルレジスタをこのコードで使用できます。 適切なレジスタがない場合は、それに応じて.registers
または.registers
編集して追加します。
- また、クラスにフィールドを追加します
.field static debugFlag:I = 0x01
そうしないと、前の段落の無限ループのコードは機能しません。
-
-d
オプションを指定せずに 、temp
ディレクトリを.apkファイルに再構築します。
java -jar apktool.jar b temp my.app.apk
もちろん、元のmy.app.apk
はこの前のどこかにmy.app.apk
必要があります。
これで
my.app.apk
パッチが適用され
my.app.apk
。 アプリケーションが開始するアクティビティのクラスの
onCreate(...)
メソッドの開始時に、無限ループに入りました。 さて、このパッチを適用した
my.app.apk
を取り、昨日の記事の段階的な指示に従ってください (「デバッグ」セクションを参照)。 この手順の9番目のステップでは、アプリケーションを起動した後、黒い画面が表示されることに注意してください。 これは正常です、そうであるはずです! これは、アプリケーションの起動直後に、パッチを適用した
onCreate(...)
メソッドが呼び出され、コントロールが無限ループに陥ったことを意味します。 しばらくしてAndroidが応答しないためにアプリケーションを閉じるように要求する場合、指示に従って厳密に拒否してさらに進んでください!
指示の12番目のステップで、NetBeansで、パッチを適用した
onCreate(...)
メソッドが配置されている.javaファイルを開きます。 NetBeansのデバッグパネルの一時停止ボタンを使用します。 次に、この開いている.javaファイルで、
onCreate(...)
入力した無限ループコードの後の最初のステートメントにブレークポイントを配置します。 次に、NetBeansデバッガーで変数を表示および編集する機能を使用して、
debugFlag
フィールドの値を
0
に変更し、NetBeansのデバッグパネルで[デバッグの続行]ボタンをクリックします。 管理は無限ループを終了し、すぐにブレークポイントに到達します。
これで、アプリケーションを最初から安全にデバッグできるようになりました
onCreate(...)
最初の
onCreate(...)
メソッドの最初の呼び出しからです。
waitForDebuggerに関するいくつかの言葉()
読者は、このトピックで少しですが、おそらく、この記事で無限ループを使用するのと同じ目的で
android.os.Debug.waitForDebugger()
メソッドを使用することに関するトピックフォーラムを読んでください。 この同じ読者は、
onCreate(...)
最初に1つの静的メソッドへの呼び出しを記述することはできますが、何らかの種類の庭を周期的に積み重ねていることに驚くでしょう。
invoke-static {}, Landroid/os/Debug;->waitForDebugger()V
メソッドはパラメータなしで呼び出されることに注意してください。つまり、適切なレジスタがない場合、ローカルレジスタを追加する必要はありません。 それは見えるだろう-美! 他に何が必要ですか?
理論的には、何も必要とせず、それを使用してください。 しかし実際には、すべてが少し複雑です。 実際、
android.os.Debug.waitForDebugger()
したフォーカスは常に機能するとは限りません。 多くの場合(私のものを含む)、
android.os.Debug.waitForDebugger()
呼び出した直後に
android.os.Debug.waitForDebugger()
アプリケーションは実際に「フリーズ」し、デバッガが参加するのを待ちます。 これはDDMSでも確認できます。アプリケーションの反対側に小さな「赤いバグ」アイコンが表示されます。 ただし、デバッガをアプリケーションに接続するとすぐに、制御はすぐに
android.os.Debug.waitForDebugger()
後の次の命令に渡され、アプリケーションは停止せずにさらに実行を開始します。
android.os.Debug.waitForDebugger()
後にブレークポイントを置く時間はありません。 これに関する議論については、例えばこちらをご覧ください。
なぜ
android.os.Debug.waitForDebugger()
がこのような人のために、そしてそのような人のために
android.os.Debug.waitForDebugger()
のか-今のところはわかりません。 おそらくコメントで誰かがこれについて説明するでしょう。 また、コメントで記事について質問することができますし、質問するべきです。 私はできるだけ早く答えようとします、しかし、私が愚かであるならば-辛抱してください。 私は皆に答えようとします。
ハッピーデバッグ!