package jp.co.cyberagent.stf.monitor; import android.app.ActivityManagerNative; import android.app.IActivityController; import android.app.IActivityManager; import android.content.Context; import android.content.Intent; import android.os.RemoteException; import android.util.Log; import jp.co.cyberagent.stf.io.MessageWritable; public class ActivityMonitor extends AbstractMonitor { private static final String TAG = "STFActivityMonitor"; private Intent currentIntent; private String currentPackage; public ActivityMonitor(Context context, MessageWritable writer) { super(context, writer); } private class ActivityController extends IActivityController.Stub { /** * The system is trying to start an activity. Return true to allow it to be started as * normal, or false to cancel/reject this activity. */ @Override public boolean activityStarting(Intent intent, String pkg) throws RemoteException { Log.i(TAG, String.format("Starting %s in package %s", intent, pkg)); currentPackage = pkg; currentIntent = intent; return true; } /** * The system is trying to return to an activity. Return true to allow it to be resumed * as normal, or false to cancel/reject this activity. */ @Override public boolean activityResuming(String pkg) throws RemoteException { Log.i(TAG, String.format("Resuming activity in package %s", pkg)); return true; } /** * An application process has crashed (in Java). Return true for the normal error * recovery (app crash dialog) to occur, false to kill it immediately. */ @Override public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg, long timeMillis, String stackTrace) throws RemoteException { Log.i(TAG, String.format("Application %s (pid %s) crashed: %s\n\n%s", processName, pid, longMsg, stackTrace)); return false; } /** * Early call as soon as an ANR is detected. */ @Override public int appEarlyNotResponding(String processName, int pid, String annotation) throws RemoteException { Log.i(TAG, String.format("Early warning about application %s (pid %d) not responding: %s", processName, pid, annotation)); return 0; } /** * An application process is not responding. Return 0 to show the "app not responding" * dialog, 1 to continue waiting, or -1 to kill it immediately. */ @Override public int appNotResponding(String processName, int pid, String processStats) throws RemoteException { Log.i(TAG, String.format("Application %s (pid %s) is not responding: %s", processName, pid, processStats)); return 1; } /** * The system process watchdog has detected that the system seems to be hung. Return 1 to * continue waiting, or -1 to let it continue with its normal kill. * * Available on API level >=18. */ @Override public int systemNotResponding(String msg) throws RemoteException { Log.i(TAG, String.format("System is not responding: %s", msg)); return 1; } } @Override public void run() { Log.i(TAG, "Monitor starting"); IActivityManager am = ActivityManagerNative.getDefault(); try { am.setActivityController(new ActivityController()); synchronized (this) { while (!isInterrupted()) { wait(); } } } catch (InterruptedException e) { // Okay } catch (RemoteException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { Log.i(TAG, "Monitor stopping"); try { am.setActivityController(null); } catch (RemoteException e) { e.printStackTrace(); } } } @Override public void peek(MessageWritable writer) { // Report current activity to the writer } }