Merge branch '582-tor-assets' into 'master'

Update Tor assets if they're older than the APK

Extract the Tor binary, GeoIP database and config file from the APK if they haven't been extracted since the APK was last updated.

On the Galaxy Nexus, skipping extraction of the binary if it's already up to date shaves about 1.5 seconds off the Tor plugin's startup time.

Closes #582.

Depends on !272.

See merge request !273
This commit is contained in:
Torsten Grote
2016-08-08 14:47:24 +00:00

View File

@@ -4,6 +4,9 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.os.FileObserver; import android.os.FileObserver;
@@ -150,16 +153,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override @Override
public boolean start() throws IOException { public boolean start() throws IOException {
if (used.getAndSet(true)) throw new IllegalStateException(); if (used.getAndSet(true)) throw new IllegalStateException();
// Install the binary, possibly overwriting an older version // Install or update the assets if necessary
if (!installBinary()) { if (!assetsAreUpToDate()) installAssets();
LOG.warning("Could not install Tor binary");
return false;
}
// Install the GeoIP database and config file if necessary
if (!isConfigInstalled() && !installConfig()) {
LOG.warning("Could not install Tor config");
return false;
}
LOG.info("Starting Tor"); LOG.info("Starting Tor");
// Watch for the auth cookie file being updated // Watch for the auth cookie file being updated
cookieFile.getParentFile().mkdirs(); cookieFile.getParentFile().mkdirs();
@@ -176,10 +171,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
Process torProcess; Process torProcess;
try { try {
torProcess = Runtime.getRuntime().exec(cmd, env, torDirectory); torProcess = Runtime.getRuntime().exec(cmd, env, torDirectory);
} catch (SecurityException e1) { } catch (SecurityException e) {
if (LOG.isLoggable(WARNING)) throw new IOException(e);
LOG.log(WARNING, e1.toString(), e1);
return false;
} }
// Log the process's standard output until it detaches // Log the process's standard output until it detaches
if (LOG.isLoggable(INFO)) { if (LOG.isLoggable(INFO)) {
@@ -201,7 +194,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (LOG.isLoggable(INFO)) listFiles(torDirectory); if (LOG.isLoggable(INFO)) listFiles(torDirectory);
return false; return false;
} }
} catch (InterruptedException e1) { } catch (InterruptedException e) {
LOG.warning("Interrupted while starting Tor"); LOG.warning("Interrupted while starting Tor");
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
return false; return false;
@@ -232,37 +225,27 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
return true; return true;
} }
private boolean installBinary() { private boolean assetsAreUpToDate() {
try {
PackageManager pm = appContext.getPackageManager();
PackageInfo pi = pm.getPackageInfo(appContext.getPackageName(), 0);
return doneFile.lastModified() > pi.lastUpdateTime;
} catch (NameNotFoundException e) {
throw new RuntimeException(e);
}
}
private void installAssets() throws IOException {
InputStream in = null; InputStream in = null;
OutputStream out = null; OutputStream out = null;
try { try {
doneFile.delete();
// Unzip the Tor binary to the filesystem // Unzip the Tor binary to the filesystem
in = getTorInputStream(); in = getTorInputStream();
out = new FileOutputStream(torFile); out = new FileOutputStream(torFile);
copy(in, out); copy(in, out);
// Make the Tor binary executable // Make the Tor binary executable
if (!torFile.setExecutable(true, true)) { if (!torFile.setExecutable(true, true)) throw new IOException();
LOG.warning("Could not make Tor binary executable");
return false;
}
return true;
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(in);
tryToClose(out);
return false;
}
}
private boolean isConfigInstalled() {
return geoIpFile.exists() && configFile.exists() && doneFile.exists();
}
private boolean installConfig() {
LOG.info("Installing Tor config");
InputStream in = null;
OutputStream out = null;
try {
// Unzip the GeoIP database to the filesystem // Unzip the GeoIP database to the filesystem
in = getGeoIpInputStream(); in = getGeoIpInputStream();
out = new FileOutputStream(geoIpFile); out = new FileOutputStream(geoIpFile);
@@ -271,14 +254,11 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
in = getConfigInputStream(); in = getConfigInputStream();
out = new FileOutputStream(configFile); out = new FileOutputStream(configFile);
copy(in, out); copy(in, out);
// Create a file to indicate that installation succeeded
doneFile.createNewFile(); doneFile.createNewFile();
return true;
} catch (IOException e) { } catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(in); tryToClose(in);
tryToClose(out); tryToClose(out);
return false; throw e;
} }
} }