ToolsInstaller: Extract to its own classes
Signed-off-by: Samuel Holland <samuel@sholland.org>
This commit is contained in:
parent
1f30e133d6
commit
08cca56388
@ -15,6 +15,7 @@ import com.wireguard.android.configStore.FileConfigStore;
|
|||||||
import com.wireguard.android.model.TunnelManager;
|
import com.wireguard.android.model.TunnelManager;
|
||||||
import com.wireguard.android.util.AsyncWorker;
|
import com.wireguard.android.util.AsyncWorker;
|
||||||
import com.wireguard.android.util.RootShell;
|
import com.wireguard.android.util.RootShell;
|
||||||
|
import com.wireguard.android.util.ToolsInstaller;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
@ -56,6 +57,8 @@ public class Application extends android.app.Application {
|
|||||||
|
|
||||||
SharedPreferences getPreferences();
|
SharedPreferences getPreferences();
|
||||||
|
|
||||||
|
ToolsInstaller getToolsInstaller();
|
||||||
|
|
||||||
TunnelManager getTunnelManager();
|
TunnelManager getTunnelManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
package com.wireguard.android.activity;
|
package com.wireguard.android.activity;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.Preference;
|
|
||||||
import android.preference.PreferenceFragment;
|
import android.preference.PreferenceFragment;
|
||||||
|
|
||||||
import com.wireguard.android.R;
|
import com.wireguard.android.R;
|
||||||
import com.wireguard.android.util.RootShell;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for changing application-global persistent settings.
|
* Interface for changing application-global persistent settings.
|
||||||
@ -30,74 +26,6 @@ public class SettingsActivity extends Activity {
|
|||||||
public void onCreate(final Bundle savedInstanceState) {
|
public void onCreate(final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
addPreferencesFromResource(R.xml.preferences);
|
addPreferencesFromResource(R.xml.preferences);
|
||||||
final Preference installTools = findPreference("install_cmd_line_tools");
|
|
||||||
installTools.setOnPreferenceClickListener(preference -> {
|
|
||||||
new ToolsInstaller(preference).execute();
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class ToolsInstaller extends AsyncTask<Void, Void, Integer> {
|
|
||||||
private static final String[][] LIBRARY_NAMED_EXECUTABLES = {
|
|
||||||
{"libwg.so", "wg"},
|
|
||||||
{"libwg-quick.so", "wg-quick"}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
private final Preference preference;
|
|
||||||
|
|
||||||
private ToolsInstaller(final Preference preference) {
|
|
||||||
context = preference.getContext();
|
|
||||||
this.preference = preference;
|
|
||||||
preference.setEnabled(false);
|
|
||||||
preference.setSummary(context.getString(R.string.install_cmd_line_tools_progress));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Integer doInBackground(final Void... voids) {
|
|
||||||
final String libDir = context.getApplicationInfo().nativeLibraryDir;
|
|
||||||
final StringBuilder cmd = new StringBuilder();
|
|
||||||
|
|
||||||
cmd.append("set -ex;");
|
|
||||||
|
|
||||||
for (final String[] libraryNamedExecutable : LIBRARY_NAMED_EXECUTABLES) {
|
|
||||||
final String arg1 = '\'' + libDir + '/' + libraryNamedExecutable[0] + '\'';
|
|
||||||
final String arg2 = "'/system/xbin/" + libraryNamedExecutable[1] + '\'';
|
|
||||||
|
|
||||||
cmd.append(String.format("cmp -s %s %s && ", arg1, arg2));
|
|
||||||
}
|
|
||||||
cmd.append("exit 114;");
|
|
||||||
|
|
||||||
cmd.append("trap 'mount -o ro,remount /system' EXIT;");
|
|
||||||
cmd.append("mount -o rw,remount /system;");
|
|
||||||
|
|
||||||
for (final String[] libraryNamedExecutable : LIBRARY_NAMED_EXECUTABLES) {
|
|
||||||
final String arg1 = '\'' + libDir + '/' + libraryNamedExecutable[0] + '\'';
|
|
||||||
final String arg2 = "'/system/xbin/" + libraryNamedExecutable[1] + '\'';
|
|
||||||
cmd.append(String.format("cp %s %s; chmod 755 %s;", arg1, arg2, arg2));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new RootShell(context).run(null, cmd.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(final Integer ret) {
|
|
||||||
final String status;
|
|
||||||
|
|
||||||
switch (ret) {
|
|
||||||
case 0:
|
|
||||||
status = context.getString(R.string.install_cmd_line_tools_success);
|
|
||||||
break;
|
|
||||||
case 114 /* OsConstants.EALREADY */:
|
|
||||||
status = context.getString(R.string.install_cmd_line_tools_already);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
status = context.getString(R.string.install_cmd_line_tools_failure);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
preference.setSummary(status);
|
|
||||||
preference.setEnabled(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,91 @@
|
|||||||
|
package com.wireguard.android.preference;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.preference.Preference;
|
||||||
|
import android.system.OsConstants;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
import com.wireguard.android.Application;
|
||||||
|
import com.wireguard.android.Application.ApplicationComponent;
|
||||||
|
import com.wireguard.android.R;
|
||||||
|
import com.wireguard.android.util.AsyncWorker;
|
||||||
|
import com.wireguard.android.util.ToolsInstaller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preference implementing a button that asynchronously runs {@code ToolsInstaller} and displays the
|
||||||
|
* result as the preference summary.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class ToolsInstallerPreference extends Preference {
|
||||||
|
private final AsyncWorker asyncWorker;
|
||||||
|
private final ToolsInstaller toolsInstaller;
|
||||||
|
private State state = State.INITIAL;
|
||||||
|
|
||||||
|
public ToolsInstallerPreference(final Context context, final AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
final ApplicationComponent applicationComponent = Application.getComponent();
|
||||||
|
asyncWorker = applicationComponent.getAsyncWorker();
|
||||||
|
toolsInstaller = applicationComponent.getToolsInstaller();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ToolsInstallerPreference(final Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static State mapResultToState(final int scriptResult) {
|
||||||
|
if (scriptResult == OsConstants.EXIT_SUCCESS)
|
||||||
|
return State.SUCCESS;
|
||||||
|
else if (scriptResult == OsConstants.EALREADY)
|
||||||
|
return State.ALREADY;
|
||||||
|
else
|
||||||
|
return State.FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence getSummary() {
|
||||||
|
return getContext().getString(state.messageResourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence getTitle() {
|
||||||
|
return getContext().getString(getTitleRes());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTitleRes() {
|
||||||
|
return R.string.tools_installer_title;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onClick() {
|
||||||
|
setState(State.WORKING);
|
||||||
|
asyncWorker.supplyAsync(toolsInstaller::install)
|
||||||
|
.thenApply(ToolsInstallerPreference::mapResultToState)
|
||||||
|
.thenAccept(this::setState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setState(final State state) {
|
||||||
|
if (this.state == state)
|
||||||
|
return;
|
||||||
|
this.state = state;
|
||||||
|
if (isEnabled() != state.shouldEnableView)
|
||||||
|
setEnabled(state.shouldEnableView);
|
||||||
|
notifyChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum State {
|
||||||
|
ALREADY(R.string.tools_installer_already, false),
|
||||||
|
FAILURE(R.string.tools_installer_failure, true),
|
||||||
|
INITIAL(R.string.tools_installer_initial, true),
|
||||||
|
SUCCESS(R.string.tools_installer_success, false),
|
||||||
|
WORKING(R.string.tools_installer_working, false);
|
||||||
|
|
||||||
|
private final int messageResourceId;
|
||||||
|
private final boolean shouldEnableView;
|
||||||
|
|
||||||
|
State(final int messageResourceId, final boolean shouldEnableView) {
|
||||||
|
this.messageResourceId = messageResourceId;
|
||||||
|
this.shouldEnableView = shouldEnableView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package com.wireguard.android.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.system.OsConstants;
|
||||||
|
|
||||||
|
import com.wireguard.android.Application.ApplicationContext;
|
||||||
|
import com.wireguard.android.Application.ApplicationScope;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to install WireGuard tools to the system partition.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@ApplicationScope
|
||||||
|
public final class ToolsInstaller {
|
||||||
|
private static final String[][] EXECUTABLES = {
|
||||||
|
{"libwg.so", "wg"},
|
||||||
|
{"libwg-quick.so", "wg-quick"},
|
||||||
|
};
|
||||||
|
private static final File[] INSTALL_DIRS = {
|
||||||
|
new File("/system/xbin"),
|
||||||
|
new File("/system/bin"),
|
||||||
|
};
|
||||||
|
|
||||||
|
private final String nativeLibraryDir;
|
||||||
|
private final RootShell rootShell;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public ToolsInstaller(@ApplicationContext final Context context, final RootShell rootShell) {
|
||||||
|
nativeLibraryDir = context.getApplicationInfo().nativeLibraryDir;
|
||||||
|
this.rootShell = rootShell;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File getInstallDir() {
|
||||||
|
final String path = System.getenv("PATH");
|
||||||
|
if (path == null)
|
||||||
|
return INSTALL_DIRS[0];
|
||||||
|
final List<String> paths = Arrays.asList(path.split(":"));
|
||||||
|
for (final File dir : INSTALL_DIRS)
|
||||||
|
if (paths.contains(dir.getPath()) && dir.isDirectory())
|
||||||
|
return dir;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int install() {
|
||||||
|
final File installDir = getInstallDir();
|
||||||
|
if (installDir == null)
|
||||||
|
return OsConstants.ENOENT;
|
||||||
|
final StringBuilder script = new StringBuilder("set -ex; ");
|
||||||
|
for (final String[] names : EXECUTABLES) {
|
||||||
|
script.append(String.format("cmp -s '%s' '%s' && ",
|
||||||
|
new File(nativeLibraryDir, names[0]),
|
||||||
|
new File(installDir, names[1])));
|
||||||
|
}
|
||||||
|
script.append("exit ").append(OsConstants.EALREADY).append("; ");
|
||||||
|
script.append("trap 'mount -o ro,remount /system' EXIT; mount -o rw,remount /system; ");
|
||||||
|
for (final String[] names : EXECUTABLES) {
|
||||||
|
script.append(String.format("cp %s %s; chmod 755 %s; ",
|
||||||
|
new File(nativeLibraryDir, names[0]),
|
||||||
|
new File(installDir, names[1]),
|
||||||
|
new File(installDir, names[1])));
|
||||||
|
}
|
||||||
|
return rootShell.run(null, script.toString());
|
||||||
|
}
|
||||||
|
}
|
@ -58,16 +58,16 @@
|
|||||||
<string name="public_key_description">Public key</string>
|
<string name="public_key_description">Public key</string>
|
||||||
<string name="restore_on_boot">Restore on boot</string>
|
<string name="restore_on_boot">Restore on boot</string>
|
||||||
<string name="restore_on_boot_summary">Restore previously enabled configurations on boot</string>
|
<string name="restore_on_boot_summary">Restore previously enabled configurations on boot</string>
|
||||||
<string name="install_cmd_line_tools">Install command line tools</string>
|
|
||||||
<string name="install_cmd_line_tools_summary">Install optional tools for scripting into /system/xbin</string>
|
|
||||||
<string name="install_cmd_line_tools_success">wg and wg-quick installed into /system/xbin</string>
|
|
||||||
<string name="install_cmd_line_tools_progress">Installing wg and wg-quick into /system/xbin</string>
|
|
||||||
<string name="install_cmd_line_tools_already">wg and wg-quick are already installed</string>
|
|
||||||
<string name="install_cmd_line_tools_failure">Command line tools could not be installed</string>
|
|
||||||
<string name="save">Save</string>
|
<string name="save">Save</string>
|
||||||
<string name="settings">Settings</string>
|
<string name="settings">Settings</string>
|
||||||
<string name="status">Status</string>
|
<string name="status">Status</string>
|
||||||
<string name="toggle">Toggle</string>
|
<string name="toggle">Toggle</string>
|
||||||
|
<string name="tools_installer_already">wg and wg-quick are already installed</string>
|
||||||
|
<string name="tools_installer_failure">Command line tools could not be installed (no root?)</string>
|
||||||
|
<string name="tools_installer_initial">Install optional tools for scripting into the system partition</string>
|
||||||
|
<string name="tools_installer_success">wg and wg-quick installed into the system partition</string>
|
||||||
|
<string name="tools_installer_title">Install command line tools</string>
|
||||||
|
<string name="tools_installer_working">Installing wg and wg-quick into the system partition</string>
|
||||||
<string name="last_change">Last change</string>
|
<string name="last_change">Last change</string>
|
||||||
<string name="never">never</string>
|
<string name="never">never</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -5,8 +5,5 @@
|
|||||||
android:key="restore_on_boot"
|
android:key="restore_on_boot"
|
||||||
android:summary="@string/restore_on_boot_summary"
|
android:summary="@string/restore_on_boot_summary"
|
||||||
android:title="@string/restore_on_boot" />
|
android:title="@string/restore_on_boot" />
|
||||||
<Preference
|
<com.wireguard.android.preference.ToolsInstallerPreference />
|
||||||
android:key="install_cmd_line_tools"
|
|
||||||
android:summary="@string/install_cmd_line_tools_summary"
|
|
||||||
android:title="@string/install_cmd_line_tools" />
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
Loading…
Reference in New Issue
Block a user