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

Commit 1a0b969d authored by Neil Fuller's avatar Neil Fuller
Browse files

Enable matching of non-system app services

Change CurrentUserServiceSupplier to support attaching to services that
are not "system" services (i.e. provided by apps from the system image).
This is to support an upcoming test change in location time zone
detection where a fake provider supplied by a CTS app can be bound.

As part of this change constructors have been removed and replaced by
factory methods, which makes the choice to allow non-system services
more obvious.

Bug: 184947690
Test: build / treehugger
Change-Id: I629228c09ad1cf91c28c20d0b4b6227d1e4b1a00
parent 764792b6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -56,7 +56,7 @@ public class GeocoderProxy {

    private GeocoderProxy(Context context) {
        mServiceWatcher = ServiceWatcher.create(context, "GeocoderProxy",
                new CurrentUserServiceSupplier(context, SERVICE_ACTION,
                CurrentUserServiceSupplier.createFromConfig(context, SERVICE_ACTION,
                        com.android.internal.R.bool.config_enableGeocoderOverlay,
                        com.android.internal.R.string.config_geocoderProviderPackageName),
                null);
+2 −2
Original line number Diff line number Diff line
@@ -73,8 +73,8 @@ public class HardwareActivityRecognitionProxy implements ServiceListener<BoundSe

        mServiceWatcher = ServiceWatcher.create(context,
                "HardwareActivityRecognitionProxy",
                new CurrentUserServiceSupplier(context, SERVICE_ACTION, useOverlayResId,
                        nonOverlayPackageResId),
                CurrentUserServiceSupplier.createFromConfig(context, SERVICE_ACTION,
                        useOverlayResId, nonOverlayPackageResId),
                this);
    }

+1 −1
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ public final class GeofenceProxy implements ServiceListener<BoundServiceInfo> {
        mGpsGeofenceHardware = Objects.requireNonNull(gpsGeofence);
        mServiceWatcher = ServiceWatcher.create(context,
                "GeofenceProxy",
                new CurrentUserServiceSupplier(context, SERVICE_ACTION,
                CurrentUserServiceSupplier.createFromConfig(context, SERVICE_ACTION,
                        com.android.internal.R.bool.config_enableGeofenceOverlay,
                        com.android.internal.R.string.config_geofenceProviderPackageName),
                this);
+1 −1
Original line number Diff line number Diff line
@@ -103,7 +103,7 @@ public class ProxyLocationProvider extends AbstractLocationProvider implements

        mContext = context;
        mServiceWatcher = ServiceWatcher.create(context, provider,
                new CurrentUserServiceSupplier(context, action, enableOverlayResId,
                CurrentUserServiceSupplier.createFromConfig(context, action, enableOverlayResId,
                        nonOverlayPackageResId), this);
        mName = provider;

+64 −25
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ import java.util.Objects;
 * not require callers to hold this permission is rejected (2) a service permission - any service
 * whose package does not hold this permission is rejected.
 */
public class CurrentUserServiceSupplier extends BroadcastReceiver implements
public final class CurrentUserServiceSupplier extends BroadcastReceiver implements
        ServiceSupplier<CurrentUserServiceSupplier.BoundServiceInfo> {

    private static final String TAG = "CurrentUserServiceSupplier";
@@ -144,6 +144,53 @@ public class CurrentUserServiceSupplier extends BroadcastReceiver implements
        }
    }

    /**
     * Creates an instance using package details retrieved from config.
     *
     * @see #create(Context, String, String, String, String)
     */
    public static CurrentUserServiceSupplier createFromConfig(Context context, String action,
            @BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) {
        String explicitPackage = retrieveExplicitPackage(context, enableOverlayResId,
                nonOverlayPackageResId);
        return CurrentUserServiceSupplier.create(context, action, explicitPackage,
                /*callerPermission=*/null, /*servicePermission=*/null);
    }

    /**
     * Creates an instance with the specific service details and permission requirements.
     *
     * @param context the context the supplier is to use
     * @param action the action the service must declare in its intent-filter
     * @param explicitPackage the package of the service, or {@code null} if the package of the
     *     service is not constrained
     * @param callerPermission a permission that the service forces callers (i.e.
     *     ServiceWatcher/system server) to hold, or {@code null} if there isn't one
     * @param servicePermission a permission that the service package should hold, or {@code null}
     *     if there isn't one
     */
    public static CurrentUserServiceSupplier create(Context context, String action,
            @Nullable String explicitPackage, @Nullable String callerPermission,
            @Nullable String servicePermission) {
        boolean matchSystemAppsOnly = true;
        return new CurrentUserServiceSupplier(context, action,
                explicitPackage, callerPermission, servicePermission, matchSystemAppsOnly);
    }

    /**
     * Creates an instance like {@link #create} except it allows connection to services that are not
     * supplied by system packages. Only intended for use during tests.
     *
     * @see #create(Context, String, String, String, String)
     */
    public static CurrentUserServiceSupplier createUnsafeForTestsOnly(Context context,
            String action, @Nullable String explicitPackage, @Nullable String callerPermission,
            @Nullable String servicePermission) {
        boolean matchSystemAppsOnly = false;
        return new CurrentUserServiceSupplier(context, action,
                explicitPackage, callerPermission, servicePermission, matchSystemAppsOnly);
    }

    private static @Nullable String retrieveExplicitPackage(Context context,
            @BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) {
        Resources resources = context.getResources();
@@ -162,31 +209,14 @@ public class CurrentUserServiceSupplier extends BroadcastReceiver implements
    private final @Nullable String mCallerPermission;
    // a permission that the service package should hold
    private final @Nullable String mServicePermission;
    // whether to use MATCH_SYSTEM_ONLY in queries
    private final boolean mMatchSystemAppsOnly;

    private volatile ServiceChangedListener mListener;

    public CurrentUserServiceSupplier(Context context, String action) {
        this(context, action, null, null, null);
    }

    public CurrentUserServiceSupplier(Context context, String action,
            @BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) {
        this(context, action,
                retrieveExplicitPackage(context, enableOverlayResId, nonOverlayPackageResId), null,
                null);
    }

    public CurrentUserServiceSupplier(Context context, String action,
            @BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId,
            @Nullable String callerPermission, @Nullable String servicePermission) {
        this(context, action,
                retrieveExplicitPackage(context, enableOverlayResId, nonOverlayPackageResId),
                callerPermission, servicePermission);
    }

    public CurrentUserServiceSupplier(Context context, String action,
    private CurrentUserServiceSupplier(Context context, String action,
            @Nullable String explicitPackage, @Nullable String callerPermission,
            @Nullable String servicePermission) {
            @Nullable String servicePermission, boolean matchSystemAppsOnly) {
        mContext = context;
        mActivityManager = Objects.requireNonNull(
                LocalServices.getService(ActivityManagerInternal.class));
@@ -198,13 +228,18 @@ public class CurrentUserServiceSupplier extends BroadcastReceiver implements

        mCallerPermission = callerPermission;
        mServicePermission = servicePermission;
        mMatchSystemAppsOnly = matchSystemAppsOnly;
    }

    @Override
    public boolean hasMatchingService() {
        int intentQueryFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
        if (mMatchSystemAppsOnly) {
            intentQueryFlags |= MATCH_SYSTEM_ONLY;
        }
        List<ResolveInfo> resolveInfos = mContext.getPackageManager()
                .queryIntentServicesAsUser(mIntent,
                        MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | MATCH_SYSTEM_ONLY,
                        intentQueryFlags,
                        UserHandle.USER_SYSTEM);
        return !resolveInfos.isEmpty();
    }
@@ -234,11 +269,15 @@ public class CurrentUserServiceSupplier extends BroadcastReceiver implements
    public BoundServiceInfo getServiceInfo() {
        BoundServiceInfo bestServiceInfo = null;

        // only allow privileged services in the correct direct boot state to match
        // only allow services in the correct direct boot state to match
        int intentQueryFlags = MATCH_DIRECT_BOOT_AUTO | GET_META_DATA;
        if (mMatchSystemAppsOnly) {
            intentQueryFlags |= MATCH_SYSTEM_ONLY;
        }
        int currentUserId = mActivityManager.getCurrentUserId();
        List<ResolveInfo> resolveInfos = mContext.getPackageManager().queryIntentServicesAsUser(
                mIntent,
                GET_META_DATA | MATCH_DIRECT_BOOT_AUTO | MATCH_SYSTEM_ONLY,
                intentQueryFlags,
                currentUserId);
        for (ResolveInfo resolveInfo : resolveInfos) {
            ServiceInfo service = Objects.requireNonNull(resolveInfo.serviceInfo);
Loading