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

Commit 15f59124 authored by /e/ robot's avatar /e/ robot
Browse files

Merge remote-tracking branch 'origin/lineage-22.2' into a15

parents ca63338e 373d214c
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -257,7 +257,12 @@ public class CompanionDeviceDiscoveryService extends Service {

        // Stop BLE scanning.
        if (mBleScanCallback != null) {
            try {
                mBleScanner.stopScan(mBleScanCallback);
            } catch (IllegalStateException e) {
                Slog.e(TAG, "Unable to stop BLE scanner. The scanner is already"
                        + " turned off or Bluetooth is disabled.");
            }
        }

        Handler.getMain().removeCallbacks(mTimeoutRunnable);
+0 −4
Original line number Diff line number Diff line
@@ -251,8 +251,6 @@ public class CompanionDeviceManagerService extends SystemService {
            for (AssociationInfo association : associationsForPackage) {
                mDisassociationProcessor.disassociate(association.getId());
            }

            mCompanionAppBinder.onPackageChanged(userId);
        }

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

            mCompanionAppBinder.onPackageChanged(userId);
        }
    }

+21 −11
Original line number Diff line number Diff line
@@ -280,7 +280,7 @@ public final class AssociationDiskStore {
    }

    @NonNull
    private static Associations readAssociationsFromInputStream(@UserIdInt int userId,
    public static Associations readAssociationsFromInputStream(@UserIdInt int userId,
            @NonNull InputStream in, @NonNull String rootTag)
            throws XmlPullParserException, IOException {
        final TypedXmlPullParser parser = Xml.resolvePullParser(in);
@@ -296,10 +296,15 @@ public final class AssociationDiskStore {
            case 1:
                while (true) {
                    parser.nextTag();
                    if (isEndOfTag(parser, rootTag)) {
                        break;
                    }
                    if (isStartOfTag(parser, XML_TAG_ASSOCIATIONS)) {
                        associations = readAssociationsV1(parser, userId);
                    } else if (isEndOfTag(parser, rootTag)) {
                        break;
                    } else {
                        Slog.e(TAG, "Unexpected tag " + parser.getName()
                                + " inside <" + rootTag + "> for user " + userId);
                        XmlUtils.skipCurrentTag(parser);
                    }
                }
                break;
@@ -314,7 +319,7 @@ public final class AssociationDiskStore {
        writeToFileSafely(file, out -> {
            final TypedXmlSerializer serializer = Xml.resolveSerializer(out);
            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
            serializer.startDocument(null, true);
            serializer.startDocument("UTF-8", true);
            serializer.startTag(null, XML_TAG_STATE);
            writeIntAttribute(serializer,
                    XML_ATTR_PERSISTENCE_VERSION, CURRENT_PERSISTENCE_VERSION);
@@ -424,13 +429,18 @@ public final class AssociationDiskStore {

        while (true) {
            parser.nextTag();
            if (isEndOfTag(parser, XML_TAG_ASSOCIATIONS)) break;
            if (!isStartOfTag(parser, XML_TAG_ASSOCIATION)) continue;

            if (isEndOfTag(parser, XML_TAG_ASSOCIATIONS)) {
                break;
            }
            if (isStartOfTag(parser, XML_TAG_ASSOCIATION)) {
                AssociationInfo association = readAssociationV1(parser, userId);
                associations.addAssociation(association);

                maxId = Math.max(maxId, association.getId());
            } else {
                Slog.e(TAG, "Unexpected tag " + parser.getName()
                        + " inside <" + XML_TAG_ASSOCIATIONS + "> for user " + userId);
                XmlUtils.skipCurrentTag(parser);
            }
        }

        associations.setMaxId(maxId);
+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;
        }
    }
}
+1 −70
Original line number Diff line number Diff line
@@ -26,24 +26,19 @@ 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;
@@ -52,11 +47,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;

/**
@@ -66,11 +57,6 @@ public final class PackageUtils {

    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
     */
@@ -118,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:
Loading