Skip to content

Commit

Permalink
gmscompat: don't use GSF for fresh installs
Browse files Browse the repository at this point in the history
On existing installs, GmsCore uses GSF to perform a one-time migration of GSF databases into
itself.
  • Loading branch information
muhomorr authored and thestinger committed Oct 15, 2024
1 parent b3499d9 commit ae5834e
Show file tree
Hide file tree
Showing 16 changed files with 79 additions and 21 deletions.
1 change: 0 additions & 1 deletion core/api/system-current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
2 changes: 0 additions & 2 deletions core/api/system-lint-baseline.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
7 changes: 7 additions & 0 deletions core/java/android/app/ContextImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
2 changes: 0 additions & 2 deletions core/java/android/app/compat/gms/GmsCompat.java
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion core/java/android/ext/PackageId.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 4 additions & 4 deletions core/java/com/android/internal/gmscompat/BinderGca2Gms.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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);
}

Expand Down
3 changes: 1 addition & 2 deletions core/java/com/android/internal/gmscompat/GmsInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,13 @@
/** @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;

// "Google" app. "GSA" (G Search App) is its internal name
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";
}
4 changes: 3 additions & 1 deletion core/java/com/android/internal/gmscompat/flags/GmsFlag.java
Original file line number Diff line number Diff line change
Expand Up @@ -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/";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -529,7 +528,6 @@ private static boolean shouldHideDisabledState(String pkgName) {
}

switch (pkgName) {
case GmsInfo.PACKAGE_GSF:
case GmsInfo.PACKAGE_GMS_CORE:
return false;
default:
Expand Down Expand Up @@ -626,4 +624,43 @@ public void setComponentEnabledSettings(List<ComponentEnabledSetting> 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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1210,6 +1211,12 @@ private static ParseResult<ParsingPackage> 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
Expand Down Expand Up @@ -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);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit ae5834e

Please sign in to comment.