ThinkPad X1 YogaにAndroid 11を入れてみる #1
公開日:
どうも、mrtskaです。
最近そこそこのスペックの2 in 1が欲しくてThinkPad X1 Yoga Gen5を買いました。
なぜX1 Yogaにしたかというのは後述します。
まいにゅーぎあ pic.twitter.com/fucKPYsP1W
— mrtska (@m__gl) December 5, 2020
初めてタッチパネル付きのWindowsというものを触りましたが、Chromeみたいなユーザー数が大量のアプリやUWPアプリはそこそこまともに使えましたがそれ以外のUXが非常に悪かったです。
具体的には、リードオンリーなテキストフィールドを触っただけで出てくるソフトウェアキーボード。
もうこれだけで最悪です。
ChromeやVS Codeでコードを読んでいるとスクロールのために画面を触ると必ずソフトウェアキーボードが下から生えてきます。
あまりに邪魔すぎてこれはちょっと調べ物(特にコード読む時)には使えません。
Windowsをタッチパネルで使う人がそんな居ないから改善が遅いのだろうとは思いますが改善されるのを待ってられるほど暇ではありません。
ならWindowsをやめれば良いではないか。ということでAndroidをX1 Yogaに入れれば良いではないかという結論に至りました。
ThinkPadにしたのには理由があって、Linuxがちゃんと動きそうだからです。
ThinkPadってサーバマシンのコンソール(非Windows)に使われたりしているので他のベンダーよりは動きやすそうかなと思います。
x86マシンにAndroidを入れると言えばAndroid-x86がありますね。
ただ、これを入れるだけでおしまいというのはちょっと面白味に欠けますし、もっといろいろ改造したいと思っていたのでAndroid-x86は使わずに自力でインストールしてみようと思います。
この記事を書いている時点ではAndroid-x86にはAndroid 11はまだ無さそうですね。私が一番乗りかもしれない?
参考までに購入したThinkPad X1 Yoga Gen5のスペックを貼っておきます。
- CPU: Core i7-10610U
- GPU: Intel UHD Graphics 630
- メモリ: 16GB
- ストレージ: NVMe 512GB
- ディスプレイ: 14inch 4K
- OS: Windows 10 Home (プロダクトキーでProにしました)
- その他: LTEモジュール, NFC, IRカメラ, ジャイロセンサー他
前置きが長くなりましたが実際に入れてみたいと思います。
注意点として、この記事を執筆している現在時点ではまともに動作していません。
そもそも使える状態になるかどうかすらまだ分からない状態なのであしからず。
この記事はX1 YogaにAndroidを入れる奮闘記のようなものになる予定です。
Linuxカーネルのビルド
AndroidとてカーネルはLinuxなのでLinuxカーネルのビルドは必要です。
そもそもちゃんとLinuxカーネルが起動してくれないとAndroid以前の問題です。
ただ、Androidのパッチが当たったものでないとダメなので本家からクローンしてきたソースをビルドしてもうまくいかないはずです。(試してない)
AndroidのカーネルソースはAOSPにあります。https://android.googlesource.com/kernel/
x86_64といういかにも都合の良さそうなリポジトリがありますがどうもメンテされてなさそうなのでこれは使いませんでした。
Snapdragonならmsmリポジトリを使えば良いですが、X1 Yoga用のカーネルソースなんてあるわけが無いのでcommonリポジトリを使いました。
Androidのページに懇切丁寧にカーネルをビルドする方法が書いてあります。
https://source.android.com/setup/build/building-kernels?hl=ja
が、X1 Yoga用のカーネルをビルドする方法など当然書いてないので手順通りにクローンした後は自力でビルドしてみます。
commonリポジトリにはいくつかブランチがありますが、最終的にはandroid-mainline-5.10
タグのソースを使いました。
最初はandroid-4.19-stable
ブランチのソースを使っていたのですが、どうやらIntel UHD Graphics 630に対応していないようでIntelのドライバに切り替わらずにEFI VGAのまま動作していました。
ただ、android-4.19-stable
にあってandroid-mainline-5.10
に無いソースがあるようなのでこのタグだけのコードだけでは足りてないようです。(kernel/sched/tune.cとか)
無くても起動しないことはないようですがエラーログが流れます。この辺もバックポートしろということなんでしょうね。
かなり試行錯誤した結果、以下のconfigに落ち着きました。
https://gist.github.com/mrtska/ae74e946ca61211e31460d0923440246
絶対に必要無いものが混じってますが(パラレルATAのドライバとか・・・)、今はとりあえず動けば良いということでこのままにします。
時間がある時にダイエットさせてみよう。
ビルドにはVMware Workstationを使いました。有料ですがVirtualBoxなどと比べるとパフォーマンスが良いですし何よりUSBパススルーが便利です。
あとはビルドします
make O=out x1_yoga_gen5_defconfig
make O=out bzImage -j 12
出来上がったbzImageは28MBほど。Ubuntu 20.04のvmlinuzが11MB程度なのでかなりデカいです。
ただ、Ubuntuではカーネルモジュールを使って必要なモジュールを後からロードするようになってるはずなのでそれらが最初から含まれてると考えたら妥当なサイズなのかもしれませんね。(にしてももっと減らせますが、、、)
ビルドしたカーネルは一旦余っていたこのSATAのSSDに入れることにします。
実際に使い始める時は512GBのNVMeのパーティションを縮小してインストールしますが現時点ではこのSATAのSSDをUSBブートする形でデバッグします。
左から順番に説明するとこうです。
- EFIシステムパーティション (fat32)
- カーネルとinitramfs置き場 (ext4)
- superパーティション (super)
- systemパーティション (ext4)
- system_extパーティション (ext4)
- productパーティション (ext4)
- vendorパーティション (ext4)
- metadataパーティション (ext4)
- userdataパーティション (f2fs)
- 空き
superパーティションが謎ですが詳しくはここに書いてあります。
https://source.android.com/devices/tech/ota/dynamic_partitions/implement
簡単に言うとAndroidは必要なパーティションが多いからsuperパーティションの中にサブパーティションとして持つようにしようということなんだと思います。
superパーティション内のパーティションのサイズはsuperパーティションのサイズに合わせてよろしくやってくれるようです。便利ですね。
カーネルとinitramfs置き場にビルドしたbzImageを置きます。
ブートローダーの用意
カーネルを起動するにはブートローダーが必要なのでこのSSDにEFIシステムパーティションをpartedやfdiskで作った後にgrub2をインストールします。
X1 Yogaは4Kなのでめちゃくちゃ字が小さいですが起動します。(反射してうまく写真撮れなかった)
AOSPのビルド
まずはAOSPのソースをクローンします。
公式の手順の通りにダウンロードしました。
https://source.android.com/setup/build/downloading
使用したタグは記事を書いている時点で最新のandroid-11.0.0_r24
を使いました。
repoを使ってクローンします。
repo init -u https://android.googlesource.com/platform/manifest -b android-11.0.0_r25
repo sync -j 12
クローンが終わったらX1 Yoga用の設定を作ります。
私が頑張って作ったものはここにあります。
https://github.com/mrtska/device_mrtska_thinkpad-x1-yoga-gen5
これをdevice/mrtska/thinkpad-20ubにクローンします。
後は手順と同様にビルドします。
. build/envsetup.sh
lunch aosp_x1_yoga_gen5-eng
make
私のPCだと5時間くらいかかります。寝る前にやると良いかもですね。
これをSSDのsuperパーティションに対してddコマンドで流し込みます。
sudo dd if=/home/mrtska/android2/out/target/product/thinkpad-20ub/super.img of=/dev/sda3 bs=4096
ramdisk.imgはinitramfsなのでこのファイルはカーネルと同じ場所に置きます。
起動
この状態でSSDをX1 Yogaに挿して起動・・・しません。
まず初めにカーネルには特に署名などは付いていないのでSecure Bootに引っ掛かります。
Secure Bootを無効にして再度チャレンジ。
(写真がなくて分かりづらいですが)起動はしてきました。が一瞬でリブートしてしまいます。
いろいろ調べた結果答えはここに書いてありました。
https://source.android.com/devices/tech/ota/dynamic_partitions/implement#kernel-command-line-changes
カーネルのコマンドラインにandroidboot.boot_devicesを足す必要があるようです。
boot_devicesの値がなんだか分かりませんが調べたところVMwareでは「pci0000:00/0000:00:15.0」、X1 Yogaでは「pci0000:00/0000:00:14.0」でした。
どうやって決まるのかは謎です。
grubの設定を変えて
androidboot.boot_devices=pci0000:00/0000:00:14.0
を足して起動します。
今度は無限に似たようなエラーが出ていて進みません。
調べたらどうも画面を描画するのに使うexternal/drm_hwcomposerだけmasterブランチにある最新のソースで且つパッチをあてないとダメなようでした。
かなりいきあたりばったりなパッチなのでこれで合ってるかどうかは微妙です。
他にもexternal/minigbmではi915を含むようにAndroid.bpを編集しないとダメでした。(こんなの分かるか!)
という訳でまる1ヶ月以上悩みまくって試行錯誤した結果ようやく画面を出すことに成功しました。
これを買った本当の理由、実はAndroidを入れて遊ぶためだった
— mrtska (@m__gl) December 13, 2020
やっとAndroid 11が起動するところまで来た!(まだ挙動怪しいけど) pic.twitter.com/R9vk0cRcet
まとめ
ここまでたどり着くのにものすごく大変でしたが画面が出てきた時の喜びはすごかったです。
まだWi-Fiも喋れなければホーム画面にも行けない(ロック解除するとクラッシュする)状態ですが少しずつ改善していけたらなと思っています。(いつ完成するのか・・・)
進展があったらパート2の記事を書こうと思います。
タグ: AOSP