From 70119087fe0b4892fc7d25663c3096485f6323ad Mon Sep 17 00:00:00 2001 From: Marvin W Date: Wed, 18 May 2016 14:10:17 +0200 Subject: [PATCH] Ensure all threads to be closed Fixes possible OOM error --- .../org/microg/gms/gcm/McsInputStream.java | 13 ++++++-- .../org/microg/gms/gcm/McsOutputStream.java | 23 +++++++------- .../java/org/microg/gms/gcm/McsService.java | 30 +++++++++++++------ 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/McsInputStream.java b/play-services-core/src/main/java/org/microg/gms/gcm/McsInputStream.java index 9506600a..776e3f67 100644 --- a/play-services-core/src/main/java/org/microg/gms/gcm/McsInputStream.java +++ b/play-services-core/src/main/java/org/microg/gms/gcm/McsInputStream.java @@ -30,6 +30,7 @@ import org.microg.gms.gcm.mcs.IqStanza; import org.microg.gms.gcm.mcs.LoginRequest; import org.microg.gms.gcm.mcs.LoginResponse; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; @@ -44,7 +45,7 @@ import static org.microg.gms.gcm.McsConstants.MSG_INPUT; import static org.microg.gms.gcm.McsConstants.MSG_INPUT_ERROR; import static org.microg.gms.gcm.McsConstants.MSG_TEARDOWN; -public class McsInputStream extends Thread { +public class McsInputStream extends Thread implements Closeable { private static final String TAG = "GmsGcmMcsInput"; private final InputStream is; @@ -56,6 +57,8 @@ public class McsInputStream extends Thread { private int streamId = 0; private long lastMsgTime = 0; + private boolean closed = false; + public McsInputStream(InputStream is, Handler mainHandler) { this(is, mainHandler, false); } @@ -70,7 +73,7 @@ public class McsInputStream extends Thread { @Override public void run() { try { - while (!Thread.currentThread().isInterrupted()) { + while (!Thread.currentThread().isInterrupted() && !closed) { android.os.Message msg = read(); if (msg != null) { mainHandler.dispatchMessage(msg); @@ -88,8 +91,12 @@ public class McsInputStream extends Thread { } } + @Override public void close() { - interrupt(); + if (!closed) { + closed = true; + interrupt(); + } } public int getStreamId() { diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/McsOutputStream.java b/play-services-core/src/main/java/org/microg/gms/gcm/McsOutputStream.java index 3c319ade..e7626c6b 100644 --- a/play-services-core/src/main/java/org/microg/gms/gcm/McsOutputStream.java +++ b/play-services-core/src/main/java/org/microg/gms/gcm/McsOutputStream.java @@ -22,18 +22,10 @@ import android.util.Log; import com.squareup.wire.Message; -import org.microg.gms.gcm.mcs.DataMessageStanza; -import org.microg.gms.gcm.mcs.HeartbeatAck; -import org.microg.gms.gcm.mcs.HeartbeatPing; -import org.microg.gms.gcm.mcs.LoginRequest; - +import java.io.Closeable; import java.io.IOException; import java.io.OutputStream; -import static org.microg.gms.gcm.McsConstants.MCS_DATA_MESSAGE_STANZA_TAG; -import static org.microg.gms.gcm.McsConstants.MCS_HEARTBEAT_ACK_TAG; -import static org.microg.gms.gcm.McsConstants.MCS_HEARTBEAT_PING_TAG; -import static org.microg.gms.gcm.McsConstants.MCS_LOGIN_REQUEST_TAG; import static org.microg.gms.gcm.McsConstants.MCS_VERSION_CODE; import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT; import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_DONE; @@ -41,7 +33,7 @@ import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_ERROR; import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_READY; import static org.microg.gms.gcm.McsConstants.MSG_TEARDOWN; -public class McsOutputStream extends Thread implements Handler.Callback { +public class McsOutputStream extends Thread implements Handler.Callback, Closeable { private static final String TAG = "GmsGcmMcsOutput"; private final OutputStream os; @@ -52,6 +44,8 @@ public class McsOutputStream extends Thread implements Handler.Callback { private Handler mainHandler; private Handler myHandler; + private boolean closed = false; + public McsOutputStream(OutputStream os, Handler mainHandler) { this(os, mainHandler, false); } @@ -101,6 +95,15 @@ public class McsOutputStream extends Thread implements Handler.Callback { return false; } + @Override + public void close() { + if (!closed) { + closed = true; + myHandler.getLooper().quit(); + interrupt(); + } + } + private synchronized void writeInternal(Message message, int tag) throws IOException { if (!initialized) { Log.d(TAG, "Write MCS version code: " + version); diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/McsService.java b/play-services-core/src/main/java/org/microg/gms/gcm/McsService.java index 4b4dd778..373e8535 100644 --- a/play-services-core/src/main/java/org/microg/gms/gcm/McsService.java +++ b/play-services-core/src/main/java/org/microg/gms/gcm/McsService.java @@ -45,6 +45,7 @@ import org.microg.gms.gcm.mcs.LoginRequest; import org.microg.gms.gcm.mcs.LoginResponse; import org.microg.gms.gcm.mcs.Setting; +import java.io.Closeable; import java.net.Socket; import java.util.Collections; import java.util.List; @@ -56,8 +57,6 @@ import static android.os.Build.VERSION.SDK_INT; import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_RECEIVE; import static org.microg.gms.gcm.GcmConstants.EXTRA_COLLAPSE_KEY; import static org.microg.gms.gcm.GcmConstants.EXTRA_FROM; -import static org.microg.gms.gcm.GcmConstants.EXTRA_MESSAGE_TYPE; -import static org.microg.gms.gcm.GcmConstants.MESSAGE_TYPE_GCM; import static org.microg.gms.gcm.McsConstants.ACTION_CONNECT; import static org.microg.gms.gcm.McsConstants.ACTION_HEARTBEAT; import static org.microg.gms.gcm.McsConstants.ACTION_RECONNECT; @@ -110,6 +109,11 @@ public class McsService extends Service implements Handler.Callback { private Intent connectIntent; private class HandlerThread extends Thread { + + public HandlerThread() { + setName("McsHandler"); + } + @Override public void run() { Looper.prepare(); @@ -155,8 +159,8 @@ public class McsService extends Service implements Handler.Callback { return false; } // consider connection to be dead if we did not receive an ack within twice the heartbeat interval - if (SystemClock.elapsedRealtime() - lastHeartbeatAckElapsedRealtime < 2 * GcmPrefs.get(null).getHeartbeatMs()) { - logd("No heartbeat for " + 2 * GcmPrefs.get(null).getHeartbeatMs() / 1000 + " seconds, connection seems to be dead."); + if (SystemClock.elapsedRealtime() - lastHeartbeatAckElapsedRealtime > 2 * GcmPrefs.get(null).getHeartbeatMs()) { + logd("No heartbeat for " + (SystemClock.elapsedRealtime() - lastHeartbeatAckElapsedRealtime) / 1000 + " seconds, connection assumed to be dead after " + 2 * GcmPrefs.get(null).getHeartbeatMs() / 1000 + " seconds"); return false; } return true; @@ -222,6 +226,8 @@ public class McsService extends Service implements Handler.Callback { private synchronized void connect() { try { + tryClose(inputStream); + tryClose(outputStream); logd("Starting MCS connection..."); Socket socket = new Socket(SERVICE_HOST, SERVICE_PORT); logd("Connected to " + SERVICE_HOST + ":" + SERVICE_PORT); @@ -434,12 +440,18 @@ public class McsService extends Service implements Handler.Callback { } } - private void handleTeardown(android.os.Message msg) { - sendOutputStream(MSG_TEARDOWN, msg.arg1, msg.obj); - if (inputStream != null) { - inputStream.close(); - inputStream = null; + private void tryClose(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (Exception ignored) { + } } + } + + private void handleTeardown(android.os.Message msg) { + tryClose(inputStream); + tryClose(outputStream); try { sslSocket.close(); } catch (Exception ignored) {