From 1a83f8281f2f5d3b71980c131d43fbca56298762 Mon Sep 17 00:00:00 2001 From: mar-v-in Date: Mon, 17 Aug 2015 23:28:01 +0200 Subject: [PATCH] Improve mcs connection wake up device when reconnecting, fix teardown incomplete on null message (#24) --- .../src/main/AndroidManifest.xml | 2 +- .../org/microg/gms/gcm/McsInputStream.java | 21 ++++-- .../java/org/microg/gms/gcm/McsService.java | 73 ++++++++++++------- .../org/microg/gms/gcm/TriggerReceiver.java | 24 +++--- 4 files changed, 77 insertions(+), 43 deletions(-) diff --git a/play-services-core/src/main/AndroidManifest.xml b/play-services-core/src/main/AndroidManifest.xml index 220761cf..015a6bd4 100644 --- a/play-services-core/src/main/AndroidManifest.xml +++ b/play-services-core/src/main/AndroidManifest.xml @@ -55,7 +55,7 @@ + android:protectionLevel="normal" /> 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 3d7de216..b867f76b 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 @@ -42,6 +42,7 @@ import static org.microg.gms.gcm.Constants.MCS_LOGIN_REQUEST_TAG; import static org.microg.gms.gcm.Constants.MCS_LOGIN_RESPONSE_TAG; import static org.microg.gms.gcm.Constants.MSG_INPUT; import static org.microg.gms.gcm.Constants.MSG_INPUT_ERROR; +import static org.microg.gms.gcm.Constants.MSG_TEARDOWN; public class McsInputStream extends Thread { private static final String TAG = "GmsGcmMcsInput"; @@ -70,15 +71,20 @@ public class McsInputStream extends Thread { public void run() { try { while (!Thread.currentThread().isInterrupted()) { - mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_INPUT, read())); + Message msg = read(); + if (msg != null) { + mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_INPUT, msg)); + } else { + mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_TEARDOWN, "null message")); + } } } catch (IOException e) { - try { - is.close(); - } catch (IOException ignored) { - } mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_INPUT_ERROR, e)); } + try { + is.close(); + } catch (IOException ignored) { + } } public void close() { @@ -115,7 +121,10 @@ public class McsInputStream extends Thread { ensureVersionRead(); int mcsTag = is.read(); int mcsSize = readVarint(); - if (mcsTag < 0 || mcsSize < 0) return null; + if (mcsTag < 0 || mcsSize < 0) { + Log.w(TAG, "mcsTag: " + mcsTag + " mcsSize: " + mcsSize); + return null; + } byte[] bytes = new byte[mcsSize]; int len = 0, read = 0; while (len < mcsSize && read >= 0) { 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 9d704873..6ad5e90c 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 @@ -26,6 +26,7 @@ import android.os.Handler; import android.os.Looper; import android.os.PowerManager; import android.os.SystemClock; +import android.support.v4.content.WakefulBroadcastReceiver; import android.util.Log; import com.squareup.wire.Message; @@ -82,12 +83,15 @@ public class McsService extends IntentService implements Handler.Callback { private static MainThread mainThread; private static Handler mainHandler; - private boolean initialized = false; private AlarmManager alarmManager; private PowerManager powerManager; private static PowerManager.WakeLock wakeLock; + private static int delay = 0; + + private Intent connectIntent; + public McsService() { super(TAG); } @@ -96,8 +100,15 @@ public class McsService extends IntentService implements Handler.Callback { @Override public void run() { Looper.prepare(); - mainHandler = new Handler(Looper.myLooper(), McsService.this); - mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_CONNECT)); + wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "mcs"); + wakeLock.setReferenceCounted(false); + synchronized (McsService.class) { + mainHandler = new Handler(Looper.myLooper(), McsService.this); + if (connectIntent != null) { + mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_CONNECT, connectIntent)); + WakefulBroadcastReceiver.completeWakefulIntent(connectIntent); + } + } Looper.loop(); } } @@ -105,36 +116,42 @@ public class McsService extends IntentService implements Handler.Callback { @Override public void onCreate() { super.onCreate(); - if (mainThread == null) { - mainThread = new MainThread(); - mainThread.start(); - } heartbeatIntent = PendingIntent.getService(this, 0, new Intent(ACTION_HEARTBEAT, null, this, McsService.class), 0); alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); powerManager = (PowerManager) getSystemService(POWER_SERVICE); - wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "mcs"); - wakeLock.setReferenceCounted(false); - - alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + HEARTBEAT_MS, HEARTBEAT_MS, heartbeatIntent); + synchronized (McsService.class) { + if (mainThread == null) { + mainThread = new MainThread(); + mainThread.start(); + } + } } - public static boolean isConnected() { + public synchronized static boolean isConnected() { return inputStream != null && inputStream.isAlive() && outputStream != null && outputStream.isAlive(); } @Override protected void onHandleIntent(Intent intent) { - wakeLock.acquire(); - if (mainHandler != null) { - if (ACTION_CONNECT.equals(intent.getAction())) { - mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_CONNECT, intent)); - } else if (ACTION_HEARTBEAT.equals(intent.getAction())) { - mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_HEARTBEAT, intent)); + synchronized (McsService.class) { + if (mainHandler != null) { + wakeLock.acquire(); + if (ACTION_CONNECT.equals(intent.getAction())) { + mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_CONNECT, intent)); + } else if (ACTION_HEARTBEAT.equals(intent.getAction())) { + mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_HEARTBEAT, intent)); + } + WakefulBroadcastReceiver.completeWakefulIntent(intent); + } else if (connectIntent == null) { + connectIntent = intent; + } else { + WakefulBroadcastReceiver.completeWakefulIntent(intent); } } } private synchronized void connect() { + if (delay < 60000) delay += 5000; try { Log.d(TAG, "Starting MCS connection..."); Socket socket = new Socket(SERVICE_HOST, SERVICE_PORT); @@ -145,6 +162,8 @@ public class McsService extends IntentService implements Handler.Callback { outputStream = new McsOutputStream(sslSocket.getOutputStream(), mainHandler); inputStream.start(); outputStream.start(); + + alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(), HEARTBEAT_MS, heartbeatIntent); } catch (Exception e) { Log.w(TAG, "Exception while connecting!", e); mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_TEARDOWN, e)); @@ -260,11 +279,7 @@ public class McsService extends IntentService implements Handler.Callback { switch (msg.what) { case MSG_INPUT: Log.d(TAG, "Incoming message: " + msg.obj); - if (msg.obj != null) { - handleInput((Message) msg.obj); - } else { - mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_TEARDOWN, "null message")); - } + handleInput((Message) msg.obj); return true; case MSG_OUTPUT: Log.d(TAG, "Outgoing message: " + msg.obj); @@ -321,6 +336,7 @@ public class McsService extends IntentService implements Handler.Callback { } else { Log.w(TAG, "Unknown message: " + message); } + delay = 0; } catch (Exception e) { mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_TEARDOWN, e)); } @@ -330,13 +346,20 @@ public class McsService extends IntentService implements Handler.Callback { sendOutputStream(MSG_TEARDOWN, msg.obj); if (inputStream != null) { inputStream.close(); + inputStream = null; } try { sslSocket.close(); } catch (Exception ignored) { } - sendBroadcast(new Intent("org.microg.gms.gcm.RECONNECT"), "org.microg.gms.STATUS_BROADCAST"); + if (delay == 0) { + sendBroadcast(new Intent("org.microg.gms.gcm.RECONNECT"), "org.microg.gms.STATUS_BROADCAST"); + } else { + alarmManager.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + delay, PendingIntent.getBroadcast(this, 1, new Intent(this, TriggerReceiver.class), 0)); + } alarmManager.cancel(heartbeatIntent); - wakeLock.release(); + if (wakeLock != null) { + wakeLock.release(); + } } } diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/TriggerReceiver.java b/play-services-core/src/main/java/org/microg/gms/gcm/TriggerReceiver.java index 020cc0fe..6f9a74ff 100644 --- a/play-services-core/src/main/java/org/microg/gms/gcm/TriggerReceiver.java +++ b/play-services-core/src/main/java/org/microg/gms/gcm/TriggerReceiver.java @@ -16,35 +16,37 @@ package org.microg.gms.gcm; -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.os.SystemClock; import android.preference.PreferenceManager; +import android.support.v4.content.WakefulBroadcastReceiver; +import android.util.Log; -public class TriggerReceiver extends BroadcastReceiver { +public class TriggerReceiver extends WakefulBroadcastReceiver { + private static final String TAG = "GmsGcmTrigger"; private static final String PREF_ENABLE_GCM = "gcm_enable_mcs_service"; - private static final long pendingDelay = 1000; @Override public void onReceive(Context context, Intent intent) { boolean force = "android.provider.Telephony.SECRET_CODE".equals(intent.getAction()); - if (!McsService.isConnected() || force) { - if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean(PREF_ENABLE_GCM, false) || force) { + if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean(PREF_ENABLE_GCM, false) || force) { + if (!McsService.isConnected() || force) { ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = cm.getActiveNetworkInfo(); if (networkInfo != null && networkInfo.isConnected() || force) { - AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - PendingIntent pendingIntent = PendingIntent.getService(context, 0, new Intent(McsService.ACTION_CONNECT, null, context, McsService.class), 0); - alarmManager.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + pendingDelay, pendingIntent); + startWakefulService(context, new Intent(McsService.ACTION_CONNECT, null, context, McsService.class)); + } else { + Log.d(TAG, "Ignoring " + intent + ": network is offline"); } + } else { + Log.d(TAG, "Ignoring " + intent + ": service is running"); } + } else { + Log.d(TAG, "Ignoring " + intent + ": gcm is disabled"); } } }