Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1a83f828 authored by Marvin W.'s avatar Marvin W. 🐿️
Browse files

Improve mcs connection

wake up device when reconnecting, fix teardown incomplete on null message (#24)
parent c826702b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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" />
+15 −6
Original line number Diff line number Diff line
@@ -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) {
            mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_INPUT_ERROR, e));
        }
        try {
            is.close();
        } catch (IOException ignored) {
        }
            mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_INPUT_ERROR, e));
        }
    }

    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) {
+48 −25
Original line number Diff line number Diff line
@@ -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();
            wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "mcs");
            wakeLock.setReferenceCounted(false);
            synchronized (McsService.class) {
                mainHandler = new Handler(Looper.myLooper(), McsService.this);
            mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_CONNECT));
                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();
        heartbeatIntent = PendingIntent.getService(this, 0, new Intent(ACTION_HEARTBEAT, null, this, McsService.class), 0);
        alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
        powerManager = (PowerManager) getSystemService(POWER_SERVICE);
        synchronized (McsService.class) {
            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);
        }
    }

    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();
        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"));
                }
                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) {
        }
        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);
        if (wakeLock != null) {
            wakeLock.release();
        }
    }
}
+13 −11
Original line number Diff line number Diff line
@@ -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 (!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");
        }
    }
}