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

Commit b98e09df authored by Atneya Nair's avatar Atneya Nair Committed by Android (Google) Code Review
Browse files

Merge "Push additional package data to audioserver" into main

parents 2c513ff8 e8d1c495
Loading
Loading
Loading
Loading
+38 −47
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@ import android.os.RemoteException;
import android.os.Trace;
import android.os.Process;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.Log;

@@ -46,7 +45,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.media.permission.INativePermissionController;
import com.android.media.permission.PermissionEnum;
import com.android.media.permission.UidPackageState;
import com.android.server.pm.pkg.PackageState;
import com.android.media.permission.UidPackageState.PackageState;

import java.util.Arrays;
import java.util.Collection;
@@ -55,11 +54,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiPredicate;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/** Responsible for synchronizing system server permission state to the native audioserver. */
public class AudioServerPermissionProvider {
@@ -108,7 +104,7 @@ public class AudioServerPermissionProvider {
    private INativePermissionController mDest;

    @GuardedBy("mLock")
    private final Map<Integer, Set<String>> mPackageMap;
    private final Map<Integer, Map<String, PackageState>> mPackageMap;

    // Values are sorted
    @GuardedBy("mLock")
@@ -121,10 +117,13 @@ public class AudioServerPermissionProvider {
    private int mHdsUid = -1;

    /**
     * @param appInfos - PackageState for all apps on the device, used to populate init state
     * @param packageMap - Map from app-ids to Map of packageNames to PackageState (also containing
     * name)
     * @param permissionPredicate - Check if a UID holds an android permission (string)
     * @param userIdSupplier - Return all users (not uids) on the device, which apps can run in
     */
    public AudioServerPermissionProvider(
            Collection<PackageState> appInfos,
            Map<Integer, Map<String, PackageState>> packageMap,
            BiPredicate<Integer, String> permissionPredicate,
            Supplier<int[]> userIdSupplier) {
        for (int i = 0; i < PermissionEnum.ENUM_SIZE; i++) {
@@ -133,7 +132,7 @@ public class AudioServerPermissionProvider {
        mUserIdSupplier = userIdSupplier;
        mPermissionPredicate = permissionPredicate;
        // Initialize the package state
        mPackageMap = generatePackageMappings(appInfos);
        mPackageMap = packageMap;
    }

    /**
@@ -162,35 +161,47 @@ public class AudioServerPermissionProvider {
    }

    /**
     * Called when a package is added or removed
     * Called when a package is added, modified, or removed
     *
     * @param uid - uid of modified package (only app-id matters)
     * @param packageName - the (new) packageName
     * @param packageState - the (new) packageState
     * @param isRemove - true if the package is being removed, false if it is being added
     */
    public void onModifyPackageState(int uid, String packageName, boolean isRemove) {
    public void onModifyPackageState(int uid, PackageState packageState, boolean isRemove) {
        // No point in maintaining package mappings for uids of different users
        uid = UserHandle.getAppId(uid);
        synchronized (mLock) {
            // Update state
            Set<String> packages;
            Map<String, PackageState> packages;
            if (!isRemove) {
                packages = mPackageMap.computeIfAbsent(uid, unused -> new ArraySet(1));
                packages.add(packageName);
                packages = mPackageMap.computeIfAbsent(uid, unused -> new HashMap<>());
                if (packageState.equals(packages.put(packageState.packageName, packageState))) {
                    // no change
                    return;
                }
            } else {
                packages = mPackageMap.get(uid);
                if (packages != null) {
                    packages.remove(packageName);
                    if (packages.isEmpty()) mPackageMap.remove(uid);
                    if (packages.remove(packageState.packageName) == null) {
                        // no change
                        return;
                    }
                    if (packages.isEmpty()) {
                        mPackageMap.remove(uid);
                    }
                } else {
                    // no change
                    return;
                }
            }
            // Push state to destination
            if (mDest == null) {
                // Will re-sync when service is back online
                return;
            }
            var state = new UidPackageState();
            state.uid = uid;
            state.packageNames = packages != null ? List.copyOf(packages) : Collections.emptyList();
            state.packageStates = List.copyOf(packages.values());
            try {
                mDest.updatePackagesForUid(state);
            } catch (RemoteException e) {
@@ -230,10 +241,9 @@ public class AudioServerPermissionProvider {
    public void setIsolatedServiceUid(int uid, int owningUid) {
        synchronized (mLock) {
            if (mHdsUid == uid) return;
            var packageNameSet = mPackageMap.get(UserHandle.getAppId(owningUid));
            if (packageNameSet != null) {
                var packageName = packageNameSet.iterator().next();
                onModifyPackageState(uid, packageName, /* isRemove= */ false);
            var packages = mPackageMap.get(UserHandle.getAppId(owningUid));
            if (packages != null) { var packageState = packages.values().iterator().next();
                onModifyPackageState(uid, packageState, /* isRemove= */ false);
            } else {
                Log.wtf(TAG, "setIsolatedService owning uid not found");
            }
@@ -263,16 +273,16 @@ public class AudioServerPermissionProvider {

    public void clearIsolatedServiceUid(int uid) {
        synchronized (mLock) {
            var packageNameSet = mPackageMap.get(UserHandle.getAppId(uid));
            var packages = mPackageMap.get(UserHandle.getAppId(uid));
            if (mHdsUid != uid) {
                Log.wtf(TAG,
                        "Unexpected isolated service uid cleared: " + uid + packageNameSet
                        "Unexpected isolated service uid cleared: " + uid + packages
                                + ", expected " + mHdsUid);
                return;
            }
            if (packageNameSet != null) {
                var packageName = packageNameSet.iterator().next();
                onModifyPackageState(uid, packageName, /* isRemove= */ true);
            if (packages != null) {
                var packageState = packages.values().iterator().next();
                onModifyPackageState(uid, packageState, /* isRemove= */ true);
            } else {
                Log.wtf(TAG, "clearIsolatedService uid not found");
            }
@@ -319,7 +329,7 @@ public class AudioServerPermissionProvider {
                                entry -> {
                                    UidPackageState state = new UidPackageState();
                                    state.uid = entry.getKey();
                                    state.packageNames = List.copyOf(entry.getValue());
                                    state.packageStates = List.copyOf(entry.getValue().values());
                                    return state;
                                })
                        .toList();
@@ -361,23 +371,4 @@ public class AudioServerPermissionProvider {
        Arrays.sort(unwrapped);
        return unwrapped;
    }

    /**
     * Aggregation operation on all package states list: groups by states by app-id and merges the
     * packageName for each state into an ArraySet.
     */
    private static Map<Integer, Set<String>> generatePackageMappings(
            Collection<PackageState> appInfos) {
        Collector<PackageState, Object, Set<String>> reducer =
                Collectors.mapping(
                        (PackageState p) -> p.getPackageName(),
                        Collectors.toCollection(() -> new ArraySet(1)));

        return appInfos.stream()
                .collect(
                        Collectors.groupingBy(
                                /* predicate */ (PackageState p) -> p.getAppId(),
                                /* factory */ HashMap::new,
                                /* downstream collector */ reducer));
    }
}
+49 −5
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import static android.Manifest.permission.QUERY_AUDIO_STATE;
import static android.Manifest.permission.WRITE_SETTINGS;
import static android.app.BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT;
import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_PACKAGE_REPLACED;
import static android.content.Intent.EXTRA_ARCHIVAL;
import static android.content.Intent.EXTRA_REPLACING;
import static android.media.AudioDeviceInfo.TYPE_BLUETOOTH_A2DP;
@@ -123,6 +124,7 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -266,6 +268,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.media.permission.UidPackageState;
import com.android.modules.expresslog.Counter;
import com.android.server.EventLogTags;
import com.android.server.LocalManagerRegistry;
@@ -314,6 +317,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BooleanSupplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;
/**
@@ -13626,16 +13630,51 @@ public class AudioService extends IAudioService.Stub
    private static final String mMetricsId = MediaMetrics.Name.AUDIO_SERVICE
            + MediaMetrics.SEPARATOR;
    /*
     * Create AIDL defined package state for audioserver
     */
    @VisibleForTesting
    static UidPackageState.PackageState makePackageState(PackageState p) {
        final var ret = new UidPackageState.PackageState();
        ret.packageName = p.getPackageName();
        ret.targetSdk = p.getTargetSdkVersion();
        ret.isPlaybackCaptureAllowed = p.isAudioPlaybackCaptureAllowed();
        return ret;
    }
    /**
     * Aggregation operation on all package states list: groups by states by app-id and merges the
     * packages per app-id into a Map keyed by the packageName.
     */
    @VisibleForTesting
    static Map<Integer, Map<String, UidPackageState.PackageState>> generatePackageMap(
            Collection<PackageState> appInfos) {
        Collector<PackageState, Object, Map<String, UidPackageState.PackageState>> reducer =
                Collectors.toMap(p -> p.getPackageName(), /* key */
                                 AudioService::makePackageState, /* val */
                                 (x, y) -> x, /* mergeFunc, x,y should be identical */
                                 () -> new ArrayMap(1) /* factory */);
        return appInfos.stream()
                .collect(
                        Collectors.groupingBy(
                                /* predicate */ (PackageState p) -> p.getAppId(),
                                /* factory */ HashMap::new,
                                /* downstream collector */ reducer));
    }
    private static AudioServerPermissionProvider initializeAudioServerPermissionProvider(
            Context context, AudioPolicyFacade audioPolicy, Executor audioserverExecutor) {
        Collection<PackageState> packageStates = null;
        try (PackageManagerLocal.UnfilteredSnapshot snapshot =
        Map<Integer, Map<String, UidPackageState.PackageState>> packageStates = null;
        try (var snapshot =
                    LocalManagerRegistry.getManager(PackageManagerLocal.class)
                        .withUnfilteredSnapshot()) {
            packageStates = snapshot.getPackageStates().values();
            packageStates = generatePackageMap(snapshot.getPackageStates().values());
        }
        var umi = LocalServices.getService(UserManagerInternal.class);
        var pmsi = LocalServices.getService(PermissionManagerServiceInternal.class);
        var pmi = LocalServices.getService(PackageManagerInternal.class);
        var provider = new AudioServerPermissionProvider(packageStates,
                (Integer uid, String perm) -> ActivityManager.checkComponentPermission(perm, uid,
                        /* owningUid = */ -1, /* exported */true)
@@ -13650,6 +13689,7 @@ public class AudioService extends IAudioService.Stub
        IntentFilter packageUpdateFilter = new IntentFilter();
        packageUpdateFilter.addAction(ACTION_PACKAGE_ADDED);
        packageUpdateFilter.addAction(ACTION_PACKAGE_REPLACED);
        packageUpdateFilter.addDataScheme("package");
        context.registerReceiverForAllUsers(new BroadcastReceiver() {
@@ -13662,9 +13702,13 @@ public class AudioService extends IAudioService.Stub
                    intent.getBooleanExtra(EXTRA_REPLACING, false) + " archival: " +
                    intent.getBooleanExtra(EXTRA_ARCHIVAL, false) + " for package " +
                    pkgName + " with uid " + uid);
                if (ACTION_PACKAGE_ADDED.equals(action)) {
                if (ACTION_PACKAGE_ADDED.equals(action)
                        || ACTION_PACKAGE_REPLACED.equals(action)) {
                    audioserverExecutor.execute(() ->
                            provider.onModifyPackageState(uid, pkgName, false /* isRemoved */));
                            provider.onModifyPackageState(
                                uid,
                                makePackageState(pmi.getPackageStateInternal(pkgName)),
                                false /* isRemoved */));
                }
            }
        }, packageUpdateFilter, null, null); // main thread is fine, since dispatch on executor
+213 −130

File changed.

Preview size limit exceeded, changes collapsed.