H.5 AndroidでのEmacsの実行

ユーザーから見るとAndroidはほとんど単一ユーザー向けのオペレーティングシステムです。ただしアプリケーションやEmacsの視点からは、非常に多数のユーザーにホストするシステムなのです。

アプリケーションはそれぞれ独自のホームディレクトリー(アプリケーションのアプリケーションデータディレクトリー; AndroidでEmacsがアクセスできるファイルを参照)をセットされて、独自のユーザーにより実行されます。29

アプリケーションはそれぞれ、多くのシステムディレクトリーや他のアプリケーションのアプリケーションデータディレクトリへのアクセスも禁止されています。

Emacsの配布物には複数のバイナリーも含まれています。実行可能ファイルはライブラリーディレクトリーにパッケージされます。そうしないとEmacsのインストールにおいて、システムがそれらをパッケージ展開しないからです。これはctagsemacsclientをサブプロセスで起動する際に、Lispコードがかわりにlibctags.solibemacsclient.soをコマンドライン指定しなければならないことを意味しています。どの名前を使用するかは変数ctags-program-nameetags-program-namehexl-program-nameemacsclient-program-namemovemail-program-nameebrowse-program-namercs2log-program-nameの値を調べて判断します。Subprocess Creation in the Emacs Lisp Reference Manualを参照してください。

Emacsの起動時ファイルを含んだ/assetsディレクトリーは、zygote (アプリケーションを起動する役目を担うシステムサービス)によって直接作成されたプロセスでなければアクセスできないように設計されています。必要となるLispは/assetsディレクトリーにあるので、これにしたがうとサブプロセスとしてEmacsを起動するのは不可能です。Emacsと一緒に提供されるlibandroid-emacs.soという名前の特別なバイナリーがライブラリーディレクトリーにインストールされて、Emacsを開始してバッチモードでLispを実行するために最善を尽くします。これはAndroidのソースコードを参照して考案されたアプローチであり、Androidの互換性定義ドキュメントによって認可されていないので効果は様々かもしれません。

前もってlibandroid-emacs.soコマンドの場所が判っていても、既存のEmacsセッションのサブプロセス以外からEmacsを開始するためには特別な配慮が必要になります。インストールされたアプリケーションパッケージ内、あるいは抽出されたリソースと共有ライブラリーがどこにあるかをEmacsに認識させなければならないからです。アプリケーションによって作成された疑似端末デバイスとパッケージマネージャーのようなシステムデバイスとの間で、実ファイルやpipeにリダイレクトされた標準IOストリームで通信を行う際にはに特殊な方法で呼び出さなければならないというシステム制限を満足する必要はありますが、OSコマンドpm path org.gnu.emacsによってアプリケーションパッケージの場所をプリントできます。この値が一度確立されたら、これを環境変数EMACS_CLASS_PATHで指定しなければなりません。これにより以下のシェルスクリプトサンプルをアクセス可能な任意の場所にemacsとしてインストールできます:

#!/system/bin/sh

package_name=`pm path org.gnu.emacs 2>/dev/null </dev/null \
               | sed 's/^package://'`
emacs=
EMACS_CLASS_PATH=$package_name

for libdir in `dirname $package_name`/lib/*; do
  ld_path=${ld_path:+${ld_path}:}$libdir
  test -x "$libdir"/libandroid-emacs.so \
    && emacs="$libdir"/libandroid-emacs.so
done

export EMACS_CLASS_PATH
test -x "$emacs" || exit 1
exec $emacs "$@"

Android 10以降では表向きはセキュリティー上の懸念という理由により、Emacs自体がアプリケーションデータディレクトリーにある実行可能ファイルを実行することも禁止されました。それらのシステムでは、通常はEmacsが回避策を講じます。ただしこの回避策には実行可能ファイルのロードを実装して、その子プロセスすべてにトレースを適用するような別プロセスを介して、すべてのサブプロセスを実行することが要求されます。これは様々な理由により問題が生じる可能性があるのです。そのような場合には変数android-use-exec-loadernilに変更することで、この回避策を無効にできます。

この回避策が効力をもつ間は、process-id関数によって取得されるプロセスIDはその実行可能ローダーのプロセスIDとなります。実行可能ローダーの子プロセスは実行可能ローダーと同じプロセスグループに所属するからです。したがってinterrupt-processやその他の関連する関数は正しく機能しますが、他の目的のためにprocess-idがリターンしたプロセスIDを用いても正しく機能しないでしょう。

このプロセスのトレースが実行されるメカニズムから派生する影響の1つとして、内部シェル(対話的なサブシェルを参照)の内部のジョブ制御機能がプロセスを停止できなくなり、EmacsがサブプロセスにたいしてSIGSTOPシグナルを生成しても効果はないでしょう。

さらにAndroid 12ではEmacs自体がバックグラウンドの間に、CPUを消費するサブプロセスも終了させられます。システムはCPUを過剰に消費するプロセスを5分間隔で判定して、もっともCPU時間を多く消費するプロセスを終了させるのです。

Android 12.1およびAndroid 13ではこの挙動を無効にするオプションが提供されています。これを行うには“USB debugging”(AndroidでのEmacsの起動を参照)を有効にして別のシステムからAndroidシステムに接続して以下を実行してください:

$ adb shell "settings put global settings_enable_monitor_phantom_procs false"

オペレーティングシステムに適用される“Languages & Input(言語と入力)”の設定は、プログラムにたいするCのlocaleセットには影響しませんが、Emacsには起動の間に考慮されます。選択された言語と地域バリアントからlocale名が生成されて、それにもとづいた言語環境(言語環境を参照)が選択されます。これがLANGやその他のlocale関連の環境変数をオーバーライドすることはありません。この方法によってセットされた言語環境にたいするコーディングシステムは、例外なくutf-8-unixになります。

EmacsがAndroid 5.0以降で開始された際には、環境変数LANG (一般的な変数を参照)はen_US.utf8にセットされます。これによりAndroidのCライブラリーにリンクされたサブプロセスが出力を適切にプリントできるようになります。それ以前のバージョンのAndroidでは何のlocaleも実装されておらず、そのためこの変数はCにセットされます。

アプリケーションプロセスはシステムによって使い捨て可能なエンティティとして扱われます。Emacsのすべてのフレームがバックグラウンドに移動されると、システムリソースを節約するために、任意のタイミングでEmacsが終了させられる可能性があります。

Android 7.1以前ではメモリー負荷がないかぎりシステムがEmacsをkillしないように、Emacsが自身を“バックグラウンドサービス”に指定します。

Android 8.0ではそのようなバックグラウンドサービスを特別に扱う機能が削除されました。とはいえEmacsには回避策があります。システムは永続的に通知を作成するアプリケーションはアクティブな作業を行っているとみなして、そのようなアプリケーションのkillを回避します。したがってそのようなシステムでは、Emacsが実行されているかぎり通知が永続的に表示されます。

バージョン13より前のAndroidでは、Emacsが通知を表示する権限は不要です。Android 13以降では、ユーザーがEmacsにそのような権限を与えるまで通知は表示されません。それにも関わらず、単に通知の表示を試みるだけで突然死を避けるには十分なのです。通知が表示されるかどうかがバックグラウンドにおけるEmacsの実行能力を損なうことはないので、通知を無効にしても問題はないでしょう。

とはいえシステムがEmacsをkillしない保証はありません。Open Handset AllianceのAndroidのサンプル実装は正しく振る舞うとはいえ、多くのメーカーのプロプライエタリーなバージョンのAndroidには、バックグラウンドにおけるプログラムの実行に追加の制限が設けられているのです。https://dontkillmyapp.com/にはそのような問題のあるメーカー、および場合によっては回避策となるようなリストがあります。

AndroidにはEmacsにアクセスできるシステムサービスを判定する権限システムも定義されています。プログラムは欲する権限を指定しなければなりません。その後に何が起こるかは、使用しているAndroidのバージョン次第です。


Footnotes

(29)

“共有ユーザーID(shared user ID)”を指定して、同じ‘パッケージ署名キー(‘package signing key)”を用いて署名、インストールされた他のアプリケーションは除外される。このような場合にはEmacsは同じユーザーで実行されるとともに、前述のアプリケーションそれぞれにたいして同じアクセス権を保有する。


This page has generated for branch:work/emacs-30_69b16e5c63840479270d32f58daea923fe725b90, commit:5e3f74b56ff47b5bcef2526c70f53f749bbd45f6 to check Japanese translation.