diff --git a/app/src/main/java/com/greenaddress/abcore/ABCoreService.java b/app/src/main/java/com/greenaddress/abcore/ABCoreService.java index 34fe7598..b798a39c 100755 --- a/app/src/main/java/com/greenaddress/abcore/ABCoreService.java +++ b/app/src/main/java/com/greenaddress/abcore/ABCoreService.java @@ -5,7 +5,6 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; -import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Build; @@ -22,24 +21,167 @@ public class ABCoreService extends Service { private final static String TAG = ABCoreService.class.getName(); private final static int NOTIFICATION_ID = 922430164; private static final String PARAM_OUT_MSG = "rpccore"; - private Process mProcess; - private Process mProcessTor; - - private static void removeNotification(final Context c) { - ((NotificationManager) c.getSystemService(NOTIFICATION_SERVICE)).cancel(NOTIFICATION_ID); - final Intent broadcastIntent = new Intent(); - broadcastIntent.setAction(MainActivity.RPCResponseReceiver.ACTION_RESP); - broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT); - broadcastIntent.putExtra(PARAM_OUT_MSG, "exception"); - broadcastIntent.putExtra("exception", ""); - c.sendBroadcast(broadcastIntent); - } + private Process mBitcoinProcess; + private Process mTorProcess; + + private final Thread bitcoinWaiterThread = new Thread(new Runnable() { + @Override + public void run() { + try { + final int exit = mBitcoinProcess.waitFor(); + Log.i(TAG, "Bitcoin process finished - " + exit); + stopSelf(); + } catch (InterruptedException e) { + Log.e(TAG, "Bitcoin InterruptedException", e); + } + } + }); + + private final Thread torWaiterThread = new Thread(new Runnable() { + @Override + public void run() { + try { + final int exit = mTorProcess.waitFor(); + Log.i(TAG, "Tor process finished - " + exit); + stopSelf(); + } catch (InterruptedException e) { + Log.e(TAG, "Tor InterruptedException", e); + } + } + }); @Override public IBinder onBind(final Intent intent) { return null; } + @Override + public int onStartCommand(final Intent intent, final int flags, final int startId) { + if (mBitcoinProcess != null || intent == null) + return START_STICKY; + + Log.i(TAG, "Core service msg"); + + try { + android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND); + + startTor(); + startBitcoin(); + + setupNotificationAndMoveToForeground(); + + } catch (final IOException e) { + Log.e(TAG, "Native exception!", e); + mBitcoinProcess = null; + mTorProcess = null; + stopSelf(); + } + Log.i(TAG, "background Task finished"); + + return START_STICKY; + } + + @Override + public void onDestroy() { + super.onDestroy(); + Log.i(TAG, "destroying core service"); + + if (mBitcoinProcess != null) { + mBitcoinProcess.destroy(); + mBitcoinProcess = null; + } + if (mTorProcess != null) { + mTorProcess.destroy(); + mTorProcess = null; + } + removeNotification(); + } + + private void startTor() throws IOException { + final String path = getNoBackupFilesDir().getCanonicalPath(); + + final ProcessBuilder torProcessBuilder = new ProcessBuilder( + String.format("%s/%s", path, "tor"), + "SafeSocks", + "1", + "SocksPort", + "auto", + "NoExec", + "1", + "CookieAuthentication", + "1", + "ControlPort", + "9051", + "DataDirectory", + path + "/tordata" + ); + + torProcessBuilder.directory(new File(path)); + + mTorProcess = torProcessBuilder.start(); + + final ProcessLogger.OnError torErrorListener = new ProcessLogger.OnError() { + @Override + public void onError(final String[] error) { + final StringBuilder bf = new StringBuilder(); + for (final String e : error) { + if (!TextUtils.isEmpty(e)) { + bf.append(String.format("%s%s", e, System.getProperty("line.separator"))); + Log.e(TAG, "Tor process error - " + bf.toString()); + } + } + } + }; + + final ProcessLogger torErrorGobbler = new ProcessLogger(mTorProcess.getErrorStream(),"TOR-ERR", torErrorListener); + final ProcessLogger torOutputGobbler = new ProcessLogger(mTorProcess.getInputStream(), "TOR", torErrorListener); + + torErrorGobbler.start(); + torOutputGobbler.start(); + + torWaiterThread.start(); + } + + private void startBitcoin() throws IOException { + final String path = getNoBackupFilesDir().getCanonicalPath(); + + // allow to pass in a different datadir directory + // HACK: if user sets a datadir in the bitcoin.conf file that should then be the one used + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + final String useDistribution = prefs.getString("usedistribution", "core"); + final String daemon = "liquid".equals(useDistribution) ? "liquidd" : "bitcoind"; + final ProcessBuilder bitcoinProcessBuilder = new ProcessBuilder( + String.format("%s/%s", path, daemon), + "--server=1", + String.format("--datadir=%s", Utils.getDataDir(this)), + String.format("--conf=%s", Utils.getBitcoinConf(this))); + + bitcoinProcessBuilder.directory(new File(path)); + + mBitcoinProcess = bitcoinProcessBuilder.start(); + + final ProcessLogger.OnError btcErrorListener = new ProcessLogger.OnError() { + @Override + public void onError(final String[] error) { + final StringBuilder bf = new StringBuilder(); + for (final String e : error) { + if (!TextUtils.isEmpty(e)) { + bf.append(String.format("%s%s", e, System.getProperty("line.separator"))); + Log.e(TAG, "Bitcoin process error - " + bf.toString()); + } + } + } + }; + + final ProcessLogger errorGobbler = new ProcessLogger(mBitcoinProcess.getErrorStream(), "BTC-ERR", btcErrorListener); + final ProcessLogger outputGobbler = new ProcessLogger(mBitcoinProcess.getInputStream(), "BTC", btcErrorListener); + + errorGobbler.start(); + outputGobbler.start(); + + bitcoinWaiterThread.start(); + } + private void setupNotificationAndMoveToForeground() { final Intent i = new Intent(this, MainActivity.class); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | @@ -70,9 +212,9 @@ private void setupNotificationAndMoveToForeground() { b.setChannelId("channel_00"); } - final Notification n = b.build(); + Log.d(TAG, "startForeground"); startForeground(NOTIFICATION_ID, n); final Intent broadcastIntent = new Intent(); @@ -82,107 +224,13 @@ private void setupNotificationAndMoveToForeground() { sendBroadcast(broadcastIntent); } - @Override - public int onStartCommand(final Intent intent, final int flags, final int startId) { - if (mProcess != null || intent == null) - return START_STICKY; - - - Log.i(TAG, "Core service msg"); - - try { - - android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND); - final String path = getNoBackupFilesDir().getCanonicalPath(); - - final ProcessBuilder torpb = new ProcessBuilder( - String.format("%s/%s", path, "tor"), - "SafeSocks", - "1", - "SocksPort", - "auto", - "NoExec", - "1", - "CookieAuthentication", - "1", - "ControlPort", - "9051", - "DataDirectory", - path + "/tordata" - ); - - torpb.directory(new File(path)); - - mProcessTor = torpb.start(); - - final ProcessLogger.OnError er = new ProcessLogger.OnError() { - @Override - public void onError(final String[] error) { - mProcess = null; - final StringBuilder bf = new StringBuilder(); - for (final String e : error) - if (!TextUtils.isEmpty(e)) - bf.append(String.format("%s%s", e, System.getProperty("line.separator"))); - - Log.i(TAG, bf.toString()); - } - }; - final ProcessLogger torErrorGobbler = new ProcessLogger(mProcessTor.getErrorStream(), er); - final ProcessLogger torOutputGobbler = new ProcessLogger(mProcessTor.getInputStream(), er); - - torErrorGobbler.start(); - torOutputGobbler.start(); - - // allow to pass in a different datadir directory - - // HACK: if user sets a datadir in the bitcoin.conf file that should then be the one - // used - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - final String useDistribution = prefs.getString("usedistribution", "core"); - final String daemon = "liquid".equals(useDistribution) ? "liquidd" : "bitcoind"; - final ProcessBuilder pb = new ProcessBuilder( - String.format("%s/%s", path, daemon), - "--server=1", - String.format("--datadir=%s", Utils.getDataDir(this)), - String.format("--conf=%s", Utils.getBitcoinConf(this))); - - pb.directory(new File(path)); - - mProcess = pb.start(); - - final ProcessLogger errorGobbler = new ProcessLogger(mProcess.getErrorStream(), er); - final ProcessLogger outputGobbler = new ProcessLogger(mProcess.getInputStream(), er); - - errorGobbler.start(); - outputGobbler.start(); - - setupNotificationAndMoveToForeground(); - - } catch (final IOException e) { - Log.i(TAG, "Native exception!"); - Log.i(TAG, e.getMessage()); - - Log.i(TAG, e.getLocalizedMessage()); - removeNotification(this); - mProcess = null; - mProcessTor = null; - e.printStackTrace(); - } - Log.i(TAG, "background Task finished"); - - return START_STICKY; - } - - @Override - public void onDestroy() { - super.onDestroy(); - Log.i(TAG, "destroying core service"); - - if (mProcess != null) { - mProcess.destroy(); - mProcessTor.destroy(); - mProcess = null; - mProcessTor = null; - } + private void removeNotification() { + ((NotificationManager) this.getSystemService(NOTIFICATION_SERVICE)).cancel(NOTIFICATION_ID); + final Intent broadcastIntent = new Intent(); + broadcastIntent.setAction(MainActivity.RPCResponseReceiver.ACTION_RESP); + broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT); + broadcastIntent.putExtra(PARAM_OUT_MSG, "exception"); + broadcastIntent.putExtra("exception", ""); + this.sendBroadcast(broadcastIntent); } } diff --git a/app/src/main/java/com/greenaddress/abcore/ProcessLogger.java b/app/src/main/java/com/greenaddress/abcore/ProcessLogger.java index b730d9e2..e1526382 100755 --- a/app/src/main/java/com/greenaddress/abcore/ProcessLogger.java +++ b/app/src/main/java/com/greenaddress/abcore/ProcessLogger.java @@ -11,37 +11,38 @@ class ProcessLogger extends Thread { - private final static String TAG = ProcessLogger.class.getName(); - private final InputStream is; - private final OnError er; + private final String mTAG; + private final InputStream mInputStream; + private final OnError mOnError; - ProcessLogger(final InputStream is, OnError er) { + ProcessLogger(final InputStream inputStream, String name, OnError onErrorCallback) { super(); - this.is = is; - this.er = er; + mTAG = ProcessLogger.class.getSimpleName() + "-" + name; + this.mInputStream = inputStream; + this.mOnError = onErrorCallback; android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND); } @Override public void run() { try { - final InputStreamReader isr = new InputStreamReader(is); + final InputStreamReader isr = new InputStreamReader(mInputStream); final BufferedReader br = new BufferedReader(isr); String line; final String[] errors = new String[3]; int counter = 0; while ((line = br.readLine()) != null) { - Log.v(TAG, line); + Log.v(mTAG, line); errors[counter++ % 3] = line; } - if (er != null) - er.onError(errors); + if (mOnError != null) + mOnError.onError(errors); } catch (final IOException ioe) { ioe.printStackTrace(); } finally { - IOUtils.closeQuietly(is); + IOUtils.closeQuietly(mInputStream); } }