Improve mcs connection

wake up device when reconnecting, fix teardown incomplete on null message (#24)
This commit is contained in:
mar-v-in 2015-08-17 23:28:01 +02:00
parent c826702bb9
commit 1a83f8281f
4 changed files with 77 additions and 43 deletions

View File

@ -55,7 +55,7 @@
<permission
android:name="org.microg.gms.STATUS_BROADCAST"
android:label="@string/perm_status_broadcast_label"
android:protectionLevel="dangerous" />
android:protectionLevel="normal" />
<uses-permission android:name="android.permission.FAKE_PACKAGE_SIGNATURE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

View File

@ -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) {

View File

@ -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();
}
}
}

View File

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