Gopalakrishna Kini
Gopalakrishna Kini

Reputation: 191

Problem with restarting the app, after an ANR event

I have implemented a ANR watchdog in my application using this GitHub repo. The watchdog monitors the UI thread and if it is blocked for more than 10 seconds, if restarts the app. My problem is it restarts the app twice, thus messing with all my logic.

This is my implementation of the WatchDog :

public class ANRWatchdog extends Thread {

private final Handler uiHandler = new Handler(Looper.getMainLooper());
private int count = 0; //
private static final int DEFAULT_WAIT_TIME = 10000; // in milliseconds
private volatile boolean anr = false;
private Context context;

public ANRWatchdog(Context context) {
    super();
    this.context = context;
}

private final Runnable counter = () -> count = (count + 1) % Integer.MAX_VALUE;

@Override
public void run() {
    setName("WatchDog");
    int lastCount;
    while (!isInterrupted()) {
        if ( anr){
            anr = false;
            return;
        }
        lastCount = count;
        uiHandler.post(counter);
        try {
            Thread.sleep(DEFAULT_WAIT_TIME);
        } catch (InterruptedException e) {
            Log.e("WatchDog",
                    "Error while making the ANR thread sleep" + e);
            return;
        }
        if (count == lastCount) {// means the value hasn't been incremented. UI thread has been blocked
            anr = true;
            Log.d("WatchDog", "Count hasn't incremented. This means ANR. Will restart the app. Thread Id : " +
                    android.os.Process.getThreadPriority(android.os.Process.myTid()));
            uiHandler.removeCallbacks(counter, null);
            uiHandler.removeCallbacksAndMessages(null);
            ANRSharedPrefs.storeANR(context, true, SystemClock.elapsedRealtime());
            ANRError error = ANRError.NewMainOnly();
            Log.e("WatchDog", "" + error);
            Log.d("WatchDog", "Now restarting the app");
            RestartAppUtil.restartApp(context);
            return;
        }
    }
}
}

Here is how the watchdog is started

public class FileLogger extends Application {


ANRWatchDog watchDog = new ANRWatchDog(this);

/**
 * Called when the application is starting, before any activity, service, or receiver objects (excluding content providers) have been created.
 */
@Override
public void onCreate() {
    super.onCreate();
    Log.i(TAG, "Now launching Android Application : " + BuildConfig.VERSION_NAME);
    File logFile = new File(ExternalStoragePath.getExternalCardPath(getApplicationContext()), "log.txt");
    try {
        String cmd = "logcat -v time -f " + logFile.getPath() + " TAG1:I TAG2:D TAG3:E *:S";
        Runtime.getRuntime().exec(cmd);
    } catch (IOException e) {
        Log.e(TAG, "Exception during writing to log " + e);
    }
    watchDog.start();
}

}

Here is how I am restarting the app i.e RestartUtil

public static void restartApp(Context context){
    context.stopService(new Intent(context, Service.class));
    Intent mStartActivity = new Intent(context, MainActivity.class);
    mStartActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    mStartActivity.putExtra(KeyConstants.ANR, true);
    int mPendingIntentId = 123456;
    PendingIntent mPendingIntent = PendingIntent.getActivity(context, mPendingIntentId,    mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
    AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
    mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
    Runtime.getRuntime().exit(0);
}

This code works and the app is restarted.

I am simulating an ANR in one of the activities using an infinite while loop. When I do that, this is what happens in the logs

10-17 13:30:08.221 19588-19608/com.company.project D/TAG1 Count hasn't incremented. This means ANR. Will restart the app. Thread Id : 0
10-17 13:30:08.221 19588-19608/com.company.project D/TAG1 Storing the ANR time : 617417608
10-17 13:30:08.231 19588-19608/com.company.project D/TAG1 Now restarting the app
10-17 13:30:18.411 20333-20353/com.company.project D/TAG1 Count hasn't incremented. This means ANR. Will restart the app. Thread Id : 0
10-17 13:30:18.411 20333-20353/com.company.project D/TAG1 Storing the ANR time : 617427797
10-17 13:30:18.421 20333-20353/com.company.project D/TAG1 Now restarting the app
10-17 13:30:18.791 20362-20362/? D/TAG1: Getting the value of ANR time 617427797
10-17 13:30:18.791 20362-20362/? D/TAG1: Received intent in main screen
10-17 13:30:20.171 20362-20362/com.company.project D/TAG1 Getting the value of ANR time
10-17 13:30:20.171 20362-20362/com.company.project D/TAG1 Received intent in main screen 617427797

The main activity receives two intents, instead of one. Also i don't understand the presence of

/? D/TAG1 

in the logs

Can anyone help me in figuring out, why the main screen gets two intents?

Upvotes: 1

Views: 959

Answers (1)

Gopalakrishna Kini
Gopalakrishna Kini

Reputation: 191

So I was finally able to solve this.

System.exit() was not enough in my case. I had to call finish() or finishAffinity() on the activity which was causing the ANR.

So in the

onCreate() 

method of every activty, I register the instance of activity in the FileLogger like this

FileLogger.setActivityName(this);

This is how the FileLogger has been modified

/**to register the activity)
public static void setActivityName(Activity activityName){
    anrActivity = activityName;
}

/**This method is called by RestartUtil method to restart the app**/
public static void kill(){
    if ( anrActivity != null) {
        anrActivity.finish();
        anrActivity.finishAffinity();
    }
    android.os.Process.killProcess(android.os.Process.myPid());
}

Upvotes: 1

Related Questions