From 5146559f89cdaaa05e7e6a5f2bb41988a4e4677b Mon Sep 17 00:00:00 2001 From: georgeto Date: Tue, 9 Jun 2020 02:52:03 +0200 Subject: [PATCH] Fix FCM registration for apps using firebase >= 20.1.1 With version 20.1.1 the Firebase Cloud Messaging SDK started to use the Firebase Installations SDK, which affects the FCM registration process. The implementation of FCM registration in microG failed to pass extra parameters that became relevant with the introduction of the Firebase Installations SDK to the FCM registration endpoint. These additional parameters are passed through to the endpoint with an 'X-' prefix. --- .../org/microg/gms/common/HttpFormClient.java | 22 ++++++- .../org/microg/gms/common/PackageUtils.java | 8 +++ .../microg/gms/gcm/PushRegisterHandler.java | 2 +- .../microg/gms/gcm/PushRegisterManager.java | 12 ++-- .../microg/gms/gcm/PushRegisterService.java | 7 +- .../org/microg/gms/gcm/RegisterRequest.java | 65 +++++++++++-------- 6 files changed, 79 insertions(+), 37 deletions(-) diff --git a/play-services-base-core/src/main/java/org/microg/gms/common/HttpFormClient.java b/play-services-base-core/src/main/java/org/microg/gms/common/HttpFormClient.java index 73115992..8aee1df7 100644 --- a/play-services-base-core/src/main/java/org/microg/gms/common/HttpFormClient.java +++ b/play-services-base-core/src/main/java/org/microg/gms/common/HttpFormClient.java @@ -46,6 +46,13 @@ public class HttpFormClient { try { field.setAccessible(true); Object objVal = field.get(request); + if (field.isAnnotationPresent(RequestContentDynamic.class)) { + Map contentParams = (Map) objVal; + for (Map.Entry param : contentParams.entrySet()) { + appendParam(content, param.getKey(), param.getValue()); + } + continue; + } String value = objVal != null ? String.valueOf(objVal) : null; Boolean boolVal = null; if (field.getType().equals(boolean.class)) { @@ -65,9 +72,7 @@ public class HttpFormClient { value = valueFromBoolVal(value, boolVal, annotation.truePresent(), annotation.falsePresent()); if (value != null || annotation.nullPresent()) { for (String key : annotation.value()) { - if (content.length() > 0) - content.append("&"); - content.append(Uri.encode(key)).append("=").append(Uri.encode(String.valueOf(value))); + appendParam(content, key, value); } } } @@ -109,6 +114,12 @@ public class HttpFormClient { } } + private static void appendParam(StringBuilder content, String key, String value) { + if (content.length() > 0) + content.append("&"); + content.append(Uri.encode(key)).append("=").append(Uri.encode(String.valueOf(value))); + } + private static T parseResponse(Class tClass, HttpURLConnection connection, String result) throws IOException { Map> headerFields = connection.getHeaderFields(); T response; @@ -227,6 +238,11 @@ public class HttpFormClient { public boolean nullPresent() default false; } + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface RequestContentDynamic { + } + @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface ResponseField { diff --git a/play-services-base-core/src/main/java/org/microg/gms/common/PackageUtils.java b/play-services-base-core/src/main/java/org/microg/gms/common/PackageUtils.java index 8cb7c0eb..9f1f2cc8 100644 --- a/play-services-base-core/src/main/java/org/microg/gms/common/PackageUtils.java +++ b/play-services-base-core/src/main/java/org/microg/gms/common/PackageUtils.java @@ -264,4 +264,12 @@ public class PackageUtils { return null; } } + + public static int targetSdkVersion(Context context, String packageName) { + try { + return context.getPackageManager().getApplicationInfo(packageName, 0).targetSdkVersion; + } catch (PackageManager.NameNotFoundException e) { + return -1; + } + } } diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterHandler.java b/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterHandler.java index f161533c..e95c98f0 100644 --- a/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterHandler.java +++ b/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterHandler.java @@ -145,7 +145,7 @@ class PushRegisterHandler extends Handler { .checkin(LastCheckinInfo.read(context)) .app(packageName) .delete(delete) - .appid(subdata.getString("appid"), subdata.getString("gmp_app_id")), + .extraParams(subdata), bundle -> sendReply(what, id, replyTo, bundle)); } } diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterManager.java b/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterManager.java index 7ae7d648..b3ffca9e 100644 --- a/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterManager.java +++ b/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterManager.java @@ -70,12 +70,16 @@ public class PushRegisterManager { public static void completeRegisterRequest(Context context, GcmDatabase database, String requestId, RegisterRequest request, BundleCallback callback) { if (request.app != null) { - if (request.appSignature == null) - request.appSignature = PackageUtils.firstSignatureDigest(context, request.app); if (request.appVersion <= 0) request.appVersion = PackageUtils.versionCode(context, request.app); - if (request.appVersionName == null) - request.appVersionName = PackageUtils.versionName(context, request.app); + if (!request.delete) { + if (request.appSignature == null) { + request.appSignature = PackageUtils.firstSignatureDigest(context, request.app); + } + request.sdkVersion = PackageUtils.targetSdkVersion(context, request.app); + if (!request.hasExtraParam(GcmConstants.EXTRA_APP_VERSION_NAME)) + request.extraParam(GcmConstants.EXTRA_APP_VERSION_NAME, PackageUtils.versionName(context, request.app)); + } } GcmDatabase.App app = database.getApp(request.app); diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterService.java b/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterService.java index 21bdd21e..96024409 100644 --- a/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterService.java +++ b/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterService.java @@ -20,7 +20,6 @@ import android.app.IntentService; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.IBinder; import android.os.Message; @@ -140,7 +139,8 @@ public class PushRegisterService extends IntentService { .build(Utils.getBuild(context)) .sender(intent.getStringExtra(EXTRA_SENDER)) .checkin(LastCheckinInfo.read(context)) - .app(packageName), + .app(packageName) + .extraParams(intent.getExtras()), bundle -> { Intent outIntent = new Intent(ACTION_C2DM_REGISTRATION); outIntent.putExtras(bundle); @@ -176,7 +176,8 @@ public class PushRegisterService extends IntentService { .build(Utils.getBuild(this)) .sender(intent.getStringExtra(EXTRA_SENDER)) .checkin(LastCheckinInfo.read(this)) - .app(packageName), + .app(packageName) + .extraParams(intent.getExtras()), bundle -> { Intent outIntent = new Intent(ACTION_C2DM_REGISTRATION); outIntent.putExtras(bundle); diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/RegisterRequest.java b/play-services-core/src/main/java/org/microg/gms/gcm/RegisterRequest.java index 6e0d7871..e4cfb851 100644 --- a/play-services-core/src/main/java/org/microg/gms/gcm/RegisterRequest.java +++ b/play-services-core/src/main/java/org/microg/gms/gcm/RegisterRequest.java @@ -16,19 +16,24 @@ package org.microg.gms.gcm; +import android.os.Bundle; +import android.text.TextUtils; + import org.microg.gms.checkin.LastCheckinInfo; import org.microg.gms.common.Build; -import org.microg.gms.common.Constants; import org.microg.gms.common.HttpFormClient; import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; import static org.microg.gms.common.HttpFormClient.RequestContent; +import static org.microg.gms.common.HttpFormClient.RequestContentDynamic; import static org.microg.gms.common.HttpFormClient.RequestHeader; public class RegisterRequest extends HttpFormClient.Request { private static final String SERVICE_URL = "https://android.clients.google.com/c2dm/register3"; - private static final String USER_AGENT = "Android-GCM/1.3 (%s %s)"; + private static final String USER_AGENT = "Android-GCM/1.5 (%s %s)"; @RequestHeader("Authorization") private String auth; @@ -42,35 +47,26 @@ public class RegisterRequest extends HttpFormClient.Request { public String appSignature; @RequestContent("app_ver") public int appVersion; - @RequestContent("app_ver_name") - public String appVersionName; @RequestContent("info") public String info; - @RequestContent({"sender", "subtype"}) + @RequestContent("sender") public String sender; - @RequestContent({"X-GOOG.USER_AID", "device"}) + @RequestContent("device") public long androidId; @RequestContent("delete") public boolean delete; public long securityToken; public String deviceName; public String buildVersion; - @RequestContent("osv") - public int sdkVersion; - @RequestContent("gmsv") - public int gmsVersion; - @RequestContent("scope") - public String scope = "*"; - @RequestContent("appid") - public String appId; - @RequestContent("gmp_app_id") - public String gmpAppId; + @RequestContent("target_ver") + public Integer sdkVersion; + @RequestContentDynamic + private Map extraParams = new LinkedHashMap<>(); @Override public void prepare() { userAgent = String.format(USER_AGENT, deviceName, buildVersion); auth = "AidLogin " + androidId + ":" + securityToken; - gmsVersion = Constants.MAX_REFERENCE_VERSION; } public RegisterRequest checkin(LastCheckinInfo lastCheckinInfo) { @@ -90,17 +86,10 @@ public class RegisterRequest extends HttpFormClient.Request { return this; } - public RegisterRequest app(String app, String appSignature, int appVersion, String appVersionName) { + public RegisterRequest app(String app, String appSignature, int appVersion) { this.app = app; this.appSignature = appSignature; this.appVersion = appVersion; - this.appVersionName = appVersionName; - return this; - } - - public RegisterRequest appid(String appid, String gmpAppId) { - this.appId = appid; - this.gmpAppId = gmpAppId; return this; } @@ -117,7 +106,6 @@ public class RegisterRequest extends HttpFormClient.Request { public RegisterRequest build(Build build) { deviceName = build.device; buildVersion = build.id; - sdkVersion = build.sdk; return this; } @@ -130,6 +118,31 @@ public class RegisterRequest extends HttpFormClient.Request { return this; } + public RegisterRequest extraParams(Bundle extraBundle) { + for (String key : extraBundle.keySet()) { + if (!key.equals(GcmConstants.EXTRA_SENDER) && !key.equals(GcmConstants.EXTRA_DELETE)) { + extraParam(key, extraBundle.getString(key)); + } + } + return this; + } + + public RegisterRequest extraParam(String key, String value) { + // Ignore empty registration extras + if (!TextUtils.isEmpty(value)) { + extraParams.put(extraParamKey(key), value); + } + return this; + } + + public boolean hasExtraParam(String key) { + return extraParams.containsKey(extraParamKey(key)); + } + + private static String extraParamKey(String key) { + return "X-" + key; + } + public RegisterResponse getResponse() throws IOException { return HttpFormClient.request(SERVICE_URL, this, RegisterResponse.class); }