2012年12月3日月曜日

【Xperia AX SO-01E】電源ボタン長押しメニューに「再起動」追加(1)

【注】この記事のカスタマイズだけでは、ちょっとした不具合が残ります。一旦「再起動」をタップ、キャンセルしてから「電源を切る」してOKすると、シャットダウンにならず再起動になってしまいます。それについては修正した記事をアップしておりますので、そちらも参照ください。

電源ボタンを長押しすると、「電源を切る」等の終了メニューが出てきますが、ここに「再起動」オプションを追加します。
「再起動」をタップしたあとのメッセージは電源を切る時と同じになります。
もっと細かく作り込むことも出来るのでしょうが、いろいろややこしそうですので、とりあえずは再起動が機能することを目標にします。

※なお、こちらの記事の方法を使うと、アイコンや項目の文字を自由に変更できるようになります。

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

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

■必要物資
・android.policy.jar(dex→odexにする際に必要)
・android.policy.odex(今回の獲物)
・baksmali-1.4.1.jar(odexをソースファイルに展開するツール)
・smali-1.4.1.jar(ソースファイルをdexにするツール)
・7za.exe(dexをjarに埋め込む際に必要)
・dexopt-wrapper(dex入りのjar→odexを生成するツール)
・bouncycastle.odex(baksmali時に必要)
・core.odex(baksmali時に必要)
・core-junit.odex(baksmali時に必要)
・ext.odex(baksmali時に必要)
・framework.odex(baksmali時に必要)
・framework_ext.odex(baksmali時に必要)

baksmaliとsmaliは、「smali」で検索してゲット。
7zaは「7-zip」で検索、コマンドラインバージョンをダウンロードしてゲット。
dexopt-wrapperは http://forum.xda-developers.com/showpost.php?p=3864655&postcount=36 からゲット。
その他jarやodexは端末からぶっこ抜きましょう。
今回のは全部端末の「/system/framework」に入っています。

■1.PCにおける作業フォルダの準備
ここでは「c:\odexwork」とします。
この中に、「old」と「new」フォルダを新規作成します(すでにある場合はそのまま使います)。
必要物資のうち、android.policy.jarとandroid.policy.odexは「old」に入れておいてください。
その他の必要物資は、作業フォルダ直下に全部ぶっこみます(すでにある物に関してはそのままでいいです)。
以降はコマンドラインでの作業になりますが、「odexwork」フォルダをShift押しながら右クリックで「コマンド ウィンドウをここで開く」すると便利です。

□odexwork ┳ □old ┳ android.policy.jar
      ┃    ┗ android.policy.odex
      ┣ □new(deodex_android.policy.jarが入る予定)
      ┣ □android.policy(作業途中で生成される。ソースファイル群が入る)
      ┣ baksmali-1.4.1.jar
      ┣ smali-1.4.1.jar
      ┣ 7za.exe
      ┣ dexopt-wrapper
      ┣ bouncycastle.odex
      ┣ core.odex
      ┣ core-junit.odex
      ┣ ext.odex
      ┣ framework.odex
      ┗ framework_ext.odex

■2.baksmaliする
C:\odexwork>java -Xmx512m -jar baksmali-1.4.1.jar --api-level 15 -x old\android.policy.odex -o android.policy

このとき、作業フォルダに必要なodexが無いとエラーが出ますが、エラーの中で何が必要か教えてくれます。
成功すると、作業フォルダ内に「android.policy」フォルダができ、その中にソースファイルがたくさん入っています。

■3.ソースファイルの作成・書き換え等
「android.policy」フォルダ内で、以下のフォルダを探して開きます。
com\android\internal\policy\impl

【3-1】
「GlobalActions$2.smali」というファイルを複製し、「GlobalActions$9.smali」にリネーム。

出来た「GlobalActions$9.smali」の内容をテキストエディタで書き換えます。

ソース内に「GlobalActions$2」が3か所くらい存在しています。(1行目、30行目、44行目あたり)
まず、それらをすべて「GlobalActions$9」 に書き換えます。

次に「.method public onPress()V」を検索(39行目あたり)

その直下の「.registers 3」を「.registers 4」に書き換えます。

# virtual methods
.method public onPress()V
    .registers 3
↓↓↓
# virtual methods
.method public onPress()V
    .registers 4  #変更

もしかしたら「.registers 3」じゃなくて「.locals 2」とかになっているかもしれませんが、とにかく数字を1つ増やします。

その10行くらい下(50行目あたり)の「const/4 v1, 0x1」を「const-string v1, "now"」に書き換え、空行を挟んで「const/4 v2, 0x1」を追加します。
さらにその直下の「invoke-static うんたらかんたら ->shutdown( うんたらかんたら」の行も書き換えます。

    move-result-object v0

    const/4 v1, 0x1

    invoke-static {v0, v1}, Lcom/android/internal/app/ShutdownThread;->shutdown(Landroid/content/Context;Z)V
↓↓↓
    move-result-object v0

    const-string v1, "now"  #変更

    const/4 v2, 0x1  #追加

    invoke-static {v0, v1, v2}, Lcom/android/internal/app/ShutdownThread;->reboot(Landroid/content/Context;Ljava/lang/String;Z)V  #変更

v1は再起動の理由(文字列)が入ります。通常の再起動の場合は"now"にしておきます。今すぐ再起動って感じですかね。
v2はシャットダウン確認のダイアログを出すかどうかの値です。0x0にすると「再起動」をタップした途端、確認無しに再起動となります。お好みで。

以上、書き換えたら上書き保存。

【3-2】
「GlobalActions.smali」というファイルを書き換えます。

「.method private createDialog()Landroid/app/AlertDialog;」を検索。(394行目あたり)

その直下の「.registers 14」を「.registers 15」に書き換えます。

.method private createDialog()Landroid/app/AlertDialog;
    .registers 14
↓↓↓
.method private createDialog()Landroid/app/AlertDialog;
    .registers 15  #変更

これも手順3-1のように「.registers 14」じゃなくて「.locals 13」とかになっているかもしれませんが、とにかく数字を1つ増やします。

その3行くらい下(398行目あたり)に「const v12, 0x1080030」というのがありますが、空行を挟んで「const v13, 0x108004d」を追加します。

    .prologue
    const v12, 0x1080030
↓↓↓
    .prologue
    const v12, 0x1080030

    const v13, 0x108004d  #追加

「0x108004d」というのは、点を丸い矢印が取り囲んだアイコンを表します。もし再起動のアイコンが「電源を切る」のアイコンと同じで良ければ、v12の値と同じく「0x1080030」にしておいてください。

その44行くらい下(444行目あたり)に、

    new-instance v1, Lcom/android/internal/policy/impl/GlobalActions$2;

    const v2, 0x10401a7

    invoke-direct {v1, p0, v12, v2}, Lcom/android/internal/policy/impl/GlobalActions$2;-><init>(Lcom/android/internal/policy/impl/GlobalActions;II)V

    invoke-virtual {v0, v1}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z

という部分があります。
この下に数行記述を追加し、以下のようにします。

    new-instance v1, Lcom/android/internal/policy/impl/GlobalActions$2;

    const v2, 0x10401a7

    invoke-direct {v1, p0, v12, v2}, Lcom/android/internal/policy/impl/GlobalActions$2;-><init>(Lcom/android/internal/policy/impl/GlobalActions;II)V

    invoke-virtual {v0, v1}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z

    new-instance v1, Lcom/android/internal/policy/impl/GlobalActions$9;  #追加

    const v2, 0x10403a9  #追加

    invoke-direct {v1, p0, v13, v2}, Lcom/android/internal/policy/impl/GlobalActions$9;-><init>(Lcom/android/internal/policy/impl/GlobalActions;II)V  #追加

    invoke-virtual {v0, v1}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z  #追加

これがメニューの「電源を切る」の下に「再起動」を追加する部分になります。

編集がすんだら上書き保存してください。

■4.smaliする
C:\odexwork>java -Xmx512m -jar smali-1.4.1.jar --api-level 15 -o classes.dex android.policy

classes.dexが生成されます。

■5.classes.dexをandroid.policy.jarに埋め込み
C:\odexwork>copy /y old\android.policy.jar new\deodex_android.policy.jar
C:\odexwork>7za a -tzip -mx0 new\deodex_android.policy.jar classes.dex
C:\odexwork>del classes.dex

オリジナルのjarと区別をつけるため、「deodex_android.policy.jar」という名前でjarをコピーしておき、その中にclasses.dexを埋め込みます。

■6.端末をCWMモードにして待機
以降は端末をCWMモードにして作業をすすめます。
理由は安全のためと、転送したファイルの所有者が最初からrootになってて気分が良いから。
CWMの作者様に感謝です。

端末の電源を入れ、SONYロゴが出てから15秒くらいして青LEDが点くのですぐさま音量DOWNボタンを押しっぱなしにし、LEDが緑に変わったらボタンを離します。
しばらくするとCWMのメニュー画面になります。
「mounts and storage」に入り、「mount /system」と「mount /data」をしておきます。
もちろんPCと端末はUSBでつないでおいてください。

■7.ファイルを端末にぶっこむ
C:\odexwork>adb push new\deodex_android.policy.jar /data/local/tmp
C:\odexwork>adb push dexopt-wrapper /data/local/tmp

多分、rootをとった時に/data/local/tmpは作られていると思うので、それ前提です。
すでにdexopt-wrapperを導入している場合、2行目は不要です。

■8.dexopt-wrapperのパーミッション変更
以降は端末のシェルに入っての作業となります。

C:\odexwork>adb shell
~ # cd /data/local/tmp
/data/local/tmp # chmod 0755 dexopt-wrapper

すでにdexopt-wrapperを導入している場合、3行目は不要です。

■9.jarからodex生成
/data/local/tmp # ./dexopt-wrapper deodex_android.policy.jar android.policy.odex /system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/framework_ext.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/filterfw.jar

deodex_android.policy.jarを元に、android.policy.odexが生成されます。
3つ目の引数がやたら長いですが、これを指定しておかないと、上手くodexが作れません。しかも順番も重要のようですので、この部分は下手にいじらないほうが良いでしょう。

本来3つ目の引数には、BOOTCLASSPATHという環境変数を指定するそうで、これはSO-01Eの場合、

/system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/framework_ext.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/filterfw.jar

なのですが、元になるjar(今回はandroid.policy.jar)が含まれているとちゃんとしたodexが生成されない場合があったので、削除してあります。

なお、dexopt-wrapperは生成ファイルを上書きできないようですので、すでに/data/local/tmpにandroid.policy.odexがある場合は、あらかじめ「rm android.policy.odex」しておきましょう。

■10.odexに署名をコピー
/data/local/tmp # busybox dd if=/system/framework/android.policy.odex of=android.policy.odex bs=1 count=20 skip=52 seek=52 conv=notrunc

手順9で生成したodexは、署名がまずいらしいので、元のodexから署名部分を移植します。

■11.パーミッション変更
すでにパーミッションが0644になってるかもしれませんが、念の為。

/data/local/tmp # chmod 0644 android.policy.odex

android.policy.odexのパーミッションを0644に変更。

■12.仕上げ
/data/local/tmp # mv /system/framework/android.policy.odex /system/framework/android.policy.odex.bak
/data/local/tmp # cp android.policy.odex /system/framework
/data/local/tmp # reboot

元のファイルをリネームしてバックアップ(すでにしたことがあれば不要)しておき、新しいandroid.policy.odexを/system/frameworkに配置。
そして再起動。
ちゃんと起動し、電源ボタン長押しでメニューが出たら成功と思われます。

8 件のコメント:

  1. はじめまして、お世話になります。
    私はSO-03Dなんですが、電源オプションに再起動とCWMリカバリは追加しています。スクリーンショットの追加もチャレンジしていますが、これがうまくいきません。
    某掲示板のGXスレを参考にframework-res.apkに画像と画像リソースID追加、android.policy.jarのGlobalAction.smali、GlobalAction$9.smali、GlobalAction$9$1.smali、PhoneWindowManager.smali、PhoneWindowManager$23.smaliの修正・追加しました。
    電源長押し時には表示されるのですが、動作しません。よろしかったらキューブキューブさんはどうやったかご教授お願いします。
    不躾で申し訳ありませんが、宜しくお願いします。

    返信削除
    返信
    1. はじめまして。
      電源メニューのスクリーンショットは、SO-01Eには初めから搭載されているので、そこに関して私は実はいじっていないんですね…。

      SO-01Eの場合、GlobalAction$3$1.smali(そちらでのGlobalAction$9$1.smaliに相当するのかな?)の中で「com.sonymobile.intent.action.SCREEN_CAPTURE」というアクションのIntentをsendBroadCastしていて、それをシステムが受け取ってスクリーンショットを撮るような感じになっていますが…SO-03Dとどれだけ違うか分からないので何とも言えませんね。
      あまりお役に立てず申し訳無いです。

      削除
  2. zをこの記事で弄ってますがGlobalActions$2.smaliを複製してG~$9にリネームとありますがG~$9のファイルが元から存在してますがどうすば良いですか?他機種ですみませんがご教授お願いします。素人で申しわけありません。

    返信削除
    返信
    1. まず機種によって$の後の数字が異なる可能性がありますので、そちらを確認してください。GlobalActions$2.smaliは多分共通していると思いますが、「うんたらかんたら->shutdown()V」が存在していれば大丈夫だと思われます。
      そしてリネームするファイル名に関して、$の後の数字は既存のファイルとかぶらなければ何でも良いです。もっと言うと数字でなくても良くて、「GlobalActions$CWM.smali」とかでも構いません。ただしその場合は、記事中に出てくる「$9」は(GlobalActions.smaliに追加するコードも含め)すべて読み替えてください。
      さらにあらかじめ言うと、この続きの記事に出てくるShutdownThread.smaliは、SO-02Eではおそらくframework.odexではなくservices.odexのcom/android/server/pmにあります。
      …正直申し上げるならば、素人を自称されるのであればカスタムはあまりお勧めしません。(一言多くて申し訳無いです。)

      削除
    2. この記事を参考にZでカスタムしてる記事がありました。詳しくありがとうございます。

      削除
  3. はじめまして、お世話になります✞vanishment✞です。ツイッターフォローさせてもらいました
    早速なんですが、先日SO-04E(ミクモデル)を買いましてこちらのサイトを参考にroot化して使っております。
    再起動追加に挑戦したいのですが・・・最初の最初でつまずきましてコメントさせてもらいました。
    odexworkというファイルはc:\Users\(ユーザー名)\Desktop\odexwork という風に作りました 中身は完璧です・・・たぶん
    で、コマンドラインでコマンドを実行すると
    Error occured while loading boot class path files. Aborting.
    org.jf.dexlib.Util.ExceptionWithContext: Cannot locate boot class path file tele
    phony-common.odex
    at org.jf.dexlib.Code.Analysis.ClassPath.loadBootClassPath(ClassPath.jav
    a:218)
    at org.jf.dexlib.Code.Analysis.ClassPath.initClassPath(ClassPath.java:14
    6)
    at org.jf.dexlib.Code.Analysis.ClassPath.InitializeClassPathFromOdex(Cla
    ssPath.java:111)
    at org.jf.baksmali.baksmali.disassembleDexFile(baksmali.java:94)
    at org.jf.baksmali.main.main(main.java:308)

    と出ます どうすればよいのでしょう
    母機は windows7 です
    不躾で申し訳ありませんが、
    キューブキューブさん、ご教授宜しくお願いします。m(_ _)m

    返信削除
  4. で、telephony-common.odexがないということでしょうか?
    SO-04Eのframeworkにはありませんでした
    適当にネットから取ってきてもよいのですか?

    返信削除
    返信
    1. スイマセンもう一回端末からコピーし直したら
      ありましたご迷惑をおかけしました

      削除