JellyBeanからServiceを隔離プロセス上で実行できるようになりました。
Serviceを隔離プロセス上で実行するにはAndroidManifestのserviceタグでisolatedProcess属性にtrueを指定します。
# デフォルト値はfalse
http://developer.android.com/guide/topics/manifest/service-element.html#isolated
<service ... android:isolatedProcess="true" />
●PIDとUID
実際にこのサービスを実行すると、呼出し元とは別のPIDで起動しているのがわかります。# ps USER PID PPID VSIZE RSS WCHAN PC NAME ... u0_a47 1068 37 171612 34304 ffffffff 40033a40 S yuki.test.isolateservice u0_i5 1083 37 170200 28668 ffffffff 40033a40 S yuki.test.isolateservice ...隔離プロセス上ではUIDも異なります。
isolatedProcess=false(同プロセス)でサービスを呼び出した場合
caller UID=10047 / PID=1198 service UID=10047 / PID=1198
isolatedProcess=true(隔離プロセス)でサービスを呼び出した場合
caller UID=10047 / PID=1068 service UID=99006 / PID=1083隔離プロセスのUIDには99000~99999が割り当てられます。
参考:android.os.Process.FIRST_ISOLATED_UID / LAST_ISOLATED_UID
●隔離プロセスの制限
隔離プロセス上で実行できる動作には厳しい制限があります。【動作制限の例】
- ContentResolverを操作できない
- BroadcastIntentを送信できない
- BroadcastReceiverを登録できない
- 自プロセスのメモリ情報を取得できない
- その他色々...
この辺の動作制限は、主にActivityManagerServiceのenforceNoIsolatedCaller()でチェックしています。
http://tools.oesf.biz/android-4.1.1_r1.0/xref/frameworks/base/services/java/com/android/server/am/ActivityManagerService.java#2240
隔離プロセスから制限有りのAPIを呼ぶとエラーが返されます。
エラーメッセージ「Isolated process not allowed to call ***」
・BroadcastIntentの送信時
java.lang.SecurityException: Isolated process not allowed to call broadcastIntent ... at android.content.ContextWrapper.sendBroadcast(ContextWrapper.java:312) at yuki.test.isolateservice.IsolatedService.onHandleIntent(IsolatedService.java:14)
・ContentResolver経由でクエリ発行時
java.lang.SecurityException: Isolated process not allowed to call getContentProvider ... at android.content.ContentResolver.query(ContentResolver.java:313) at yuki.test.isolateservice.IsolatedService.onHandleIntent(IsolatedService.java:18)
●隔離プロセス上にあるサービスとの通信
隔離プロセス上にあるサービスとの通信はstartやbindといった基本APIに限られます。バインド状態にあるサービスの独自APIをコールすることはできません。
サービス接続時に渡されるIBinderにはBinderProxyインスタンスが格納されています。
private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { LocalBinder binder = (LocalBinder)service; // ClassCastException発生! }そのため、サービスインスタンスが取得できません。
●隔離プロセスの使いどころ
ドキュメントとして、使用すべきシーンやガイドラインが見当たりませんが、、、最小権限の原理と、サービスが基本的にバックグラウンドで動作するという特性から、
セキュリティに関連するアップデートと思われます。
隔離プロセスを応用したベストプラクティスがあれば新たに記事を投稿しようと思います。
以上です。