2013年3月4日月曜日

【Xperia AX SO-01E】戻るキー長押しでアプリキル(3)

戻るキー長押しによって、最前面で起動中のアプリを終了する機能を追加する記事、なんと3回目です。
2回目の記事まででとりあえず動くようにはしましたが、アプリキル部分のコードを見直してみました。
より素直な挙動になるのではないかと思います。
なお今回の記事は、前々回前回のカスタムをすでにやっていることが前提となります。

前提は以下です。
・rootとってあること
・作業PCはadbコマンドが使える環境であること
・作業PCにjavaが入っていること
・端末のビルド番号は9.0.G.1.76
・CWMを導入してあること
・母艦はWindows 7
・トラブっても自力で復旧できること(つまり自己責任)

いじるファイルは、以下になります。
/system/framework/android.policy.odex

■android.policy.odex
android.policy.odexをbaksmaliした展開先の中で、以下のフォルダを探して開きます。
com\android\internal\policy\impl

前回作成した「PhoneWindowManager$KillConcept.smali」ファイルの内容を書き換えます。
内容は以下になります。

.class Lcom/android/internal/policy/impl/PhoneWindowManager$KillConcept;
.super Ljava/lang/Object;
.source "PhoneWindowManager.java"

# interfaces
.implements Ljava/lang/Runnable;


# annotations
.annotation system Ldalvik/annotation/EnclosingClass;
    value = Lcom/android/internal/policy/impl/PhoneWindowManager;
.end annotation

.annotation system Ldalvik/annotation/InnerClass;
    accessFlags = 0x0
    name = null
.end annotation


# instance fields
.field final synthetic this$0:Lcom/android/internal/policy/impl/PhoneWindowManager;


# direct methods
.method constructor <init>(Lcom/android/internal/policy/impl/PhoneWindowManager;)V
    .registers 2
    .parameter

    .prologue
    .line 4204
    iput-object p1, p0, Lcom/android/internal/policy/impl/PhoneWindowManager$KillConcept;->this$0:Lcom/android/internal/policy/impl/PhoneWindowManager;

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

    return-void
.end method


# virtual methods
.method public run()V
    .registers 10

    .prologue
    iget-object v0, p0, Lcom/android/internal/policy/impl/PhoneWindowManager$KillConcept;->this$0:Lcom/android/internal/policy/impl/PhoneWindowManager;

    const/4 v1, 0x0

    const/4 v2, 0x0

    const/4 v3, 0x0

    invoke-virtual {v0, v1, v2, v3}, Lcom/android/internal/policy/impl/PhoneWindowManager;->performHapticFeedbackLw(Landroid/view/WindowManagerPolicy$WindowState;IZ)Z

    iget-object v1, v0, Lcom/android/internal/policy/impl/PhoneWindowManager;->mContext:Landroid/content/Context;

    new-instance v2, Landroid/content/Intent;

    const-string v3, "android.intent.action.MAIN"

    invoke-direct {v2, v3}, Landroid/content/Intent;-><init>(Ljava/lang/String;)V

    const-string v3, "android.intent.category.HOME"

    invoke-virtual {v2, v3}, Landroid/content/Intent;->addCategory(Ljava/lang/String;)Landroid/content/Intent;

    invoke-virtual {v1}, Landroid/content/Context;->getPackageManager()Landroid/content/pm/PackageManager;

    move-result-object v3

    const/4 v4, 0x0

    invoke-virtual {v3, v2, v4}, Landroid/content/pm/PackageManager;->resolveActivity(Landroid/content/Intent;I)Landroid/content/pm/ResolveInfo;

    move-result-object v2

    iget-object v2, v2, Landroid/content/pm/ResolveInfo;->activityInfo:Landroid/content/pm/ActivityInfo;

    if-eqz v2, :cond_1

    iget-object v2, v2, Landroid/content/pm/ActivityInfo;->packageName:Ljava/lang/String;

    const-string v3, "android"

    invoke-virtual {v3, v2}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v3

    if-nez v3, :cond_1

    goto :cond_2

    :cond_1
    const-string v2, "com.android.launcher"

    :cond_2
    const-string v3, "activity"

    invoke-virtual {v1, v3}, Landroid/content/Context;->getSystemService(Ljava/lang/String;)Ljava/lang/Object;

    move-result-object v3

    check-cast v3, Landroid/app/ActivityManager;

    const/4 v4, 0x1

    invoke-virtual {v3, v4}, Landroid/app/ActivityManager;->getRunningTasks(I)Ljava/util/List;

    move-result-object v4

    invoke-interface {v4}, Ljava/util/List;->iterator()Ljava/util/Iterator;

    move-result-object v4

    invoke-interface {v4}, Ljava/util/Iterator;->hasNext()Z

    move-result v5

    if-eqz v5, :cond_10

    invoke-interface {v4}, Ljava/util/Iterator;->next()Ljava/lang/Object;

    move-result-object v4

    check-cast v4, Landroid/app/ActivityManager$RunningTaskInfo;

    iget-object v5, v4, Landroid/app/ActivityManager$RunningTaskInfo;->topActivity:Landroid/content/ComponentName;

    invoke-virtual {v5}, Landroid/content/ComponentName;->getPackageName()Ljava/lang/String;

    move-result-object v5

    invoke-virtual {v2, v5}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v6

    if-nez v6, :cond_10

    invoke-static {}, Landroid/app/ActivityManagerNative;->getDefault()Landroid/app/IActivityManager;

    move-result-object v6

    invoke-interface {v6}, Landroid/app/IActivityManager;->getRunningAppProcesses()Ljava/util/List;

    move-result-object v6

    invoke-interface {v6}, Ljava/util/List;->iterator()Ljava/util/Iterator;

    move-result-object v6

    :cond_3
    invoke-interface {v6}, Ljava/util/Iterator;->hasNext()Z

    move-result v7

    if-eqz v7, :cond_10

    invoke-interface {v6}, Ljava/util/Iterator;->next()Ljava/lang/Object;

    move-result-object v7

    check-cast v7, Landroid/app/ActivityManager$RunningAppProcessInfo;

    iget-object v8, v7, Landroid/app/ActivityManager$RunningAppProcessInfo;->processName:Ljava/lang/String;

    invoke-virtual {v5, v8}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v8

    if-eqz v8, :cond_3

    iget v5, v4, Landroid/app/ActivityManager$RunningTaskInfo;->id:I

    const/4 v2, 0x1

    invoke-virtual {v3, v5, v2}, Landroid/app/ActivityManager;->removeTask(II)Z

    const/4 v6, 0x1

    const-string v2, "com.android.externalres"

    const/4 v3, 0x4

    invoke-virtual {v1, v2, v3}, Landroid/content/Context;->createPackageContext(Ljava/lang/String;I)Landroid/content/Context;

    move-result-object v2

    invoke-virtual {v2}, Landroid/content/Context;->getResources()Landroid/content/res/Resources;

    move-result-object v2

    const v3, 0x7f030002

    invoke-virtual {v2, v3}, Landroid/content/res/Resources;->getText(I)Ljava/lang/CharSequence;

    move-result-object v2

    const/4 v3, 0x0

    invoke-static {v1, v2, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v2

    invoke-virtual {v2}, Landroid/widget/Toast;->show()V

    :cond_10
    return-void
.end method

アプリ終了を実行する部分です。
「removeTask」というメソッドを呼び出し、フォアグラウンドアプリをキルするようにしています。
途中の「const v5, 0x7f030002」という部分はもちろん、external-res.apkに追加した文字列のIDに合わせてください。

■仕上げ
上記変更後、deodex_android.policy.jarを生成し、CWMモードで端末に送信、dexopt-wrapper等の作業を行いつつ、/system/frameworkのandroid.policy.odexを置き換えてください。

11 件のコメント:

  1. はじめまして、Xperia ULのMODファイルを作成しています。
    キューブキューブさんを含めいろいろな方の情報を参考にしてコード移植しているだけですが、電源メニューの再起動追加もできました。(テスト漏れで電源長押し時のアラートダイアログ表示がミスってるのは内緒です)

    アセンブラのコードで move-result-objectというのがあるのですが、どう解釈していいのか悩んでます。
    教えていただけないでしょうか?

    あと、戻るキー長押しでアプリキルのコード移植をしたのですが、「開発者オプションの表示は確認済み」で「戻るキーを押してもタスクキルされてない」という状況です。ZModのソースを参考にさせていただき、PhoneWindowManager.smaliを少し修正すれば使えるとにらんだのですが、甘かったようです。
    何か見るポイントありますでしょうか?

    返信削除
    返信
    1. 自己解決しました。PhoneWindowManager.smaliのコード移植でレジスタの操作をミスしていました。PhoneWindowManager$KillConcept.smaliはそのまま使用させていただいており、実装完了しました。
      本当に有益な情報を載せていただきありがとうございます。
      これからも待ってます。

      削除
    2. おめでとうございます。
      ちなみに、もうお調べになられたのであれば恐縮ですが、move-result-objectは、その直前のinvoke(関数呼び出し)の戻り値をレジスタに入れる命令です。
      「-object」が付いてるのは、レジスタに入るのが数値とかのプリミティブ型ではなくて、オブジェクトであるということを表しています。
      smaliに関する記事はいつかまとめたいとは思ってるのですが、分量が多くて、いつになるやら…。

      削除
    3. 貴重な情報をありがとうございました。やっぱり戻り値を入れる命令だったんですね。
      アセンブラのコードを見てて、そんな気はしてたんですが、命令セットの意味に確信が持てなくて、いれていいのか悪いのか悩んでたので、すごく助かります。
      まとめるのは確かに大変ですよね。コード見て理解できなければ手を出せないのも事実ですし…。
      カメラ関係に手を出したいのですが、Zのオリジナルソースを所持していないので、変更点が分からず、移植するのに手をこまねいてます。

      削除
    4. スクリーンショット消音でしたら、Zの場合
      SystemUI.odex
      com\android\systemui\screenshot\GlobalScreenshot$3.smali
      61行目あたりの
      invoke-virtual {v0, v1}, Landroid/media/MediaActionSound;->play(I)V
      を削除かコメントアウトでいけますね。

      カメラ音オプションの有効化は、これもZの場合ですが、
      SemcCameraUI.apk\smali\com\sonyericsson\android\camera\configuration\SystemPropertiesReader.smali
      .method private constructor ()V メソッド内、
      73行目を、「const/4 v1, 0x1」→「const/4 v1, 0x0」
      また、
      SemcCamera3D.apk\smali\com\sonyericsson\android\camera3d\CameraConfigManager.smali
      .method private setForceSound(Ljava/lang/String;)V メソッド内、
      6261行目を「const/4 v1, 0x1」→「const/4 v1, 0x0」
      これでいけたそうです。
      (自分では試してないですが、Z持ちの方がいけたと言ってました。)

      削除
    5. カメラ音オプションの有効化はULでもそれでOKです。
      スクリーンショットはこんなとこにあったんですね。ファイルを削除して対応するのが簡単だったんですが、貴重な情報ですm_ _m

      UL_MODですが、下記まで実装して公開してます。
      加えて、ローカルではボリュームキーでスタンバイ復帰も実装しました。
      ただキューブキューブさん達のを移植させていただいてるだけですが、本当に恐縮です。

      (1) シャッター音設定
      (2) ナビバー5キー(サーチとメニュー追加)
      (3) バッテリアイコン非表示
      (4) 全アプリ終了ボタン位置変更
      (5) ステータスバーのアイコンを見やすくした
      (6) ドック使用時の自動回転無効化
      (7) 充電完了時にLEDを消灯
      (8) Wi-Fiアイコンとアンテナ表示統合
      (9) 画面の最低輝度の変更(20->5)
      (10)ナビゲーションバー高さの変更(48->40)
      (11)ステータスバーに日付/時刻2段階表示追加
      (12)通知領域開いた時の右の日付表示消去
      (13)キャッシュスクロール無効
      (14)電源長押しで再起動項目追加(再起動しますか?のダイアログも実装)
      <0.5.1~0.5.4は実験中の施策Verで0.5.5で完了>
      (15)戻るキー長押しタスクキル
        ※設定→開発者向けオプション→長押しでアプリ終了にチェックを入れてください
      (16)ボリューム調整値変更
        受話音量、着信、音楽、アラーム、メディア、BlueTooth

      削除
    6. いやいや、素晴らしい。どんどん移植してください。
      Xperiaに繁栄あらんことを。

      削除
  2. こんにちわ。
    先日までXperiaを使っていたのですが、嫁に渡したため、
    現在、HTC ONEを使っています。

    そこで、この便利なMODを一部でも移植をしたいと考えているのですが、
    Xperia以外への移植というのは可能なのでしょうか?
    (ひとまず、アプリKillは欲しい)

    正直、コードは全く読めないのでどの部分のコードを書くかなどは勘で行こうかと思います。

    可能なのでしょうか?お手数ですが、教えて下さい。

    返信削除
    返信
    1. 同じAndroidですので、コードはそう変わらないと思いますし、カスタム方法は同じなはずです。可能かどうかで言えば、可能です。
      ただし、レジスタ番号等が機種によって変わっていたりすることも多々ありますので、若干プログラミングの心得が無いと厳しいかもしれません。

      削除
    2. そうですか。。。ちょっと厳しそうですね。
      Xposedで作るという考えもあるかと思うのですが、
      このMODをXposedに移植する計画などは無いでしょうか?

      頑張ってXposedを覚えたほうが早い気がしてきました。

      削除
    3. Xposedは諸々の理由で個人的には敬遠しております。
      変更に再起動が必要なのが大きいですね。
      まあ食わず嫌いでもあるのですが。

      削除