mirror of
https://github.com/syncthing/syncthing-android.git
synced 2024-11-29 15:51:17 +00:00
Merge branch 'master' of https://github.com/syncthing/syncthing-android into fixDoubleBinaryStarts
This commit is contained in:
commit
17098106eb
3 changed files with 93 additions and 52 deletions
|
@ -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,12 +95,7 @@ public class FirstStartActivity extends Activity implements Button.OnClickListen
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (!haveStoragePermission()) {
|
startApp();
|
||||||
requestStoragePermission();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
startApp();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
nice = Runtime.getRuntime().exec((mUseRoot) ? "su" : "sh");
|
List<String> libSyncthingPID = getSyncthingPIDs();
|
||||||
niceOut = new DataOutputStream(nice.getOutputStream());
|
if (libSyncthingPID.isEmpty()) {
|
||||||
niceOut.writeBytes("set `ps | grep libsyncthing.so`\n");
|
Log.w(TAG, "niceSyncthing: Found no running instances of " + Constants.FILENAME_SYNCTHING_BINARY);
|
||||||
niceOut.writeBytes("ionice $2 be 7\n"); // best-effort, low priority
|
} else {
|
||||||
niceOut.writeBytes("exit\n");
|
nice = Runtime.getRuntime().exec((mUseRoot) ? "su" : "sh");
|
||||||
log(nice.getErrorStream(), Log.WARN, false);
|
niceOut = new DataOutputStream(nice.getOutputStream());
|
||||||
niceOut.flush();
|
for (String runningPID : libSyncthingPID) {
|
||||||
ret = nice.waitFor();
|
// Set best-effort, low priority using ionice.
|
||||||
Log.i(TAG_NICE, "ionice performed on libsyncthing.so");
|
niceOut.writeBytes("ionice " + runningPID + " be 7\n");
|
||||||
|
}
|
||||||
|
niceOut.writeBytes("exit\n");
|
||||||
|
log(nice.getErrorStream(), Log.WARN, false);
|
||||||
|
niceOut.flush();
|
||||||
|
ret = nice.waitFor();
|
||||||
|
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");
|
for (String runningPID : libSyncthingPID) {
|
||||||
psOut.flush();
|
killProcessId(runningPID, i > 0);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onKilledListener.onKilled();
|
onKilledListener.onKilled();
|
||||||
|
|
Loading…
Reference in a new issue