From ae10e8c458cd87b5bbcf1e40e1ce430335c9bb65 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 10 Aug 2012 10:05:38 +0200 Subject: [PATCH] Watch for changes to the log file so we can reopen it If the log fragment is shown while the daemon starts (which is not the case at the moment, but maybe later on tablets) the file reader would not notice that the file got truncated. The same applies if the file is deleted directly on the file system e.g. with adb shell. --- .../strongswan/android/ui/LogFragment.java | 91 ++++++++++++++++++- 1 file changed, 86 insertions(+), 5 deletions(-) diff --git a/src/frontends/android/src/org/strongswan/android/ui/LogFragment.java b/src/frontends/android/src/org/strongswan/android/ui/LogFragment.java index 23cd2aa46..8740e0c46 100644 --- a/src/frontends/android/src/org/strongswan/android/ui/LogFragment.java +++ b/src/frontends/android/src/org/strongswan/android/ui/LogFragment.java @@ -26,6 +26,7 @@ import org.strongswan.android.logic.CharonVpnService; import android.app.Fragment; import android.os.Bundle; +import android.os.FileObserver; import android.os.Handler; import android.view.LayoutInflater; import android.view.View; @@ -41,6 +42,7 @@ public class LogFragment extends Fragment implements Runnable private BufferedReader mReader; private Thread mThread; private volatile boolean mRunning; + private FileObserver mDirectoryObserver; @Override public void onCreate(Bundle savedInstanceState) @@ -50,6 +52,8 @@ public class LogFragment extends Fragment implements Runnable mLogFilePath = getActivity().getFilesDir() + File.separator + CharonVpnService.LOG_FILE; /* use a handler to update the log view */ mLogHandler = new Handler(); + + mDirectoryObserver = new LogDirectoryObserver(getActivity().getFilesDir().getAbsolutePath()); } @Override @@ -65,7 +69,23 @@ public class LogFragment extends Fragment implements Runnable public void onStart() { super.onStart(); - mLogView.setText(""); + startLogReader(); + mDirectoryObserver.startWatching(); + } + + @Override + public void onStop() + { + super.onStop(); + mDirectoryObserver.stopWatching(); + stopLogReader(); + } + + /** + * Start reading from the log file + */ + private void startLogReader() + { try { mReader = new BufferedReader(new FileReader(mLogFilePath)); @@ -74,15 +94,18 @@ public class LogFragment extends Fragment implements Runnable { mReader = new BufferedReader(new StringReader("")); } + + mLogView.setText(""); mRunning = true; mThread = new Thread(this); mThread.start(); } - @Override - public void onStop() + /** + * Stop reading from the log file + */ + private void stopLogReader() { - super.onStop(); try { mRunning = false; @@ -97,6 +120,7 @@ public class LogFragment extends Fragment implements Runnable /** * Write the given log line to the TextView. We strip the prefix off to save * some space (it is not that helpful for regular users anyway). + * * @param line log line to log */ public void logLine(final String line) @@ -126,7 +150,7 @@ public class LogFragment extends Fragment implements Runnable while (mRunning) { try - { + { /* this works as long as the file is not truncated */ String line = mReader.readLine(); if (line == null) { /* wait until there is more to log */ @@ -143,4 +167,61 @@ public class LogFragment extends Fragment implements Runnable } } } + + /** + * FileObserver that checks for changes regarding the log file. Since charon + * truncates it (for which there is no explicit event) we check for any modification + * to the file, keep track of the file size and reopen it if it got smaller. + */ + private class LogDirectoryObserver extends FileObserver + { + private final File mFile; + private long mSize; + + public LogDirectoryObserver(String path) + { + super(path, FileObserver.CREATE | FileObserver.MODIFY | FileObserver.DELETE); + mFile = new File(mLogFilePath); + mSize = mFile.length(); + } + + @Override + public void onEvent(int event, String path) + { + if (path == null || !path.equals(CharonVpnService.LOG_FILE)) + { + return; + } + switch (event) + { /* even though we only subscribed for these we check them, + * as strange events are sometimes received */ + case FileObserver.CREATE: + case FileObserver.DELETE: + restartLogReader(); + break; + case FileObserver.MODIFY: + /* if the size got smaller reopen the log file, as it was probably truncated */ + long size = mFile.length(); + if (size < mSize) + { + restartLogReader(); + } + mSize = size; + break; + } + } + + private void restartLogReader() + { + /* we are called from a separate thread, so we use the handler */ + mLogHandler.post(new Runnable() { + @Override + public void run() + { + stopLogReader(); + startLogReader(); + } + }); + } + } }