GNU Emacs 32.0.50 (9008bf64c3) のマニュアルを PLaMo 翻訳で機械翻訳したものです。誤訳を含むことがあります。原文: https://www.gnu.org/software/emacs/manual/html_node/emacs/Android-Environment.html ・ emacs-doc.conao3.com

H.5 AndroidでEmacsを動かす

ユーザーの視点から見れば、Androidは概ね単一ユーザー向けのオペレーティングシステムだが、アプリケーションやEmacsの視点から見れば、このシステムには圧倒的な数のユーザーが存在している。

各アプリケーションは独自のユーザーで動作し、そのホームディレクトリにはアプリのデータディレクトリが設定されます(AndroidでEmacsがアクセス可能なファイルを参照)。41

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

Emacsディストリビューションには、いくつかのバイナリも含まれています。これらは実行可能ファイルですが、ライブラリディレクトリにライブラリとしてパッケージ化されています。そうしないと、Emacsのインストール時にシステムがそれらを展開できないためです。つまり、emacsclient の代わりに、サブプロセスでいずれかのプログラムを起動する際は、コマンドラインで libemacsclient.so を指定する必要があります。どの名称を使用すべきかについては、変数 etags-program-name、hexl-program-name、emacsclient-program-name、movemail-program-name、ebrowse-program-name、および rcs2log-program-name の値を参照してください。Emacs Lispリファレンスマニュアル の サブプロセスの作成 を参照してください。

Emacsの起動ファイルを含む/assetsディレクトリは、アプリケーションの起動を担うシステムサービスであるzygoteによって直接作成されたプロセスからはアクセスできないようになっています。必要なLispは/assetsディレクトリにあるため、結果としてEmacsが自身をサブプロセスとして起動することは不可能です。Emacsにはlibandroid-emacs.soという名称の特殊なバイナリが用意されており、これはライブラリディレクトリにインストールされ、バッチモードでLispを実行することを目的としてEmacsの起動を試みます。その手法はAndroidのソースコードを参考に考案されたものであり、Androidの互換性定義ドキュメントで承認されているわけではないため、動作は環境によって異なる可能性があります。

libandroid-emacs.so コマンドの場所があらかじめ判明している場合でも、既存の Emacs セッションのサブプロセス以外から Emacs を実行するには、インストール済みアプリケーションパッケージ内またはそこから抽出されたリソースや共有ライブラリの場所を認識させる必要があるため、特別な準備が求められます。OS コマンド pm path org.gnu.emacs はアプリケーションパッケージの場所を出力しますが、ユーザーアプリケーションによって作成された擬似端末デバイスとパッケージマネージャなどのシステムサービスとの間の通信に関するシステム上の制限を満たすため、当該コマンドは特殊な方法で呼び出す必要があります。つまり、標準 IO ストリームを実ファイルまたはパイプにリダイレクトさせる必要があります。この値が特定されたら、環境変数 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-loader を nil に変更することで、この回避策を無効にできます。

この回避策が有効な場合、process-id 関数を通じて取得されるプロセスIDは実行可能ローダープロセスのものとなり、その子プロセスはローダーと同じプロセスグループに属します。その結果、interrupt-process およびその他の関連関数は正しく動作しますが、process-id が返すプロセスIDを他の目的で使用することはできません。

プロセストレーシングが行われる仕組みの一側面として、下位シェル(インタラクティブサブシェルを参照)内部のジョブ制御機能ではプロセスを停止できず、Emacsによって作成されたサブプロセスへのSIGSTOPシグナルも効果を発揮しないという点が挙げられます。

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

Android 12.1 および Android 13 では、この動作を無効にするオプションが用意されています。この機能を利用するには、「USBデバッグ」を有効にし(Android での Emacs の起動を参照)、Android 端末を別のコンピュータに接続して、以下を実行してください:

$ adb shell "settings put global settings_enable_monitor_phantom_procs false"

オペレーティングシステムに適用される「言語と入力」の設定は、プログラムに設定されるCロケールには影響しませんが、Emacsの起動時には考慮されます。選択された言語と地域バリアントからロケール名が生成され、それに基づいて言語環境(言語環境を参照)が選択されますが、これによりLANGやその他のロケール関連の環境変数が上書きされることはありません。このようにして設定される言語環境のコーディングシステムは、例外なくutf-8-unixとなります。

代わりに、Android 5.0以降でEmacsを起動すると、環境変数 LANG(一般変数を参照)が en_US.utf8 に設定され、これによりAndroid Cライブラリにリンクされたサブプロセスが適切に出力を行うようになります。それ以前のバージョンのAndroidではロケールが全く実装されていないため、この変数は C に設定されます。

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

Android 7.1以前では、Emacsは自らを「バックグラウンドサービス」として定義しており、これによりシステムは、メモリ負荷が高まらない限りEmacsを強制終了させないようになっています。

Android 8.0では、バックグラウンドサービスがこのような特別な扱いを受ける機能が廃止されました。しかし、Emacsは回避策を講じています。システムは、永続的な通知を生成するアプリケーションを「アクティブな処理を行っている」とみなし、そうしたアプリケーションの強制終了を避けるようになっています。そのため、これらのシステムでは、Emacsは動作している限り永続的な通知を表示し続けます。

Android 13より前では、Emacsは通知を表示するための権限を必要としませんでした。Android 13以降では、ユーザーがEmacsにそのような権限を付与するまで、通知は非表示になります。とはいえ、単に通知を表示しようと試みるだけでも突然の強制終了を防ぐには十分であり、通知が表示されるか否かはEmacsのバックグラウンド実行能力に影響せず、また悪影響なく無効化することも可能です。

ただし、システムがEmacsを強制終了させないという保証はありません。Open Handset AllianceによるAndroidのサンプル実装は正常に動作しますが、多くのメーカーが独自のAndroidバージョンにおいて、バックグラウンドでのプログラム実行に追加の制限を設けています。こうした問題のあるメーカーの一覧や、場合によっては回避策が https://dontkillmyapp.com/ に掲載されています。

Androidでは、Emacsがどのシステムサービスにアクセスできるかを決定する権限システムも定義されています。プログラムは必要な権限を指定する必要があり、その後の動作は使用されているAndroidのバージョンによって異なります:


脚注

(41)

「共有ユーザーID」が指定され、かつ同一の「パッケージ署名鍵」で署名された他のアプリケーションがインストールされている場合を除きます。この場合、Emacsは同一ユーザーとして動作し、前述の各アプリケーションと同じファイルにアクセスできます。