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");
}
}
}