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

Verified Commit 26f2e859 authored by Marvin W.'s avatar Marvin W. 🐿️
Browse files

Ensure checkin before gcm registration, fix gcm permission requests

parent b0e52b7a
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -198,8 +198,6 @@
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.AIRPLANE_MODE" />
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
                <action android:name="android.net.conn.BACKGROUND_DATA_SETTING_CHANGED" />

                <action android:name="android.server.checkin.CHECKIN" />

@@ -478,7 +476,7 @@
            android:name="org.microg.gms.ui.AskPushPermission"
            android:excludeFromRecents="true"
            android:process=":ui"
            android:theme="@style/Theme.AppCompat.DayNight.Dialog.Alert" />
            android:theme="@style/Theme.AppCompat.DayNight.Dialog.Alert.NoActionBar" />

        <activity
            android:name="org.microg.gms.ui.AboutFragment$AsActivity"
+15 −1
Original line number Diff line number Diff line
@@ -18,14 +18,16 @@ package org.microg.gms.checkin;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.os.ResultReceiver;
import android.util.Log;

import androidx.legacy.content.WakefulBroadcastReceiver;
@@ -39,11 +41,15 @@ import org.microg.gms.people.PeopleManager;

public class CheckinService extends IntentService {
    private static final String TAG = "GmsCheckinSvc";
    public static final long MAX_VALID_CHECKIN_AGE = 24 * 60 * 60 * 1000; // 12 hours
    public static final long REGULAR_CHECKIN_INTERVAL = 12 * 60 * 60 * 1000; // 12 hours
    public static final long BACKUP_CHECKIN_DELAY = 3 * 60 * 60 * 1000; // 3 hours
    public static final String BIND_ACTION = "com.google.android.gms.checkin.BIND_TO_SERVICE";
    public static final String EXTRA_FORCE_CHECKIN = "force";
    @Deprecated
    public static final String EXTRA_CALLBACK_INTENT = "callback";
    public static final String EXTRA_RESULT_RECEIVER = "receiver";
    public static final String EXTRA_NEW_CHECKIN_TIME = "checkin_time";

    private ICheckinService iface = new ICheckinService.Stub() {
        @Override
@@ -73,6 +79,14 @@ public class CheckinService extends IntentService {
                    if (intent.hasExtra(EXTRA_CALLBACK_INTENT)) {
                        startService((Intent) intent.getParcelableExtra(EXTRA_CALLBACK_INTENT));
                    }
                    if (intent.hasExtra(EXTRA_RESULT_RECEIVER)) {
                        ResultReceiver receiver = intent.getParcelableExtra(EXTRA_RESULT_RECEIVER);
                        if (receiver != null) {
                            Bundle bundle = new Bundle();
                            bundle.putLong(EXTRA_NEW_CHECKIN_TIME, info.lastCheckin);
                            receiver.send(Activity.RESULT_OK, bundle);
                        }
                    }
                }
            }
        } catch (Exception e) {
+3 −3
Original line number Diff line number Diff line
@@ -31,20 +31,20 @@ import static org.microg.gms.checkin.CheckinService.REGULAR_CHECKIN_INTERVAL;

public class TriggerReceiver extends WakefulBroadcastReceiver {
    private static final String TAG = "GmsCheckinTrigger";
    private static boolean registered = false;

    @Override
    public void onReceive(Context context, Intent intent) {
        try {
            boolean force = "android.provider.Telephony.SECRET_CODE".equals(intent.getAction());
            ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

            if (CheckinPrefs.get(context).isEnabled() || force) {
                if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction()) &&
                        LastCheckinInfo.read(context).lastCheckin > System.currentTimeMillis() - REGULAR_CHECKIN_INTERVAL) {
                if (LastCheckinInfo.read(context).lastCheckin > System.currentTimeMillis() - REGULAR_CHECKIN_INTERVAL && !force) {
                    CheckinService.schedule(context);
                    return;
                }

                ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo networkInfo = cm.getActiveNetworkInfo();
                if (networkInfo != null && networkInfo.isConnected() || force) {
                    Intent subIntent = new Intent(context, CheckinService.class);
+0 −193
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 microG Project Team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.microg.gms.gcm;

import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

import org.microg.gms.checkin.LastCheckinInfo;
import org.microg.gms.common.ForegroundServiceContext;
import org.microg.gms.common.PackageUtils;
import org.microg.gms.common.Utils;

import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_REGISTRATION;
import static org.microg.gms.gcm.GcmConstants.ERROR_SERVICE_NOT_AVAILABLE;
import static org.microg.gms.gcm.GcmConstants.EXTRA_APP;
import static org.microg.gms.gcm.GcmConstants.EXTRA_APP_OVERRIDE;
import static org.microg.gms.gcm.GcmConstants.EXTRA_ERROR;
import static org.microg.gms.gcm.McsConstants.ACTION_ACK;
import static org.microg.gms.gcm.McsConstants.ACTION_SEND;

class PushRegisterHandler extends Handler {
    private static final String TAG = "GmsGcmRegisterHdl";

    private Context context;
    private int callingUid;
    private GcmDatabase database;

    public PushRegisterHandler(Context context, GcmDatabase database) {
        this.context = context;
        this.database = database;
    }

    @Override
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        this.callingUid = Binder.getCallingUid();
        return super.sendMessageAtTime(msg, uptimeMillis);
    }

    private void sendReplyViaMessage(int what, int id, Messenger replyTo, Bundle messageData) {
        Message response = Message.obtain();
        response.what = what;
        response.arg1 = id;
        response.setData(messageData);
        try {
            replyTo.send(response);
        } catch (RemoteException e) {
            Log.w(TAG, e);
        }
    }

    private void sendReplyViaIntent(Intent outIntent, Messenger replyTo) {
        Message message = Message.obtain();
        message.obj = outIntent;
        try {
            replyTo.send(message);
        } catch (RemoteException e) {
            Log.w(TAG, e);
        }
    }

    private void sendReply(int what, int id, Messenger replyTo, Bundle data, boolean oneWay) {
        if (what == 0) {
            Intent outIntent = new Intent(ACTION_C2DM_REGISTRATION);
            outIntent.putExtras(data);
            sendReplyViaIntent(outIntent, replyTo);
            return;
        }
        Bundle messageData = new Bundle();
        messageData.putBundle("data", data);
        sendReplyViaMessage(what, id, replyTo, messageData);
    }

    private void replyError(int what, int id, Messenger replyTo, String errorMessage, boolean oneWay) {
        Bundle bundle = new Bundle();
        bundle.putString(EXTRA_ERROR, errorMessage);
        sendReply(what, id, replyTo, bundle, oneWay);
    }

    private void replyNotAvailable(int what, int id, Messenger replyTo) {
        replyError(what, id, replyTo, ERROR_SERVICE_NOT_AVAILABLE, false);
    }

    private PendingIntent getSelfAuthIntent() {
        Intent intent = new Intent();
        intent.setPackage("com.google.example.invalidpackage");
        return PendingIntent.getBroadcast(context, 0, intent, 0);
    }

    @Override
    public void handleMessage(Message msg) {
        if (msg.what == 0) {
            if (msg.obj instanceof Intent) {
                Message nuMsg = Message.obtain();
                nuMsg.what = msg.what;
                nuMsg.arg1 = 0;
                nuMsg.replyTo = null;
                PendingIntent pendingIntent = ((Intent) msg.obj).getParcelableExtra(EXTRA_APP);
                String packageName = PackageUtils.packageFromPendingIntent(pendingIntent);
                Bundle data = new Bundle();
                data.putBoolean("oneWay", false);
                data.putString("pkg", packageName);
                data.putBundle("data", msg.getData());
                nuMsg.setData(data);
                msg = nuMsg;
            } else {
                return;
            }
        }

        int what = msg.what;
        int id = msg.arg1;
        Messenger replyTo = msg.replyTo;
        if (replyTo == null) {
            Log.w(TAG, "replyTo is null");
            return;
        }
        Bundle data = msg.getData();

        String packageName = data.getString("pkg");
        Bundle subdata = data.getBundle("data");

        try {
            PackageUtils.checkPackageUid(context, packageName, callingUid);
        } catch (SecurityException e) {
            Log.w(TAG, e);
            return;
        }

        Log.d(TAG, "handleMessage: package=" + packageName + " what=" + what + " id=" + id);

        boolean oneWay = data.getBoolean("oneWay", false);

        switch (what) {
            case 0:
            case 1:
                // TODO: We should checkin and/or ask for permission here.
                String sender = subdata.getString("sender");
                boolean delete = subdata.get("delete") != null;

                PushRegisterManager.completeRegisterRequest(context, database,
                        new RegisterRequest()
                                .build(Utils.getBuild(context))
                                .sender(sender)
                                .checkin(LastCheckinInfo.read(context))
                                .app(packageName)
                                .delete(delete)
                                .extraParams(subdata),
                        bundle -> sendReply(what, id, replyTo, bundle, oneWay));
                break;
            case 2:
                String messageId = subdata.getString("google.message_id");
                Log.d(TAG, "Ack " + messageId + " for " + packageName);
                Intent i = new Intent(context, McsService.class);
                i.setAction(ACTION_ACK);
                i.putExtra(EXTRA_APP, getSelfAuthIntent());
                new ForegroundServiceContext(context).startService(i);
                break;
            default:
                Bundle bundle = new Bundle();
                bundle.putBoolean("unsupported", true);
                sendReplyViaMessage(what, id, replyTo, bundle);
                return;
        }

        if (oneWay) {
            Bundle bundle = new Bundle();
            bundle.putBoolean("ack", true);
            sendReplyViaMessage(what, id, replyTo, bundle);
        }
    }
}
+0 −41
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 microG Project Team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.microg.gms.gcm;

import android.content.Context;
import android.content.Intent;

import androidx.legacy.content.WakefulBroadcastReceiver;

import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_REGISTER;
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_UNREGISTER;

public class PushRegisterReceiver extends WakefulBroadcastReceiver {
    private static final String TAG = "GmsGcmRegisterRcv";

    @Override
    public void onReceive(Context context, Intent intent) {
        Intent intent2 = new Intent(context, PushRegisterService.class);
        if (intent.getExtras().get("delete") != null) {
            intent2.setAction(ACTION_C2DM_UNREGISTER);
        } else {
            intent2.setAction(ACTION_C2DM_REGISTER);
        }
        intent2.putExtras(intent.getExtras());
        startWakefulService(context, intent2);
    }
}
Loading