Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
277 changes: 161 additions & 116 deletions app/src/main/java/com/greenaddress/abcore/ABCoreService.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -22,24 +21,164 @@ 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);
// if the Tor process stops, the Bitcoin process will already stop itself
} 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();

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("--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 |
Expand Down Expand Up @@ -70,9 +209,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();
Expand All @@ -82,107 +221,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);
}
}
23 changes: 12 additions & 11 deletions app/src/main/java/com/greenaddress/abcore/ProcessLogger.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down