diff --git a/core/api/system-current.txt b/core/api/system-current.txt index b21c84e3ea3b6..5a074dc0be8df 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -4912,7 +4912,6 @@ package android.ext { field public static final String EUICC_SUPPORT_PIXEL_NAME = "com.google.euiccpixel"; field public static final int GMS_CORE = 2; // 0x2 field public static final String GMS_CORE_NAME = "com.google.android.gms"; - field public static final int GSF = 1; // 0x1 field public static final String GSF_NAME = "com.google.android.gsf"; field public static final int G_CAMERA = 8; // 0x8 field public static final String G_CAMERA_NAME = "com.google.android.GoogleCamera"; diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt index 8c92584fcb0fa..d6527f94c65f8 100644 --- a/core/api/system-lint-baseline.txt +++ b/core/api/system-lint-baseline.txt @@ -2227,8 +2227,6 @@ UnflaggedApi: android.ext.PackageId#GMS_CORE: New API must be flagged with @FlaggedApi: field android.ext.PackageId.GMS_CORE UnflaggedApi: android.ext.PackageId#GMS_CORE_NAME: New API must be flagged with @FlaggedApi: field android.ext.PackageId.GMS_CORE_NAME -UnflaggedApi: android.ext.PackageId#GSF: - New API must be flagged with @FlaggedApi: field android.ext.PackageId.GSF UnflaggedApi: android.ext.PackageId#GSF_NAME: New API must be flagged with @FlaggedApi: field android.ext.PackageId.GSF_NAME UnflaggedApi: android.ext.PackageId#G_CAMERA: diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 1b685a07ff019..a92b1c63f5a63 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2794,6 +2794,13 @@ public Context createContextForSdkInSandbox(ApplicationInfo sdkInfo, int flags) @Override public Context createPackageContext(String packageName, int flags) throws NameNotFoundException { + if (GmsCompat.isEnabled()) { + Context res = GmcPackageManager.maybeOverrideGsfPackageContext(packageName); + if (res != null) { + return res; + } + } + return createPackageContextAsUser(packageName, flags, mUser); } diff --git a/core/java/android/app/compat/gms/GmsCompat.java b/core/java/android/app/compat/gms/GmsCompat.java index 1e61e46aacc66..0048e2df5584f 100644 --- a/core/java/android/app/compat/gms/GmsCompat.java +++ b/core/java/android/app/compat/gms/GmsCompat.java @@ -134,7 +134,6 @@ public static boolean isEnabledFor(int packageId, boolean isPrivileged) { return switch (packageId) { case - PackageId.GSF, PackageId.GMS_CORE, PackageId.PLAY_STORE, PackageId.G_SEARCH_APP, @@ -156,7 +155,6 @@ public static boolean canBeEnabledFor(String pkgName) { return switch (pkgName) { case - PackageId.GSF_NAME, PackageId.GMS_CORE_NAME, PackageId.PLAY_STORE_NAME, PackageId.G_SEARCH_APP_NAME, diff --git a/core/java/android/ext/PackageId.java b/core/java/android/ext/PackageId.java index a792ecc363d9f..2db9922539c5b 100644 --- a/core/java/android/ext/PackageId.java +++ b/core/java/android/ext/PackageId.java @@ -13,7 +13,7 @@ public interface PackageId { int UNKNOWN = 0; String GSF_NAME = "com.google.android.gsf"; - int GSF = 1; + // no longer needed: int GSF = 1 String GMS_CORE_NAME = "com.google.android.gms"; int GMS_CORE = 2; diff --git a/core/java/com/android/internal/gmscompat/BinderGca2Gms.java b/core/java/com/android/internal/gmscompat/BinderGca2Gms.java index 0fd6cd98f76ad..14c646e3e319b 100644 --- a/core/java/com/android/internal/gmscompat/BinderGca2Gms.java +++ b/core/java/com/android/internal/gmscompat/BinderGca2Gms.java @@ -12,6 +12,7 @@ import android.util.ArraySet; import android.util.Log; +import com.android.internal.gmscompat.flags.GmsFlag; import com.android.internal.gmscompat.util.GmcActivityUtils; import java.util.concurrent.Callable; @@ -46,13 +47,12 @@ public void invalidateConfigCaches() { updatePhenotype(phenotypeDb, GmsHooks.config()); } - // Gservices flags are hosted by GservicesProvider ContentProvider in - // "Google Services Framework" app. + // Gservices flags are hosted by GservicesProvider ContentProvider in GmsCore. // Its clients register change listeners via // BroadcastReceivers (com.google.gservices.intent.action.GSERVICES_CHANGED) and // ContentResolver#registerContentObserver(). // Code below performs a delete of a non-existing key (key is chosen randomly). - // GSF will notify all of its listeners after this operation, despite database remaining + // GmsCore will notify all of its listeners after this operation, despite database remaining // unchanged. There's no other simple way to achieve the same effect (AFAIK). // // Additional values from GmsCompatConfig will be added only inside client's processes, @@ -62,7 +62,7 @@ public void invalidateConfigCaches() { ContentValues cv = new ContentValues(); cv.put("iquee6jo8ooquoomaeraip7gah4shee8phiet0Ahng0yeipei3", (String) null); - Uri gservicesUri = Uri.parse("content://" + GmsInfo.PACKAGE_GSF + ".gservices/override"); + Uri gservicesUri = Uri.parse("content://" + GmsFlag.GSERVICES_CONTENT_PROVIDER_AUTHORITY + "/override"); cr.update(gservicesUri, cv, null, null); } diff --git a/core/java/com/android/internal/gmscompat/GmsInfo.java b/core/java/com/android/internal/gmscompat/GmsInfo.java index 986e106b37782..d30b8b14162d8 100644 --- a/core/java/com/android/internal/gmscompat/GmsInfo.java +++ b/core/java/com/android/internal/gmscompat/GmsInfo.java @@ -21,7 +21,6 @@ /** @hide */ public final class GmsInfo { // Package names for GMS apps - public static final String PACKAGE_GSF = PackageId.GSF_NAME; // "Google Services Framework" public static final String PACKAGE_GMS_CORE = PackageId.GMS_CORE_NAME; // "Play services" public static final String PACKAGE_PLAY_STORE = PackageId.PLAY_STORE_NAME; @@ -29,6 +28,6 @@ public final class GmsInfo { public static final String PACKAGE_GSA = PackageId.G_SEARCH_APP_NAME; // Used for restricting accessibility of exported components, reducing the scope of broadcasts, etc. - // Held by GSF, GmsCore, Play Store. + // Held by GmsCore and Play Store. public static final String SIGNATURE_PROTECTED_PERMISSION = "com.google.android.providers.gsf.permission.WRITE_GSERVICES"; } diff --git a/core/java/com/android/internal/gmscompat/flags/GmsFlag.java b/core/java/com/android/internal/gmscompat/flags/GmsFlag.java index b1e0be535ec35..9f185bf1d9b42 100644 --- a/core/java/com/android/internal/gmscompat/flags/GmsFlag.java +++ b/core/java/com/android/internal/gmscompat/flags/GmsFlag.java @@ -49,9 +49,11 @@ public class GmsFlag implements Parcelable { public @Nullable String[] permissions; public static final String NAMESPACE_GSERVICES = "gservices"; + // Gservices content provider is hosted by GmsCore since Android 15. It was hosted by GSF before 15. + public static final String GSERVICES_CONTENT_PROVIDER_AUTHORITY = "com.google.android.gsf.gservices"; public static final String GSERVICES_URI = "content://" - + GmsInfo.PACKAGE_GSF + '.' + NAMESPACE_GSERVICES + "/prefix"; + + GSERVICES_CONTENT_PROVIDER_AUTHORITY + "/prefix"; public static final String PHENOTYPE_URI_PREFIX = "content://" + GmsInfo.PACKAGE_GMS_CORE + ".phenotype/"; diff --git a/core/java/com/android/internal/gmscompat/sysservice/GmcPackageManager.java b/core/java/com/android/internal/gmscompat/sysservice/GmcPackageManager.java index 2f0a64e63363c..cb441bf3a5dba 100644 --- a/core/java/com/android/internal/gmscompat/sysservice/GmcPackageManager.java +++ b/core/java/com/android/internal/gmscompat/sysservice/GmcPackageManager.java @@ -35,14 +35,13 @@ import android.content.pm.InstallSourceInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; +import android.content.pm.PackageManager; import android.content.pm.SharedLibraryInfo; import android.content.pm.VersionedPackage; import android.ext.PackageId; -import android.os.Build; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; -import android.provider.Settings; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -529,7 +528,6 @@ private static boolean shouldHideDisabledState(String pkgName) { } switch (pkgName) { - case GmsInfo.PACKAGE_GSF: case GmsInfo.PACKAGE_GMS_CORE: return false; default: @@ -626,4 +624,43 @@ public void setComponentEnabledSettings(List settings) } } + /** @see android.app.ContextImpl#createPackageContext */ + @Nullable + public static Context maybeOverrideGsfPackageContext(String packageName) { + if (!GmsCompat.isGmsCore()) { + return null; + } + + if (!PackageId.GSF_NAME.equals(packageName)) { + return null; + } + + // On first launch, GmsCore attempts to migrate GSF databases into itself. GSF is a + // hasCode=false package since Android 15 and is not needed for fresh installs of GmsCore. + // If GSF is absent, GmsCore crashes when it tries to create package context for GSF as + // part of database migration. To prevent this crash, return GmsCore app context instead + // of GSF package context, which turns database migration into a no-op. + + Context ctx = GmsCompat.appContext(); + PackageManager pkgManager = ctx.getPackageManager(); + + try { + pkgManager.getApplicationInfo(packageName, 0); + } catch (PackageManager.NameNotFoundException e) { + Log.d(TAG, "replacing GSF package context with GmsCore app context", new Throwable()); + return ctx; + } + + try { + PackageInfo pi = pkgManager.getPackageInfo(PackageId.GMS_CORE_NAME, 0); + if (pi.sharedUserId == null) { + // GmsCore has left the GSF sharedUid but GSF is still present + Log.d(TAG, "maybeReplaceGsfPackageName: sharedUserId is null, ignoring GSF", new Throwable()); + return ctx; + } + return null; + } catch (NameNotFoundException e) { + throw new IllegalStateException(e); + } + } } diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java index 6a5fbb4dece74..afbac62477af5 100644 --- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java +++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java @@ -63,6 +63,7 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; +import android.ext.PackageId; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -1210,6 +1211,12 @@ private static ParseResult parseSharedUser(ParseInput input, if (PackageManager.ENABLE_SHARED_UID_MIGRATION) { int max = anInteger(0, R.styleable.AndroidManifest_sharedUserMaxSdkVersion, sa); leaving = (max != 0) && (max < Build.VERSION.RESOURCES_SDK_INT); + + if (android.ext.PackageId.GMS_CORE_NAME.equals(pkg.getPackageName())) { + // Ignore sharedUid for fresh installs of GmsCore. On existing installs, sharedUid + // is needed for access to GSF. + leaving = true; + } } return input.success(pkg @@ -2507,6 +2514,12 @@ private void parseBaseAppBasicFlags(ParsingPackage pkg, TypedArray sa) { } else if (enabledOverride == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { pkg.setEnabled(true); } + + if (PackageId.GSF_NAME.equals(pkg.getPackageName())) { + // GSF is a hasCode=false package on GMS Android 15+. GrapheneOS doesn't include GSF as a + // preinstalled app, so pre-35 GSF remains after update from pre-Android 15. + pkg.setDeclaredHavingCode(false); + } } /** diff --git a/services/core/java/com/android/server/ext/PackageManagerHooks.java b/services/core/java/com/android/server/ext/PackageManagerHooks.java index d57eddb3fe39f..d9139afb04cd5 100644 --- a/services/core/java/com/android/server/ext/PackageManagerHooks.java +++ b/services/core/java/com/android/server/ext/PackageManagerHooks.java @@ -152,7 +152,6 @@ public static boolean shouldFilterApplication( AndroidPackage pkg = targetPkgSetting.getPkg(); if (pkg != null) { switch (PackageExt.get(pkg).getPackageId()) { - case PackageId.GSF: case PackageId.GMS_CORE: case PackageId.PLAY_STORE: case PackageId.EUICC_SUPPORT_PIXEL: diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index ca0ec37da3857..9bcf7bd7fbebb 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -3855,6 +3855,13 @@ private PackageLite validateApkInstallLocked() throws PackageManagerException { // {@link PackageLite#getTargetSdk()} mValidatedTargetSdk = packageLite.getTargetSdk(); + if (mPackageName.equals(PackageId.GSF_NAME)) { + // Installation of GSF is not needed for GmsCompat. However, other apps might use + // package that holds the GSF package name without permission checks since GSF is a + // preinstalled package on GMS Android. + throw new PackageManagerException(INSTALL_FAILED_SESSION_INVALID, "GSF installation is not allowed"); + } + final String initiatingPackageName = mInstallSource.mInitiatingPackageName; if (initiatingPackageName != null && !isInstallerShell && !android.util.PackageUtils.getFirstPartyAppSourcePackageName(mContext) @@ -3873,7 +3880,6 @@ private PackageLite validateApkInstallLocked() throws PackageManagerException { if (!skipExtraChecks) { switch (mPackageName) { - case PackageId.GSF_NAME: case PackageId.GMS_CORE_NAME: case PackageId.PLAY_STORE_NAME: { if (isInstallerPlayStore) { diff --git a/services/core/java/com/android/server/pm/ext/GmsCompatPkgParsingHooks.java b/services/core/java/com/android/server/pm/ext/GmsCompatPkgParsingHooks.java index 7f1e37249d044..ca8aa18e96a5c 100644 --- a/services/core/java/com/android/server/pm/ext/GmsCompatPkgParsingHooks.java +++ b/services/core/java/com/android/server/pm/ext/GmsCompatPkgParsingHooks.java @@ -26,7 +26,6 @@ public static PackageParsingHooks maybeGet(String pkgName) { } return switch (pkgName) { - case PackageId.GSF_NAME -> new GsfParsingHooks(); case PackageId.GMS_CORE_NAME -> new GmsCoreHooks.ParsingHooks(); case PackageId.PLAY_STORE_NAME -> new PlayStoreHooks.ParsingHooks(); case PackageId.G_CARRIER_SETTINGS_NAME -> new GCarrierSettingsHooks.ParsingHooks(); diff --git a/services/core/java/com/android/server/pm/ext/GsfParsingHooks.java b/services/core/java/com/android/server/pm/ext/GsfParsingHooks.java index 269623caf4f29..77284eecef0e4 100644 --- a/services/core/java/com/android/server/pm/ext/GsfParsingHooks.java +++ b/services/core/java/com/android/server/pm/ext/GsfParsingHooks.java @@ -4,8 +4,9 @@ import com.android.internal.pm.pkg.component.ParsedPermission; import com.android.internal.pm.pkg.component.ParsedProvider; +import com.android.internal.pm.pkg.parsing.PackageParsingHooks; -class GsfParsingHooks extends GmsCompatPkgParsingHooks { +class GsfParsingHooks extends PackageParsingHooks { @Override public boolean shouldSkipPermissionDefinition(ParsedPermission p) { diff --git a/services/core/java/com/android/server/pm/ext/PackageExtInit.java b/services/core/java/com/android/server/pm/ext/PackageExtInit.java index 1cc38c9d254c5..e32b844db0853 100644 --- a/services/core/java/com/android/server/pm/ext/PackageExtInit.java +++ b/services/core/java/com/android/server/pm/ext/PackageExtInit.java @@ -67,7 +67,6 @@ private int getExtFlags() { private int getPackageId() { return switch (pkg.getPackageName()) { - case GSF_NAME -> validate(GSF, 30L, mainGmsCerts()); case GMS_CORE_NAME -> validate(GMS_CORE, 21_00_00_000L, mainGmsCerts()); case PLAY_STORE_NAME -> validate(PLAY_STORE, 0L, mainGmsCerts()); case G_SEARCH_APP_NAME -> validate(G_SEARCH_APP, 0L, mainGmsCerts()); diff --git a/services/core/java/com/android/server/pm/ext/PackageHooksRegistry.java b/services/core/java/com/android/server/pm/ext/PackageHooksRegistry.java index 5cdb290df2501..968d59e41643b 100644 --- a/services/core/java/com/android/server/pm/ext/PackageHooksRegistry.java +++ b/services/core/java/com/android/server/pm/ext/PackageHooksRegistry.java @@ -13,6 +13,7 @@ public static PackageParsingHooks getParsingHooks(String pkgName) { } return switch (pkgName) { + case PackageId.GSF_NAME -> new GsfParsingHooks(); case PackageId.EUICC_SUPPORT_PIXEL_NAME -> new EuiccSupportPixelHooks.ParsingHooks(); case PackageId.G_EUICC_LPA_NAME -> new EuiccGoogleHooks.ParsingHooks(); case PackageId.PIXEL_CAMERA_SERVICES_NAME -> new PixelCameraServicesHooks.ParsingHooks();