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

Commit 0cbb7cbe authored by Paul Hadfield's avatar Paul Hadfield Committed by Android (Google) Code Review
Browse files

Merge "Fix onPackageChanged handling of disabled packages"

parents a65c5f1b d68bb378
Loading
Loading
Loading
Loading
+52 −2
Original line number Original line Diff line number Diff line
@@ -16,6 +16,9 @@


package com.android.server.backup;
package com.android.server.backup;


import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;

import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.annotation.WorkerThread;
@@ -28,7 +31,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ResolveInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.ArrayMap;
@@ -42,8 +44,8 @@ import com.android.internal.util.Preconditions;
import com.android.server.backup.transport.BackupTransportClient;
import com.android.server.backup.transport.BackupTransportClient;
import com.android.server.backup.transport.OnTransportRegisteredListener;
import com.android.server.backup.transport.OnTransportRegisteredListener;
import com.android.server.backup.transport.TransportConnection;
import com.android.server.backup.transport.TransportConnection;
import com.android.server.backup.transport.TransportConnectionManager;
import com.android.server.backup.transport.TransportConnectionListener;
import com.android.server.backup.transport.TransportConnectionListener;
import com.android.server.backup.transport.TransportConnectionManager;
import com.android.server.backup.transport.TransportNotAvailableException;
import com.android.server.backup.transport.TransportNotAvailableException;
import com.android.server.backup.transport.TransportNotRegisteredException;
import com.android.server.backup.transport.TransportNotRegisteredException;
import com.android.server.backup.transport.TransportStats;
import com.android.server.backup.transport.TransportStats;
@@ -58,6 +60,7 @@ import java.util.function.Predicate;
/** Handles in-memory bookkeeping of all BackupTransport objects. */
/** Handles in-memory bookkeeping of all BackupTransport objects. */
public class TransportManager {
public class TransportManager {
    private static final String TAG = "BackupTransportManager";
    private static final String TAG = "BackupTransportManager";
    private static final boolean MORE_DEBUG = false;


    @VisibleForTesting
    @VisibleForTesting
    public static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
    public static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
@@ -130,14 +133,61 @@ public class TransportManager {
        }
        }
    }
    }


    void onPackageEnabled(String packageName) {
        onPackageAdded(packageName);
    }

    void onPackageDisabled(String packageName) {
        onPackageRemoved(packageName);
    }

    @WorkerThread
    @WorkerThread
    void onPackageChanged(String packageName, String... components) {
    void onPackageChanged(String packageName, String... components) {
        // Determine if the overall package has changed and not just its
        // components - see {@link EXTRA_CHANGED_COMPONENT_NAME_LIST}.  When we
        // know a package was enabled/disabled we'll handle that directly and
        // not continue with onPackageChanged.
        if (components.length == 1 && components[0].equals(packageName)) {
            int enabled;
            try {
                enabled = mPackageManager.getApplicationEnabledSetting(packageName);
            } catch (IllegalArgumentException ex) {
                // packageName doesn't exist: likely due to a race with it being uninstalled.
                if (MORE_DEBUG) {
                    Slog.d(TAG, "Package " + packageName + " was changed, but no longer exists.");
                }
                return;
            }
            switch (enabled) {
                case COMPONENT_ENABLED_STATE_ENABLED: {
                    if (MORE_DEBUG) {
                        Slog.d(TAG, "Package " + packageName + " was enabled.");
                    }
                    onPackageEnabled(packageName);
                    return;
                }
                case COMPONENT_ENABLED_STATE_DISABLED: {
                    if (MORE_DEBUG) {
                        Slog.d(TAG, "Package " + packageName + " was disabled.");
                    }
                    onPackageDisabled(packageName);
                    return;
                }
                default: {
                    Slog.w(TAG, "Package " + packageName + " enabled setting: " + enabled);
                    return;
                }
            }
        }
        // Unfortunately this can't be atomic because we risk a deadlock if
        // Unfortunately this can't be atomic because we risk a deadlock if
        // registerTransportsFromPackage() is put inside the synchronized block
        // registerTransportsFromPackage() is put inside the synchronized block
        Set<ComponentName> transportComponents = new ArraySet<>(components.length);
        Set<ComponentName> transportComponents = new ArraySet<>(components.length);
        for (String componentName : components) {
        for (String componentName : components) {
            transportComponents.add(new ComponentName(packageName, componentName));
            transportComponents.add(new ComponentName(packageName, componentName));
        }
        }
        if (transportComponents.isEmpty()) {
            return;
        }
        synchronized (mTransportLock) {
        synchronized (mTransportLock) {
            mRegisteredTransportsDescriptionMap.keySet().removeIf(transportComponents::contains);
            mRegisteredTransportsDescriptionMap.keySet().removeIf(transportComponents::contains);
        }
        }
+84 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,10 @@


package com.android.server.backup;
package com.android.server.backup;


import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;

import static com.android.server.backup.testing.TransportData.genericTransport;
import static com.android.server.backup.testing.TransportData.genericTransport;
import static com.android.server.backup.testing.TransportTestUtils.mockTransport;
import static com.android.server.backup.testing.TransportTestUtils.mockTransport;
import static com.android.server.backup.testing.TransportTestUtils.setUpTransportsForTransportManager;
import static com.android.server.backup.testing.TransportTestUtils.setUpTransportsForTransportManager;
@@ -311,6 +315,86 @@ public class TransportManagerTest {
                .onTransportRegistered(mTransportA2.transportName, mTransportA2.transportDirName);
                .onTransportRegistered(mTransportA2.transportName, mTransportA2.transportDirName);
    }
    }


    @Test
    public void testOnPackageChanged_whenPackageChanged_packageDisabledUnregistersTransport()
            throws Exception {
        TransportManager transportManager =
                createTransportManagerWithRegisteredTransports(mTransportA1, mTransportB1);
        reset(mListener);

        mContext.getPackageManager()
                .setApplicationEnabledSetting(
                        PACKAGE_A,
                        Integer.valueOf(COMPONENT_ENABLED_STATE_DISABLED),
                        0 /*flags*/);
        transportManager.onPackageChanged(PACKAGE_A, PACKAGE_A);

        assertRegisteredTransports(transportManager, singletonList(mTransportB1));
        verify(mListener, never()).onTransportRegistered(any(), any());
    }

    @Test
    public void testOnPackageChanged_whenPackageChanged_packageEnabledRegistersTransport()
            throws Exception {
        TransportManager transportManager =
                createTransportManagerWithRegisteredTransports(mTransportA1, mTransportB1);
        reset(mListener);

        mContext.getPackageManager()
                .setApplicationEnabledSetting(
                        PACKAGE_A,
                        Integer.valueOf(COMPONENT_ENABLED_STATE_DISABLED),
                        0 /*flags*/);
        transportManager.onPackageChanged(PACKAGE_A, PACKAGE_A);

        assertRegisteredTransports(transportManager, singletonList(mTransportB1));
        verify(mListener, never()).onTransportRegistered(any(), any());

        mContext.getPackageManager()
                .setApplicationEnabledSetting(
                        PACKAGE_A,
                        Integer.valueOf(COMPONENT_ENABLED_STATE_ENABLED),
                        0 /*flags*/);
        transportManager.onPackageChanged(PACKAGE_A, PACKAGE_A);

        assertRegisteredTransports(transportManager, asList(mTransportA1, mTransportB1));
        verify(mListener)
                .onTransportRegistered(mTransportA1.transportName, mTransportA1.transportDirName);
    }

    @Test
    public void testOnPackageChanged_whenPackageChanged_unknownComponentStateIsIgnored()
            throws Exception {
        TransportManager transportManager =
                createTransportManagerWithRegisteredTransports(mTransportA1, mTransportB1);
        reset(mListener);

        mContext.getPackageManager()
                .setApplicationEnabledSetting(
                        PACKAGE_A,
                        Integer.valueOf(COMPONENT_ENABLED_STATE_DEFAULT),
                        0 /*flags*/);
        transportManager.onPackageChanged(PACKAGE_A, PACKAGE_A);

        assertRegisteredTransports(transportManager, asList(mTransportA1, mTransportB1));
        verify(mListener, never()).onTransportRegistered(any(), any());
    }

    @Test
    public void testOnPackageChanged_whenPackageChanged_unknownPackageExceptionIsIgnored()
            throws Exception {
        TransportManager transportManager =
                createTransportManagerWithRegisteredTransports(mTransportA1, mTransportB1);
        reset(mListener);

        // empty packageName triggers Robolectric ApplicationPackageManager to throw
        // exception as if package does not exist.
        transportManager.onPackageChanged("", "");

        assertRegisteredTransports(transportManager, asList(mTransportA1, mTransportB1));
        verify(mListener, never()).onTransportRegistered(any(), any());
    }

    @Test
    @Test
    public void testRegisterAndSelectTransport_whenTransportRegistered() throws Exception {
    public void testRegisterAndSelectTransport_whenTransportRegistered() throws Exception {
        TransportManager transportManager =
        TransportManager transportManager =
+20 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package com.android.server.testing.shadows;
package com.android.server.testing.shadows;


import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.NameNotFoundException;
import static android.content.pm.PackageManager.NameNotFoundException;


import android.app.ApplicationPackageManager;
import android.app.ApplicationPackageManager;
@@ -44,6 +45,7 @@ public class ShadowApplicationPackageManager
    private static final List<PackageInfo> sInstalledPackages = new ArrayList<>();
    private static final List<PackageInfo> sInstalledPackages = new ArrayList<>();
    private static final Map<String, Integer> sPackageUids = new ArrayMap<>();
    private static final Map<String, Integer> sPackageUids = new ArrayMap<>();
    private static final Map<Integer, Map<String, Integer>> sUserPackageUids = new ArrayMap<>();
    private static final Map<Integer, Map<String, Integer>> sUserPackageUids = new ArrayMap<>();
    private static final Map<String, Integer> sPackageAppEnabledStates = new ArrayMap<>();


    /**
    /**
     * Registers the package {@code packageName} to be returned when invoking {@link
     * Registers the package {@code packageName} to be returned when invoking {@link
@@ -53,6 +55,7 @@ public class ShadowApplicationPackageManager
    public static void addInstalledPackage(String packageName, PackageInfo packageInfo) {
    public static void addInstalledPackage(String packageName, PackageInfo packageInfo) {
        sPackageInfos.put(packageName, packageInfo);
        sPackageInfos.put(packageName, packageInfo);
        sInstalledPackages.add(packageInfo);
        sInstalledPackages.add(packageInfo);
        sPackageAppEnabledStates.put(packageName, Integer.valueOf(COMPONENT_ENABLED_STATE_DEFAULT));
    }
    }


    /**
    /**
@@ -76,6 +79,22 @@ public class ShadowApplicationPackageManager
        sUserPackageUids.put(userId, userPackageUids);
        sUserPackageUids.put(userId, userPackageUids);
    }
    }


    @Override
    protected int getApplicationEnabledSetting(String packageName) {
        if (packageName.isEmpty()) {
            throw new IllegalArgumentException("Robo: Package '' does not exist.");
        }
        if (!sPackageAppEnabledStates.containsKey(packageName)) {
            return COMPONENT_ENABLED_STATE_DEFAULT;
        }
        return sPackageAppEnabledStates.get(packageName);
    }

    @Override
    protected void setApplicationEnabledSetting(String packageName, int newState, int flags) {
        sPackageAppEnabledStates.put(packageName, Integer.valueOf(newState));  // flags unused here.
    }

    @Override
    @Override
    protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
    protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
            throws NameNotFoundException {
            throws NameNotFoundException {
@@ -115,6 +134,7 @@ public class ShadowApplicationPackageManager
    public static void reset() {
    public static void reset() {
        sPackageInfos.clear();
        sPackageInfos.clear();
        sInstalledPackages.clear();
        sInstalledPackages.clear();
        sPackageAppEnabledStates.clear();
        org.robolectric.shadows.ShadowApplicationPackageManager.reset();
        org.robolectric.shadows.ShadowApplicationPackageManager.reset();
    }
    }
}
}