mirror of
https://github.com/YTVanced/VancedMicroG
synced 2024-11-27 21:53:00 +00:00
Update portions of GCM implementation
- Fix bug causing unregister to be send multiple times - More work related to #23, #29 and #31
This commit is contained in:
parent
02e6ffce4d
commit
766a6a1b47
6 changed files with 100 additions and 59 deletions
|
@ -35,4 +35,9 @@ public class Constants {
|
|||
public static final int MSG_TEARDOWN = 30;
|
||||
public static final int MSG_CONNECT = 40;
|
||||
public static final int MSG_HEARTBEAT = 41;
|
||||
|
||||
public static String ACTION_CONNECT = "org.microg.gms.gcm.mcs.CONNECT";
|
||||
public static String ACTION_RECONNECT = "org.microg.gms.gcm.mcs.RECONNECT";
|
||||
public static String ACTION_HEARTBEAT = "org.microg.gms.gcm.mcs.HEARTBEAT";
|
||||
public static String EXTRA_REASON = "org.microg.gms.gcm.mcs.REASON";
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ public class McsInputStream extends Thread {
|
|||
try {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
Message msg = read();
|
||||
Log.d(TAG, "Incoming message: " + msg);
|
||||
if (msg != null) {
|
||||
mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_INPUT, msg));
|
||||
} else {
|
||||
|
@ -109,7 +110,7 @@ public class McsInputStream extends Thread {
|
|||
if (!initialized) {
|
||||
try {
|
||||
version = is.read();
|
||||
Log.d(TAG, "Reading from MCS version=" + version);
|
||||
Log.d(TAG, "Reading from MCS version: " + version);
|
||||
initialized = true;
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
|
|
|
@ -80,6 +80,7 @@ public class McsOutputStream extends Thread implements Handler.Callback {
|
|||
case MSG_OUTPUT:
|
||||
try {
|
||||
Message message = (Message) msg.obj;
|
||||
Log.d(TAG, "Outgoing message: " + message);
|
||||
if (msg.obj instanceof DataMessageStanza) {
|
||||
writeInternal(message, MCS_DATA_MESSAGE_STANZA_TAG);
|
||||
} else if (msg.obj instanceof LoginRequest) {
|
||||
|
|
|
@ -17,12 +17,13 @@
|
|||
package org.microg.gms.gcm;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.IntentService;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.os.SystemClock;
|
||||
|
@ -48,6 +49,10 @@ import java.util.Collections;
|
|||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static org.microg.gms.gcm.Constants.ACTION_CONNECT;
|
||||
import static org.microg.gms.gcm.Constants.ACTION_HEARTBEAT;
|
||||
import static org.microg.gms.gcm.Constants.ACTION_RECONNECT;
|
||||
import static org.microg.gms.gcm.Constants.EXTRA_REASON;
|
||||
import static org.microg.gms.gcm.Constants.MSG_CONNECT;
|
||||
import static org.microg.gms.gcm.Constants.MSG_HEARTBEAT;
|
||||
import static org.microg.gms.gcm.Constants.MSG_INPUT;
|
||||
|
@ -57,12 +62,9 @@ import static org.microg.gms.gcm.Constants.MSG_OUTPUT_ERROR;
|
|||
import static org.microg.gms.gcm.Constants.MSG_OUTPUT_READY;
|
||||
import static org.microg.gms.gcm.Constants.MSG_TEARDOWN;
|
||||
|
||||
public class McsService extends IntentService implements Handler.Callback {
|
||||
public class McsService extends Service implements Handler.Callback {
|
||||
private static final String TAG = "GmsGcmMcsSvc";
|
||||
|
||||
public static String ACTION_CONNECT = "org.microg.gms.gcm.mcs.CONNECT";
|
||||
public static String ACTION_HEARTBEAT = "org.microg.gms.gcm.mcs.HEARTBEAT";
|
||||
|
||||
public static final String PREFERENCES_NAME = "mcs";
|
||||
public static final String PREF_LAST_PERSISTENT_ID = "last_persistent_id";
|
||||
|
||||
|
@ -81,8 +83,8 @@ public class McsService extends IntentService implements Handler.Callback {
|
|||
|
||||
private PendingIntent heartbeatIntent;
|
||||
|
||||
private static MainThread mainThread;
|
||||
private static Handler mainHandler;
|
||||
private static HandlerThread handlerThread;
|
||||
private static Handler rootHandler;
|
||||
|
||||
private AlarmManager alarmManager;
|
||||
private PowerManager powerManager;
|
||||
|
@ -92,20 +94,16 @@ public class McsService extends IntentService implements Handler.Callback {
|
|||
|
||||
private Intent connectIntent;
|
||||
|
||||
public McsService() {
|
||||
super(TAG);
|
||||
}
|
||||
|
||||
private class MainThread extends Thread {
|
||||
private class HandlerThread extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
Looper.prepare();
|
||||
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "mcs");
|
||||
wakeLock.setReferenceCounted(false);
|
||||
synchronized (McsService.class) {
|
||||
mainHandler = new Handler(Looper.myLooper(), McsService.this);
|
||||
rootHandler = new Handler(Looper.myLooper(), McsService.this);
|
||||
if (connectIntent != null) {
|
||||
mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_CONNECT, connectIntent));
|
||||
rootHandler.sendMessage(rootHandler.obtainMessage(MSG_CONNECT, connectIntent));
|
||||
WakefulBroadcastReceiver.completeWakefulIntent(connectIntent);
|
||||
}
|
||||
}
|
||||
|
@ -120,27 +118,34 @@ public class McsService extends IntentService implements Handler.Callback {
|
|||
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
|
||||
powerManager = (PowerManager) getSystemService(POWER_SERVICE);
|
||||
synchronized (McsService.class) {
|
||||
if (mainThread == null) {
|
||||
mainThread = new MainThread();
|
||||
mainThread.start();
|
||||
if (handlerThread == null) {
|
||||
handlerThread = new HandlerThread();
|
||||
handlerThread.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized static boolean isConnected() {
|
||||
return inputStream != null && inputStream.isAlive() && outputStream != null && outputStream.isAlive();
|
||||
}
|
||||
|
||||
public static void scheduleReconnect(Context context) {
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
|
||||
alarmManager.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + getCurrentDelay(),
|
||||
PendingIntent.getBroadcast(context, 1, new Intent("org.microg.gms.gcm.RECONNECT", null, context, TriggerReceiver.class), 0));
|
||||
long delay = getCurrentDelay();
|
||||
Log.d(TAG, "Scheduling reconnect in " + delay / 1000 + " seconds...");
|
||||
alarmManager.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + delay,
|
||||
PendingIntent.getBroadcast(context, 1, new Intent(ACTION_RECONNECT, null, context, TriggerReceiver.class), 0));
|
||||
}
|
||||
|
||||
public synchronized static long getCurrentDelay() {
|
||||
long delay = currentDelay == 0 ? 5000 : currentDelay;
|
||||
if (currentDelay < 60000) currentDelay += 5000;
|
||||
if (currentDelay >= 60000 && currentDelay < 60000) currentDelay += 60000;
|
||||
if (currentDelay < 60000) currentDelay += 10000;
|
||||
if (currentDelay >= 60000 && currentDelay < 600000) currentDelay += 60000;
|
||||
return delay;
|
||||
}
|
||||
|
||||
|
@ -148,15 +153,18 @@ public class McsService extends IntentService implements Handler.Callback {
|
|||
currentDelay = 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
synchronized (McsService.class) {
|
||||
if (mainHandler != null) {
|
||||
if (rootHandler != null) {
|
||||
wakeLock.acquire();
|
||||
Object reason = intent == null ? "I am so sticky!" :
|
||||
intent.hasExtra(EXTRA_REASON) ? intent.getExtras().get(EXTRA_REASON) : intent;
|
||||
if (ACTION_CONNECT.equals(intent.getAction())) {
|
||||
mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_CONNECT, intent));
|
||||
rootHandler.sendMessage(rootHandler.obtainMessage(MSG_CONNECT, reason));
|
||||
} else if (ACTION_HEARTBEAT.equals(intent.getAction())) {
|
||||
mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_HEARTBEAT, intent));
|
||||
rootHandler.sendMessage(rootHandler.obtainMessage(MSG_HEARTBEAT, reason));
|
||||
}
|
||||
WakefulBroadcastReceiver.completeWakefulIntent(intent);
|
||||
} else if (connectIntent == null) {
|
||||
|
@ -165,6 +173,7 @@ public class McsService extends IntentService implements Handler.Callback {
|
|||
WakefulBroadcastReceiver.completeWakefulIntent(intent);
|
||||
}
|
||||
}
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
private synchronized void connect() {
|
||||
|
@ -174,15 +183,15 @@ public class McsService extends IntentService implements Handler.Callback {
|
|||
Log.d(TAG, "Connected to " + SERVICE_HOST + ":" + SERVICE_PORT);
|
||||
sslSocket = SSLContext.getDefault().getSocketFactory().createSocket(socket, SERVICE_HOST, SERVICE_PORT, true);
|
||||
Log.d(TAG, "Activated SSL with " + SERVICE_HOST + ":" + SERVICE_PORT);
|
||||
inputStream = new McsInputStream(sslSocket.getInputStream(), mainHandler);
|
||||
outputStream = new McsOutputStream(sslSocket.getOutputStream(), mainHandler);
|
||||
inputStream = new McsInputStream(sslSocket.getInputStream(), rootHandler);
|
||||
outputStream = new McsOutputStream(sslSocket.getOutputStream(), rootHandler);
|
||||
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));
|
||||
rootHandler.sendMessage(rootHandler.obtainMessage(MSG_TEARDOWN, e));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,7 +287,7 @@ public class McsService extends IntentService implements Handler.Callback {
|
|||
}
|
||||
|
||||
private void send(Message message) {
|
||||
mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_OUTPUT, message));
|
||||
rootHandler.sendMessage(rootHandler.obtainMessage(MSG_OUTPUT, message));
|
||||
}
|
||||
|
||||
private void sendOutputStream(int what, Object obj) {
|
||||
|
@ -286,7 +295,7 @@ public class McsService extends IntentService implements Handler.Callback {
|
|||
if (os != null) {
|
||||
Handler outputHandler = os.getHandler();
|
||||
if (outputHandler != null)
|
||||
outputHandler.dispatchMessage(outputHandler.obtainMessage(what, obj));
|
||||
outputHandler.sendMessage(outputHandler.obtainMessage(what, obj));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,17 +303,15 @@ public class McsService extends IntentService implements Handler.Callback {
|
|||
public boolean handleMessage(android.os.Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_INPUT:
|
||||
Log.d(TAG, "Incoming message: " + msg.obj);
|
||||
handleInput((Message) msg.obj);
|
||||
return true;
|
||||
case MSG_OUTPUT:
|
||||
Log.d(TAG, "Outgoing message: " + msg.obj);
|
||||
sendOutputStream(MSG_OUTPUT, msg.obj);
|
||||
return true;
|
||||
case MSG_INPUT_ERROR:
|
||||
case MSG_OUTPUT_ERROR:
|
||||
Log.d(TAG, "I/O error: " + msg.obj);
|
||||
mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_TEARDOWN, msg.obj));
|
||||
rootHandler.sendMessage(rootHandler.obtainMessage(MSG_TEARDOWN, msg.obj));
|
||||
return true;
|
||||
case MSG_TEARDOWN:
|
||||
Log.d(TAG, "Teardown initiated, reason: " + msg.obj);
|
||||
|
@ -326,6 +333,7 @@ public class McsService extends IntentService implements Handler.Callback {
|
|||
send(ping.build());
|
||||
} else {
|
||||
Log.d(TAG, "Ignoring heartbeat, not connected!");
|
||||
scheduleReconnect(this);
|
||||
}
|
||||
return true;
|
||||
case MSG_OUTPUT_READY:
|
||||
|
@ -354,7 +362,7 @@ public class McsService extends IntentService implements Handler.Callback {
|
|||
}
|
||||
resetCurrentDelay();
|
||||
} catch (Exception e) {
|
||||
mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_TEARDOWN, e));
|
||||
rootHandler.sendMessage(rootHandler.obtainMessage(MSG_TEARDOWN, e));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ import android.app.IntentService;
|
|||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.util.Log;
|
||||
|
@ -35,8 +35,16 @@ import java.io.IOException;
|
|||
public class PushRegisterService extends IntentService {
|
||||
private static final String TAG = "GmsGcmRegisterSvc";
|
||||
|
||||
private static final String REMOVED = "%%REMOVED%%";
|
||||
private static final String ERROR = "%%ERROR%%";
|
||||
|
||||
public PushRegisterService() {
|
||||
super(TAG);
|
||||
setIntentRedelivery(false);
|
||||
}
|
||||
|
||||
private SharedPreferences getSharedPreferences() {
|
||||
return getSharedPreferences("gcm_registrations", MODE_PRIVATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -68,17 +76,20 @@ public class PushRegisterService extends IntentService {
|
|||
PendingIntent pendingIntent = intent.getParcelableExtra("app");
|
||||
String sender = intent.getStringExtra("sender");
|
||||
String app = packageFromPendingIntent(pendingIntent);
|
||||
Bundle extras = intent.getExtras();
|
||||
extras.keySet();
|
||||
Log.d(TAG, "register[req]: " + extras);
|
||||
Log.d(TAG, "register[res]: " + intent.toString() + " extras=" + intent.getExtras());
|
||||
|
||||
Intent outIntent = new Intent("com.google.android.c2dm.intent.REGISTRATION");
|
||||
outIntent.setPackage(app);
|
||||
String regId = register(this, app, sender, null, false).token;
|
||||
String appSignature = PackageUtils.firstSignatureDigest(this, app);
|
||||
|
||||
String regId = register(this, app, appSignature, sender, null, false).token;
|
||||
if (regId != null) {
|
||||
outIntent.putExtra("registration_id", regId);
|
||||
getSharedPreferences().edit().putString(app + ":" + appSignature, regId).apply();
|
||||
} else {
|
||||
outIntent.putExtra("error", "SERVICE_NOT_AVAILABLE");
|
||||
getSharedPreferences().edit().putString(app + ":" + appSignature, "-").apply();
|
||||
}
|
||||
|
||||
Log.d(TAG, "register[res]: " + outIntent + " extras=" + outIntent.getExtras());
|
||||
try {
|
||||
if (intent.hasExtra("google.messenger")) {
|
||||
|
@ -91,17 +102,19 @@ public class PushRegisterService extends IntentService {
|
|||
} catch (Exception e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
|
||||
outIntent.setPackage(app);
|
||||
sendOrderedBroadcast(outIntent, null);
|
||||
}
|
||||
|
||||
public static RegisterResponse register(Context context, String app, String sender, String info, boolean delete) {
|
||||
public static RegisterResponse register(Context context, String app, String appSignature, String sender, String info, boolean delete) {
|
||||
try {
|
||||
RegisterResponse response = new RegisterRequest()
|
||||
.build(Utils.getBuild(context))
|
||||
.sender(sender)
|
||||
.info(info)
|
||||
.checkin(LastCheckinInfo.read(context))
|
||||
.app(app, PackageUtils.firstSignatureDigest(context, app), PackageUtils.versionCode(context, app))
|
||||
.app(app, appSignature, PackageUtils.versionCode(context, app))
|
||||
.delete(delete)
|
||||
.getResponse();
|
||||
Log.d(TAG, "received response: " + response);
|
||||
|
@ -116,24 +129,27 @@ public class PushRegisterService extends IntentService {
|
|||
private void unregister(Intent intent) {
|
||||
PendingIntent pendingIntent = intent.getParcelableExtra("app");
|
||||
String app = packageFromPendingIntent(pendingIntent);
|
||||
Log.d(TAG, "unregister[res]: " + intent.toString() + " extras=" + intent.getExtras());
|
||||
|
||||
Intent outIntent = new Intent("com.google.android.c2dm.intent.REGISTRATION");
|
||||
outIntent.setPackage(app);
|
||||
String appSignature = PackageUtils.firstSignatureDigest(this, app);
|
||||
|
||||
RegisterResponse response = register(this, app, null, null, true);
|
||||
if (!app.equals(response.deleted)) {
|
||||
outIntent.putExtra("error", "SERVICE_NOT_AVAILABLE");
|
||||
|
||||
long retry = 0;
|
||||
if (response.retryAfter != null && !response.retryAfter.contains(":")) {
|
||||
retry = Long.parseLong(response.retryAfter);
|
||||
}
|
||||
|
||||
if (retry > 0) {
|
||||
outIntent.putExtra("Retry-After", retry);
|
||||
}
|
||||
} else {
|
||||
if (REMOVED.equals(getSharedPreferences().getString(app + ":" + appSignature, null))) {
|
||||
outIntent.putExtra("unregistered", app);
|
||||
} else {
|
||||
RegisterResponse response = register(this, app, appSignature, null, null, true);
|
||||
if (!app.equals(response.deleted)) {
|
||||
outIntent.putExtra("error", "SERVICE_NOT_AVAILABLE");
|
||||
getSharedPreferences().edit().putString(app + ":" + PackageUtils.firstSignatureDigest(this, app), ERROR).apply();
|
||||
|
||||
long retry = 0;
|
||||
if (response.retryAfter != null && !response.retryAfter.contains(":")) {
|
||||
outIntent.putExtra("Retry-After", Long.parseLong(response.retryAfter));
|
||||
}
|
||||
} else {
|
||||
outIntent.putExtra("unregistered", app);
|
||||
getSharedPreferences().edit().putString(app + ":" + PackageUtils.firstSignatureDigest(this, app), REMOVED).apply();
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(TAG, "unregister[res]: " + outIntent.toString() + " extras=" + outIntent.getExtras());
|
||||
|
@ -148,6 +164,8 @@ public class PushRegisterService extends IntentService {
|
|||
} catch (Exception e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
|
||||
outIntent.setPackage(app);
|
||||
sendOrderedBroadcast(outIntent, null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,10 @@ import android.util.Log;
|
|||
|
||||
import org.microg.gms.checkin.LastCheckinInfo;
|
||||
|
||||
import static org.microg.gms.gcm.Constants.ACTION_CONNECT;
|
||||
import static org.microg.gms.gcm.Constants.ACTION_HEARTBEAT;
|
||||
import static org.microg.gms.gcm.Constants.EXTRA_REASON;
|
||||
|
||||
public class TriggerReceiver extends WakefulBroadcastReceiver {
|
||||
private static final String TAG = "GmsGcmTrigger";
|
||||
private static final String PREF_ENABLE_GCM = "gcm_enable_mcs_service";
|
||||
|
@ -41,19 +45,23 @@ public class TriggerReceiver extends WakefulBroadcastReceiver {
|
|||
}
|
||||
if (LastCheckinInfo.read(context).androidId == 0) {
|
||||
Log.d(TAG, "Ignoring " + intent + ": need to checkin first.");
|
||||
return;
|
||||
}
|
||||
|
||||
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
|
||||
if (networkInfo != null && networkInfo.isConnected() || force) {
|
||||
if (!McsService.isConnected() || force) {
|
||||
startWakefulService(context, new Intent(McsService.ACTION_CONNECT, null, context, McsService.class));
|
||||
Log.d(TAG, "Not connected to GCM but should be, asking the service to start up");
|
||||
startWakefulService(context, new Intent(ACTION_CONNECT, null, context, McsService.class)
|
||||
.putExtra(EXTRA_REASON, intent));
|
||||
} else {
|
||||
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
|
||||
Log.d(TAG, "Ignoring " + intent + ": service is running. schedule reconnect instead.");
|
||||
McsService.scheduleReconnect(context);
|
||||
} else {
|
||||
Log.d(TAG, "Ignoring " + intent + ": service is running. heartbeat instead.");
|
||||
startWakefulService(context, new Intent(McsService.ACTION_HEARTBEAT, null, context, McsService.class));
|
||||
startWakefulService(context, new Intent(ACTION_HEARTBEAT, null, context, McsService.class)
|
||||
.putExtra(EXTRA_REASON, intent));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue