2018年1月14日日曜日

Xperia XZ,X Performance 向けOreo用カスタムカーネルを作成する。

 しばらくぶりの投稿になります。
 自分は現在のところF8132(Xperia X Performance)を使用しています。
カスタムカーネルとしては長らくAndroplus Kernelにお世話になってきましたが、Oreo用のカーネルはリリースされずサポート完了になってしまいました(恐らくメインの活動場所が他の端末になったためと、この記事の途中でも詳述しますが、コンパイルに失敗するためだと思います)。

 という訳でしばらくはXDAに投稿されたパッチ済みのStockカーネルを使っていましたが、せっかくだから前にもカーネルコンパイルまではやってみたことから出来るところまで対応してみようと思い今回カーネル開発をやってみました。
 当然初心者ですが、自分のデバイスをいじる権利(=Bootloader Unlock済み、もちろんメーカにはクレームは出せず自己責任ですが)は持っていることだし知識を増やす意味でやってみました。

注意)

カスタムカーネルのインストールにはブートローダーアンロックが必要になります(この時点で国内キャリア版は使えません。)
 また、カスタムカーネルで実現できる制御範囲はStockよりも多岐に亘りますが、これは必ずしも行うべきというわけではなく、大概はStockのチューニングでも実現可能です。
 また、カスタムカーネルの自作時は当然ながら通常のModと比較し、端末の不動作(ブートループ)に接する場合が高くなりますのでご注意下さい(誤ったカーネルをインストールした場合、最悪ハードブリックして起動出来なくなります)。

1)必須なもの

とりあえずカーネルを自己満足でコンパイルしてboot.imgをビルドするには、これだけあればOKです。

  • PCによる開発環境
カスタムカーネルをコンパイルするためのPC。OSがWindows環境の場合、BusyBoxやVMWareなどで仮想環境が必要だと思います(私の場合はメインの環境がLinux Mint 18.3のためそのまま実行)。

  • SonyMobileのオープンソースファイル
(最新版は1月14日現在、41.3.A.2.24)Open source archive for 41.3.A.2.24

  • クロスツールチェインのコンパイラ

PCでスマホCPU向けにカーネルをコンパイルします。これをクロスツールチェインという。
AOSP(Andorid Open Source Project)・Linaro(ARM界隈の業界団体)なども開発環境を提供していますが、Androplus Kernelほかカスタムカーネル界隈でよく使われているUBERTCをダウンロードして試用しました。
(実はAOSP版も動かしてみたのですが、たまたまリンカがないせいか最後まで生成できないので断念)

本来はXperifirmでダウンロードしたFTFイメージから抽出したStockカーネルイメージ(elfファイル)を解体してFlashtoolで書込み出来るように(+root化の際に必要なパッチを当てる)ツールですが、今回はカーネル本体作成後に必要なもの (ramdiskイメージ)を作成+root化する際に無効化するパッチ当てするのにこれを使用しました。
上記のrootkernelと同じ動作を行うためのものですが、現状ではこれ生成したinitdイメージでの起動は失敗しています(詳細は今後よく検証したいと思います)。
なら何に使用するかというと、既に作成済みのboot.imgを解凍して生成パラメータやinitdイメージなどを抽出することが可能なツールがあるからです。

2)深入りするために必要なもの

前項ではstockカーネルから直接boot.imgを作成できる環境について説明しましたが、せっかくカスタムカーネル作るならば、以下のものも用意しましょう。
githubにあるものをZIPダウンロードかgit cloneでダウンロードします(gitでダウンロード後はリポジトリを41.3.A.2.24_r2に変更してください)。
ただし、先述の通り2つの理由でこのままではコンパイルに失敗します。
一つはソールコードのマージ中に依存関係がおかしくなったせいか”drivers/clk/msm/clock-cpu-8996.c”でコンパイル失敗します。
もう一つはPushリクエストにあり今回のリポジトリで反映されたBluetooth関連のソースコードがStockと互換性がないためそのままではコンパイルが通りません。
  • ソースコードなどを並列比較表示可能なソフトウェア
LinuxではMeldというツールが有り、私はこれを使用しています。
このツール、ファイル単位の比較だけではなくディレクトリ単位での比較も可能なため、StockとAndroplusのソースコードをツリー毎比較する用途などで活用しました。
また、3つのソースでの比較も可能なため、オリジナル・変更中・引用元等複数並べて表示も可能です。

3)一連の流れ

基本的には以下の流れとなります。
  • クロスツールチェインのインストール
  • Stockソースコードのダウンロードと解凍
  • カーネルのビルド(まずはStockから変更せず)
  • Androplusカーネルからのソースコード移植
  • カーネルのビルド(パッチ当てしたもの)
  • ftfファイルからStockのramdiskを抽出→root向けパッチ当て
  • 改変ramdiskと生成カーネルからboot.img生成
  • 生成したboot.imgを端末に書込み+DRMfixのzipを書込み

4)準備

  • クロスツールチェインをインストール
自分のホームディレクトリ配下にtoolchainなどのフォルダを作って解凍すればOKです。
  • Stockソースコードを解凍
Linuxカーネル以外にもいろいろ入っていますが、とりあえずはkernel以外は不要のようです。
Androplusカーネルディレクトリ直下にあるbuild_dora_dsds(doraの部分にはkaguraとなっているものもある。doraはX Performanceを、kaguraはXZを示す)をテキストエディタで開くか、Githubで表示してください。
過去のバージョンにはなりますが、Androplusの開発者はこの記述を行ってカーネルをビルドすることが出来た形になります。最後のブートイメージの作成以外はほぼこの方法で間違いありません。
カーネル開発に慣れているならやらなくてもいいですが、初めての場合は先に開いたbuild_dora_dsdsの記述方法に基づいてout/arch/arm64/boot配下にImage.gz-dtbが生成されているまでをやってみてください。
このときポイントとなる設定/コマンドは以下のとおりです
export ARCH=arm64
→ARCHという環境変数にarm64設定(この環境はarmの64bitであることを示します)
export PATH=~/aarch64-linux-android-4.9-kernel/bin/:$PATH
→ツールチェインのbinディレクトリを環境変数PATHに追加(本例ではホームディレクトリ下のaarch64-linux-andoid-4.9-kernelに配置。これでmakeコマンドが自動的にコンパイラなどをツールチェインから呼び出し出来るようになります)。当然ツールチェインの実配置場所に応じて変更してください。
export CROSS_COMPILE=aarch64-linux-anroid-
→環境変数CROSS_COMPILE(カーネルコンパイル時に使用するツールチェインの各ツール呼び出し前の接頭句になります)をaarch64-linux-anroid-に設定(これはツールチェインのbinディレクトリ内のファイル名を見て確認してください。)
export KBUILD_DIFFCONFIG=dora_diffconfig
→環境変数KBUILD_DIFFCONFIGにdora_diffconfigに指定します。(dora_diffconfigにはコードネームdora向けの専用カーネル設定が記載されているのでそれを指定する。当然自分の作りたいコードネームにここは変更)
make msm-perf_defconfig O=./out
.configファイル(カーネルをビルドするためのコンフィグファイル)を生成する。出力先はカーネルソースの下にoutというディレクトリを生成しそこになる。
make O=./out
カーネルをコンパイルする。Stockの場合はツールチェインがおかしくなければ最後にこのようなメッセージが表示されて out/arch/arm64/boot/Image.gz-dtbファイルが生成されているはずで、カーネルのビルドに成功したことになります(XDAなどで記載されている情報を見る限り、X Performance やXZが使用しているカーネルバージョン3.18の場合GCCのバージョンが4.9より新しい場合はそのままではコンパイル失敗するようです。と言う訳でUBERCの4.9が最適と思われる)。

  LINK    vmlinux
  LD      vmlinux.o
  MODPOST vmlinux.o
  GEN     .version
  CHK     include/generated/compile.h
  UPD     include/generated/compile.h
  CC      init/version.o
  LD      init/built-in.o
  KSYM    .tmp_kallsyms1.o
  KSYM    .tmp_kallsyms2.o
  LD      vmlinux
  SORTEX  vmlinux
  SYSMAP  System.map
../arch/arm64/boot/Makefile:46: 警告: ターゲット 'arch/arm64/boot/Image-dtb' のためのレシピを置き換えます
../arch/arm64/boot/Makefile:33: 警告: ターゲット 'arch/arm64/boot/Image-dtb' のための古いレシピは無視されます
  OBJCOPY arch/arm64/boot/Image
  GZIP    arch/arm64/boot/Image.gz
  DTC     arch/arm64/boot/dts/qcom/msm8996-v3-tone-dora_generic.dtb
  DTC     arch/arm64/boot/dts/qcom/msm8996-v3.0-pmi8996-tone-dora_generic.dtb
  DTC     arch/arm64/boot/dts/qcom/msm8996-v3-pmi8996-tone-dora_generic.dtb
  DTC     arch/arm64/boot/dts/qcom/msm8996-v3.0-tone-dora_generic.dtb
  CAT     arch/arm64/boot/Image.gz-dtb
  Building modules, stage 2.
  MODPOST 0 modules
make[1]: ディレクトリ 'out' から出ます

上記のメッセージでちょっと注目して欲しいのは"GZIP arch/arm64/boot/Image.gz"以降の数行です。
前にPCでandroid端末のKernelビルドした方は気づくと思いますが、見慣れない DTCというものが出ているかと思います。
 これはARM向けのLinuxではDTBという形で対象ハードウェアの構成をカーネルコンパイルの際のファイルとして添付する構造のようです。また、Oreo以降ではこのDTBを使用したdm-verityによる/systemディレクトリ改変防止機能が動作しています
(これの解除方法は後ほど説明します)。

5)Anroplusカーネルのソースコードを移植

AndroplusカーネルからのソースコードをStockに移植します。Meldなどで開発対象のソースとダウンロード済みのAndroplusカーネルのソースを比較表示すると分かりやすいでしょう。
(先の説明通り、Androplusカーネルをそのままコンパイルすると何故か失敗します。Meldで差分を見ても、当該箇所は特におかしくないのでこの方法しかないかもしれません)。
  • Makefileのコンパイル設定最適化(ARMのアーキテクチャーに合わせ最適化します。)
Makefile(修正)
  • dm-verity向けの/systemパテーションチェックを無効化
(先のrootkernelツールでは強引に解凍したカーネルイメージのバイナリを書き換えていますが、カーネルコンパイル場合はソースコードを書き換えればその必要はなくなります)
arch/arm/boot/dts/qcom/
 msm8996-tone-common.dtsi(修正)
→46行目の fsmgr_flags = "wait,verify"; を fsmgr_flags = "wait"; に修正
  • 旧バージョンのAndroplusカーネルから共用コンフィグの差分を入手
githubのBranchを41.2.A.7.76(一つ前)に戻し、arch/arm64/configs/diffconfig/common_diffconfigから160行以降を複写して追加する。
このとき注意して欲しいのは、追加した設定のうち237〜241行のf2fs関連のものは現状のソースコードでは動作しないため、コメントアウトで無効化するか、下記の方法でコンパイルが通るようにする必要があります。
  • IOスケジューラ(fiops・sioを追加)
block/
 Kconfig.iosched (修正)
 Makefile(修正)
 fiops-iosched.c(複写)
 sio-iosched.c(複写)
  • 各種プロセッサのスケジューラ
CPU向けにalucard・darkness・nightmareスケジューラの追加、GPU向けにmsm_adreno_tzを修正+simpleondemandスケジューラを追加
drivers/base/
 power/
  main.c(修正)
  wakeup.c(修正)
 cpufreq/
  Kconfig(修正)
  Makefile(修正)
  cpufreq_alucard.c(複写)
  cpufreq_darkness.c(複写)
  cpufreq_governor.c(修正)
  cpufreq_nightmare.c(複写)
  qcom-cpufreq.c(修正)
 devfreq/
  devfreq.c(修正)
  governor_msm_adreno_tz.c(修正)
  governor_simpleondemand.c(修正)
include/linux/
 cpufreq.h(修正)
  • タッチパネル
マルチタッチ関連 普通にマルチタッチは動作しているので私はインストールしていません
drivers/input/touchscreen/
 clearpad_core.c(修正)
  • videoエンコード・デコードドライバのデバッグ設定off
drivers/media/platform/msm/vidc/
 msm_vidc_debug.c(修正)
  • mmc(SDカード)
モジュールロード時のパーミッション設定(私はインストールしていません)
drivers/mmc/core/
 core.c(修正)
  • qualcommのSoCに関する状態を通知する?+デバッグ表示off
drivers/soc/qcom/
 Kconfig(修正)
 Makefile(修正)
 mpm-of.c(修正)
 state_notifier.c(複写)
include/linux/
 display_state.h(複写)
 state_notifier.h(複写)
  • USB-hidドライバ
キーボード・マウス設定(私はインストールしていません)
drivers/usb/gadget/function/
 f_fs.c(修正)
 f_hid.c(修正)
 f_hid.h(複写)
 f_hid_android_keyboard.c(複写)
 f_hid_android_mouse.c(複写)
 Makefile(修正)
 android.c(修正)
  • KCALドライバ(カーネルレベルで画面の色調を変更)
drivers/video/msm/mdss/
 Kconfig(修正)
 Makefile(修正)
 mdss_dsi.c(修正)
 mdss_dsi_host.c(修正)
 mdss_dsi_panel.c(修正)
 mdss_edp.c(修正)
 mdss_fb.c(修正)
 mdss_mdp_kcal_ctrl.c(複写)
 mdss_mdp_pp_cache_config.c(修正)
  • f2fsサポート
fs/f2fs/data.c
 そのままコンパイルすると1304:12: error: redefinition of 'get_data_block_bmap'と表示されてエラーとなります。これはget_data_block_bmapが再定義されているという意味なので、1304行目以降のこの関数を無効化すればコンパイルは通ります。
(ただし動作は未確認)
  • Safety-Netバイパス関連
fs/proc/
 cmdline.c(修正)
  • カーネルモジュールのバージョンチェック除外?(私はインストールしていません)
kernel/
 module.c
KSM(Kernel Samepage Merge)のデフォルト動作停止
mm/
 ksm.c
  • Bluetooth関連のパッチ(現バージョンではpull requestでパッチが当たっていますが、そのままだとコンパイルが通りません)
net/bluetooth/
 l2cap_core.c
(Androplus Kernelのソースでは3544行と3545行に同じ語句が続いているので3545行を消す。また、3546行の", endptr - ptr"を消す。)
  • 許可されたTCP輻輳制御アルゴリズムを上書きする(TCPアルゴリズム切替時に有効
net/ipv4/sysctl_net_ipv4.c(修正)
  • 802.11で変更無しでキーを再インストールするパッチ
以下の記述を見てパッチ当て)
net/mac80211/
 key.c(修正)
  • selinuxの設定?(私はインストールしていません)
security/selinux/
 selinuxfx.c

6)カーネルのコンパイル+生成

先の準備の方法でカーネルをコンパイルします。先に散々書いてしまいましたができれば少しづつ移植したほうが確実にコンパイルが通ると思います。

7)ftfファイルよりカーネルイメージを抽出→ramdiskファイルのパッチあて→ramdisk抽出+bootimg生成用のパラメータ導出

  1. ftfファイルよりkernel.sin抽出 
    flashtoolで取り扱うftfファイルには当然ファームウェアのアップデートに必要なシステムデータが全て含まれており、その中にはカーネルイメージも有ります。
    ftfファイルは拡張子が.ftfですが、単純なzipファイルのため、これをzipに修正して適当なアーカイバーから解凍しkernel.sinというファイルを抽出します。
  2. kernel.sinからkernel.elfを抽出
    次に、kernel.sinファイルからelfファイルを抽出します。
    これはflashtoolで行います。Tools->Sin Editor で開くダイアログで先程抽出したsinファイルを指定した後、Extract dataボタンを押してelfファイルを抽出します。
  3. kernel.elfファイルでrootカーネル向けのパッチ当て
    rootkernel.shを実行し、kernel.elfから一旦パッチ当て済みのStock.imgを作成します。(これを直接焼いた場合はStockカーネルでパッチ済みとなります)
    先のkernel.elfからboot.imgを生成するコマンドは以下のとおりです。
    bash rootkernel.sh kernel.24.elf boot.img
  4. root用boot.imgからramdiskファイルを抽出
    ストックカーネルのboot.imgからramdiskの圧縮データを抽出します。
    使うのはbuild_tools_xperia/のtoolsにあるunpackbootimgを使用します。
    入力ファイルをboot.img、出力先をwork2にした場合、以下のコマンドで抽出します(ただしOreoのdtbファイルはカーネルと一緒に圧縮されているため分離出来ないようです)。
    ./tools/unpackbootimg -i boot.img -o work2
    出力先には色々なファイルが一緒に生成されますが、そのうち以下のテキストファイルを確認してください(各ファイルに記録された値は、下の"--"に続く文字列、mkbootimgのパラメータに対応する)。
boot.img-base --base
boot.img-board --board
boot.img-cmdline --cmdline
boot.img-kerneloff --kernel_offset
boot.img-pagesize --pagesize
boot.img-ramdikoff --ramdisk_offset
boot.img-secondoff --second_offset
boot.img-tagsoff --tags_offset

8)boot.imgの最終生成

最後に先のコマンドで生成されたramdiskとカーネルデータからboot.imgを生成
この時に使用するコマンドはbuild_tools_xperia/のtoolsにあるmkbootimgを使用します。先に説明したbuild_dora_dsdsと記述方法は一緒ですが、パラメータがOreoでは異なっています。
以下に私が製作に成功したmkbootimgの指定パラメータを掲載します。

mkbootimg --kernel out/arch/arm64/boot/Image.gz-dtb \--ramdisk boot.img-ramdisk.gz \--cmdline "androidboot.hardware=qcom user_debug=31 msm_rtb.filter=0x237 ehci-hcd.park=3 lpm_levels.sleep_disabled=1 cma=32M@0-0xffffffff coherent_pool=2M zram.backend=z3fold" \--pagesize 4096 \--ramdisk_offset 0x82200000 \--tags_offset 0x00000100 \--kernel_offset 0x00008000 \--second_offset 0x00f00000 \--output boot.img

9)boot.imgの端末への書込み

あとは最後です。生成したboot.imgをfastbootコマンドで端末に焼き込みし、実際に動作するかの確認になります。
 ただし、起動前にtwrpに起動し、かならずdrmパッチを/system領域に書き込まないとDRM関連のエラーが発生します。
 msm8996の他のマシーンのカスタムカーネルからソースコードを移植するのも有りかと思います。
 私はAndroplusカーネルの最近のビルドでは無効化されていたcore_ctlを復活させて使ってみています。X Performanceの場合、big×2+LITTLE×2の構成ですが、普段LITTLEだけを動作させて重い処理を行う場合はbigを起こすほうがバッテリ持ちは明らかに良いと思います。