From 2e22a37fe35b92c139e30cf3a67443eef750c4e3 Mon Sep 17 00:00:00 2001 From: inthewaves Date: Tue, 7 Jul 2026 22:29:09 -0700 Subject: [PATCH] add gservices flags provider redirect hook Currently restricted to EuiccSupportPixel flags --- .../java/android/app/ActivityThreadHooks.java | 12 ++++++ core/java/android/app/AppBindArgs.java | 1 + .../app/ContentProviderRedirector.java | 3 ++ .../android/internal/app/GservicesFlags.java | 37 +++++++++++++++++++ .../server/ext/PackageManagerHooks.java | 33 +++++++++++++++++ 5 files changed, 86 insertions(+) create mode 100644 core/java/com/android/internal/app/GservicesFlags.java diff --git a/core/java/android/app/ActivityThreadHooks.java b/core/java/android/app/ActivityThreadHooks.java index 6542e25e887de..004fd21062dbb 100644 --- a/core/java/android/app/ActivityThreadHooks.java +++ b/core/java/android/app/ActivityThreadHooks.java @@ -8,8 +8,10 @@ import android.location.HookedLocationManager; import android.os.Bundle; import android.os.Process; +import android.util.Log; import com.android.internal.app.ContactScopes; +import com.android.internal.app.GservicesFlags; import com.android.internal.app.StorageScopesAppHooks; import com.android.internal.gmscompat.GmsHooks; @@ -17,6 +19,8 @@ class ActivityThreadHooks { + private static final String GSERVICES_FLAGS_TAG = "GservicesFlags"; + private static volatile boolean called; // called after the initial app context is constructed @@ -42,6 +46,14 @@ static Bundle onBind(ActivityThread.AppBindData appBindData) { DynCodeLoading.handleAppBindFlags(flags[AppBindArgs.FLAGS_IDX_DYN_CODE_LOADING]); + if (flags[AppBindArgs.FLAGS_IDX_GSERVICES_FLAGS_REDIRECT] != 0) { + if (Log.isLoggable(GSERVICES_FLAGS_TAG, Log.VERBOSE)) { + Log.v(GSERVICES_FLAGS_TAG, "enabling Gservices flags redirect for " + + appBindData.appInfo.packageName); + } + GservicesFlags.enable(); + } + return args; } diff --git a/core/java/android/app/AppBindArgs.java b/core/java/android/app/AppBindArgs.java index 207e6946f5acf..5058213017643 100644 --- a/core/java/android/app/AppBindArgs.java +++ b/core/java/android/app/AppBindArgs.java @@ -9,6 +9,7 @@ public interface AppBindArgs { int FLAGS_IDX_SPECIAL_RUNTIME_PERMISSIONS = 0; int FLAGS_IDX_HOOKED_LOCATION_MANAGER = 1; int FLAGS_IDX_DYN_CODE_LOADING = 2; + int FLAGS_IDX_GSERVICES_FLAGS_REDIRECT = 3; int FLAGS_ARRAY_LEN = 10; } diff --git a/core/java/com/android/internal/app/ContentProviderRedirector.java b/core/java/com/android/internal/app/ContentProviderRedirector.java index a326ad7bd101b..737c68beb8927 100644 --- a/core/java/com/android/internal/app/ContentProviderRedirector.java +++ b/core/java/com/android/internal/app/ContentProviderRedirector.java @@ -35,6 +35,9 @@ public static String translateContentProviderAuthority(String auth) { if (t == null) { t = ContactScopes.maybeTranslateAuthority(auth); } + if (t == null) { + t = GservicesFlags.maybeTranslateAuthority(auth); + } return t != null ? t : auth; } diff --git a/core/java/com/android/internal/app/GservicesFlags.java b/core/java/com/android/internal/app/GservicesFlags.java new file mode 100644 index 0000000000000..7f900fff0d641 --- /dev/null +++ b/core/java/com/android/internal/app/GservicesFlags.java @@ -0,0 +1,37 @@ +package com.android.internal.app; + +import android.util.Log; + +/** + * Process-local Gservices flags provider redirect. + */ +public class GservicesFlags { + private static final String TAG = "GservicesFlags"; + + public static final String GSERVICES_AUTHORITY = "com.google.android.gsf.gservices"; + private static final String GMSCOMPAT_GSERVICES_AUTHORITY = + "app.grapheneos.gmscompat.gservices"; + + private static volatile boolean isEnabled; + + public static void enable() { + isEnabled = true; + ContentProviderRedirector.enable(); + } + + public static String maybeTranslateAuthority(String auth) { + if (!isEnabled) { + return null; + } + + if (GSERVICES_AUTHORITY.equals(auth)) { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "redirecting authority " + GSERVICES_AUTHORITY + + " to " + GMSCOMPAT_GSERVICES_AUTHORITY); + } + return GMSCOMPAT_GSERVICES_AUTHORITY; + } + + return null; + } +} diff --git a/services/core/java/com/android/server/ext/PackageManagerHooks.java b/services/core/java/com/android/server/ext/PackageManagerHooks.java index 4b8642dd19eb6..ba94e62d61368 100644 --- a/services/core/java/com/android/server/ext/PackageManagerHooks.java +++ b/services/core/java/com/android/server/ext/PackageManagerHooks.java @@ -9,14 +9,17 @@ import android.content.pm.GosPackageStateFlag; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; +import android.content.pm.ProviderInfo; import android.ext.PackageId; import android.location.HookedLocationManager; import android.os.Bundle; import android.os.UserHandle; import android.util.ArraySet; +import android.util.Log; import android.util.Slog; import com.android.internal.app.ContactScopes; +import com.android.internal.app.GservicesFlags; import com.android.server.pm.Computer; import com.android.server.pm.GosPackageStatePmHooks; import com.android.server.pm.ext.PackageExt; @@ -28,6 +31,7 @@ import static java.util.Objects.requireNonNull; public class PackageManagerHooks { + private static final String TAG = "PackageManagerHooks"; // Called when package enabled setting for a system package is deserialized from storage @Nullable @@ -119,6 +123,8 @@ public static Bundle getExtraAppBindArgs(Context context, PackageManagerInternal flagsArr[AppBindArgs.FLAGS_IDX_DYN_CODE_LOADING] = android.ext.dcl.DynCodeLoading.getAppBindFlags(context, userId, appInfo, unfilteredGosPs); + flagsArr[AppBindArgs.FLAGS_IDX_GSERVICES_FLAGS_REDIRECT] = + getGservicesFlagsRedirectFlag(pmComputer, appInfo, appUid, userId); var b = new Bundle(); b.putParcelable(AppBindArgs.KEY_GOS_PACKAGE_STATE, gosPs); @@ -128,6 +134,33 @@ public static Bundle getExtraAppBindArgs(Context context, PackageManagerInternal return b; } + private static int getGservicesFlagsRedirectFlag( + Computer pmComputer, ApplicationInfo appInfo, int appUid, int userId) { + if (appInfo.ext().getPackageId() != PackageId.EUICC_SUPPORT_PIXEL) { + return 0; + } + + // EuiccSupportPixel's package visibility policy prevents it from seeing GmsCore when + // GmsCore is installed as a user app. If Gservices flags redirection is added for other + // apps, handle their enablement policy separately instead of assuming the same visibility. + ProviderInfo provider = pmComputer.resolveContentProvider( + GservicesFlags.GSERVICES_AUTHORITY, 0L, userId, appUid); + + if (provider != null + && provider.applicationInfo.ext().getPackageId() == PackageId.GMS_CORE) { + Slog.w(TAG, "not enabling Gservices flags redirect for " + appInfo.packageName + + ": can query " + + PackageId.GMS_CORE_NAME); + return 0; + } + + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Slog.v(TAG, "enabling Gservices flags redirect for " + appInfo.packageName); + } + + return 1; + } + // Called when AppsFilter decides whether to restrict package visibility public static boolean shouldFilterApplication( @Nullable PackageStateInternal callingPkgSetting,