ActivityManagerとActivityManagerNative

「フォアグラウンドプロセスとは別のプロセスからフォアグラウンドプロセスを終了させる」
という要求があったのでActivityManager関連を調べてみた。

ActivityManager#killBackgroundProcessesを使用すればバックグラウンドのプロセスがkillできるので、フォアグラウンドプロセスをバックグラウンドに移行させてやればよい。
フォアグラウンドプロセスとは別のプロセスが、フォアグラウンドプロセスをバックグラウンドに移行させる公開APIは存在しないようだが、ActivityManager#moveTaskToFrontを使って一つ前にフォアグラウンドにいたプロセスをフォアグラウンドに持ってきてやればよさそうだ。

しかし、このAPIはAPILevel11(Android3.0)からしか使えないようだ。
ではAPILevel10以前ではどうすればいいか?
ActivityManagerのソースを読んでみるとmoveTaskToFrontの実装は次のようになっていた。

public void moveTaskToFront(int taskId, int flags) {
    try {
        ActivityManagerNative.getDefault().moveTaskToFront(taskId, flags);
    } catch (RemoteException e) {
        // System dead, we will be dead too soon!
    }
}

ActivityManagerNative.getDefault()の戻り値はIActivityManagerで、実体はActivityManagerProxyになっている。
このインタフェース自体は非公開ではあるが、実装さえあればリフレクションで呼び出すことは可能なので、APILevel4(Android1.6)のソースでgrepしてみたら見事にヒットした。
結構昔から存在してたのね。
ということで、APILevel10以前の環境でも非公開だが使用することは可能であるという結論に。

因みに、moveTaskToBack(int task),killApplicationWithUid(String pkg, int uid)なんてメソッドもある。
APILevel5(Android2.0)にはkillApplicationProcess(String processName, int uid)というメソッドも追加されている。
しかし、killApplication〜のメソッドは、起動中のActivityから自分自身のパッケージ名とProcess.myUid()で取得できるUIDを渡したがSecurityExceptionが発生して動作しなかった。
指定したUIDではkillできないようだったが、起動しているプロセスのUIDと同じだったのでダメな理由がよく分からなかった。。。

追記
プロセスをバックグラウンドに移行させても、バックグラウンドに移行するのに数100msecかかってしまい、killしようとしてもタイミング的にkillできない場合がある。
そんな時はプロセスの状態を確認して確実にバックグラウンドに移行したのを確認してからkillしてやればよい。