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

Commit f3171a69 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Cache CDM associations"

parents 46b42ef3 4b178ad3
Loading
Loading
Loading
Loading
+76 −27
Original line number Original line Diff line number Diff line
@@ -17,7 +17,8 @@


package com.android.server.companion;
package com.android.server.companion;


import static com.android.internal.util.CollectionUtils.size;
import static com.android.internal.util.CollectionUtils.emptyIfNull;
import static com.android.internal.util.CollectionUtils.forEach;
import static com.android.internal.util.FunctionalUtils.uncheckExceptions;
import static com.android.internal.util.FunctionalUtils.uncheckExceptions;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -72,6 +73,7 @@ import android.util.Log;
import android.util.Slog;
import android.util.Slog;
import android.util.Xml;
import android.util.Xml;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IAppOpsService;
import com.android.internal.content.PackageMonitor;
import com.android.internal.content.PackageMonitor;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.AndroidFuture;
@@ -95,8 +97,10 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.HashSet;
import java.util.List;
import java.util.List;
import java.util.Objects;
import java.util.Objects;
@@ -142,6 +146,9 @@ public class CompanionDeviceManagerService extends SystemService implements Bind


    private final Object mLock = new Object();
    private final Object mLock = new Object();


    @GuardedBy("mLock")
    private @Nullable Set<Association> mCachedAssociations = null;

    public CompanionDeviceManagerService(Context context) {
    public CompanionDeviceManagerService(Context context) {
        super(context);
        super(context);
        mImpl = new CompanionDeviceManagerImpl();
        mImpl = new CompanionDeviceManagerImpl();
@@ -176,7 +183,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
            @Override
            @Override
            public void onPackageModified(String packageName) {
            public void onPackageModified(String packageName) {
                int userId = getChangingUserId();
                int userId = getChangingUserId();
                if (!ArrayUtils.isEmpty(readAllAssociations(userId, packageName))) {
                if (!ArrayUtils.isEmpty(getAllAssociations(userId, packageName))) {
                    updateSpecialAccessPermissionForAssociatedPackage(packageName, userId);
                    updateSpecialAccessPermissionForAssociatedPackage(packageName, userId);
                }
                }
            }
            }
@@ -192,7 +199,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
    @Override
    @Override
    public void onUserUnlocking(@NonNull TargetUser user) {
    public void onUserUnlocking(@NonNull TargetUser user) {
        int userHandle = user.getUserIdentifier();
        int userHandle = user.getUserIdentifier();
        Set<Association> associations = readAllAssociations(userHandle);
        Set<Association> associations = getAllAssociations(userHandle);
        if (associations == null || associations.isEmpty()) {
        if (associations == null || associations.isEmpty()) {
            return;
            return;
        }
        }
@@ -222,7 +229,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
            }
            }


            try {
            try {
                Set<Association> associations = readAllAssociations(userId);
                Set<Association> associations = getAllAssociations(userId);
                if (associations == null) {
                if (associations == null) {
                    continue;
                    continue;
                }
                }
@@ -342,7 +349,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
                checkUsesFeature(callingPackage, getCallingUserId());
                checkUsesFeature(callingPackage, getCallingUserId());
            }
            }
            return new ArrayList<>(CollectionUtils.map(
            return new ArrayList<>(CollectionUtils.map(
                    readAllAssociations(userId, callingPackage),
                    getAllAssociations(userId, callingPackage),
                    a -> a.getDeviceMacAddress()));
                    a -> a.getDeviceMacAddress()));
        }
        }


@@ -353,7 +360,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
                        + android.Manifest.permission.MANAGE_COMPANION_DEVICES);
                        + android.Manifest.permission.MANAGE_COMPANION_DEVICES);
            }
            }


            return new ArrayList<>(readAllAssociations(userId, null /* packageFilter */));
            return new ArrayList<>(getAllAssociations(userId, null /* packageFilter */));
        }
        }


        //TODO also revoke notification access
        //TODO also revoke notification access
@@ -437,14 +444,14 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
            }
            }


            return CollectionUtils.any(
            return CollectionUtils.any(
                    readAllAssociations(userId, packageName),
                    getAllAssociations(userId, packageName),
                    a -> Objects.equals(a.getDeviceMacAddress(), macAddress));
                    a -> Objects.equals(a.getDeviceMacAddress(), macAddress));
        }
        }


        private void checkCanCallNotificationApi(String callingPackage) throws RemoteException {
        private void checkCanCallNotificationApi(String callingPackage) throws RemoteException {
            checkCallerIsSystemOr(callingPackage);
            checkCallerIsSystemOr(callingPackage);
            int userId = getCallingUserId();
            int userId = getCallingUserId();
            checkState(!ArrayUtils.isEmpty(readAllAssociations(userId, callingPackage)),
            checkState(!ArrayUtils.isEmpty(getAllAssociations(userId, callingPackage)),
                    "App must have an association before calling this API");
                    "App must have an association before calling this API");
            checkUsesFeature(callingPackage, userId);
            checkUsesFeature(callingPackage, userId);
        }
        }
@@ -472,6 +479,21 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
                throws RemoteException {
                throws RemoteException {
            new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
            new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
        }
        }

        @Override
        public void dump(@NonNull FileDescriptor fd,
                @NonNull PrintWriter fout,
                @Nullable String[] args) {
            fout.append("Companion Device Associations:").append('\n');
            synchronized (mLock) {
                forEach(mCachedAssociations, a -> {
                    fout.append("  ")
                            .append("u").append("" + a.getUserId()).append(": ")
                            .append(a.getPackageName()).append(" - ")
                            .append(a.getDeviceMacAddress()).append('\n');
                });
            }
        }
    }
    }


    private static int getCallingUserId() {
    private static int getCallingUserId() {
@@ -581,20 +603,37 @@ public class CompanionDeviceManagerService extends SystemService implements Bind


    private void updateAssociations(Function<Set<Association>, Set<Association>> update,
    private void updateAssociations(Function<Set<Association>, Set<Association>> update,
            int userId) {
            int userId) {
        final AtomicFile file = getStorageFileForUser(userId);
        synchronized (mLock) {
        synchronized (file) {
            final Set<Association> old = getAllAssociations(userId);
            Set<Association> associations = readAllAssociations(userId);
            Set<Association> associations = new ArraySet<>(old);
            final Set<Association> old = CollectionUtils.copyOf(associations);
            associations = update.apply(associations);
            associations = update.apply(associations);
            if (size(old) == size(associations)) return;


            Set<Association> finalAssociations = associations;
            Set<String> companionAppPackages = new HashSet<>();
            Set<String> companionAppPackages = new HashSet<>();
            for (Association association : finalAssociations) {
            for (Association association : associations) {
                companionAppPackages.add(association.getPackageName());
                companionAppPackages.add(association.getPackageName());
            }
            }


            file.write((out) -> {
            if (DEBUG) {
                Slog.i(LOG_TAG, "Updating associations: " + old + "  -->  " + associations);
            }
            mCachedAssociations = Collections.unmodifiableSet(associations);
            BackgroundThread.getHandler().sendMessage(PooledLambda.obtainMessage(
                    CompanionDeviceManagerService::persistAssociations,
                    this, associations, userId));

            ActivityTaskManagerInternal atmInternal = LocalServices.getService(
                    ActivityTaskManagerInternal.class);
            atmInternal.setCompanionAppPackages(userId, companionAppPackages);
        }
    }

    private void persistAssociations(Set<Association> associations, int userId) {
        if (DEBUG) {
            Slog.i(LOG_TAG, "Writing associations to disk: " + associations);
        }
        final AtomicFile file = getStorageFileForUser(userId);
        synchronized (file) {
            file.write(out -> {
                XmlSerializer xml = Xml.newSerializer();
                XmlSerializer xml = Xml.newSerializer();
                try {
                try {
                    xml.setOutput(out, StandardCharsets.UTF_8.name());
                    xml.setOutput(out, StandardCharsets.UTF_8.name());
@@ -602,7 +641,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
                    xml.startDocument(null, true);
                    xml.startDocument(null, true);
                    xml.startTag(null, XML_TAG_ASSOCIATIONS);
                    xml.startTag(null, XML_TAG_ASSOCIATIONS);


                    CollectionUtils.forEach(finalAssociations, association -> {
                    forEach(associations, association -> {
                        xml.startTag(null, XML_TAG_ASSOCIATION)
                        xml.startTag(null, XML_TAG_ASSOCIATION)
                                .attribute(null, XML_ATTR_PACKAGE, association.getPackageName())
                                .attribute(null, XML_ATTR_PACKAGE, association.getPackageName())
                                .attribute(null, XML_ATTR_DEVICE, association.getDeviceMacAddress())
                                .attribute(null, XML_ATTR_DEVICE, association.getDeviceMacAddress())
@@ -615,11 +654,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
                    Slog.e(LOG_TAG, "Error while writing associations file", e);
                    Slog.e(LOG_TAG, "Error while writing associations file", e);
                    throw ExceptionUtils.propagate(e);
                    throw ExceptionUtils.propagate(e);
                }
                }

            });
            });
            ActivityTaskManagerInternal atmInternal = LocalServices.getService(
                    ActivityTaskManagerInternal.class);
            atmInternal.setCompanionAppPackages(userId, companionAppPackages);
        }
        }
    }
    }


@@ -632,12 +667,27 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
    }
    }


    @Nullable
    @Nullable
    private Set<Association> readAllAssociations(int userId) {
    private Set<Association> getAllAssociations(int userId) {
        return readAllAssociations(userId, null);
        synchronized (mLock) {
            if (mCachedAssociations == null) {
                mCachedAssociations = Collections.unmodifiableSet(
                        emptyIfNull(readAllAssociations(userId)));
                if (DEBUG) {
                    Slog.i(LOG_TAG, "Read associations from disk: " + mCachedAssociations);
                }
            }
            return mCachedAssociations;
        }
    }
    }


    @Nullable
    @Nullable
    private Set<Association> readAllAssociations(int userId, @Nullable String packageFilter) {
    private Set<Association> getAllAssociations(int userId, @Nullable String packageFilter) {
        return CollectionUtils.filter(
                getAllAssociations(userId),
                a -> Objects.equals(packageFilter, a.getPackageName()));
    }

    private Set<Association> readAllAssociations(int userId) {
        final AtomicFile file = getStorageFileForUser(userId);
        final AtomicFile file = getStorageFileForUser(userId);


        if (!file.getBaseFile().exists()) return null;
        if (!file.getBaseFile().exists()) return null;
@@ -656,7 +706,6 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
                    final String deviceAddress = parser.getAttributeValue(null, XML_ATTR_DEVICE);
                    final String deviceAddress = parser.getAttributeValue(null, XML_ATTR_DEVICE);


                    if (appPackage == null || deviceAddress == null) continue;
                    if (appPackage == null || deviceAddress == null) continue;
                    if (packageFilter != null && !packageFilter.equals(appPackage)) continue;


                    result = ArrayUtils.add(result,
                    result = ArrayUtils.add(result,
                            new Association(userId, deviceAddress, appPackage));
                            new Association(userId, deviceAddress, appPackage));
@@ -684,8 +733,8 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
        public int onCommand(String cmd) {
        public int onCommand(String cmd) {
            switch (cmd) {
            switch (cmd) {
                case "list": {
                case "list": {
                    CollectionUtils.forEach(
                    forEach(
                            readAllAssociations(getNextArgInt()),
                            getAllAssociations(getNextArgInt()),
                            a -> getOutPrintWriter()
                            a -> getOutPrintWriter()
                                    .println(a.getPackageName() + " " + a.getDeviceMacAddress()));
                                    .println(a.getPackageName() + " " + a.getDeviceMacAddress()));
                } break;
                } break;