1

I am trying to log the exception plus the user navigation for x amount of time. For example, when my application got an exception I will append it in a text file. Now from that point of time of time, I need to log only for a certain time. e.g., 1 hour. Is it possible to do it? This is the code I wrote to get the exception information and log it in a file. Please someone help me with this. Thanks in advance.

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        Thread.setDefaultUncaughtExceptionHandler(handleAppCrash);
 
    }


    private Thread.UncaughtExceptionHandler handleAppCrash =
                new Thread.UncaughtExceptionHandler() {
                    @SuppressLint("LongLogTag")
                    @Override
                    public void uncaughtException(Thread thread, Throwable ex) {
                        if (!file.exists()) {
                            file.mkdir();
                        }
                        try {
                            data = android_version + "@" + Device + "@" + username + "@" + version + "@" + dates + "@" + Logtrace;
    
                            File gpxfile = new File(file, fname);
                            FileWriter writer = new FileWriter(gpxfile,true);
                            writer.append(data);
                            writer.flush();
                            writer.close();
                        } catch (
                                Exception e) {
                            e.printStackTrace();
                        }
         }
     };
auspicious99
  • 3,902
  • 1
  • 44
  • 58
Sundar Nivash
  • 306
  • 6
  • 25
  • To help people to help you, can you explain more about the problem? After you wrote this code, what happened? It doesn't work at all? There are some compile time errors? It could get logs only for a shorter amount of time? These sorts of details are important, plus what you tried to fix the issue. – auspicious99 Jun 12 '20 at 17:26
  • @auspicious99 i tried to log crash and navigation in a file. Now I dont know how to make this log file write for a certain amount of time, For example if the app crashed it will come to this thread and start the write action, now for 1 hour i need to log the user navigation inside the same file and stop correctly at the end of 1 hour. – Sundar Nivash Jun 12 '20 at 17:33
  • I mean, you are fine with your code for logging the crash, and just need help with the next part, i.e., logging user navigation? If so, then the question first is, since the thread is dying, how do you want to keep your app "alive"? Do you want to auto-restart it? For example, https://stackoverflow.com/questions/2681499/android-how-to-auto-restart-application-after-its-been-force-closed , or you want to start a new activity and kill the old process, e.g., https://trivedihardik.wordpress.com/2011/08/20/how-to-avoid-force-close-error-in-android/ ? – auspicious99 Jun 13 '20 at 11:15
  • @auspicious99 Yes I want to auto restart and log for a x amount of time. Thanks for correcting me. What I need is getting clear now. I need to restart the app and log only for 1 hour and stop the logging process. Can you help me with this? – Sundar Nivash Jun 13 '20 at 12:51

2 Answers2

0

You are looking for a way to

  • restart the app
  • write more logs to the same file that you created in the UncaughtExceptionHandler.

Firstly, to restart the app, you can take the following steps:

  1. Created a pending intent, e.g., in your onCreate (where Intent intent has class scope, already defined, i.e., not just defined within onCreate):

    intent = PendingIntent.getActivity(
        YourApplication.getInstance().getBaseContext(),
        0,
        new Intent(getIntent()),
        getIntent().getFlags());
    
  2. After your try/catch in your UncaughtExceptionHandler, start an alarm to trigger your app in some amount of time, e.g., 1 second; and you must follow this with a System.exit();. This is so the current dying app will properly quit, so that in 1 second, when the alarm triggers, it will start the app again (but it won't if the app is still running).

    AlarmManager mgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, intent);
    System.exit(2);
    
  3. You could optionally store the name of the file (fname in your code) to SharedPreferences (for writing to the same file when the app restarts). Or it could be a fixed hardcoded name that your app knows, and doesn't need to save the name.

  4. You could saved a Boolean in SharedPreferences to let your app know that you are restarting from an uncaught exception.

Secondly, whenever the app starts:

  1. Check the Boolean in SharedPreferences; if it is a normal start, proceed like normal.

  2. If it is a restart after uncaught exception, then retrieve the file name from SharedPreferences (or get it hard coded), then you can write more logs to the file. As in Android, a file is uniquely determined by path and file name. With the same file name, you can open the same file.

auspicious99
  • 3,902
  • 1
  • 44
  • 58
0

Define a background service

To do anything in the background for a prolonged time you should use a service. I'm using a JobService in this example.

<service android:name="org.example.LogService"
         android:exported="false"
         android:permission="android.permission.BIND_JOB_SERVICE"
         android:process=":logprocess"/>

Note the process tag, it is important, because you'll want to kill your current process after an uncaught exception.

public class LogService extends JobService {
    private Thread thread;

    @Override
    public boolean onStartJob(final JobParameters params) {
        if (!file.exists()) {
            file.mkdir();
        }
        thread = new Thread(() -> {
            try {
                data = params.getExtras().getString("data");
                File gpxfile = new File(file, fname);
                FileWriter writer = new FileWriter(gpxfile,true);
                writer.append(data);
                //continue to write your logs to the file here for as long as you want. you could copy logcat to the file for example.
                writer.flush();
                writer.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            jobFinished(params, false);
        });
        thread.start();
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        thread.interrupt();
        return true;
    }
}

Call your background service

public void uncaughtException(Thread thread, Throwable ex) {
    JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
    PersistableBundle extras = new PersistableBundle();
    extras.putString("data", android_version + "@" + Device + "@" + username + "@" + version + "@" + dates + "@" + Logtrace);
    JobInfo.Builder builder = new JobInfo.Builder(0, new ComponentName(context, LogService.class))
    builder.setExtras(extras);
    builder.setOverrideDeadline(1000);
    scheduler.schedule(builder.build());

    //stop the current process.
    Process.killProcess(Process.myPid());
    System.exit(10);
}

Killing the current process is optional but recommended, the application could be in a bad state after an uncaught exception. If you want to restart your application you can call startActivity from the LogService.


Note: You've not given any details on what exactly you want to log for x amount of time, so this code only has a comment where the log collection goes.

Note 2: This code was adapted from the ACRA project of which I am a maintainer, specifically manifest JobSenderService DefaultSenderScheduler and ProcessFinisher

F43nd1r
  • 7,690
  • 3
  • 24
  • 62