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

Commit 8e737857 authored by Christopher Tate's avatar Christopher Tate
Browse files

Don't schedule jobs in 'bad' apps

When an app has been temporarily marked 'bad' because it's been
crashing, binding to its services will appear to succeed but not
actually begin execution.  This led to spurious timeouts when jobs were
scheduled in this state.

Fix by incorporating a 'bad' state check into the job runnability
determination.

Fixes: 125505588
Test: atest CtsJobSchedulerTestCases
Test: manual (repeatedly crashing app then running jobs)
Change-Id: I04003265086d74517e7838f1d1332cc4d3ef483c
parent e4edae37
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -329,6 +329,9 @@ public abstract class ActivityManagerInternal {
    /** Returns true if the given uid is the app in the foreground. */
    /** Returns true if the given uid is the app in the foreground. */
    public abstract boolean isAppForeground(int uid);
    public abstract boolean isAppForeground(int uid);


    /** Returns true if the given uid is currently marked 'bad' */
    public abstract boolean isAppBad(ApplicationInfo info);

    /** Remove pending backup for the given userId. */
    /** Remove pending backup for the given userId. */
    public abstract void clearPendingBackup(int userId);
    public abstract void clearPendingBackup(int userId);


+11 −0
Original line number Original line Diff line number Diff line
@@ -5492,6 +5492,12 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
        }
    }
    }
    private boolean isAppBad(ApplicationInfo info) {
        synchronized (this) {
            return mAppErrors.isBadProcessLocked(info);
        }
    }
    // NOTE: this is an internal method used by the OnShellCommand implementation only and should
    // NOTE: this is an internal method used by the OnShellCommand implementation only and should
    // be guarded by permission checking.
    // be guarded by permission checking.
    int getUidState(int uid) {
    int getUidState(int uid) {
@@ -18077,6 +18083,11 @@ public class ActivityManagerService extends IActivityManager.Stub
            return ActivityManagerService.this.isAppForeground(uid);
            return ActivityManagerService.this.isAppForeground(uid);
        }
        }
        @Override
        public boolean isAppBad(ApplicationInfo info) {
            return ActivityManagerService.this.isAppBad(info);
        }
        @Override
        @Override
        public void clearPendingBackup(int userId) {
        public void clearPendingBackup(int userId) {
            ActivityManagerService.this.clearPendingBackup(userId);
            ActivityManagerService.this.clearPendingBackup(userId);
+17 −8
Original line number Original line Diff line number Diff line
@@ -2494,24 +2494,33 @@ public class JobSchedulerService extends com.android.server.SystemService
            }
            }
        }
        }


        // The expensive check last: validate that the defined package+service is
        // The expensive check: validate that the defined package+service is
        // still present & viable.
        // still present & viable.
        final boolean componentPresent;
        final ServiceInfo service;
        try {
        try {
            componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
            service = AppGlobals.getPackageManager().getServiceInfo(
                    job.getServiceComponent(), PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                    job.getServiceComponent(), PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                    job.getUserId()) != null);
                    job.getUserId());
        } catch (RemoteException e) {
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
            throw e.rethrowAsRuntimeException();
        }
        }


        if (service == null) {
            if (DEBUG) {
            if (DEBUG) {
                Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
                Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
                    + " componentPresent=" + componentPresent);
                        + " component not present");
            }
            return false;
        }
        }


        // Everything else checked out so far, so this is the final yes/no check
        // Everything else checked out so far, so this is the final yes/no check
        return componentPresent;
        final boolean appIsBad = mActivityManagerInternal.isAppBad(service.applicationInfo);
        if (DEBUG) {
            if (appIsBad) {
                Slog.i(TAG, "App is bad for " + job.toShortString() + " so not runnable");
            }
        }
        return !appIsBad;
    }
    }


    private void evaluateControllerStatesLocked(final JobStatus job) {
    private void evaluateControllerStatesLocked(final JobStatus job) {