ユーザーの視点から見れば、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のバージョンによって異なります:
android.permission.ACCESS_ADSERVICES_AD_ID
android.permission.ACCESS_ADSERVICES_ATTRIBUTION
android.permission.ACCESS_ADSERVICES_CUSTOM_AUDIENCE
android.permission.ACCESS_ADSERVICES_TOPICS
android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_LOCAL_NETWORK
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.AUTHENTICATE_ACCOUNTS
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CALL_COMPANION_APP
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS
android.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS
android.permission.CREDENTIAL_MANAGER_SET_ORIGIN
android.permission.DELIVER_COMPANION_MESSAGES
android.permission.DETECT_SCREEN_CAPTURE
android.permission.DISABLE_KEYGUARD
android.permission.ENFORCE_UPDATE_OWNERSHIP
android.permission.EXPAND_STATUS_BAR
android.permission.FLASHLIGHT
android.permission.FOREGROUND_SERVICE
android.permission.FOREGROUND_SERVICE_CAMERA
android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE
android.permission.FOREGROUND_SERVICE_DATA_SYNC
android.permission.FOREGROUND_SERVICE_FILE_MANAGEMENT
android.permission.FOREGROUND_SERVICE_HEALTH
android.permission.FOREGROUND_SERVICE_LOCATION
android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK
android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION
android.permission.FOREGROUND_SERVICE_MICROPHONE
android.permission.FOREGROUND_SERVICE_PHONE_CALL
android.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING
android.permission.FOREGROUND_SERVICE_SPECIAL_USE
android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED
android.permission.GET_PACKAGE_SIZE
android.permission.GET_TASKS
android.permission.HIDE_OVERLAY_WINDOWS
android.permission.HIGH_SAMPLING_RATE_SENSORS
android.permission.INTERNET
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MANAGE_ACCOUNTS
android.permission.MANAGE_OWN_CALLS
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.NFC_PREFERRED_PAYMENT_INFO
android.permission.NFC_TRANSACTION_EVENT
android.permission.PERSISTENT_ACTIVITY
android.permission.QUERY_ALL_PACKAGES
android.permission.READ_BASIC_PHONE_STATE
android.permission.READ_INSTALL_SESSIONS
android.permission.READ_NEARBY_STREAMING_POLICY
android.permission.READ_PROFILE
android.permission.READ_SOCIAL_STREAM
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.READ_USER_DICTIONARY
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_COMPANION_PROFILE_GLASSES
android.permission.REQUEST_COMPANION_PROFILE_WATCH
android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND
android.permission.REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND
android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND
android.permission.REQUEST_DELETE_PACKAGES
android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
android.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE
android.permission.REQUEST_PASSWORD_COMPLEXITY
android.permission.RESTART_PACKAGES
android.permission.RUN_USER_INITIATED_JOBS
android.permission.SET_WALLPAPER
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.SUBSCRIBED_FEEDS_WRITE
android.permission.TRANSMIT_IR
android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION
android.permission.USE_BIOMETRIC
android.permission.USE_CREDENTIALS
android.permission.USE_EXACT_ALARM
android.permission.USE_FINGERPRINT
android.permission.USE_FULL_SCREEN_INTENT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_PROFILE
android.permission.WRITE_SMS
android.permission.WRITE_SOCIAL_STREAM
android.permission.WRITE_SYNC_SETTINGS
android.permission.WRITE_USER_DICTIONARY
その他の権限は、システム設定アプリからユーザーが付与する必要があります。設定方法はデバイスによって異なるため、詳細はデバイスのメーカーにお問い合わせください。
android.permission.ACCESS_COARSE_LOCATION
android.permission.ACCESS_FINE_LOCATION
android.permission.BODY_SENSORS
android.permission.CALL_PHONE
android.permission.CAMERA
android.permission.CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD
android.permission.GET_ACCOUNTS
android.permission.POST_NOTIFICATIONS
android.permission.PROCESS_OUTGOING_CALLS
android.permission.READ_CALENDAR
android.permission.READ_CALL_LOG
android.permission.READ_CELL_BROADCASTS
android.permission.READ_CONTACTS
android.permission.READ_EXTERNAL_STORAGE
android.permission.READ_PHONE_NUMBERS
android.permission.READ_PHONE_STATE
android.permission.READ_SMS
android.permission.RECEIVE_MMS
android.permission.RECEIVE_SMS
android.permission.RECEIVE_WAP_PUSH
android.permission.RECORD_AUDIO
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.SEND_SMS
android.permission.SMS_FINANCIAL_TRANSACTIONS
android.permission.SYSTEM_ALERT_WINDOW
android.permission.WRITE_CALENDAR
android.permission.WRITE_CALL_LOG
android.permission.WRITE_CONTACTS
android.permission.WRITE_EXTERNAL_STORAGE
android.permission.WRITE_SETTINGS
android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_WIFI_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.FLASHLIGHT
android.permission.GET_PACKAGE_SIZE
android.permission.GET_TASKS
android.permission.INTERNET
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.PERSISTENT_ACTIVITY
android.permission.QUERY_ALL_PACKAGES
android.permission.READ_BASIC_PHONE_STATE
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.READ_USER_DICTIONARY
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_DELETE_PACKAGES
android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
android.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE
android.permission.RESTART_PACKAGES
android.permission.SET_WALLPAPER
android.permission.SET_WALLPAPER_HINTS
android.permission.TRANSMIT_IR
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_SYNC_SETTINGS
android.permission.WRITE_USER_DICTIONARY
これらの権限のほとんどは Emacs 自身では使用されませんが、他のプログラムで役立つ可能性があるため、Emacs によって宣言されています。例えば、連絡先へのアクセス権限は EUDC で役立つ場合があります。
「共有ユーザーID」が指定され、かつ同一の「パッケージ署名鍵」で署名された他のアプリケーションがインストールされている場合を除きます。この場合、Emacsは同一ユーザーとして動作し、前述の各アプリケーションと同じファイルにアクセスできます。