1
0
Fork 0
mirror of https://github.com/syncthing/syncthing-android.git synced 2024-11-26 06:11:19 +00:00

Merge branch 'master' of https://github.com/syncthing/syncthing-android into fixDoubleBinaryStarts

This commit is contained in:
Catfriend1 2018-05-27 21:34:03 +02:00
commit 17098106eb
3 changed files with 93 additions and 52 deletions

View file

@ -9,6 +9,7 @@ import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.Toast; import android.widget.Toast;
@ -21,6 +22,7 @@ import javax.inject.Inject;
public class FirstStartActivity extends Activity implements Button.OnClickListener { public class FirstStartActivity extends Activity implements Button.OnClickListener {
private static String TAG = "FirstStartActivity";
private static final int REQUEST_WRITE_STORAGE = 142; private static final int REQUEST_WRITE_STORAGE = 142;
@Inject SharedPreferences mPreferences; @Inject SharedPreferences mPreferences;
@ -32,18 +34,13 @@ public class FirstStartActivity extends Activity implements Button.OnClickListen
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
((SyncthingApp) getApplication()).component().inject(this); ((SyncthingApp) getApplication()).component().inject(this);
startService(new Intent(this, SyncthingService.class));
if (!isFirstStart()) { if (!isFirstStart()) {
if (haveStoragePermission()) {
startApp(); startApp();
return; return;
} }
else {
requestStoragePermission();
}
}
// Show first start UI.
setContentView(R.layout.activity_first_start); setContentView(R.layout.activity_first_start);
Button cont = findViewById(R.id.cont); Button cont = findViewById(R.id.cont);
cont.setOnClickListener(this); cont.setOnClickListener(this);
@ -54,11 +51,23 @@ public class FirstStartActivity extends Activity implements Button.OnClickListen
} }
private void startApp() { private void startApp() {
if (!haveStoragePermission()) {
requestStoragePermission();
/**
* startApp will be called in {@link #onRequestPermissionsResult()}
* after permission was granted.
*/
return;
}
boolean isFirstStart = isFirstStart(); boolean isFirstStart = isFirstStart();
if (isFirstStart) { if (isFirstStart) {
Log.v(TAG, "User completed first start UI.");
mPreferences.edit().putBoolean("first_start", false).apply(); mPreferences.edit().putBoolean("first_start", false).apply();
} }
startService(new Intent(this, SyncthingService.class));
// In case start_into_web_gui option is enabled, start both activities so that back // In case start_into_web_gui option is enabled, start both activities so that back
// navigation works as expected. // navigation works as expected.
Intent mainIntent = new Intent(this, MainActivity.class); Intent mainIntent = new Intent(this, MainActivity.class);
@ -86,13 +95,8 @@ public class FirstStartActivity extends Activity implements Button.OnClickListen
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (!haveStoragePermission()) {
requestStoragePermission();
}
else {
startApp(); startApp();
} }
}
@Override @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,

View file

@ -8,6 +8,8 @@ import java.util.concurrent.TimeUnit;
public class Constants { public class Constants {
public static final String FILENAME_SYNCTHING_BINARY = "libsyncthing.so";
public static final String PREF_ALWAYS_RUN_IN_BACKGROUND = "always_run_in_background"; public static final String PREF_ALWAYS_RUN_IN_BACKGROUND = "always_run_in_background";
public static final String PREF_SYNC_ONLY_WIFI = "sync_only_wifi"; public static final String PREF_SYNC_ONLY_WIFI = "sync_only_wifi";
public static final String PREF_SYNC_ONLY_WIFI_SSIDS = "sync_only_wifi_ssids_set"; public static final String PREF_SYNC_ONLY_WIFI_SSIDS = "sync_only_wifi_ssids_set";
@ -81,7 +83,7 @@ public class Constants {
} }
static File getSyncthingBinary(Context context) { static File getSyncthingBinary(Context context) {
return new File(context.getApplicationInfo().nativeLibraryDir, "libsyncthing.so"); return new File(context.getApplicationInfo().nativeLibraryDir, FILENAME_SYNCTHING_BINARY);
} }
static File getLogFile(Context context) { static File getLogFile(Context context) {

View file

@ -12,6 +12,7 @@ import com.google.common.base.Charsets;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.nutomic.syncthingandroid.R; import com.nutomic.syncthingandroid.R;
import com.nutomic.syncthingandroid.SyncthingApp; import com.nutomic.syncthingandroid.SyncthingApp;
import com.nutomic.syncthingandroid.service.Constants;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
@ -24,7 +25,9 @@ import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.LineNumberReader; import java.io.LineNumberReader;
import java.security.InvalidParameterException; import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
@ -208,6 +211,51 @@ public class SyncthingRunnable implements Runnable {
return mPreferences.getBoolean(Constants.PREF_USE_WAKE_LOCK, false); return mPreferences.getBoolean(Constants.PREF_USE_WAKE_LOCK, false);
} }
/**
* Look for running libsyncthing.so processes and return an array
* containing the PIDs of found instances.
*/
private List<String> getSyncthingPIDs() {
List<String> libSyncthingPID = new ArrayList<String>();
Process ps = null;
DataOutputStream psOut = null;
BufferedReader br = null;
try {
ps = Runtime.getRuntime().exec((mUseRoot) ? "su" : "sh");
psOut = new DataOutputStream(ps.getOutputStream());
psOut.writeBytes("ps\n");
psOut.writeBytes("exit\n");
psOut.flush();
ps.waitFor();
br = new BufferedReader(new InputStreamReader(ps.getInputStream(), "UTF-8"));
String line;
while ((line = br.readLine()) != null) {
if (line.contains(Constants.FILENAME_SYNCTHING_BINARY)) {
String syncthingPID = line.trim().split("\\s+")[1];
Log.v(TAG, "getSyncthingPIDs: Found process PID [" + syncthingPID + "]");
libSyncthingPID.add(syncthingPID);
}
}
} catch (IOException | InterruptedException e) {
Log.w(TAG_KILL, "Failed list Syncthing processes", e);
} finally {
try {
if (br != null) {
br.close();
}
if (psOut != null) {
psOut.close();
}
} catch (IOException e) {
Log.w(TAG_KILL, "Failed close the psOut stream", e);
}
if (ps != null) {
ps.destroy();
}
}
return libSyncthingPID;
}
/** /**
* Look for a running libsyncthing.so process and nice its IO. * Look for a running libsyncthing.so process and nice its IO.
*/ */
@ -219,15 +267,22 @@ public class SyncthingRunnable implements Runnable {
int ret = 1; int ret = 1;
try { try {
Thread.sleep(1000); // Wait a second before getting the pid Thread.sleep(1000); // Wait a second before getting the pid
List<String> libSyncthingPID = getSyncthingPIDs();
if (libSyncthingPID.isEmpty()) {
Log.w(TAG, "niceSyncthing: Found no running instances of " + Constants.FILENAME_SYNCTHING_BINARY);
} else {
nice = Runtime.getRuntime().exec((mUseRoot) ? "su" : "sh"); nice = Runtime.getRuntime().exec((mUseRoot) ? "su" : "sh");
niceOut = new DataOutputStream(nice.getOutputStream()); niceOut = new DataOutputStream(nice.getOutputStream());
niceOut.writeBytes("set `ps | grep libsyncthing.so`\n"); for (String runningPID : libSyncthingPID) {
niceOut.writeBytes("ionice $2 be 7\n"); // best-effort, low priority // Set best-effort, low priority using ionice.
niceOut.writeBytes("ionice " + runningPID + " be 7\n");
}
niceOut.writeBytes("exit\n"); niceOut.writeBytes("exit\n");
log(nice.getErrorStream(), Log.WARN, false); log(nice.getErrorStream(), Log.WARN, false);
niceOut.flush(); niceOut.flush();
ret = nice.waitFor(); ret = nice.waitFor();
Log.i(TAG_NICE, "ionice performed on libsyncthing.so"); Log.i(TAG_NICE, "ionice performed on " + Constants.FILENAME_SYNCTHING_BINARY);
}
} catch (IOException | InterruptedException e) { } catch (IOException | InterruptedException e) {
Log.e(TAG_NICE, "Failed to execute ionice binary", e); Log.e(TAG_NICE, "Failed to execute ionice binary", e);
} finally { } finally {
@ -259,34 +314,14 @@ public class SyncthingRunnable implements Runnable {
public void killSyncthing(OnSyncthingKilled onKilledListener) { public void killSyncthing(OnSyncthingKilled onKilledListener) {
new Thread(() -> { new Thread(() -> {
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
Process ps = null; List<String> libSyncthingPID = getSyncthingPIDs();
DataOutputStream psOut = null; if (libSyncthingPID.isEmpty()) {
try { Log.d(TAG, "killSyncthing: Found no more running instances of " + Constants.FILENAME_SYNCTHING_BINARY);
ps = Runtime.getRuntime().exec((mUseRoot) ? "su" : "sh"); break;
psOut = new DataOutputStream(ps.getOutputStream());
psOut.writeBytes("ps | grep libsyncthing.so\n");
psOut.writeBytes("exit\n");
psOut.flush();
ps.waitFor();
InputStreamReader isr = new InputStreamReader(ps.getInputStream(), "UTF-8");
BufferedReader br = new BufferedReader(isr);
String id;
while ((id = br.readLine()) != null) {
id = id.trim().split("\\s+")[1];
killProcessId(id, i > 0);
}
} catch (IOException | InterruptedException e) {
Log.w(TAG_KILL, "Failed list Syncthing processes", e);
} finally {
try {
if (psOut != null)
psOut.close();
} catch (IOException e) {
Log.w(TAG_KILL, "Failed close the psOut stream", e);
}
if (ps != null) {
ps.destroy();
} }
for (String runningPID : libSyncthingPID) {
killProcessId(runningPID, i > 0);
} }
} }
onKilledListener.onKilled(); onKilledListener.onKilled();