2015年1月12日月曜日

BLUL不可能なAndroid端末でモジュールを作成する方法(Xperia Z  SO-02E編)

 さて、備忘録を兼ねて記録を残していきます。
 日本国内のスマホは現在販売されているものはBLUL(ブートローダの解錠)が出来ないため、端末の自由な改造が出来ません。
 私はパズドラ他スマホではゲームはほとんどしないため、そんな不自由な状態ではつかいたくないので、自分の知識を付ける目的でroot取得後にCPUガバナを移植してみることにしました。

 え、ストックのガバナが性能と省電力のバランスが最高ではないのかって?そうかもしれないけど、もしかしたらそうではないかもしれない。やってみて損はないでしょ?
 また、自分はXperiaユーザのためSONY mobile製品の話しか記載しておりませんが、他社でも同じ方法で作成することが出来るかと思います。

1)前提条件

  • 端末の管理者権限(root)取得
    大前提。root取得した時点で、故障時にドコモショップほか通信キャリアのショップへの持ち込みはしないと心に誓うこと。
  • 動作環境
    コンパイルのためのtoolchainはLinux環境でしか検証しておりません
    もしかしたらWindows・MACで動作するかもしれませんが、どちらも環境は作っていなのでわかりません。
  • android SDKをインストールしadbが動作することを事前に確認すること。
    また、"adb shell"にて端末のLinuxのシェルが普通に使えること。
  • ストックカーネルのビルド方法を理解する
    SONY mobile の Developper Worldの以下のリンクを事前に読み、ストックカーネルを自分の母艦(PC)上で作成する仕組みについてざっと理解すること。
    how-to-build-and-flash-a-linux-kernel

2)カーネルソースコードのダウンロード

SONY mobile の Developper Worldから自分の端末で使用するカーネルソースをダウンロードする。
http://developer.sonymobile.com/downloads/opensource/
 ここにあなたの端末の新しいOSイメージが出た際にOpen source archiveが公開されるのでそれをダウンロード。
 ちなみにこのドキュメントを最初に書いた時点(2015年1月)ではXperia Z(SO-02E)向けの最新ビルドは10.5.1.B.0.68(2014年11月27日に公開)。
 ダウンロードしたソースコードを自分のPC上で解凍する。ちなみにkernelフォルダ内部だけで良い。

3)クロスコンパイラのダウンロード

先に記載したリンクにあるGoogleのAndroid SDKに添付のクロスコンパイラ(toolchain)をダウンロードし、PATHを通しておく。
 このコンパイラでカーネル・モジュールをmakeする際には必ず「ARCH=arm CROSS_COMPLE=$CROSS_COMPILE」と指定する形になる。
 環境変数$CROSS_COMPILEは先にダウンロードしたtoolchainのうち、bin/arm-eabi-を指定する。この値はMakefileに記述するか、.bashrcに記述しておけば良い。もちろん環境変数を使いたくない場合はフルパスで指定すればよい。

4)ストックカーネルのビルド

私がストックカーネル向け追加モジュールをビルドした際、一番スムーズに動作したのは追加モジュールのソースコードをストックカーネルのソースコードとは別のディレクトリに配置し、make時にストックカーネルのソースディレクトリを指定する方法でした(やり方は後述)。
 という訳で、予めストックカーネルを以下の方法でビルドします。
 a)EXTRAVERSIONの一致
  adb shellで端末のシェルを動作させ、uname -rコマンドでストックカーネルのバージョン表示をします。
  また、/system/lib/modulesにある何らかのモジュールに対してmodinfo ****.ko(****にはその場所にあるモジュールを指定。どれでもいいです、例えばlcd.ko)してvermagicの記載文字列を確認してください。
  vermagicの例 
vermagic:       3.4.0-gdfbed73 SMP preempt mod_unload modversions ARMv7
次にストックカーネルのルートディレクトリにあるMakefileの先頭にEXTRAVERSIONと記載があり空欄ですがそこにunameやlsmodの記載を合わせてください。
  例えば上のvermagicの場合は「EXTRAVERSION = -gdfbed73」と指定します

 b)Configの生成
  以下のコマンドでSO-02E向けのコンフィグを複写します。
make ARCH=arm CROSS_COMPILE=$CROSS_COMPILE fusion3_yuga_dcm_defconfig
(この時、「ARCH=arm CROSS_COMPILE=$CROSS_COMPILE」とありますが、要らない可能性が高い。)
  ここでは、「arch/arm/configs/」にある「fusion3_yuga_dcm_defconfig」をストックカーネルの.configに複写しています。
  先に紹介したSONY mobileの「how-to-build-and-flash-a-linux-kernel」ではXperia Z向けに別なコンフィグ名が指定されていましたが、SO-02Eの場合は一連の開発ボードのコードネーム=fusion3、Xperia Zの開発コードネーム=yuga、ドコモ=dcmのためこれで間違いありません。

  次にvermagicを合わせるため、先のコマンドで作成された.configファイルをエディタで開きます。CONFIG_LOCALVERSIONを探し、先に調べた"-gdfbed73"と入力して下さい。
  もしこの方法が気に入らない場合は、.configファイルの CONFIG_LOCALVERSIONは空欄にし、MakefileEXTRAVERSIONを編集して下さい。
  カスタムカーネルを作成する場合はこのあとで「make menuconfig」を実行し、カーネルの設定を色々変更しますが、ストックカーネル向けのモジュールを作成する場合は元のコンフィグを変更する必要はありません。逆に指定するとModule.symversが変更されて動作しない可能性があります(これがストックカーネルに追加モジュールを統合してメイクしない理由)。

 c)カーネルイメージ作成のための事前準備
  以下のコマンドでカーネルイメージ作成のための事前準備をします(もしかしたら不要かも)。
make ARCH=arm CROSS_COMPILE=$CROSS_COMPILE prepare
make ARCH=arm CROSS_COMPILE=$CROSS_COMPILE scripts/mod/

 d)ストックカーネルのビルド
  以下のコマンドでストックカーネルをビルドすると、Module.symversが作成され、外部モジュールのコンパイルが正常に動作します。
make -j8 ARCH=arm CROSS_COMPILE=$CROSS_COMPILE
要は一回カーネルをビルドし、内部モジュールのsymbol番号を確定させる処理です。
  なお、makeで指定している以下のオプションはこのような意味です。
  • -j
       同時にコンパイル出来るスレッド数
  • ARCH=
      コンパイルする際のCPUアーキテクチャー(armを指定)
  • CROSS_COMPILE=
      makeに教えるクロスコンパイラのパス(先にダウンロードしたクロスコンパイラの配置場所を環境変数で指定すれば良い)

5)ストックカーネル向けのモジュールのダウンロード

Xperia Z向けのCPUガバナのソースコードとして、以下の場所よりダウンロードしました。
  ①【ROM焼き】docomo Xperia GX/SX SO-04D/05D root1 で154氏が作成したモジュールのソースコード
http://www.mediafire.com/download/ob4clfek421bdw6/T.TX.V.4.3_kernel_modules.zip
(次項で記載のsymbol番号の件はこれで理解出来ました。感謝)
また、intellidemandやsmartassH3など最新版は以下の場所よりダウンロードしました。
  ②AnDyXXが作成したXperia Z向けのcpuガバナのソースコード
  https://github.com/AnDyXX/Xperia-devices
(ただしコチラはsymbol番号の件によりそのままではビルドできないものがある。)

6)モジュールのビルド

a)mediafireのソースコードのMakefileを加工
  自分向けの環境と違うので直してしまいましょう。
  外部のモジュールのソースコードをビルドする際、ストックカーネルでカーネルイメージを生成する際にmakeで指定したコマンドに以下のものを追加する必要があります。
  • -C
       ストックカーネルのソースディレクトリを指定
  • SUBDIRS=
      「今回ビルドするモジュールのディレクトリ」を指定
SUBDIRSを指定した場合はその後ろにmodulesを付けること。
  modulesを付けたくない場合はM=「今回ビルドするモジュールのディレクトリ」とする。
  まとめると以下の通り(/home/hogehoge配下のkernelにストックカーネルのソースコードを配置し、moduleに今回ビルド用のソースを配置した場合。)。
  make ARCH=arm CROSS_COMPILE=$CROSS_COMPILE -C /home/hogehoge/kernel SUBDIRS=/home/hogehoge/module modules
もしくは
  make ARCH=arm CROSS_COMPILE=$CROSS_COMPILE -C /home/hogehoge/kernel M=/home/hogehoge/module
これだけでmakeコマンド一発でモジュールのビルドは終了する。
  なお、自分の欲しいモジュールだけ指定する場合はMakefileの記載をobj += *****.oに直して複数行に分けてしまおう。
  (作成不要なモジュールの行頭に#を付けてコメント化することで生成しなくても済むため。)
 b)GitHubのソースコード修正
  GitHubでダウンロードしたソースコードはsymbol番号(要はストックカーネルのシステムコールのアドレス番地)が参照できずに警告出力される。
  この状態ではkoファイル(カーネルモジュール)が生成されるが、端末に複写してもモジュールを追加することはできない。
  そこでmediafireのソースコードにあるsymsearch.cの仕組みを利用してストックカーネルからsymbol番号を生成出来るようにする。
  • まずは一度ビルドし、phase2のWarningを出力させる。この時表示されるメッセージは以下のような感じ
    WARNING: "cpufreq_notify_utilization" [xperiaz_smartassH3.ko] undefined!
    これは"cpufreq_notify_utilization"のsymbol番号がわからないという意味。
  • 先のmediafireのソースコードではsymsearch.koを利用することでストックカーネル内部からsymbol番号を導出していたので、以下の通り処理させる。
    Warningが表示されたソースコードの先頭部分に以下のような記述を追加する
    SYMSEARCH_DECLARE_FUNCTION_STATIC(void, cpufreq_notify_utilization_s, struct cpufreq_policy *, unsigned int);
    これは、void cpufreq_notify_utilization_s(struct cpufreq_policy *, unsigned int)という関数を定義したという意味。
    先にUndefinedだった関数(この場合はcpufreq_notify_utilization)をストックカーネルのinclude/linuxからgrepで探し、当該ヘッダファイルからその関数定義を探して上記のようにマクロで記載する。
  • 次に当該ガバナの初期化処理(大概はソースファイルの最後の方にある)に以下の記述を追加
    SYMSEARCH_BIND_FUNCTION_TO(smartassH3, cpufreq_notify_utilization, cpufreq_notify_utilization_s);
    これは内部関数のcpufreq_notify_utilizationとcpufreq_notify_utilization_sを関連付けさせるという意味。
最終的にはmediafireのソースコードと双方睨めっこしてよく確認しながら行うこと。
  修正後、makeで正常にモジュールが作成されてエラーが表示されなければ終了。

7)端末へのモジュール複写と試運転

 adb push で端末にモジュールを複写する。その後、insmod でモジュールを読込させ、正常に動作することを確認する。
 当然ながらsymsearchを利用した場合は当該モジュールの読込前にsymsearch.koを読込させなければなりません。
 この時dmesgに"no symbol version for module_layout"などが表示されないか確認すること。
 追加したCPUガバナをアプリで変更(Faux Clock他)し、動作を確認してみる。
 insmodで作ったモジュールを追加した状態だけだと仮におかしくなったとしても暴走し再起動するだけなので、比較的安心してもよい。ただしIOスケジューラの場合は再起動によりSDカードの破損のおそれがあるため要注意のこと。
 正常に動作することを確認できたら、init.dにスクリプトを記載して端末のリブート時にinsmodされるようにする。
 init.dスクリプトの作成が面倒な場合やroot化したがinit.dに対応しない端末では、端末の起動後にModule Loaderアプリで自分で指定して希望のモジュールを読込するのもお勧めです。

8)移植したCPUガバナの感想

androplusの作者もお話している通り、SmartassH3が出来が良い感想を持っています。使用率の割に電池の持ちがよい感触。ただし、CPUガバナを変更可能なアプリで各コアの周波数を見ている限りでは1コア動作時は上限貼り付き(1.5GHz)にもみえるため、さらに省電力なガバナがあるかもしれません。

9)モジュールのソース・バイナリ提供

ソースコードはGitHubに置いておきました。こちら
作成したモジュールはTunableの設定が落ち着いたらアップしたいと思います。もちろん、動作保証は致しませんので。

4 件のコメント:

  1. 参考にさせて頂いております。
    この間みた時より追記されていらっしゃるようでとてもわかり易くなっていますね(*´∀`*)

    丁度AndroPlusさんのblogのコメント部分を読んだあとだったので納得しました(*´∀`*)
    自分は kexec_load.ko を作ろうとしているのですが、こちらは上手く行っていません・・・

    返信削除
  2. あと、mediafireのリンクが間違っているような・・・

    返信削除
  3. コメントありがとうございます。
    mediafireのリンクの件、たしかに別なものでしたね。という訳で修正しておきます。
    kexec_load、最初拝見した際はわかりませんでしたが裏でググった限りでは完成したら結構美味しいじゃありませんか。
    是非頑張って下さい。

    返信削除
    返信
    1. Masuda様

      お世話になっております。
      mediafireのリンクありがとうございます。
      自分、多分、kexec_load.ko 作れないと思います(爆

      ここは是非Masuda様にゴホンゴホン・・・

      削除