From 6bb7be22ce74348f956feb4b713058df8f6c446e Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Fri, 25 Nov 2016 23:05:52 +0100 Subject: Implement getting the cached log via pipe to UI process --- .../de/blinkt/openvpn/core/IServiceStatus.aidl | 7 +- .../blinkt/openvpn/core/ICSOpenVPNApplication.java | 2 - .../de/blinkt/openvpn/core/LogFileHandler.java | 107 +++++++++++---------- .../blinkt/openvpn/core/OpenVPNStatusService.java | 43 ++++++++- .../de/blinkt/openvpn/core/StatusListener.java | 31 ++++-- .../java/de/blinkt/openvpn/core/VpnStatus.java | 4 +- 6 files changed, 128 insertions(+), 66 deletions(-) diff --git a/main/src/main/aidl/de/blinkt/openvpn/core/IServiceStatus.aidl b/main/src/main/aidl/de/blinkt/openvpn/core/IServiceStatus.aidl index b73284bb..cbcb0181 100644 --- a/main/src/main/aidl/de/blinkt/openvpn/core/IServiceStatus.aidl +++ b/main/src/main/aidl/de/blinkt/openvpn/core/IServiceStatus.aidl @@ -3,13 +3,14 @@ package de.blinkt.openvpn.core; // Declare any non-default types here with import statements import de.blinkt.openvpn.core.IStatusCallbacks; - +import android.os.ParcelFileDescriptor; interface IServiceStatus { /** - * Registers to receive OpenVPN Status Updates + * Registers to receive OpenVPN Status Updates and gets a + * ParcelFileDescript back that contains the log up to that point */ - void registerStatusCallback(in IStatusCallbacks cb); + ParcelFileDescriptor registerStatusCallback(in IStatusCallbacks cb); /** * Remove a previously registered callback interface. diff --git a/main/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java b/main/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java index 7d10063f..4220b2be 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java +++ b/main/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java @@ -24,8 +24,6 @@ public class ICSOpenVPNApplication extends Application { super.onCreate(); PRNGFixes.apply(); - VpnStatus.initLogCache(getApplicationContext().getCacheDir()); - mStatus = new StatusListener(); mStatus.init(getApplicationContext()); } diff --git a/main/src/main/java/de/blinkt/openvpn/core/LogFileHandler.java b/main/src/main/java/de/blinkt/openvpn/core/LogFileHandler.java index 6add8ae0..aec6b3c6 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/LogFileHandler.java +++ b/main/src/main/java/de/blinkt/openvpn/core/LogFileHandler.java @@ -136,7 +136,7 @@ class LogFileHandler extends Handler { readCacheContents(new FileInputStream(logfile)); - } catch (java.io.IOException | java.lang.RuntimeException e ) { + } catch (java.io.IOException | java.lang.RuntimeException e) { VpnStatus.logError("Reading cached logfile failed"); VpnStatus.logException(e); e.printStackTrace(); @@ -146,69 +146,70 @@ class LogFileHandler extends Handler { protected void readCacheContents(InputStream in) throws IOException { + try { + BufferedInputStream logFile = new BufferedInputStream(in); + + byte[] buf = new byte[16384]; + int read = logFile.read(buf, 0, 5); + int itemsRead = 0; - BufferedInputStream logFile = new BufferedInputStream(in); + readloop: + while (read >= 5) { + int skipped = 0; + while (buf[skipped] != MAGIC_BYTE) { + skipped++; + if (!(logFile.read(buf, skipped + 4, 1) == 1) || skipped + 10 > buf.length) { + VpnStatus.logDebug(String.format(Locale.US, "Skipped %d bytes and no a magic byte found", skipped)); + break readloop; + } + } + if (skipped > 0) + VpnStatus.logDebug(String.format(Locale.US, "Skipped %d bytes before finding a magic byte", skipped)); - byte[] buf = new byte[16384]; - int read = logFile.read(buf, 0, 5); - int itemsRead = 0; + int len = ByteBuffer.wrap(buf, skipped + 1, 4).asIntBuffer().get(); + // Marshalled LogItem + int pos = 0; + byte buf2[] = new byte[buf.length]; - readloop: - while (read >= 5) { - int skipped = 0; - while (buf[skipped] != MAGIC_BYTE) { - skipped++; - if (!(logFile.read(buf, skipped + 4, 1) == 1) || skipped + 10 > buf.length) { - VpnStatus.logDebug(String.format(Locale.US, "Skipped %d bytes and no a magic byte found", skipped)); - break readloop; - } - } - if (skipped > 0) - VpnStatus.logDebug(String.format(Locale.US, "Skipped %d bytes before finding a magic byte", skipped)); - - int len = ByteBuffer.wrap(buf, skipped+1, 4).asIntBuffer().get(); - - // Marshalled LogItem - int pos = 0; - byte buf2[] = new byte[buf.length]; - - while (pos < len) { - byte b = (byte) logFile.read(); - if (b == MAGIC_BYTE) { - VpnStatus.logDebug(String.format(Locale.US, "Unexpected magic byte found at pos %d, abort current log item", pos)); - read = logFile.read(buf, 1, 4) + 1; - continue readloop; - } else if (b == MAGIC_BYTE + 1) { - b = (byte) logFile.read(); - if (b == 0) - b = MAGIC_BYTE; - else if (b == 1) - b = MAGIC_BYTE + 1; - else { - VpnStatus.logDebug(String.format(Locale.US, "Escaped byte not 0 or 1: %d", b)); + while (pos < len) { + byte b = (byte) logFile.read(); + if (b == MAGIC_BYTE) { + VpnStatus.logDebug(String.format(Locale.US, "Unexpected magic byte found at pos %d, abort current log item", pos)); read = logFile.read(buf, 1, 4) + 1; continue readloop; + } else if (b == MAGIC_BYTE + 1) { + b = (byte) logFile.read(); + if (b == 0) + b = MAGIC_BYTE; + else if (b == 1) + b = MAGIC_BYTE + 1; + else { + VpnStatus.logDebug(String.format(Locale.US, "Escaped byte not 0 or 1: %d", b)); + read = logFile.read(buf, 1, 4) + 1; + continue readloop; + } } + buf2[pos++] = b; } - buf2[pos++] = b; - } - restoreLogItem(buf2, len); + restoreLogItem(buf2, len); - //Next item - read = logFile.read(buf, 0, 5); - itemsRead++; - if (itemsRead > 2 * VpnStatus.MAXLOGENTRIES) { - VpnStatus.logError("Too many logentries read from cache, aborting."); - read = 0; - } + //Next item + read = logFile.read(buf, 0, 5); + itemsRead++; + if (itemsRead > 2 * VpnStatus.MAXLOGENTRIES) { + VpnStatus.logError("Too many logentries read from cache, aborting."); + read = 0; + } + } + VpnStatus.logDebug(R.string.reread_log, itemsRead); + } finally { + VpnStatus.readFileLog = true; + VpnStatus.readFileLock.notifyAll(); } - VpnStatus.logDebug(R.string.reread_log, itemsRead); - - } protected void restoreLogItem(byte[] buf, int len) throws UnsupportedEncodingException { @@ -219,11 +220,11 @@ class LogFileHandler extends Handler { } else { VpnStatus.logError(String.format(Locale.getDefault(), "Could not read log item from file: %d: %s", - len, bytesToHex(buf, Math.max(len, 80)))); + len, bytesToHex(buf, Math.max(len, 80)))); } } - final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); + private final static char[] hexArray = "0123456789ABCDEF".toCharArray(); public static String bytesToHex(byte[] bytes, int len) { len = Math.min(bytes.length, len); diff --git a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNStatusService.java b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNStatusService.java index 24ae7704..afac749c 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNStatusService.java +++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNStatusService.java @@ -10,11 +10,15 @@ import android.content.Intent; import android.os.Handler; import android.os.IBinder; import android.os.Message; +import android.os.ParcelFileDescriptor; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.support.annotation.Nullable; import android.util.Pair; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; import java.lang.ref.WeakReference; import de.blinkt.openvpn.api.ExternalOpenVPNService; @@ -59,8 +63,45 @@ public class OpenVPNStatusService extends Service implements VpnStatus.LogListen private static final IServiceStatus.Stub mBinder = new IServiceStatus.Stub() { @Override - public void registerStatusCallback(IStatusCallbacks cb) throws RemoteException { + public ParcelFileDescriptor registerStatusCallback(IStatusCallbacks cb) throws RemoteException { + final LogItem[] logbuffer = VpnStatus.getlogbuffer(); mCallbacks.register(cb); + try { + final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe(); + new Thread("pushLogs") { + @Override + public void run() { + DataOutputStream fd = new DataOutputStream(new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1])); + try { + synchronized (VpnStatus.readFileLock) { + if (!VpnStatus.readFileLog) { + VpnStatus.readFileLock.wait(); + } + } + } catch (InterruptedException e) { + VpnStatus.logException(e); + } + try { + + for (LogItem logItem : logbuffer) { + byte[] bytes = logItem.getMarschaledBytes(); + fd.writeShort(bytes.length); + fd.write(bytes); + } + // Mark end + fd.writeShort(0x7fff); + fd.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + } + }.start(); + return pipe[0]; + } catch (IOException e) { + e.printStackTrace(); + throw new RemoteException(e.getMessage()); + } } @Override diff --git a/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java b/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java index 8df1dfed..19a2668d 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java +++ b/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java @@ -10,13 +10,19 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import java.io.DataInputStream; +import java.io.File; +import java.io.IOException; + /** * Created by arne on 09.11.16. */ -public class StatusListener { +public class StatusListener { + private File mCacheDir; private ServiceConnection mConnection = new ServiceConnection() { @@ -29,12 +35,25 @@ public class StatusListener { /* Check if this a local service ... */ if (service.queryLocalInterface("de.blinkt.openvpn.core.IServiceStatus") == null) { VpnStatus.setConnectedVPNProfile(serviceStatus.getLastConnectedVPN()); - serviceStatus.registerStatusCallback(mCallback); - + ParcelFileDescriptor pfd = serviceStatus.registerStatusCallback(mCallback); + DataInputStream fd = new DataInputStream(new ParcelFileDescriptor.AutoCloseInputStream(pfd)); + + short len = fd.readShort(); + byte[] buf = new byte[4095]; + while (len != 0x7fff) { + fd.readFully(buf, 0, len); + LogItem logitem = new LogItem(buf, len); + VpnStatus.newLogItem(logitem, false); + len = fd.readShort(); + } + fd.close(); + } else { + VpnStatus.initLogCache(mCacheDir); } - } catch (RemoteException e) { + } catch (RemoteException | IOException e) { e.printStackTrace(); + VpnStatus.logException(e); } } @@ -45,11 +64,11 @@ public class StatusListener { }; - void init(Context c) - { + void init(Context c) { Intent intent = new Intent(c, OpenVPNStatusService.class); intent.setAction(OpenVPNService.START_SERVICE); + mCacheDir = c.getCacheDir(); c.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); diff --git a/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java b/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java index 84cb4719..cd0e3e4f 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java +++ b/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java @@ -23,7 +23,7 @@ import de.blinkt.openvpn.VpnProfile; public class VpnStatus { - public static LinkedList logbuffer; + private static final LinkedList logbuffer; private static Vector logListener; private static Vector stateListener; @@ -39,6 +39,8 @@ public class VpnStatus { private static HandlerThread mHandlerThread; private static String mLastConnectedVPNUUID; + static boolean readFileLog =false; + final static java.lang.Object readFileLock = new Object(); public static void logException(LogLevel ll, String context, Exception e) { StringWriter sw = new StringWriter(); -- cgit v1.2.3