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

Commit 880389e6 authored by Philip P. Moltmann's avatar Philip P. Moltmann
Browse files

Clear USB device defaults when user is removed

If a user is removed it is either the parent user of the profile or a
child user. If the parent is removed the whole profile group settings
are removed, but if only a child user is removed we have to remove the
user settings from the groups settings.

Test: Registered a USB device default for a child and parent user and
removed them. Checked dumpsys usb before and after
Fixes: 31995672

Change-Id: I984cd294dc01437b042687684c058eb79332f520
parent 017f1dc5
Loading
Loading
Loading
Loading
+113 −43
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.UserHandle;
import android.os.UserManager;
@@ -42,6 +43,7 @@ import android.util.Log;
import android.util.Slog;
import android.util.Xml;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.Immutable;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.FastXmlSerializer;
@@ -60,7 +62,9 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import libcore.io.IoUtils;

@@ -87,13 +91,23 @@ class UsbProfileGroupSettingsManager {
    private final UserManager mUserManager;
    private final @NonNull UsbSettingsManager mSettingsManager;

    // Maps DeviceFilter to user preferred application package
    /** Maps DeviceFilter to user preferred application package */
    @GuardedBy("mLock")
    private final HashMap<DeviceFilter, UserPackage> mDevicePreferenceMap = new HashMap<>();
    // Maps AccessoryFilter to user preferred application package

    /** Maps AccessoryFilter to user preferred application package */
    @GuardedBy("mLock")
    private final HashMap<AccessoryFilter, UserPackage> mAccessoryPreferenceMap = new HashMap<>();

    private final Object mLock = new Object();

    /**
     * If a async task to persist the mDevicePreferenceMap and mAccessoryPreferenceMap is currently
     * scheduled.
     */
    @GuardedBy("mLock")
    private boolean mIsWriteSettingsScheduled;

    /**
     * A package of a user.
     */
@@ -591,6 +605,42 @@ class UsbProfileGroupSettingsManager {
                });
    }

    /**
     * Remove all defaults for a user.
     *
     * @param userToRemove The user the defaults belong to.
     */
    void removeAllDefaultsForUser(@NonNull UserHandle userToRemove) {
        synchronized (mLock) {
            boolean needToPersist = false;
            Iterator<Map.Entry<DeviceFilter, UserPackage>> devicePreferenceIt = mDevicePreferenceMap
                    .entrySet().iterator();
            while (devicePreferenceIt.hasNext()) {
                Map.Entry<DeviceFilter, UserPackage> entry = devicePreferenceIt.next();

                if (entry.getValue().user.equals(userToRemove)) {
                    devicePreferenceIt.remove();
                    needToPersist = true;
                }
            }

            Iterator<Map.Entry<AccessoryFilter, UserPackage>> accessoryPreferenceIt =
                    mAccessoryPreferenceMap.entrySet().iterator();
            while (accessoryPreferenceIt.hasNext()) {
                Map.Entry<AccessoryFilter, UserPackage> entry = accessoryPreferenceIt.next();

                if (entry.getValue().user.equals(userToRemove)) {
                    accessoryPreferenceIt.remove();
                    needToPersist = true;
                }
            }

            if (needToPersist) {
                scheduleWriteSettingsLocked();
            }
        }
    }

    private void readPreference(XmlPullParser parser)
            throws XmlPullParserException, IOException {
        String packageName = null;
@@ -657,7 +707,7 @@ class UsbProfileGroupSettingsManager {
                IoUtils.closeQuietly(fis);
            }

            writeSettingsLocked();
            scheduleWriteSettingsLocked();

            // Success or failure, we delete single-user file
            sSingleUserSettingsFile.delete();
@@ -695,9 +745,23 @@ class UsbProfileGroupSettingsManager {
        }
    }

    private void writeSettingsLocked() {
        if (DEBUG) Slog.v(TAG, "writeSettingsLocked()");
    /**
     * Schedule a async task to persist {@link #mDevicePreferenceMap} and
     * {@link #mAccessoryPreferenceMap}. If a task is already scheduled but not completed, do
     * nothing as the currently scheduled one will do the work.
     * <p>Called with {@link #mLock} held.</p>
     * <p>In the uncommon case that the system crashes in between the scheduling and the write the
     * update is lost.</p>
     */
    private void scheduleWriteSettingsLocked() {
        if (mIsWriteSettingsScheduled) {
            return;
        } else {
            mIsWriteSettingsScheduled = true;
        }

        AsyncTask.execute(() -> {
            synchronized (mLock) {
                FileOutputStream fos = null;
                try {
                    fos = mSettingsFile.startWrite();
@@ -705,12 +769,14 @@ class UsbProfileGroupSettingsManager {
                    FastXmlSerializer serializer = new FastXmlSerializer();
                    serializer.setOutput(fos, StandardCharsets.UTF_8.name());
                    serializer.startDocument(null, true);
            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
                    serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
                                    true);
                    serializer.startTag(null, "settings");

                    for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
                        serializer.startTag(null, "preference");
                serializer.attribute(null, "package", mDevicePreferenceMap.get(filter).packageName);
                        serializer.attribute(null, "package",
                                mDevicePreferenceMap.get(filter).packageName);
                        serializer.attribute(null, "user",
                                String.valueOf(getSerial(mDevicePreferenceMap.get(filter).user)));
                        filter.write(serializer);
@@ -721,8 +787,8 @@ class UsbProfileGroupSettingsManager {
                        serializer.startTag(null, "preference");
                        serializer.attribute(null, "package",
                                mAccessoryPreferenceMap.get(filter).packageName);
                serializer.attribute(null, "user",
                        String.valueOf(getSerial(mAccessoryPreferenceMap.get(filter).user)));
                        serializer.attribute(null, "user", String.valueOf(
                                        getSerial(mAccessoryPreferenceMap.get(filter).user)));
                        filter.write(serializer);
                        serializer.endTag(null, "preference");
                    }
@@ -737,6 +803,10 @@ class UsbProfileGroupSettingsManager {
                        mSettingsFile.failWrite(fos);
                    }
                }

                mIsWriteSettingsScheduled = false;
            }
        });
    }

    // Checks to see if a package matches a device or accessory.
@@ -1141,7 +1211,7 @@ class UsbProfileGroupSettingsManager {
            }

            if (changed) {
                writeSettingsLocked();
                scheduleWriteSettingsLocked();
            }
        }
    }
@@ -1178,7 +1248,7 @@ class UsbProfileGroupSettingsManager {
                }
            }
            if (changed) {
                writeSettingsLocked();
                scheduleWriteSettingsLocked();
            }
        }
    }
@@ -1204,7 +1274,7 @@ class UsbProfileGroupSettingsManager {
                }
            }
            if (changed) {
                writeSettingsLocked();
                scheduleWriteSettingsLocked();
            }
        }
    }
@@ -1237,7 +1307,7 @@ class UsbProfileGroupSettingsManager {

        synchronized (mLock) {
            if (clearPackageDefaultsLocked(userPackage)) {
                writeSettingsLocked();
                scheduleWriteSettingsLocked();
            }
        }
    }
+5 −4
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.usb;

import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
@@ -83,7 +84,7 @@ public class UsbService extends IUsbManager.Stub {

        @Override
        public void onStopUser(int userHandle) {
            mUsbService.onStopUser(userHandle);
            mUsbService.onStopUser(UserHandle.of(userHandle));
        }
    }

@@ -177,10 +178,10 @@ public class UsbService extends IUsbManager.Stub {
    /**
     * Execute operations when a user is stopped.
     *
     * @param stoppedUserId The id of the used that is stopped
     * @param stoppedUser The user that is stopped
     */
    private void onStopUser(@UserIdInt int stoppedUserId) {
        mSettingsManager.remove(stoppedUserId);
    private void onStopUser(@NonNull UserHandle stoppedUser) {
        mSettingsManager.remove(stoppedUser);
    }

    public void systemReady() {
+18 −3
Original line number Diff line number Diff line
@@ -108,11 +108,26 @@ class UsbSettingsManager {
    /**
     * Remove the settings for a user.
     *
     * @param userIdToRemove The user o remove
     * @param userToRemove The user to remove
     */
    void remove(@UserIdInt int userIdToRemove) {
    void remove(@NonNull UserHandle userToRemove) {
        synchronized (mSettingsByUser) {
            mSettingsByUser.remove(userIdToRemove);
            mSettingsByUser.remove(userToRemove.getIdentifier());
        }

        synchronized (mSettingsByProfileGroup) {
            if (mSettingsByProfileGroup.indexOfKey(userToRemove.getIdentifier()) >= 0) {
                // The user to remove is the parent user of the group. The parent is the last user
                // that gets removed. All state will be removed with the user
                mSettingsByProfileGroup.remove(userToRemove.getIdentifier());
            } else {
                // We cannot find the parent user of the user that is removed, hence try to remove
                // it from all profile groups.
                int numProfileGroups = mSettingsByProfileGroup.size();
                for (int i = 0; i < numProfileGroups; i++) {
                    mSettingsByProfileGroup.valueAt(i).removeAllDefaultsForUser(userToRemove);
                }
            }
        }
    }