ユーザーから見るとAndroidはほとんど単一ユーザー向けのオペレーティングシステムです。ただしアプリケーションやEmacsの視点からは、非常に多数のユーザーにホストするシステムなのです。
アプリケーションはそれぞれ独自のホームディレクトリー(アプリケーションのアプリケーションデータディレクトリー; AndroidでEmacsがアクセスできるファイルを参照)をセットされて、独自のユーザーにより実行されます。29
アプリケーションはそれぞれ、多くのシステムディレクトリーや他のアプリケーションのアプリケーションデータディレクトリへのアクセスも禁止されています。
Emacsの配布物には複数のバイナリーも含まれています。実行可能ファイルはライブラリーディレクトリーにパッケージされます。そうしないとEmacsのインストールにおいて、システムがそれらをパッケージ展開しないからです。これはctags
やemacsclient
をサブプロセスで起動する際に、Lispコードがかわりにlibctags.so
やlibemacsclient.so
をコマンドライン指定しなければならないことを意味しています。どの名前を使用するかは変数ctags-program-name
、etags-program-name
、hexl-program-name
、emacsclient-program-name
、movemail-program-name
、ebrowse-program-name
、rcs2log-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-loader
をnil
に変更することで、この回避策を無効にできます。
この回避策が効力をもつ間は、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のバージョン次第です。
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_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(shared user ID)”を指定して、同じ‘パッケージ署名キー(‘package signing key)”を用いて署名、インストールされた他のアプリケーションは除外される。このような場合にはEmacsは同じユーザーで実行されるとともに、前述のアプリケーションそれぞれにたいして同じアクセス権を保有する。