diff --git a/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingRunnable.java b/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingRunnable.java new file mode 100644 index 00000000..7ee72a2b --- /dev/null +++ b/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingRunnable.java @@ -0,0 +1,136 @@ +package com.nutomic.syncthingandroid.syncthing; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Handler; +import android.util.Log; +import android.view.WindowManager; + +import com.nutomic.syncthingandroid.R; + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +/** + * Runs the syncthing binary from command line, and prints its output to logcat. + */ +public class SyncthingRunnable implements Runnable { + + private static final String TAG = "SyncthingRunnable"; + + private static final String TAG_NATIVE = "SyncthingNativeCode"; + + /** + * Path to the native, integrated syncthing binary, relative to the data folder + */ + private static final String BINARY_NAME = "lib/libsyncthing.so"; + + private Handler mHandler; + + private Context mContext; + + public SyncthingRunnable(Context context) { + mContext = context; + mHandler = new Handler(); + } + + @Override + public void run() { + DataOutputStream dos = null; + int ret = 1; + Process process = null; + try { + process = Runtime.getRuntime().exec("sh"); + dos = new DataOutputStream(process.getOutputStream()); + // Set home directory to data folder for syncthing to use. + dos.writeBytes("HOME=" + mContext.getFilesDir() + " "); + // Call syncthing with -home (as it would otherwise use "~/.config/syncthing/". + dos.writeBytes(mContext.getApplicationInfo().dataDir + "/" + BINARY_NAME + " " + + "-home " + mContext.getFilesDir() + "\n"); + dos.writeBytes("exit\n"); + dos.flush(); + + log(process.getErrorStream()); + + ret = process.waitFor(); + } + catch(IOException e) { + Log.e(TAG, "Failed to execute syncthing binary or read output", e); + } + catch(InterruptedException e) { + Log.e(TAG, "Failed to execute syncthing binary or read output", e); + } + finally { + try { + dos.close(); + } + catch (IOException e) { + Log.w(TAG, "Failed to close shell stream", e); + } + process.destroy(); + final int retVal = ret; + if (ret != 0) { + Log.w(TAG_NATIVE, "Syncthing binary crashed with error code " + Integer.toString(retVal)); + postCrashDialog(retVal); + } + } + } + + /** + * Displays a dialog with an info message and the return value. + * + * @param retVal + */ + private void postCrashDialog(final int retVal) { + mHandler.post(new Runnable() { + public void run() { + AlertDialog dialog = new AlertDialog.Builder(mContext) + .setTitle(R.string.binary_crashed_title) + .setMessage(mContext.getString(R.string.binary_crashed_message, retVal)) + .setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, + int i) { + System.exit(0); + } + }) + .create(); + dialog.getWindow() + .setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); + dialog.show(); + } + }); + } + + /** + * Logs the outputs of a stream to logcat and mNativeLog. + * + * @param is The stream to log. + */ + private void log(final InputStream is) { + new Thread(new Runnable() { + @Override + public void run() { + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + String line; + try { + while ((line = br.readLine()) != null) { + Log.i(TAG_NATIVE, line); + } + } + catch (IOException e) { + // NOTE: This is sometimes called on shutdown, as + // Process.destroy() closes the stream. + Log.w(TAG, "Failed to read syncthing command line output", e); + } + } + }).start(); + } + +} diff --git a/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingService.java b/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingService.java index 0729f3c9..a2eb507d 100644 --- a/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingService.java +++ b/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingService.java @@ -10,13 +10,11 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.os.AsyncTask; -import android.os.Handler; import android.os.IBinder; import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; import android.util.Log; import android.util.Pair; -import android.view.WindowManager; import com.nutomic.syncthingandroid.R; import com.nutomic.syncthingandroid.gui.MainActivity; @@ -30,14 +28,11 @@ import org.apache.http.client.methods.HttpHead; import org.apache.http.conn.HttpHostConnectException; import org.apache.http.impl.client.DefaultHttpClient; -import java.io.BufferedReader; -import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.lang.ref.WeakReference; import java.util.HashSet; import java.util.Iterator; @@ -49,8 +44,6 @@ public class SyncthingService extends Service { private static final String TAG = "SyncthingService"; - private static final String TAG_NATIVE = "SyncthingNativeCode"; - private static final int NOTIFICATION_RUNNING = 1; /** @@ -63,11 +56,6 @@ public class SyncthingService extends Service { */ public static final int GUI_UPDATE_INTERVAL = 1000; - /** - * Path to the native, integrated syncthing binary, relative to the data folder - */ - private static final String BINARY_NAME = "lib/libsyncthing.so"; - /** * Interval in ms, at which connections to the web gui are performed on first start * to find out if it's online. @@ -185,7 +173,7 @@ public class SyncthingService extends Service { mCurrentState = State.STARTING; registerOnWebGuiAvailableListener(mApi); new PollWebGuiAvailableTask().execute(); - new Thread(new SyncthingRunnable()).start(); + new Thread(new SyncthingRunnable(this)).start(); } // Stop syncthing. else { @@ -204,100 +192,6 @@ public class SyncthingService extends Service { onApiChange(); } - private Handler mMainThreadHandler; - - /** - * Runs the syncthing binary from command line, and prints its output to logcat (on exit). - */ - private class SyncthingRunnable implements Runnable { - @Override - public void run() { - DataOutputStream dos = null; - int ret = 1; - Process process = null; - try { - process = Runtime.getRuntime().exec("sh"); - dos = new DataOutputStream(process.getOutputStream()); - // Set home directory to data folder for syncthing to use. - dos.writeBytes("HOME=" + getFilesDir() + " "); - // Call syncthing with -home (as it would otherwise use "~/.config/syncthing/". - dos.writeBytes(getApplicationInfo().dataDir + "/" + BINARY_NAME + " " + - "-home " + getFilesDir() + "\n"); - dos.writeBytes("exit\n"); - dos.flush(); - - log(process.getInputStream()); - - ret = process.waitFor(); - } - catch(IOException e) { - Log.e(TAG, "Failed to execute syncthing binary or read output", e); - } - catch(InterruptedException e) { - Log.e(TAG, "Failed to execute syncthing binary or read output", e); - } - finally { - try { - dos.close(); - } - catch (IOException e) { - Log.w(TAG, "Failed to close shell stream", e); - } - process.destroy(); - final int retVal = ret; - if (ret != 0) { - mMainThreadHandler.post(new Runnable() { - public void run() { - Log.w(TAG_NATIVE, "Syncthing binary crashed with error code " + - Integer.toString(retVal)); - AlertDialog dialog = new AlertDialog.Builder(SyncthingService.this) - .setTitle(R.string.binary_crashed_title) - .setMessage(getString(R.string.binary_crashed_message, retVal)) - .setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, - int i) { - System.exit(0); - } - }) - .create(); - dialog.getWindow() - .setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); - dialog.show(); - } - }); - } - } - } - } - - /** - * Logs the outputs of a stream to logcat and mNativeLog. - * - * @param is The stream to log. - */ - private void log(final InputStream is) { - new Thread(new Runnable() { - @Override - public void run() { - InputStreamReader isr = new InputStreamReader(is); - BufferedReader br = new BufferedReader(isr); - String line; - try { - while ((line = br.readLine()) != null) { - Log.i(TAG_NATIVE, line); - } - } - catch (IOException e) { - // NOTE: This is sometimes called on shutdown, as - // Process.destroy() closes the stream. - Log.w(TAG, "Failed to read syncthing command line output", e); - } - } - }).start(); - } - /** * Polls SYNCTHING_URL until it returns HTTP status OK, then calls all listeners * in mOnWebGuiAvailableListeners and clears it. @@ -401,7 +295,6 @@ public class SyncthingService extends Service { n.flags |= Notification.FLAG_ONGOING_EVENT; startForeground(NOTIFICATION_RUNNING, n); - mMainThreadHandler = new Handler(); mDeviceStateHolder = new DeviceStateHolder(SyncthingService.this); registerReceiver(mDeviceStateHolder, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); new StartupTask().execute(); @@ -568,12 +461,13 @@ public class SyncthingService extends Service { } }) .setNegativeButton(R.string.exit, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - activity.finish(); - } - }) + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + activity.finish(); + } + } + ) .show() .setCancelable(false); }