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

Commit b8ddf755 authored by Evan Chen's avatar Evan Chen Committed by Android (Google) Code Review
Browse files

Merge "Remove CompanionServicesRegister" into main

parents 0d188614 ef81f7e9
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -259,8 +259,6 @@ public class CompanionDeviceManagerService extends SystemService {
            for (AssociationInfo association : associationsForPackage) {
                mDisassociationProcessor.disassociate(association.getId(), REASON_PKG_DATA_CLEARED);
            }

            mCompanionAppBinder.onPackageChanged(userId);
        }

        // Clear observable UUIDs for the package.
@@ -276,8 +274,6 @@ public class CompanionDeviceManagerService extends SystemService {
                mAssociationStore.getAssociationsByPackage(userId, packageName);
        if (!associations.isEmpty()) {
            mCompanionExemptionProcessor.exemptPackage(userId, packageName, false);

            mCompanionAppBinder.onPackageChanged(userId);
        }
    }

+55 −34
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.companion.devicepresence;

import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -25,14 +26,16 @@ import android.companion.CompanionDeviceService;
import android.companion.DevicePresenceEvent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Handler;
import android.util.Pair;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.PerUser;
import com.android.server.companion.CompanionDeviceManagerService;
import com.android.server.companion.utils.PackageUtils;

import java.io.PrintWriter;
import java.util.ArrayList;
@@ -70,12 +73,16 @@ import java.util.Set;
public class CompanionAppBinder {
    private static final String TAG = "CDM_CompanionAppBinder";

    private static final Intent COMPANION_SERVICE_INTENT =
            new Intent(CompanionDeviceService.SERVICE_INTERFACE);

    private static final String PROPERTY_PRIMARY_TAG =
            "android.companion.PROPERTY_PRIMARY_COMPANION_DEVICE_SERVICE";

    private static final long REBIND_TIMEOUT = 10 * 1000; // 10 sec

    @NonNull
    private final Context mContext;
    @NonNull
    private final CompanionServicesRegister mCompanionServicesRegister;

    @NonNull
    @GuardedBy("mBoundCompanionApplications")
@@ -87,20 +94,10 @@ public class CompanionAppBinder {

    public CompanionAppBinder(@NonNull Context context) {
        mContext = context;
        mCompanionServicesRegister = new CompanionServicesRegister();
        mBoundCompanionApplications = new HashMap<>();
        mScheduledForRebindingCompanionApplications = new HashSet<>();
    }

    /**
     * On package changed.
     */
    public void onPackageChanged(@UserIdInt int userId) {
        // Note: To invalidate the user space for simplicity. We could alternatively manage each
        //       package, but that would easily cause errors if one case is mis-handled.
        mCompanionServicesRegister.invalidate(userId);
    }

    /**
     * CDM binds to the companion app.
     */
@@ -109,8 +106,9 @@ public class CompanionAppBinder {
        Slog.i(TAG, "Binding user=[" + userId + "], package=[" + packageName + "], isSelfManaged=["
                + isSelfManaged + "]...");

        final List<ComponentName> companionServices =
                mCompanionServicesRegister.forPackage(userId, packageName);
        final List<ComponentName> companionServices = getCompanionServiceComponentsForPackage(
                mContext, packageName, userId);

        if (companionServices.isEmpty()) {
            Slog.e(TAG, "Can not bind companion applications u" + userId + "/" + packageName + ": "
                    + "eligible CompanionDeviceService not found.\n"
@@ -299,28 +297,51 @@ public class CompanionAppBinder {
        return connectors != null ? connectors.get(0) : null;
    }

    private class CompanionServicesRegister extends PerUser<Map<String, List<ComponentName>>> {
        @Override
        @NonNull
        public synchronized Map<String, List<ComponentName>> forUser(
                @UserIdInt int userId) {
            return super.forUser(userId);
    /**
     * @return list of {@link CompanionDeviceService}-s per package for a given user.
     *         Services marked as "primary" would always appear at the head of the lists, *before*
     *         all non-primary services.
     */
    private @NonNull List<ComponentName> getCompanionServiceComponentsForPackage(
            @NonNull Context context, @NonNull String packageName, @UserIdInt int userId) {
        final PackageManager pm = context.getPackageManager();
        final List<ResolveInfo> companionServices = pm.queryIntentServicesAsUser(
                COMPANION_SERVICE_INTENT, PackageManager.ResolveInfoFlags.of(0), userId);
        final List<ComponentName> componentNames = new ArrayList<>();

        for (ResolveInfo resolveInfo : companionServices) {
            final ServiceInfo service = resolveInfo.serviceInfo;
            final ComponentName componentName = service.getComponentName();

            if (!componentName.getPackageName().equals(packageName)) continue;

            final boolean requiresPermission = Manifest.permission.BIND_COMPANION_DEVICE_SERVICE
                    .equals(resolveInfo.serviceInfo.permission);
            if (!requiresPermission) {
                Slog.w(TAG, "CompanionDeviceService "
                        + service.getComponentName().flattenToShortString() + " must require "
                        + "android.permission.BIND_COMPANION_DEVICE_SERVICE");
                break;
            }

            if (isPrimaryCompanionDeviceService(pm, componentName, userId)) {
                // "Primary" service should be at the head of the list.
                componentNames.add(0, componentName);
            } else {
                componentNames.add(componentName);
            }

        @NonNull
        synchronized List<ComponentName> forPackage(
                @UserIdInt int userId, @NonNull String packageName) {
            return forUser(userId).getOrDefault(packageName, Collections.emptyList());
        }

        synchronized void invalidate(@UserIdInt int userId) {
            remove(userId);
        return componentNames;
    }

        @Override
        @NonNull
        protected final Map<String, List<ComponentName>> create(@UserIdInt int userId) {
            return PackageUtils.getCompanionServicesForUser(mContext, userId);
    private boolean isPrimaryCompanionDeviceService(@NonNull PackageManager pm,
            @NonNull ComponentName componentName, @UserIdInt int userId) {
        try {
            return pm.getPropertyAsUser(PROPERTY_PRIMARY_TAG, componentName.getPackageName(),
                    componentName.getClassName(), userId).getBoolean();
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }
    }
}
+0 −71
Original line number Diff line number Diff line
@@ -26,25 +26,18 @@ import static com.android.internal.R.array.config_companionDevicePackages;
import static com.android.internal.R.array.config_companionPermSyncEnabledCerts;
import static com.android.internal.R.array.config_companionPermSyncEnabledPackages;

import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.ecm.EnhancedConfirmationManager;
import android.companion.CompanionDeviceService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.PackageInfoFlags;
import android.content.pm.PackageManager.ResolveInfoFlags;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
import android.os.Binder;
import android.os.Process;
@@ -53,11 +46,7 @@ import android.util.Slog;

import com.android.internal.util.ArrayUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
@@ -68,11 +57,6 @@ public final class PackageUtils {
    public static final int PACKAGE_NOT_FOUND = -1;
    private static final String TAG = "CDM_PackageUtils";

    private static final Intent COMPANION_SERVICE_INTENT =
            new Intent(CompanionDeviceService.SERVICE_INTERFACE);
    private static final String PROPERTY_PRIMARY_TAG =
            "android.companion.PROPERTY_PRIMARY_COMPANION_DEVICE_SERVICE";

    /**
     * Get package info
     */
@@ -120,61 +104,6 @@ public final class PackageUtils {
                + " in manifest to use this API");
    }

    /**
     * @return list of {@link CompanionDeviceService}-s per package for a given user.
     *         Services marked as "primary" would always appear at the head of the lists, *before*
     *         all non-primary services.
     */
    public static @NonNull Map<String, List<ComponentName>> getCompanionServicesForUser(
            @NonNull Context context, @UserIdInt int userId) {
        final PackageManager pm = context.getPackageManager();
        final List<ResolveInfo> companionServices = pm.queryIntentServicesAsUser(
                COMPANION_SERVICE_INTENT, ResolveInfoFlags.of(0), userId);

        final Map<String, List<ComponentName>> packageNameToServiceInfoList =
                new HashMap<>(companionServices.size());

        for (ResolveInfo resolveInfo : companionServices) {
            final ServiceInfo service = resolveInfo.serviceInfo;

            final boolean requiresPermission = Manifest.permission.BIND_COMPANION_DEVICE_SERVICE
                    .equals(resolveInfo.serviceInfo.permission);
            if (!requiresPermission) {
                Slog.w(TAG, "CompanionDeviceService "
                        + service.getComponentName().flattenToShortString() + " must require "
                        + "android.permission.BIND_COMPANION_DEVICE_SERVICE");
                continue;
            }

            // We'll need to prepend "primary" services, while appending the other (non-primary)
            // services to the list.
            final ArrayList<ComponentName> services =
                    (ArrayList<ComponentName>) packageNameToServiceInfoList.computeIfAbsent(
                            service.packageName, it -> new ArrayList<>(1));

            final ComponentName componentName = service.getComponentName();

            if (isPrimaryCompanionDeviceService(pm, componentName, userId)) {
                // "Primary" service should be at the head of the list.
                services.add(0, componentName);
            } else {
                services.add(componentName);
            }
        }

        return packageNameToServiceInfoList;
    }

    private static boolean isPrimaryCompanionDeviceService(@NonNull PackageManager pm,
            @NonNull ComponentName componentName, @UserIdInt int userId) {
        try {
            return pm.getPropertyAsUser(PROPERTY_PRIMARY_TAG, componentName.getPackageName(),
                    componentName.getClassName(), userId).getBoolean();
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }
    }

    /**
     * Check if the package is allowlisted in the overlay config.
     * For this we'll check to config arrays: