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

Commit 92d6bc4d authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Cancel all jobs associated with an uninstalled app."

parents 0feb3ca3 13c5ea1f
Loading
Loading
Loading
Loading
+37 −11
Original line number Original line Diff line number Diff line
@@ -882,6 +882,8 @@ public class JobSchedulerService extends com.android.server.SystemService
                                            // a user-initiated action, it should be fine to just
                                            // a user-initiated action, it should be fine to just
                                            // put USER instead of UNINSTALL or DISABLED.
                                            // put USER instead of UNINSTALL or DISABLED.
                                            cancelJobsForPackageAndUidLocked(pkgName, pkgUid,
                                            cancelJobsForPackageAndUidLocked(pkgName, pkgUid,
                                                    /* includeSchedulingApp */ true,
                                                    /* includeSourceApp */ true,
                                                    JobParameters.STOP_REASON_USER,
                                                    JobParameters.STOP_REASON_USER,
                                                    JobParameters.INTERNAL_STOP_REASON_UNINSTALL,
                                                    JobParameters.INTERNAL_STOP_REASON_UNINSTALL,
                                                    "app disabled");
                                                    "app disabled");
@@ -932,6 +934,7 @@ public class JobSchedulerService extends com.android.server.SystemService
                    // get here, but since this is generally a user-initiated action, it should
                    // get here, but since this is generally a user-initiated action, it should
                    // be fine to just put USER instead of UNINSTALL or DISABLED.
                    // be fine to just put USER instead of UNINSTALL or DISABLED.
                    cancelJobsForPackageAndUidLocked(pkgName, pkgUid,
                    cancelJobsForPackageAndUidLocked(pkgName, pkgUid,
                            /* includeSchedulingApp */ true, /* includeSourceApp */ true,
                            JobParameters.STOP_REASON_USER,
                            JobParameters.STOP_REASON_USER,
                            JobParameters.INTERNAL_STOP_REASON_UNINSTALL, "app uninstalled");
                            JobParameters.INTERNAL_STOP_REASON_UNINSTALL, "app uninstalled");
                    for (int c = 0; c < mControllers.size(); ++c) {
                    for (int c = 0; c < mControllers.size(); ++c) {
@@ -986,7 +989,12 @@ public class JobSchedulerService extends com.android.server.SystemService
                        Slog.d(TAG, "Removing jobs for pkg " + pkgName + " at uid " + pkgUid);
                        Slog.d(TAG, "Removing jobs for pkg " + pkgName + " at uid " + pkgUid);
                    }
                    }
                    synchronized (mLock) {
                    synchronized (mLock) {
                        // Exclude jobs scheduled on behalf of this app for now because SyncManager
                        // and other job proxy agents may not know to reschedule the job properly
                        // after force stop.
                        // TODO(209852664): determine how to best handle syncs & other proxied jobs
                        cancelJobsForPackageAndUidLocked(pkgName, pkgUid,
                        cancelJobsForPackageAndUidLocked(pkgName, pkgUid,
                                /* includeSchedulingApp */ true, /* includeSourceApp */ false,
                                JobParameters.STOP_REASON_USER,
                                JobParameters.STOP_REASON_USER,
                                JobParameters.INTERNAL_STOP_REASON_CANCELED,
                                JobParameters.INTERNAL_STOP_REASON_CANCELED,
                                "app force stopped");
                                "app force stopped");
@@ -1304,16 +1312,18 @@ public class JobSchedulerService extends com.android.server.SystemService
        }
        }
    }
    }


    private void cancelJobsForUserLocked(int userHandle) {
    private final Consumer<JobStatus> mCancelJobDueToUserRemovalConsumer = (toRemove) -> {
        final List<JobStatus> jobsForUser = mJobs.getJobsByUser(userHandle);
        // There's no guarantee that the process has been stopped by the time we get
        for (int i = 0; i < jobsForUser.size(); i++) {
        // here, but since this is a user-initiated action, it should be fine to just
            JobStatus toRemove = jobsForUser.get(i);
        // put USER instead of UNINSTALL or DISABLED.
            // There's no guarantee that the process has been stopped by the time we get here,
            // but since this is a user-initiated action, it should be fine to just put USER
            // instead of UNINSTALL or DISABLED.
        cancelJobImplLocked(toRemove, null, JobParameters.STOP_REASON_USER,
        cancelJobImplLocked(toRemove, null, JobParameters.STOP_REASON_USER,
                JobParameters.INTERNAL_STOP_REASON_UNINSTALL, "user removed");
                JobParameters.INTERNAL_STOP_REASON_UNINSTALL, "user removed");
        }
    };

    private void cancelJobsForUserLocked(int userHandle) {
        mJobs.forEachJob(
                (job) -> job.getUserId() == userHandle || job.getSourceUserId() == userHandle,
                mCancelJobDueToUserRemovalConsumer);
    }
    }


    private void cancelJobsForNonExistentUsers() {
    private void cancelJobsForNonExistentUsers() {
@@ -1324,15 +1334,31 @@ public class JobSchedulerService extends com.android.server.SystemService
    }
    }


    private void cancelJobsForPackageAndUidLocked(String pkgName, int uid,
    private void cancelJobsForPackageAndUidLocked(String pkgName, int uid,
            boolean includeSchedulingApp, boolean includeSourceApp,
            @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
            @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
        if (!includeSchedulingApp && !includeSourceApp) {
            Slog.wtfStack(TAG,
                    "Didn't indicate whether to cancel jobs for scheduling and/or source app");
            includeSourceApp = true;
        }
        if ("android".equals(pkgName)) {
        if ("android".equals(pkgName)) {
            Slog.wtfStack(TAG, "Can't cancel all jobs for system package");
            Slog.wtfStack(TAG, "Can't cancel all jobs for system package");
            return;
            return;
        }
        }
        final List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
        final List<JobStatus> jobsForUid = new ArrayList<>();
        if (includeSchedulingApp) {
            mJobs.getJobsByUid(uid, jobsForUid);
        }
        if (includeSourceApp) {
            mJobs.getJobsBySourceUid(uid, jobsForUid);
        }
        for (int i = jobsForUid.size() - 1; i >= 0; i--) {
        for (int i = jobsForUid.size() - 1; i >= 0; i--) {
            final JobStatus job = jobsForUid.get(i);
            final JobStatus job = jobsForUid.get(i);
            if (job.getSourcePackageName().equals(pkgName)) {
            final boolean shouldCancel =
                    (includeSchedulingApp
                            && job.getServiceComponent().getPackageName().equals(pkgName))
                    || (includeSourceApp && job.getSourcePackageName().equals(pkgName));
            if (shouldCancel) {
                cancelJobImplLocked(job, null, reason, internalReasonCode, debugReason);
                cancelJobImplLocked(job, null, reason, internalReasonCode, debugReason);
            }
            }
        }
        }
+33 −18
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import static com.android.server.job.JobSchedulerService.sSystemClock;
import static com.android.server.job.JobSchedulerService.sSystemClock;


import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.job.JobInfo;
import android.app.job.JobInfo;
import android.content.ComponentName;
import android.content.ComponentName;
@@ -32,7 +33,6 @@ import android.os.Handler;
import android.os.PersistableBundle;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.Process;
import android.os.SystemClock;
import android.os.SystemClock;
import android.os.UserHandle;
import android.text.TextUtils;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.ArraySet;
@@ -287,26 +287,37 @@ public final class JobStore {
    }
    }


    /**
    /**
     * @param userHandle User for whom we are querying the list of jobs.
     * @param sourceUid Uid of the source app.
     * @return A list of all the jobs scheduled for the provided user. Never null.
     * @return A list of all the jobs scheduled for the source app. Never null.
     */
     */
    public List<JobStatus> getJobsByUser(int userHandle) {
    @NonNull
        return mJobSet.getJobsByUser(userHandle);
    public List<JobStatus> getJobsBySourceUid(int sourceUid) {
        return mJobSet.getJobsBySourceUid(sourceUid);
    }

    public void getJobsBySourceUid(int sourceUid, @NonNull List<JobStatus> insertInto) {
        mJobSet.getJobsBySourceUid(sourceUid, insertInto);
    }
    }


    /**
    /**
     * @param uid Uid of the requesting app.
     * @param uid Uid of the requesting app.
     * @return All JobStatus objects for a given uid from the master list. Never null.
     * @return All JobStatus objects for a given uid from the master list. Never null.
     */
     */
    @NonNull
    public List<JobStatus> getJobsByUid(int uid) {
    public List<JobStatus> getJobsByUid(int uid) {
        return mJobSet.getJobsByUid(uid);
        return mJobSet.getJobsByUid(uid);
    }
    }


    public void getJobsByUid(int uid, @NonNull List<JobStatus> insertInto) {
        mJobSet.getJobsByUid(uid, insertInto);
    }

    /**
    /**
     * @param uid Uid of the requesting app.
     * @param uid Uid of the requesting app.
     * @param jobId Job id, specified at schedule-time.
     * @param jobId Job id, specified at schedule-time.
     * @return the JobStatus that matches the provided uId and jobId, or null if none found.
     * @return the JobStatus that matches the provided uId and jobId, or null if none found.
     */
     */
    @Nullable
    public JobStatus getJobByUidAndJobId(int uid, int jobId) {
    public JobStatus getJobByUidAndJobId(int uid, int jobId) {
        return mJobSet.get(uid, jobId);
        return mJobSet.get(uid, jobId);
    }
    }
@@ -1220,25 +1231,29 @@ public final class JobStore {


        public List<JobStatus> getJobsByUid(int uid) {
        public List<JobStatus> getJobsByUid(int uid) {
            ArrayList<JobStatus> matchingJobs = new ArrayList<JobStatus>();
            ArrayList<JobStatus> matchingJobs = new ArrayList<JobStatus>();
            getJobsByUid(uid, matchingJobs);
            return matchingJobs;
        }

        public void getJobsByUid(int uid, List<JobStatus> insertInto) {
            ArraySet<JobStatus> jobs = mJobs.get(uid);
            ArraySet<JobStatus> jobs = mJobs.get(uid);
            if (jobs != null) {
            if (jobs != null) {
                matchingJobs.addAll(jobs);
                insertInto.addAll(jobs);
            }
            }
            return matchingJobs;
        }
        }


        // By user, not by uid, so we need to traverse by key and check
        @NonNull
        public List<JobStatus> getJobsByUser(int userId) {
        public List<JobStatus> getJobsBySourceUid(int sourceUid) {
            final ArrayList<JobStatus> result = new ArrayList<JobStatus>();
            final ArrayList<JobStatus> result = new ArrayList<JobStatus>();
            for (int i = mJobsPerSourceUid.size() - 1; i >= 0; i--) {
            getJobsBySourceUid(sourceUid, result);
                if (UserHandle.getUserId(mJobsPerSourceUid.keyAt(i)) == userId) {
            return result;
                    final ArraySet<JobStatus> jobs = mJobsPerSourceUid.valueAt(i);
                    if (jobs != null) {
                        result.addAll(jobs);
                    }
        }
        }

        public void getJobsBySourceUid(int sourceUid, List<JobStatus> insertInto) {
            final ArraySet<JobStatus> jobs = mJobsPerSourceUid.get(sourceUid);
            if (jobs != null) {
                insertInto.addAll(jobs);
            }
            }
            return result;
        }
        }


        public boolean add(JobStatus job) {
        public boolean add(JobStatus job) {
@@ -1382,7 +1397,7 @@ public final class JobStore {
        }
        }


        public void forEachJob(@Nullable Predicate<JobStatus> filterPredicate,
        public void forEachJob(@Nullable Predicate<JobStatus> filterPredicate,
                Consumer<JobStatus> functor) {
                @NonNull Consumer<JobStatus> functor) {
            for (int uidIndex = mJobs.size() - 1; uidIndex >= 0; uidIndex--) {
            for (int uidIndex = mJobs.size() - 1; uidIndex >= 0; uidIndex--) {
                ArraySet<JobStatus> jobs = mJobs.valueAt(uidIndex);
                ArraySet<JobStatus> jobs = mJobs.valueAt(uidIndex);
                if (jobs != null) {
                if (jobs != null) {