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

Commit 540e123b authored by Wale Ogunwale's avatar Wale Ogunwale
Browse files

Clean-up component states in AMS when component is disabled

Bug: 15804187
Change-Id: I2b5856c5a0a012f34698fb64f8596d32924bbd1f
parent 3974fb23
Loading
Loading
Loading
Loading
+41 −33
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import android.app.ActivityThread;
import android.os.Build;
@@ -119,14 +120,13 @@ public final class ActiveServices {
    // at the same time.
    final int mMaxStartingBackground;

    final SparseArray<ServiceMap> mServiceMap = new SparseArray<ServiceMap>();
    final SparseArray<ServiceMap> mServiceMap = new SparseArray<>();

    /**
     * All currently bound service connections.  Keys are the IBinder of
     * the client's IServiceConnection.
     */
    final ArrayMap<IBinder, ArrayList<ConnectionRecord>> mServiceConnections
            = new ArrayMap<IBinder, ArrayList<ConnectionRecord>>();
    final ArrayMap<IBinder, ArrayList<ConnectionRecord>> mServiceConnections = new ArrayMap<>();

    /**
     * List of services that we have been asked to start,
@@ -134,20 +134,20 @@ public final class ActiveServices {
     * while waiting for their corresponding application thread to get
     * going.
     */
    final ArrayList<ServiceRecord> mPendingServices
            = new ArrayList<ServiceRecord>();
    final ArrayList<ServiceRecord> mPendingServices = new ArrayList<>();

    /**
     * List of services that are scheduled to restart following a crash.
     */
    final ArrayList<ServiceRecord> mRestartingServices
            = new ArrayList<ServiceRecord>();
    final ArrayList<ServiceRecord> mRestartingServices = new ArrayList<>();

    /**
     * List of services that are in the process of being destroyed.
     */
    final ArrayList<ServiceRecord> mDestroyingServices
            = new ArrayList<ServiceRecord>();
    final ArrayList<ServiceRecord> mDestroyingServices = new ArrayList<>();

    /** Temporary list for holding the results of calls to {@link #collectPackageServicesLocked} */
    private ArrayList<ServiceRecord> mTmpCollectionResults = null;

    /** Amount of time to allow a last ANR message to exist before freeing the memory. */
    static final int LAST_ANR_LIFETIME_DURATION_MSECS = 2 * 60 * 60 * 1000; // Two hours
@@ -162,10 +162,6 @@ public final class ActiveServices {
        }
    };

    static final class DelayingProcess extends ArrayList<ServiceRecord> {
        long timeoout;
    }

    /**
     * Information about services for a single user.
     */
@@ -2076,14 +2072,16 @@ public final class ActiveServices {
        }
    }

    private boolean collectForceStopServicesLocked(String name, int userId,
            boolean evenPersistent, boolean doit,
            ArrayMap<ComponentName, ServiceRecord> services,
            ArrayList<ServiceRecord> result) {
    private boolean collectPackageServicesLocked(String packageName, Set<String> filterByClasses,
            boolean evenPersistent, boolean doit, ArrayMap<ComponentName, ServiceRecord> services) {
        boolean didSomething = false;
        for (int i=0; i<services.size(); i++) {
        for (int i = services.size() - 1; i >= 0; i--) {
            ServiceRecord service = services.valueAt(i);
            if ((name == null || service.packageName.equals(name))
            final boolean sameComponent = packageName == null
                    || (service.packageName.equals(packageName)
                        && (filterByClasses == null
                            || filterByClasses.contains(service.name.getClassName())));
            if (sameComponent
                    && (service.app == null || evenPersistent || !service.app.persistent)) {
                if (!doit) {
                    return true;
@@ -2098,19 +2096,27 @@ public final class ActiveServices {
                }
                service.app = null;
                service.isolatedProc = null;
                result.add(service);
                if (mTmpCollectionResults == null) {
                    mTmpCollectionResults = new ArrayList<>();
                }
                mTmpCollectionResults.add(service);
            }
        }
        return didSomething;
    }

    boolean forceStopLocked(String name, int userId, boolean evenPersistent, boolean doit) {
    boolean bringDownDisabledPackageServicesLocked(String packageName, Set<String> filterByClasses,
            int userId, boolean evenPersistent, boolean doit) {
        boolean didSomething = false;
        ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();

        if (mTmpCollectionResults != null) {
            mTmpCollectionResults.clear();
        }

        if (userId == UserHandle.USER_ALL) {
            for (int i=0; i<mServiceMap.size(); i++) {
                didSomething |= collectForceStopServicesLocked(name, userId, evenPersistent,
                        doit, mServiceMap.valueAt(i).mServicesByName, services);
            for (int i = mServiceMap.size() - 1; i >= 0; i--) {
                didSomething |= collectPackageServicesLocked(packageName, filterByClasses,
                        evenPersistent, doit, mServiceMap.valueAt(i).mServicesByName);
                if (!doit && didSomething) {
                    return true;
                }
@@ -2119,22 +2125,24 @@ public final class ActiveServices {
            ServiceMap smap = mServiceMap.get(userId);
            if (smap != null) {
                ArrayMap<ComponentName, ServiceRecord> items = smap.mServicesByName;
                didSomething = collectForceStopServicesLocked(name, userId, evenPersistent,
                        doit, items, services);
                didSomething = collectPackageServicesLocked(packageName, filterByClasses,
                        evenPersistent, doit, items);
            }
        }

        int N = services.size();
        for (int i=0; i<N; i++) {
            bringDownServiceLocked(services.get(i));
        if (mTmpCollectionResults != null) {
            for (int i = mTmpCollectionResults.size() - 1; i >= 0; i--) {
                bringDownServiceLocked(mTmpCollectionResults.get(i));
            }
            mTmpCollectionResults.clear();
        }
        return didSomething;
    }

    void cleanUpRemovedTaskLocked(TaskRecord tr, ComponentName component, Intent baseIntent) {
        ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
        ArrayList<ServiceRecord> services = new ArrayList<>();
        ArrayMap<ComponentName, ServiceRecord> alls = getServices(tr.userId);
        for (int i=0; i<alls.size(); i++) {
        for (int i = alls.size() - 1; i >= 0; i--) {
            ServiceRecord sr = alls.valueAt(i);
            if (sr.packageName.equals(component.getPackageName())) {
                services.add(sr);
@@ -2142,7 +2150,7 @@ public final class ActiveServices {
        }

        // Take care of any running services associated with the app.
        for (int i=0; i<services.size(); i++) {
        for (int i = services.size() - 1; i >= 0; i--) {
            ServiceRecord sr = services.get(i);
            if (sr.startRequested) {
                if ((sr.serviceInfo.flags&ServiceInfo.FLAG_STOP_WITH_TASK) != 0) {
+116 −47
Original line number Diff line number Diff line
@@ -5363,27 +5363,105 @@ public final class ActivityManagerService extends ActivityManagerNative
        return N > 0;
    }
    private final boolean forceStopPackageLocked(String name, int appId,
    private void cleanupDisabledPackageComponentsLocked(
            String packageName, int userId, String[] changedClasses) {
        Set<String> disabledClasses = null;
        boolean packageDisabled = false;
        IPackageManager pm = AppGlobals.getPackageManager();
        if (changedClasses == null) {
            // Nothing changed...
            return;
        }
        // Determine enable/disable state of the package and its components.
        int enabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
        for (int i = changedClasses.length - 1; i >= 0; i--) {
            final String changedClass = changedClasses[i];
            if (changedClass.equals(packageName)) {
                try {
                    // Entire package setting changed
                    enabled = pm.getApplicationEnabledSetting(packageName,
                            (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_OWNER);
                } catch (RemoteException e) {
                    // Can't happen...
                }
                packageDisabled = enabled != PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                        && enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
                if (packageDisabled) {
                    // Entire package is disabled.
                    // No need to continue to check component states.
                    disabledClasses = null;
                    break;
                }
            } else {
                try {
                    enabled = pm.getComponentEnabledSetting(
                            new ComponentName(packageName, changedClass),
                            (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_OWNER);
                } catch (RemoteException e) {
                    // Can't happen...
                }
                if (enabled != PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                        && enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
                    if (disabledClasses == null) {
                        disabledClasses = new ArraySet<>(changedClasses.length);
                    }
                    disabledClasses.add(changedClass);
                }
            }
        }
        if (!packageDisabled && disabledClasses == null) {
            // Nothing to do here...
            return;
        }
        // Clean-up disabled activities.
        if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
                packageName, disabledClasses, true, false, userId) && mBooted) {
            mStackSupervisor.resumeTopActivitiesLocked();
            mStackSupervisor.scheduleIdleLocked();
        }
        // Clean-up disabled tasks
        cleanupDisabledPackageTasksLocked(packageName, disabledClasses, userId);
        // Clean-up disabled services.
        mServices.bringDownDisabledPackageServicesLocked(
                packageName, disabledClasses, userId, false, true);
        // Clean-up disabled providers.
        ArrayList<ContentProviderRecord> providers = new ArrayList<>();
        mProviderMap.collectPackageProvidersLocked(
                packageName, disabledClasses, true, false, userId, providers);
        for (int i = providers.size() - 1; i >= 0; i--) {
            removeDyingProviderLocked(null, providers.get(i), true);
        }
    }
    private final boolean forceStopPackageLocked(String packageName, int appId,
            boolean callerWillRestart, boolean purgeCache, boolean doit,
            boolean evenPersistent, boolean uninstalling, int userId, String reason) {
        int i;
        int N;
        if (userId == UserHandle.USER_ALL && name == null) {
        if (userId == UserHandle.USER_ALL && packageName == null) {
            Slog.w(TAG, "Can't force stop all processes of all users, that is insane!");
        }
        if (appId < 0 && name != null) {
        if (appId < 0 && packageName != null) {
            try {
                appId = UserHandle.getAppId(
                        AppGlobals.getPackageManager().getPackageUid(name, 0));
                        AppGlobals.getPackageManager().getPackageUid(packageName, 0));
            } catch (RemoteException e) {
            }
        }
        if (doit) {
            if (name != null) {
                Slog.i(TAG, "Force stopping " + name + " appid=" + appId
            if (packageName != null) {
                Slog.i(TAG, "Force stopping " + packageName + " appid=" + appId
                        + " user=" + userId + ": " + reason);
            } else {
                Slog.i(TAG, "Force stopping u" + userId + ": " + reason);
@@ -5395,7 +5473,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                for (i = ba.size() - 1; i >= 0; i--) {
                    boolean remove = false;
                    final int entUid = ba.keyAt(i);
                    if (name != null) {
                    if (packageName != null) {
                        if (userId == UserHandle.USER_ALL) {
                            if (UserHandle.getAppId(entUid) == appId) {
                                remove = true;
@@ -5418,46 +5496,47 @@ public final class ActivityManagerService extends ActivityManagerNative
            }
        }
        boolean didSomething = killPackageProcessesLocked(name, appId, userId,
        boolean didSomething = killPackageProcessesLocked(packageName, appId, userId,
                -100, callerWillRestart, true, doit, evenPersistent,
                name == null ? ("stop user " + userId) : ("stop " + name));
                packageName == null ? ("stop user " + userId) : ("stop " + packageName));
        if (mStackSupervisor.forceStopPackageLocked(name, doit, evenPersistent, userId)) {
        if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
                packageName, null, doit, evenPersistent, userId)) {
            if (!doit) {
                return true;
            }
            didSomething = true;
        }
        if (mServices.forceStopLocked(name, userId, evenPersistent, doit)) {
        if (mServices.bringDownDisabledPackageServicesLocked(
                packageName, null, userId, evenPersistent, doit)) {
            if (!doit) {
                return true;
            }
            didSomething = true;
        }
        if (name == null) {
        if (packageName == null) {
            // Remove all sticky broadcasts from this user.
            mStickyBroadcasts.remove(userId);
        }
        ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
        if (mProviderMap.collectForceStopProviders(name, appId, doit, evenPersistent,
        ArrayList<ContentProviderRecord> providers = new ArrayList<>();
        if (mProviderMap.collectPackageProvidersLocked(packageName, null, doit, evenPersistent,
                userId, providers)) {
            if (!doit) {
                return true;
            }
            didSomething = true;
        }
        N = providers.size();
        for (i=0; i<N; i++) {
        for (i = providers.size() - 1; i >= 0; i--) {
            removeDyingProviderLocked(null, providers.get(i), true);
        }
        // Remove transient permissions granted from/to this package/user
        removeUriPermissionsForPackageLocked(name, userId, false);
        removeUriPermissionsForPackageLocked(packageName, userId, false);
        if (name == null || uninstalling) {
        if (packageName == null || uninstalling) {
            // Remove pending intents.  For now we only do this when force
            // stopping users, because we have some problems when doing this
            // for packages -- app widgets are not currently cleaned up for
@@ -5476,7 +5555,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                        it.remove();
                        continue;
                    }
                    if (name == null) {
                    if (packageName == null) {
                        // Stopping user, remove all objects for the user.
                        if (pir.key.userId != userId) {
                            // Not the same user, skip it.
@@ -5491,7 +5570,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                            // Different user, skip it.
                            continue;
                        }
                        if (!pir.key.packageName.equals(name)) {
                        if (!pir.key.packageName.equals(packageName)) {
                            // Different package, skip it.
                            continue;
                        }
@@ -5510,10 +5589,10 @@ public final class ActivityManagerService extends ActivityManagerNative
        }
        if (doit) {
            if (purgeCache && name != null) {
            if (purgeCache && packageName != null) {
                AttributeCache ac = AttributeCache.instance();
                if (ac != null) {
                    ac.removePackage(name);
                    ac.removePackage(packageName);
                }
            }
            if (mBooted) {
@@ -8331,30 +8410,21 @@ public final class ActivityManagerService extends ActivityManagerNative
        }
    }
    private void removeTasksByRemovedPackageComponentsLocked(String packageName, int userId) {
        final IPackageManager pm = AppGlobals.getPackageManager();
        final HashSet<ComponentName> componentsKnownToExist = new HashSet<ComponentName>();
    private void cleanupDisabledPackageTasksLocked(String packageName, Set<String> filterByClasses,
            int userId) {
        for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
            TaskRecord tr = mRecentTasks.get(i);
            if (tr.userId != userId) continue;
            if (userId != UserHandle.USER_ALL && tr.userId != userId) {
                continue;
            }
            ComponentName cn = tr.intent.getComponent();
            if (cn != null && cn.getPackageName().equals(packageName)) {
                // Skip if component still exists in the package.
                if (componentsKnownToExist.contains(cn)) continue;
                try {
                    ActivityInfo info = pm.getActivityInfo(cn, 0, userId);
                    if (info != null) {
                        componentsKnownToExist.add(cn);
                    } else {
            final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName)
                    && (filterByClasses == null || filterByClasses.contains(cn.getClassName()));
            if (sameComponent) {
                removeTaskByIdLocked(tr.taskId, false);
            }
                } catch (RemoteException e) {
                    Log.e(TAG, "Activity info query failed. component=" + cn, e);
                }
            }
        }
    }
@@ -16071,7 +16141,9 @@ public final class ActivityManagerService extends ActivityManagerNative
                                        mBatteryStatsService.notePackageUninstalled(ssp);
                                    }
                                } else {
                                    removeTasksByRemovedPackageComponentsLocked(ssp, userId);
                                    cleanupDisabledPackageComponentsLocked(ssp, userId,
                                            intent.getStringArrayExtra(
                                                    Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST));
                                    if (userId == UserHandle.USER_OWNER) {
                                        mTaskPersister.addOtherDeviceTasksToRecentsLocked(ssp);
                                    }
@@ -16089,9 +16161,6 @@ public final class ActivityManagerService extends ActivityManagerNative
                                intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                        mCompatModePackages.handlePackageAddedLocked(ssp, replacing);
                        if (replacing) {
                            removeTasksByRemovedPackageComponentsLocked(ssp, userId);
                        }
                        if (userId == UserHandle.USER_OWNER) {
                            mTaskPersister.addOtherDeviceTasksToRecentsLocked(ssp);
                        }
+9 −5
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * State and management of a single stack of activities.
@@ -4000,7 +4001,8 @@ final class ActivityStack {
        }
    }

    boolean forceStopPackageLocked(String name, boolean doit, boolean evenPersistent, int userId) {
    boolean finishDisabledPackageActivitiesLocked(String packageName, Set<String> filterByClasses,
            boolean doit, boolean evenPersistent, int userId) {
        boolean didSomething = false;
        TaskRecord lastTask = null;
        ComponentName homeActivity = null;
@@ -4009,10 +4011,12 @@ final class ActivityStack {
            int numActivities = activities.size();
            for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
                ActivityRecord r = activities.get(activityNdx);
                final boolean samePackage = r.packageName.equals(name)
                        || (name == null && r.userId == userId);
                final boolean sameComponent =
                        (r.packageName.equals(packageName) && (filterByClasses == null
                                || filterByClasses.contains(r.realActivity.getClassName())))
                        || (packageName == null && r.userId == userId);
                if ((userId == UserHandle.USER_ALL || r.userId == userId)
                        && (samePackage || r.task == lastTask)
                        && (sameComponent || r.task == lastTask)
                        && (r.app == null || evenPersistent || !r.app.persistent)) {
                    if (!doit) {
                        if (r.finishing) {
@@ -4032,7 +4036,7 @@ final class ActivityStack {
                    }
                    didSomething = true;
                    Slog.i(TAG, "  Force finishing activity " + r);
                    if (samePackage) {
                    if (sameComponent) {
                        if (r.app != null) {
                            r.app.removed = true;
                        }
+5 −2
Original line number Diff line number Diff line
@@ -118,6 +118,7 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public final class ActivityStackSupervisor implements DisplayListener {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
@@ -2507,14 +2508,16 @@ public final class ActivityStackSupervisor implements DisplayListener {
    /**
     * @return true if some activity was finished (or would have finished if doit were true).
     */
    boolean forceStopPackageLocked(String name, boolean doit, boolean evenPersistent, int userId) {
    boolean finishDisabledPackageActivitiesLocked(String packageName, Set<String> filterByClasses,
            boolean doit, boolean evenPersistent, int userId) {
        boolean didSomething = false;
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            final int numStacks = stacks.size();
            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
                final ActivityStack stack = stacks.get(stackNdx);
                if (stack.forceStopPackageLocked(name, doit, evenPersistent, userId)) {
                if (stack.finishDisabledPackageActivitiesLocked(
                        packageName, filterByClasses, doit, evenPersistent, userId)) {
                    didSomething = true;
                }
            }
+2 −2
Original line number Diff line number Diff line
@@ -85,7 +85,7 @@ public final class BroadcastQueue {
     * a bunch of processes to execute IntentReceiver components.  Background-
     * and foreground-priority broadcasts are queued separately.
     */
    final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<BroadcastRecord>();
    final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();

    /**
     * List of all active broadcasts that are to be executed one at a time.
@@ -94,7 +94,7 @@ public final class BroadcastQueue {
     * broadcasts, separate background- and foreground-priority queues are
     * maintained.
     */
    final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<BroadcastRecord>();
    final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();

    /**
     * Historical data of past broadcasts, for debugging.  This is a ring buffer
Loading