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

Commit 73e55b38 authored by Paul Hadfield's avatar Paul Hadfield Committed by Automerger Merge Worker
Browse files

Merge "Fix onPackageChanged handling of disabled packages" into tm-dev am: c65678a3

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17105465

Change-Id: I6207c3745a03ffa592f6ac01cc6219779abd0fee
parents d19b21b1 c65678a3
Loading
Loading
Loading
Loading
+52 −2
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

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

    @VisibleForTesting
    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
    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
        // registerTransportsFromPackage() is put inside the synchronized block
        Set<ComponentName> transportComponents = new ArraySet<>(components.length);
        for (String componentName : components) {
            transportComponents.add(new ComponentName(packageName, componentName));
        }
        if (transportComponents.isEmpty()) {
            return;
        }
        synchronized (mTransportLock) {
            mRegisteredTransportsDescriptionMap.keySet().removeIf(transportComponents::contains);
        }
+84 −0
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

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.TransportTestUtils.mockTransport;
import static com.android.server.backup.testing.TransportTestUtils.setUpTransportsForTransportManager;
@@ -311,6 +315,86 @@ public class TransportManagerTest {
                .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
    public void testRegisterAndSelectTransport_whenTransportRegistered() throws Exception {
        TransportManager transportManager =
+20 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.testing.shadows;

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

import android.app.ApplicationPackageManager;
@@ -44,6 +45,7 @@ public class ShadowApplicationPackageManager
    private static final List<PackageInfo> sInstalledPackages = new ArrayList<>();
    private static final Map<String, Integer> sPackageUids = 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
@@ -53,6 +55,7 @@ public class ShadowApplicationPackageManager
    public static void addInstalledPackage(String packageName, PackageInfo packageInfo) {
        sPackageInfos.put(packageName, packageInfo);
        sInstalledPackages.add(packageInfo);
        sPackageAppEnabledStates.put(packageName, Integer.valueOf(COMPONENT_ENABLED_STATE_DEFAULT));
    }

    /**
@@ -76,6 +79,22 @@ public class ShadowApplicationPackageManager
        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
    protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
            throws NameNotFoundException {
@@ -115,6 +134,7 @@ public class ShadowApplicationPackageManager
    public static void reset() {
        sPackageInfos.clear();
        sInstalledPackages.clear();
        sPackageAppEnabledStates.clear();
        org.robolectric.shadows.ShadowApplicationPackageManager.reset();
    }
}