catch dead object exceptions when acquiring wake locks
This commit is contained in:
parent
ffc35f5bc5
commit
4a706aad03
|
@ -26,6 +26,7 @@ import eu.siacs.conversations.services.AbstractConnectionManager;
|
||||||
import eu.siacs.conversations.services.XmppConnectionService;
|
import eu.siacs.conversations.services.XmppConnectionService;
|
||||||
import eu.siacs.conversations.utils.CryptoHelper;
|
import eu.siacs.conversations.utils.CryptoHelper;
|
||||||
import eu.siacs.conversations.utils.FileWriterException;
|
import eu.siacs.conversations.utils.FileWriterException;
|
||||||
|
import eu.siacs.conversations.utils.WakeLockHelper;
|
||||||
|
|
||||||
public class HttpDownloadConnection implements Transferable {
|
public class HttpDownloadConnection implements Transferable {
|
||||||
|
|
||||||
|
@ -365,7 +366,7 @@ public class HttpDownloadConnection implements Transferable {
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
connection.disconnect();
|
connection.disconnect();
|
||||||
}
|
}
|
||||||
wakeLock.release();
|
WakeLockHelper.release(wakeLock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ import eu.siacs.conversations.persistance.FileBackend;
|
||||||
import eu.siacs.conversations.services.AbstractConnectionManager;
|
import eu.siacs.conversations.services.AbstractConnectionManager;
|
||||||
import eu.siacs.conversations.services.XmppConnectionService;
|
import eu.siacs.conversations.services.XmppConnectionService;
|
||||||
import eu.siacs.conversations.utils.CryptoHelper;
|
import eu.siacs.conversations.utils.CryptoHelper;
|
||||||
|
import eu.siacs.conversations.utils.WakeLockHelper;
|
||||||
import eu.siacs.conversations.xml.Namespace;
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
import eu.siacs.conversations.xml.Element;
|
import eu.siacs.conversations.xml.Element;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
||||||
|
@ -237,9 +238,7 @@ public class HttpUploadConnection implements Transferable {
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
connection.disconnect();
|
connection.disconnect();
|
||||||
}
|
}
|
||||||
if (wakeLock.isHeld()) {
|
WakeLockHelper.release(wakeLock);
|
||||||
wakeLock.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,7 @@ import eu.siacs.conversations.utils.ReplacingSerialSingleThreadExecutor;
|
||||||
import eu.siacs.conversations.utils.ReplacingTaskManager;
|
import eu.siacs.conversations.utils.ReplacingTaskManager;
|
||||||
import eu.siacs.conversations.utils.Resolver;
|
import eu.siacs.conversations.utils.Resolver;
|
||||||
import eu.siacs.conversations.utils.SerialSingleThreadExecutor;
|
import eu.siacs.conversations.utils.SerialSingleThreadExecutor;
|
||||||
|
import eu.siacs.conversations.utils.WakeLockHelper;
|
||||||
import eu.siacs.conversations.xml.Namespace;
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
import eu.siacs.conversations.utils.XmppUri;
|
import eu.siacs.conversations.utils.XmppUri;
|
||||||
import eu.siacs.conversations.xml.Element;
|
import eu.siacs.conversations.xml.Element;
|
||||||
|
@ -659,7 +660,7 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
this.wakeLock.acquire();
|
WakeLockHelper.acquire(wakeLock);
|
||||||
boolean pingNow = ConnectivityManager.CONNECTIVITY_ACTION.equals(action);
|
boolean pingNow = ConnectivityManager.CONNECTIVITY_ACTION.equals(action);
|
||||||
HashSet<Account> pingCandidates = new HashSet<>();
|
HashSet<Account> pingCandidates = new HashSet<>();
|
||||||
for (Account account : accounts) {
|
for (Account account : accounts) {
|
||||||
|
@ -677,12 +678,7 @@ public class XmppConnectionService extends Service {
|
||||||
scheduleWakeUpCall(lowTimeout ? Config.LOW_PING_TIMEOUT : Config.PING_TIMEOUT, account.getUuid().hashCode());
|
scheduleWakeUpCall(lowTimeout ? Config.LOW_PING_TIMEOUT : Config.PING_TIMEOUT, account.getUuid().hashCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (wakeLock.isHeld()) {
|
WakeLockHelper.release(wakeLock);
|
||||||
try {
|
|
||||||
wakeLock.release();
|
|
||||||
} catch (final RuntimeException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (SystemClock.elapsedRealtime() - mLastExpiryRun.get() >= Config.EXPIRY_INTERVAL) {
|
if (SystemClock.elapsedRealtime() - mLastExpiryRun.get() >= Config.EXPIRY_INTERVAL) {
|
||||||
expireOldMessages();
|
expireOldMessages();
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Daniel Gultsch All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
* other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.siacs.conversations.utils;
|
||||||
|
|
||||||
|
import android.os.PowerManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
|
|
||||||
|
public class WakeLockHelper {
|
||||||
|
|
||||||
|
public static void acquire(PowerManager.WakeLock wakeLock) {
|
||||||
|
try {
|
||||||
|
wakeLock.acquire(2000);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.d(Config.LOGTAG, "unable to acquire wake lock", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void release(PowerManager.WakeLock wakeLock) {
|
||||||
|
if (wakeLock == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (wakeLock.isHeld()) {
|
||||||
|
wakeLock.release();
|
||||||
|
}
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.d(Config.LOGTAG, "unable to release wake lock", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ import eu.siacs.conversations.entities.DownloadableFile;
|
||||||
import eu.siacs.conversations.persistance.FileBackend;
|
import eu.siacs.conversations.persistance.FileBackend;
|
||||||
import eu.siacs.conversations.utils.CryptoHelper;
|
import eu.siacs.conversations.utils.CryptoHelper;
|
||||||
import eu.siacs.conversations.utils.SocksSocketFactory;
|
import eu.siacs.conversations.utils.SocksSocketFactory;
|
||||||
|
import eu.siacs.conversations.utils.WakeLockHelper;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.Content;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.Content;
|
||||||
|
|
||||||
public class JingleSocks5Transport extends JingleTransport {
|
public class JingleSocks5Transport extends JingleTransport {
|
||||||
|
@ -27,17 +28,16 @@ public class JingleSocks5Transport extends JingleTransport {
|
||||||
private InputStream inputStream;
|
private InputStream inputStream;
|
||||||
private boolean isEstablished = false;
|
private boolean isEstablished = false;
|
||||||
private boolean activated = false;
|
private boolean activated = false;
|
||||||
protected Socket socket;
|
private Socket socket;
|
||||||
|
|
||||||
public JingleSocks5Transport(JingleConnection jingleConnection,
|
JingleSocks5Transport(JingleConnection jingleConnection, JingleCandidate candidate) {
|
||||||
JingleCandidate candidate) {
|
|
||||||
this.candidate = candidate;
|
this.candidate = candidate;
|
||||||
this.connection = jingleConnection;
|
this.connection = jingleConnection;
|
||||||
try {
|
try {
|
||||||
MessageDigest mDigest = MessageDigest.getInstance("SHA-1");
|
MessageDigest mDigest = MessageDigest.getInstance("SHA-1");
|
||||||
StringBuilder destBuilder = new StringBuilder();
|
StringBuilder destBuilder = new StringBuilder();
|
||||||
if (jingleConnection.getFtVersion() == Content.Version.FT_3) {
|
if (jingleConnection.getFtVersion() == Content.Version.FT_3) {
|
||||||
Log.d(Config.LOGTAG,this.connection.getAccount().getJid().asBareJid()+": using session Id instead of transport Id for proxy destination");
|
Log.d(Config.LOGTAG, this.connection.getAccount().getJid().asBareJid() + ": using session Id instead of transport Id for proxy destination");
|
||||||
destBuilder.append(jingleConnection.getSessionId());
|
destBuilder.append(jingleConnection.getSessionId());
|
||||||
} else {
|
} else {
|
||||||
destBuilder.append(jingleConnection.getTransportId());
|
destBuilder.append(jingleConnection.getTransportId());
|
||||||
|
@ -58,124 +58,112 @@ public class JingleSocks5Transport extends JingleTransport {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect(final OnTransportConnected callback) {
|
public void connect(final OnTransportConnected callback) {
|
||||||
new Thread(new Runnable() {
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
@Override
|
final boolean useTor = connection.getAccount().isOnion() || connection.getConnectionManager().getXmppConnectionService().useTorToConnect();
|
||||||
public void run() {
|
if (useTor) {
|
||||||
try {
|
socket = SocksSocketFactory.createSocketOverTor(candidate.getHost(), candidate.getPort());
|
||||||
final boolean useTor = connection.getAccount().isOnion() || connection.getConnectionManager().getXmppConnectionService().useTorToConnect();
|
} else {
|
||||||
if (useTor) {
|
socket = new Socket();
|
||||||
socket = SocksSocketFactory.createSocketOverTor(candidate.getHost(),candidate.getPort());
|
SocketAddress address = new InetSocketAddress(candidate.getHost(), candidate.getPort());
|
||||||
} else {
|
socket.connect(address, Config.SOCKET_TIMEOUT * 1000);
|
||||||
socket = new Socket();
|
|
||||||
SocketAddress address = new InetSocketAddress(candidate.getHost(),candidate.getPort());
|
|
||||||
socket.connect(address,Config.SOCKET_TIMEOUT * 1000);
|
|
||||||
}
|
|
||||||
inputStream = socket.getInputStream();
|
|
||||||
outputStream = socket.getOutputStream();
|
|
||||||
SocksSocketFactory.createSocksConnection(socket,destination,0);
|
|
||||||
isEstablished = true;
|
|
||||||
callback.established();
|
|
||||||
} catch (IOException e) {
|
|
||||||
callback.failed();
|
|
||||||
}
|
}
|
||||||
|
inputStream = socket.getInputStream();
|
||||||
|
outputStream = socket.getOutputStream();
|
||||||
|
SocksSocketFactory.createSocksConnection(socket, destination, 0);
|
||||||
|
isEstablished = true;
|
||||||
|
callback.established();
|
||||||
|
} catch (IOException e) {
|
||||||
|
callback.failed();
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void send(final DownloadableFile file, final OnFileTransmissionStatusChanged callback) {
|
public void send(final DownloadableFile file, final OnFileTransmissionStatusChanged callback) {
|
||||||
new Thread(new Runnable() {
|
new Thread(() -> {
|
||||||
|
InputStream fileInputStream = null;
|
||||||
@Override
|
final PowerManager.WakeLock wakeLock = connection.getConnectionManager().createWakeLock("jingle_send_" + connection.getSessionId());
|
||||||
public void run() {
|
try {
|
||||||
InputStream fileInputStream = null;
|
wakeLock.acquire();
|
||||||
final PowerManager.WakeLock wakeLock = connection.getConnectionManager().createWakeLock("jingle_send_"+connection.getSessionId());
|
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||||
try {
|
digest.reset();
|
||||||
wakeLock.acquire();
|
fileInputStream = connection.getFileInputStream();
|
||||||
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
if (fileInputStream == null) {
|
||||||
digest.reset();
|
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": could not create input stream");
|
||||||
fileInputStream = connection.getFileInputStream();
|
|
||||||
if (fileInputStream == null) {
|
|
||||||
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": could not create input stream");
|
|
||||||
callback.onFileTransferAborted();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
long size = file.getExpectedSize();
|
|
||||||
long transmitted = 0;
|
|
||||||
int count;
|
|
||||||
byte[] buffer = new byte[8192];
|
|
||||||
while ((count = fileInputStream.read(buffer)) > 0) {
|
|
||||||
outputStream.write(buffer, 0, count);
|
|
||||||
digest.update(buffer, 0, count);
|
|
||||||
transmitted += count;
|
|
||||||
connection.updateProgress((int) ((((double) transmitted) / size) * 100));
|
|
||||||
}
|
|
||||||
outputStream.flush();
|
|
||||||
file.setSha1Sum(digest.digest());
|
|
||||||
if (callback != null) {
|
|
||||||
callback.onFileTransmitted(file);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": "+e.getMessage());
|
|
||||||
callback.onFileTransferAborted();
|
callback.onFileTransferAborted();
|
||||||
} finally {
|
return;
|
||||||
FileBackend.close(fileInputStream);
|
|
||||||
wakeLock.release();
|
|
||||||
}
|
}
|
||||||
|
long size = file.getExpectedSize();
|
||||||
|
long transmitted = 0;
|
||||||
|
int count;
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
while ((count = fileInputStream.read(buffer)) > 0) {
|
||||||
|
outputStream.write(buffer, 0, count);
|
||||||
|
digest.update(buffer, 0, count);
|
||||||
|
transmitted += count;
|
||||||
|
connection.updateProgress((int) ((((double) transmitted) / size) * 100));
|
||||||
|
}
|
||||||
|
outputStream.flush();
|
||||||
|
file.setSha1Sum(digest.digest());
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onFileTransmitted(file);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": " + e.getMessage());
|
||||||
|
callback.onFileTransferAborted();
|
||||||
|
} finally {
|
||||||
|
FileBackend.close(fileInputStream);
|
||||||
|
WakeLockHelper.release(wakeLock);
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void receive(final DownloadableFile file, final OnFileTransmissionStatusChanged callback) {
|
public void receive(final DownloadableFile file, final OnFileTransmissionStatusChanged callback) {
|
||||||
new Thread(new Runnable() {
|
new Thread(() -> {
|
||||||
|
OutputStream fileOutputStream = null;
|
||||||
@Override
|
final PowerManager.WakeLock wakeLock = connection.getConnectionManager().createWakeLock("jingle_receive_" + connection.getSessionId());
|
||||||
public void run() {
|
try {
|
||||||
OutputStream fileOutputStream = null;
|
wakeLock.acquire();
|
||||||
final PowerManager.WakeLock wakeLock = connection.getConnectionManager().createWakeLock("jingle_receive_"+connection.getSessionId());
|
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||||
try {
|
digest.reset();
|
||||||
wakeLock.acquire();
|
//inputStream.skip(45);
|
||||||
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
socket.setSoTimeout(30000);
|
||||||
digest.reset();
|
fileOutputStream = connection.getFileOutputStream();
|
||||||
//inputStream.skip(45);
|
if (fileOutputStream == null) {
|
||||||
socket.setSoTimeout(30000);
|
|
||||||
fileOutputStream = connection.getFileOutputStream();
|
|
||||||
if (fileOutputStream == null) {
|
|
||||||
callback.onFileTransferAborted();
|
|
||||||
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": could not create output stream");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
double size = file.getExpectedSize();
|
|
||||||
long remainingSize = file.getExpectedSize();
|
|
||||||
byte[] buffer = new byte[8192];
|
|
||||||
int count;
|
|
||||||
while (remainingSize > 0) {
|
|
||||||
count = inputStream.read(buffer);
|
|
||||||
if (count == -1) {
|
|
||||||
callback.onFileTransferAborted();
|
|
||||||
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": file ended prematurely with "+remainingSize+" bytes remaining");
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
fileOutputStream.write(buffer, 0, count);
|
|
||||||
digest.update(buffer, 0, count);
|
|
||||||
remainingSize -= count;
|
|
||||||
}
|
|
||||||
connection.updateProgress((int) (((size - remainingSize) / size) * 100));
|
|
||||||
}
|
|
||||||
fileOutputStream.flush();
|
|
||||||
fileOutputStream.close();
|
|
||||||
file.setSha1Sum(digest.digest());
|
|
||||||
callback.onFileTransmitted(file);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": "+e.getMessage());
|
|
||||||
callback.onFileTransferAborted();
|
callback.onFileTransferAborted();
|
||||||
} finally {
|
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": could not create output stream");
|
||||||
wakeLock.release();
|
return;
|
||||||
FileBackend.close(fileOutputStream);
|
|
||||||
FileBackend.close(inputStream);
|
|
||||||
}
|
}
|
||||||
|
double size = file.getExpectedSize();
|
||||||
|
long remainingSize = file.getExpectedSize();
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
int count;
|
||||||
|
while (remainingSize > 0) {
|
||||||
|
count = inputStream.read(buffer);
|
||||||
|
if (count == -1) {
|
||||||
|
callback.onFileTransferAborted();
|
||||||
|
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": file ended prematurely with " + remainingSize + " bytes remaining");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
fileOutputStream.write(buffer, 0, count);
|
||||||
|
digest.update(buffer, 0, count);
|
||||||
|
remainingSize -= count;
|
||||||
|
}
|
||||||
|
connection.updateProgress((int) (((size - remainingSize) / size) * 100));
|
||||||
|
}
|
||||||
|
fileOutputStream.flush();
|
||||||
|
fileOutputStream.close();
|
||||||
|
file.setSha1Sum(digest.digest());
|
||||||
|
callback.onFileTransmitted(file);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": " + e.getMessage());
|
||||||
|
callback.onFileTransferAborted();
|
||||||
|
} finally {
|
||||||
|
WakeLockHelper.release(wakeLock);
|
||||||
|
FileBackend.close(fileOutputStream);
|
||||||
|
FileBackend.close(inputStream);
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue