18 March 2015

IdeaPad A1をAndroid 2.3.4 にダウングレード

IdeaPad A1の処理能力ではAndroid 4.0.4は重すぎ、画面タップのレスポンスが遅れまくり、プチフリを繰り返すため、やはりこの機器の当初バージョンであるAndroid 2.3.4に戻すことにする。

4.0.4へのアップグレードと使い心地については、『IdeaPad A1をAndroid 4.0.4 (ICS)にアップデートした使い心地』を参照

検証環境

  • 機種 : Lenovo製 IdePad A1 , 16GBytes版 2228-3DJ
  • 購入価格 : 16,907円 (2012年9月 Amazon.co.jp)
  • CPU : OMAP 3622, シングルコア 1GHz
  • メモリー : 512 MB RAM, 内蔵SDカード 16GB, microSDスロット×1
  • 画面 : 1024 x 600 pixels, 7 inch
  • 質量 : 400g

OSのアップデート

OSの書き換えは2種類の方法があり、(1)OSイメージを含んだブート可能なmicroSDカードを用いる場合、(2)IdeaPad本体のアップデート機構を利用して、microSDカードのOSイメージを読み込ませる場合、という2種類。

(1)の方法については、Lenovo公式サイトに記載されている方法『How to Unbrick fix/full factory restore - IdeaTab A1 and A1107』で、同サイトからブート可能なmicroSDイメージも入手できる。

もうひとつは、Lenovo公式サイトの「OSイメージ配布場所」よりOSイメージのzipファイルを入手して、それをmicroSDカードに単純にファイルコピーして使う。

今回は、(2)の方法を試してみることとする。

OSイメージのダウンロードと、パッチ適用

Lenovo公式サイトの「OSイメージ配布場所」より次のファームウエアをダウンロードする。なお、各種言語版が配布されているの、今回は末尾がROW (= rest of world の略) のものをダウンロードする。

A107W0_A234_001_015_2643_ROW.zip 27-Feb-2012 05:27 160M

公式サイトでは、これをmicroSDカードにupdate.zipと改名して書き込んで、OTAでアップデートできるとされているが、Android 4.0.4の時に起動時に固まってしまう不具合があったため、次のサイトに示されているようにパッチを当てる必要がある。

Update – Lenovo(R) IdeaPad A1-07 (16GB) + Android(TM) 4.0.4 (Ice Cream Sandwich)
Lenovo(R) IdeaPad A1-07 (16GB) + Android(TM) 4.0.4 (Ice Cream Sandwich AKA ICS)

具体的には、上記のサイトよりダウンロードしたパッチ・ファイル updater-script.a234.patch を、OSイメージzipの中のMETA-INF/com/google/android/updater-scriptに適用して書き戻してやれば良い。コマンドラインでは次のようになり、

$ wget http://download.lenovo.com/slates/a1/OTA/A107W0_A234_001_015_2643_ROW.zip
$ unzip A107W0_A234_001_015_2643_ROW.zip
$ patch META-INF/com/google/android/updater-script updater-script.a234.patch
$ zip -r update * -x updater-script.a234.patch update.zip

実際にパッチを当てたupdater-scriptは次のようになっている。元のファイルは2GB, 16GB版それぞれの処理が全てコメントアウトされているので、該当機種のものを生かしてやるという処理のようだ

念の為、それぞれのファイルをここに置いておく : updater-script.a234.patchをダウンロードするupdater-scriptをダウンロードする元のupdater-scriptをダウンロードする

META-INF/com/google/android/updater-script
#updater-script.a234
 
ui_print("");
ui_print("1. extract fuse");
assert(show_progress(0.010000, 1));
assert(package_extract_file("fuse", "/tmp/fuse"));
assert(set_perm(0, 0, 0755, "/tmp/fuse"));
assert(package_extract_file("mg_up", "/tmp/mg_up"));
assert(set_perm(0, 0, 0755, "/tmp/mg_up"));
assert(set_progress(0.010000));
 
 
# This choose which mbr to use
ui_print("2. fuse mbr.img");
assert(show_progress(0.010000, 1));
#ui_print("#. choose mbr.");
#assert(package_extract_file("mbr2GB.img", "/tmp/mbr2GB.img"));
assert(package_extract_file("mbr16GB.img", "/tmp/mbr16GB.img"));
#ifelse(is_16Ginand("/dev/block/mmcblk0"),assert(run_program("/tmp/fuse", "mbr", "/tmp/mbr16GB.img")),assert(run_program("/tmp/fuse", "mbr", "/tmp/mbr2GB.img")));
assert(run_program("/tmp/fuse", "mbr", "/tmp/mbr16GB.img"));
#ifelse(is_16Ginand("/dev/block/mmcblk0"),ui_print("fuse mbr 16GB"),ui_print("fuse mbr 2GB"));
ui_print("fuse mbr 16GB");
#delete("/tmp/mbr2GB.img");
delete("/tmp/mbr16GB.img");
#ui_print("#. out off choose mbr.");
assert(set_progress(0.020000));
 
#ui_print("*. **********************");
#assert(package_extract_file("Install.sh", "/tmp/Install.sh"));
#assert(run_program("/tmp/Install.sh","",""));
#delete("/tmp/Install.sh");
#ui_print("*. **********************");
 
ui_print("3. format partitions");
assert(show_progress(0.450000, 60));
assert(run_program("/tmp/fuse", "system", "format"));
assert(run_program("/tmp/fuse", "cache", "format"));
assert(run_program("/tmp/fuse", "userdata", "format"));
assert(run_program("/tmp/fuse", "inand-secure", "format"));
assert(run_program("/tmp/fuse", "inand-storage", "format"));
 
 
# This segment is masked when inand is invalid
ui_print("4 fuse mbr_boot");
assert(show_progress(0.010000, 1));
assert(package_extract_file("mbr_boot", "/tmp/mbr_boot"));
assert(run_program("/tmp/fuse", "mbr_boot", "/tmp/mbr_boot"));
delete("/tmp/mbr_boot");
assert(set_progress(0.030000));
 
ui_print("5. fuse xloader");
assert(show_progress(0.020000, 3));
assert(package_extract_file("MLO", "/tmp/MLO"));
assert(run_program("/tmp/fuse", "xloader", "/tmp/MLO"));
delete("/tmp/MLO");
assert(set_progress(0.590000));
 
ui_print("6. fuse u-boot.bin");
assert(show_progress(0.020000, 3));
assert(package_extract_file("u-boot.bin", "/tmp/u-boot.bin"));
assert(run_program("/tmp/fuse", "uboot", "/tmp/u-boot.bin"));
delete("/tmp/u-boot.bin");
assert(set_progress(0.590000));
 
ui_print("7. fuse uImage.img");
assert(show_progress(0.030000, 5));
assert(package_extract_file("uImage", "/tmp/uImage"));
assert(run_program("/tmp/fuse", "kernel", "/tmp/uImage"));
delete("/tmp/uImage");
assert(set_progress(0.620000));
 
ui_print("8. fuse ramdisk_mmc.img");
assert(show_progress(0.030000, 5));
assert(package_extract_file("ramdisk-uboot.img", "/tmp/ramdisk_mmc.img"));
assert(run_program("/tmp/fuse", "ramdisk", "/tmp/ramdisk_mmc.img"));
delete("/tmp/ramdisk_mmc.img");
assert(set_progress(0.650000));
 
ui_print("9. fuse recovery_mmc.img");
assert(show_progress(0.030000, 5));
assert(package_extract_file("recovery_mmc.img", "/tmp/recovery_mmc.img"));
assert(run_program("/tmp/fuse", "recovery", "/tmp/recovery_mmc.img"));
delete("/tmp/recovery_mmc.img");
assert(set_progress(0.680000));
 
ui_print("10. fuse logo.img");
assert(show_progress(0.030000, 5));
assert(package_extract_file("logo.img", "/tmp/logo.img"));
assert(run_program("/tmp/fuse", "logo", "/tmp/logo.img"));
delete("/tmp/logo.img");
assert(set_progress(0.680000));
 
ui_print("11. fuse system.img");
assert(show_progress(0.300000, 50));
assert(package_extract_file("system.zip", "/tmp/system.zip"));
assert(run_program("/tmp/fuse", "system", "/tmp/system.zip"));
delete("/tmp/system.zip");
assert(set_progress(0.700000));
 
ui_print("12. fuse data.img");
assert(show_progress(0.020000, 50));
assert(package_extract_file("data.zip", "/tmp/data.zip"));
assert(run_program("/tmp/fuse", "userdata", "/tmp/data.zip"));
delete("/tmp/data.zip");
assert(set_progress(0.800000));
 
#ui_print("11. upgrade CAP touch");
#assert(show_progress(0.020000, 0));
#assert(package_extract_file("pixcir_fw.pix", "/tmp/pixcir_fw.pix"));
#assert(run_program("/tmp/fuse", "pixcirfw", "/tmp/pixcir_fw.pix"));
#delete("/tmp/pixcir_fw.pix");
 
assert(show_progress(0.30000, 50));
ui_print("13. backup data.img");
assert(mount("ext3","/dev/block/mmcblk0p1","/tmp/system"));
assert(package_extract_file("data.zip", "/tmp/system/data.zip"));
assert(unmount("/tmp/system"));
assert(set_progress(0.850000));
 
assert(run_program("/tmp/fuse", "inand-storage", "format"));
ui_print("14. mg_up mga.mga");
assert(show_progress(0.002000, 50));
assert(package_extract_file("mga.mga", "/tmp/mga.mga"));
assert(run_program("/tmp/mg_up", "/tmp/mga.mga"));
delete("/tmp/mga.mga");
#assert(set_progress(0.900000));
assert(set_progress(0.900000));
delete("/tmp/fuse");
assert(set_progress(1.000000));
 
ui_print("15. Upgrade finish...");

このようにして出来たOSイメージファイル(update.zip)を、FAT32で普通にフォーマットしたmicroSDカードに書き込む。(dd コマンドでイメージ書込するのではなく、cp コマンドでファイルコピーする)

IdeaPad A1の電源を切り、「ボリューム・ダウン・ボタン」と「電源ボタン」を同時に押したままにして電源を入れ、“Lenovo”ロゴが出たら「電源ボタン」のみ手を離し、「ボリューム・ダウン・ボタン」はOSイメージzipが読み込まれる画面になるまで押したままにする。

Android 2.3.4インストール後の画面

20150318-ideapad-gb-lockscreen.jpg
ロック画面

20150318-ideapad-gb-home1.jpg
ホーム画面(中央)

20150318-ideapad-gb-home2.jpg
ホーム画面(左側)

20150318-ideapad-gb-appsdrawer.jpg
アプリ・ドロワー

20150318-ideapad-gb-appsdrawer2.jpg
アプリ・ドロワー2ページ目 (ルート権限奪取後 Superuserアプリが登録された状態)

20150318-ideapad-gb-hardinfo.jpg
設定 − タブレット情報

20150318-ideapad-gb-storageinfo.jpg
設定 − ストレージ情報

20150318-ideapad-gb-activeprocess.jpg
設定 − 実行中のプロセス

20150318-ideapad-gb-appsdownloaded.jpg
設定 − ダウンロード済みアプリケーション

20150318-ideapad-gb-appsonsdcard.jpg
設定 − 内蔵SDカード上のアプリケーション

ルート権限の奪取

Trash 915 何か - 2643_ROW用』に掲載されているpatch-rooted_signed.zipを、フォーマットしたmicroSDカードに書き込み、OSのアップデートの時と同じく、「ボリューム・ダウン・ボタン」と「電源ボタン」を同時に押したままにして電源を入れ、“Lenovo”ロゴが出たら「電源ボタン」のみ手を離し、「ボリューム・ダウン・ボタン」はOSイメージzipが読み込まれる画面になるまで押したままにする。

アプリ・ドロワーにSuperuserアプリが登録されていれば、成功している。

不要アプリの無効化

パッケージ名アプリ名 等
cl1.fuhuiLenovo バックアップツール
cl1.fuhui.comLenovo バックアップツール
cl1.sdkaLenovo バックアップツール
com.amazon.kindleAmazon Kindle
com.android.inputmethod.pinyin中国語IME
com.android.launcherLenovo ランチャー(ホームアプリ)
com.cooliris.mediaギャラリー
com.ebuddy.androideBuddy メッセンジャー
com.foxconn.download.ftpLenovo OTAアップデート ※
com.google.android.talkGoogle ハングアウト
com.lenovo.leos.userhelpLenovo ユーザーガイド
com.mobihand.cds
com.mobihand.inapppurchase
com.mobihand.skylightLenovo App Shop
com.osa.android.navdroydNavDroyd
lenovo.jb.gokeyboardLenovo Go Keyboard IME

※ OTAアップデートは、今後IdeaPad A1の新OSが公開されオンラインでアップデート (設定 − タブレット情報 − システムアップデート)でアップデートしないため、不要と判断。

apkファイルを削除して/systemの容量を増やしたい場合

確実に使わないとわかっているものは、パッケージの「無効化」ではなく「削除」を行える。まず、パッケージを無効化pm disable クラス名してから、通常通り削除できないか試してみる

# pm disable com.mobihand.skylight
# pm uninstall com.mobihand.skylight
Failure

通常通り削除できないのであれば、強制的にパッケージファイルを削除し、パッケージ管理のXMLファイル/data/system/packages.xmlからも痕跡を削除する。

# mount -o remount,rw /system /system      ← まず読み書き可能で再マウント (起動後1回で良い)
# pm path com.mobihand.skylight
package:/system/app/LenovoAppShop.apk
# rm /system/app/LenovoAppShop.apk

パッケージファイルごと消したのは、次のファイル

クラス名ファイル名アプリ名 等
cl1.fuhuiBackupI.apkLenovo バックアップツール
cl1.fuhui.comBackupII.apkLenovo バックアップツール
cl1.sdkaSDcard.apkLenovo バックアップツール
com.android.inputmethod.pinyinPinyinIME.apk中国語IME
com.android.launcherLauncher2.apkLenovo ランチャー(ホームアプリ)
com.mobihand.cdsCDS_b118.apk
com.mobihand.inapppurchaseMobiHandBillingService.apk
com.mobihand.skylightLenovoAppShop.apkLenovo App Shop

cl1.fuhui や cl1.sdka は、Google検索でも招待が判明しなかったが、パッケージファイルを取り出して中身を確認すると、中国語で変数名を定義したバックアップツールだった。中国語のは全部消しても大丈夫ですよね…(笑 。 Lenovo ランチャーは2メガバイトもあるため、迷わず削除。

パッケージ管理ファイルで削除するのは、<package>タグで囲まれた次のような範囲になる。

/data/system/packages.xml
 〜 略 〜
<package name="com.android.calculator2" codePath="/system/app/Calculator.apk" nativeLibraryPath="/data/data/com.android.calculator2/lib" flags="1" ft="135606f95a0" it="135606f95a0" ut="135606f95a0" version="10" userId="10029">
<sigs count="1">
<cert index="6" key="3082 ... fd04" />
</sigs>
</package>
<package name="com.mobihand.cds" codePath="/system/app/CDS_b118.apk" nativeLibraryPath="/data/data/com.mobihand.cds/lib" flags="1" ft="135606f95a0" it="135606f95a0" ut="135606f95a0" version="118" userId="10037" enabled="false">
<sigs count="1">
<cert index="1" />
</sigs>
</package>
<package name="org.mozilla.firefox" codePath="/data/app/org.mozilla.firefox-1.apk" nativeLibraryPath="/data/data/org.mozilla.firefox/lib" flags="0" ft="14c31b48380" it="14c31b4a815" ut="14c31b4a815" version="2015031400" sharedUserId="10061">
<sigs count="1">
<cert index="7" key="3082 ... 0a9ce" />
</sigs>
<perms />
</package>
 〜 略 〜

/systemの空き領域がどれだけ増えたか…

Lenovo製アプリをせっせと消して、500kBytes程度だった空きが、39MBytesにまで広がりました。

# df
Filesystem             Size   Used   Free   Blksize
/dev                   242M    32K   242M   4096
/mnt/asec              242M     0K   242M   4096
/mnt/obb               242M     0K   242M   4096
/system                277M   237M    39M   1024
/cache                 184M     5M   179M   1024
/data                    1G   394M     1G   4096
/.secure                32M     4M    27M   1024
/mnt/sdcard             12G     9M    12G   4096

画面解像度(dpi)の変更

設定ファイル /system/build.prop内にro.sf.lcd_density=240というdpi設定箇所があるので、ここを変更する。 作業の前に /system ディレクトリを読み書き可能になるよう再マウントを行う

# mount -o remount,rw /system /system
 
# ls -l /system/build*
-rwxrwxrwx root     root         2492 2012-02-09 13:47 build.prop    ← 属性は 0777

下記の変更前、元のbuild.propをダウンロードする

/system/build.prop
 〜 略 〜
# system.prop for A1_07
# This overrides settings in the products/generic/system.prop file
#
rild.libpath=/system/lib/libsierra-ril.so
rild.libargs=-d /dev/ttyUSB2
ro.sf.lcd_density=240
com.ti.omap_enhancement=true
opencore.asmd=1
keyguard.no_require_sim=1
wifi.interface=eth0
alsa.mixer.playback.master=DAC2 Analog
alsa.mixer.capture.master=Analog
#ro.media.dec.aud.wma.enabled=1
#ro.media.dec.vid.wmv.enabled=1
dalvik.vm.heapsize=64m
ro.opengles.version=131072
 〜 略 〜

ちなみに、Android 4.0.4のファームウエアでは、ro.sf.lcd_density=160となっており、今回はro.sf.lcd_density=200に設定してみた。デフォルトの240dpiと、変更後の200dpiの違いは次のような感じだ

20150318-ideapad-gb-dpicompare.jpg
200dpiと240dpiの比較

個人的には、もう少し大きめの文字の210dpiくらいかなぁ…

同期が停止しないエラー

このエラーが発生したので初期化したわけだが、この不具合は初期化しても直っていない。暫定的な対応としては、設定 − アカウント より、全てのアカウントで「同期をキャンセル」を選択すれば良い

20150318-ideapad-gb-syncstop.jpg
設定 − アカウント で、メニューを表示して「同期をキャンセル」を実行する。

この状態を放っておくと、CPUビジー状態のままで急速にバッテリーが消耗することになる。

20150318-ideapad-gb-battery.jpg
設定 − タブレット情報 − 電池使用量 − 電池使用時間

この画面で、「スリープなし」に青いバーが表示されている場合は、スリープに入っていないことになる。同期エラーが出続けているときは、スリープできないのでバッテリーが急速に消耗する。

根本的な問題解決方法は、こちら → 『(Android 2.3.4) YouTube同期が終了せずバッテリーが異常消耗する

Xposedの導入

Android 4.0以降を対象としたXposedが、2.3.4 Gingerbread向けにバックポートされたものがある。動作保証はされていないと思うが、私が使っているモジュールでは特に問題は起こっていない

公式ページ : Xposed back-ported to Gingerbread (update to 2.6.1)

ここで配布されている XposedInstaller-2.6.1-gb-p5.apk をインストールし、さらにAndroid 2.3.4に対応したモジュール一覧は公式ページに掲載されているXMLで見ることができる。

いろいろ便利なツールがあると思うが、何分研究不足で、下記のCool Toolのみをインストールして使っている。

Cool Tool

ステータスバーにCPU負荷やバッテリー残量、ネットワーク転送量などの数値やグラフを表示するツール。公式ページFAQ

20150318-ideapad-gb-xposed-cooltool.jpg

デバッグ接続のアイコンが被ってしまっているが、情報表示位置は自在に変更できる。(自動的に逃げてくれるということはないようだ…)