小ネタ。Adbを介してAndroidのアプリを強制終了する方法は, “testing – Stopping an Android app from console – Stack Overflow” によれば,例えばAndroid TVのホームアプリ(Android TV Home com.google.android.tvlauncher)が対象であれば:
adb shell am force-stop com.google.android.tvlauncher
さて,AndroidTV準拠ストリーミング・メディア・プレーヤAmigo 7xJPのホームアプリが固まることがある。Amigo 7xJPには様々な方法で遠隔でアクセスできるようにしようとしているが,TeamViewerを使った画面共有がその一つ。それでアクセスしている最中に固まられると,TeamViewerからは打つ手がなくなる。キーボードのHomeキーを押すことで解消することもあるがそうならないことも多い。
(下に続く)
一つの対処法は,スマートプラグを利用して外部から強制的に再起動すること(スマートプラグについてはいろいろ記事を書いた)。しかしできればそうせずに対処したい。それに上記am
コマンドが利用できないか。
PC上のAdbシェルで起動されるamコマンドの実体は以下。
$ adb shell Amigo7xJP:/ $ which am /system/bin/am
Termuxのシェルで相対パスで起動されるamコマンドは上と異なる(以下)。
絶対パスで上のamコマンドを起動しようとすると以下のようなエラーになる。
~ $ am force-stop com.google.android.tvlauncher ...(長いエラーメッセージ)... Error: unknown command 'force-stop' ~ $ which am /data/data/com.termux/files/usr/bin/am ~ $ /system/bin/am force-stop com.google.android.tvlauncher cmd: Failure calling service activity: Failed transaction (2147483646)
pkgコマンドで見てみるとこのTermux版amコマンドはtermux-amというパッケージとしてインストールされているようで,リポジトリはここと思われる。Termuxのamコマンドの実体はスクリプトで,内容は以下。リポジトリではam-apk-installedとされているもの。
~ $ cat `which am` #!/data/data/com.termux/files/usr/bin/sh export CLASSPATH=/data/data/com.termux/files/usr/libexec/termux-am/am.apk unset LD_LIBRARY_PATH LD_PRELOAD exec /system/bin/app_process / com.termux.termuxam.Am "$@"
要はTermux環境で普通に起動できるamコマンドはいわば「パチもん」で,Adbを通じて利用できる「本物」と同じではない。後者はforce-stopオプションが利用できるが,前者ではできない。そして,Termux環境下では後者を直接呼ぶことはできない。
“Terminal or ADB command to force-stop applications – Android Enthusiasts Stack Exchange” にあるkillallもTermuxのは/data/data/com.termux/files/usr/bin/killallでAdbシェルで使われるのは/system/bin/killall。前者ではホームアプリのプロセスが見えていないようであるし( “com.google.android.tvlauncher: no process found” ),後者は以下のようなエラーを吐き,残念ながら目的が達成できない。
killall: pid 24686: Operation not permitted killall: com.google.android.tvlauncher: Operation not permitted
一つの解決策はSSHトンネルでを掘ってLAN外部からもリモートAdbを可能にすること。これは可能ではあろうが,完全なパスワードレスでやはり怖い。
気づいてみると,実はTermux自身にandroid-toolsパッケージをインストールすることで,adb等Android開発用ツールが使えるようになる。これでSSHで外部からTermux環境にログインした状態で,システムのamコマンドが利用できる。
~ $ adb start-server ~ $ adb shell which am /system/bin/am
他にも違いはあり,以下のようにアクティビティを起動しようした場合,違いがないように見えるが,実際には本物のamコマンドでないと起動しない。
~ $ am start -n org.schabi.newpipe/org.schabi.newpipe.MainActivity Starting: Intent { cmp=org.schabi.newpipe/.MainActivity } ~ $ adb shell am start -n org.schabi.newpipe/org.schabi.newpipe.MainActivity Starting: Intent { cmp=org.schabi.newpipe/.MainActivity }
シェルスクリプトでパイプ中定義する変数はグローバルではない,ということにハマったが,結論こんな感じ ⇦ ちなみにIFSへの代入方法に誤解があることがわかったので改定。改善点を上げればきりがないが自分がやりたいことは基本達成できた。
今回スクリプトの引数にパッケージ名ではなく,自分がつけたニックネームも許容できるようにしたかった。そのため連想配列を使いたかったが,一方その機能をビルトインで持つが肥大したBashではなく,軽量シェルのDashを使いたかった。そのため,以下にあるような策を採用。
- “Associative Arrays in Shell Scripts – Unix & Linux Stack Exchange“
- “Arrays in Unix Bourne Shell – Unix & Linux Stack Exchange“
- “Bourne Shell自習テキスト” — 昔これでBourne Shellのスクリプティングを勉強した気が…
ただ,その過程でシェルスクリプトでパイプ中定義する変数はグローバルではないことになかなか気づけずはまった。
「Termux環境下でアプリを強制終了」への5件のフィードバック