Loading apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +52 −9 Original line number Diff line number Diff line Loading @@ -24,7 +24,9 @@ import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import android.annotation.BytesLong; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManagerInternal; import android.app.Notification; import android.app.compat.CompatChanges; import android.app.job.IJobCallback; import android.app.job.IJobService; import android.app.job.JobInfo; Loading @@ -32,6 +34,9 @@ import android.app.job.JobParameters; import android.app.job.JobProtoEnums; import android.app.job.JobWorkItem; import android.app.usage.UsageStatsManagerInternal; import android.compat.annotation.ChangeId; import android.compat.annotation.Disabled; import android.compat.annotation.EnabledAfter; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading @@ -57,6 +62,7 @@ import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; import com.android.internal.os.TimeoutRecord; import com.android.internal.util.FrameworkStatsLog; import com.android.server.EventLogTags; import com.android.server.LocalServices; Loading Loading @@ -87,6 +93,15 @@ public final class JobServiceContext implements ServiceConnection { private static final boolean DEBUG = JobSchedulerService.DEBUG; private static final boolean DEBUG_STANDBY = JobSchedulerService.DEBUG_STANDBY; /** * Whether to trigger an ANR when apps are slow to respond on pre-UDC APIs and functionality. */ @ChangeId @Disabled // TODO(258236856): Enable after test is fixed // @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) private static final long ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES = 258236856L; private static final String TAG = "JobServiceContext"; /** Amount of time the JobScheduler waits for the initial service launch+bind. */ private static final long OP_BIND_TIMEOUT_MILLIS = 18 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; Loading Loading @@ -119,6 +134,7 @@ public final class JobServiceContext implements ServiceConnection { /** Used for service binding, etc. */ private final Context mContext; private final Object mLock; private final ActivityManagerInternal mActivityManagerInternal; private final IBatteryStats mBatteryStats; private final EconomyManagerInternal mEconomyManagerInternal; private final JobPackageTracker mJobPackageTracker; Loading Loading @@ -270,6 +286,7 @@ public final class JobServiceContext implements ServiceConnection { mContext = service.getContext(); mLock = service.getLock(); mService = service; mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mBatteryStats = batteryStats; mEconomyManagerInternal = LocalServices.getService(EconomyManagerInternal.class); mJobPackageTracker = tracker; Loading Loading @@ -1121,23 +1138,31 @@ public final class JobServiceContext implements ServiceConnection { private void handleOpTimeoutLocked() { switch (mVerb) { case VERB_BINDING: Slog.w(TAG, "Time-out while trying to bind " + getRunningJobNameLocked() + ", dropping."); closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while binding"); onSlowAppResponseLocked(/* reschedule */ false, /* updateStopReasons */ true, /* debugReason */ "timed out while binding", /* anrMessage */ "Timed out while trying to bind", CompatChanges.isChangeEnabled(ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES, mRunningJob.getUid())); break; case VERB_STARTING: // Client unresponsive - wedged or failed to respond in time. We don't really // know what happened so let's log it and notify the JobScheduler // FINISHED/NO-RETRY. Slog.w(TAG, "No response from client for onStartJob " + getRunningJobNameLocked()); closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while starting"); onSlowAppResponseLocked(/* reschedule */ false, /* updateStopReasons */ true, /* debugReason */ "timed out while starting", /* anrMessage */ "No response to onStartJob", CompatChanges.isChangeEnabled(ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES, mRunningJob.getUid())); break; case VERB_STOPPING: // At least we got somewhere, so fail but ask the JobScheduler to reschedule. Slog.w(TAG, "No response from client for onStopJob " + getRunningJobNameLocked()); closeAndCleanupJobLocked(true /* needsReschedule */, "timed out while stopping"); // Don't update the stop reasons since we were already stopping the job for some // other reason. onSlowAppResponseLocked(/* reschedule */ true, /* updateStopReasons */ false, /* debugReason */ "timed out while stopping", /* anrMessage */ "No response to onStopJob", CompatChanges.isChangeEnabled(ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES, mRunningJob.getUid())); break; case VERB_EXECUTING: if (mPendingStopReason != JobParameters.STOP_REASON_UNDEFINED) { Loading Loading @@ -1218,6 +1243,24 @@ public final class JobServiceContext implements ServiceConnection { } } @GuardedBy("mLock") private void onSlowAppResponseLocked(boolean reschedule, boolean updateStopReasons, @NonNull String debugReason, @NonNull String anrMessage, boolean triggerAnr) { Slog.w(TAG, anrMessage + " for " + getRunningJobNameLocked()); if (updateStopReasons) { mParams.setStopReason( JobParameters.STOP_REASON_UNDEFINED, JobParameters.INTERNAL_STOP_REASON_ANR, debugReason); } if (triggerAnr) { mActivityManagerInternal.appNotResponding( mRunningJob.serviceProcessName, mRunningJob.getUid(), TimeoutRecord.forJobService(anrMessage)); } closeAndCleanupJobLocked(reschedule, debugReason); } /** * The provided job has finished, either by calling * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)} Loading core/java/android/app/ActivityManagerInternal.java +6 −0 Original line number Diff line number Diff line Loading @@ -508,6 +508,12 @@ public abstract class ActivityManagerInternal { */ public abstract void broadcastCloseSystemDialogs(String reason); /** * Trigger an ANR for the specified process. */ public abstract void appNotResponding(@NonNull String processName, int uid, @NonNull TimeoutRecord timeoutRecord); /** * Kills all background processes, except those matching any of the specified properties. * Loading core/java/com/android/internal/os/TimeoutRecord.java +10 −1 Original line number Diff line number Diff line Loading @@ -41,7 +41,9 @@ public class TimeoutRecord { TimeoutKind.SERVICE_EXEC, TimeoutKind.CONTENT_PROVIDER, TimeoutKind.APP_REGISTERED, TimeoutKind.SHORT_FGS_TIMEOUT}) TimeoutKind.SHORT_FGS_TIMEOUT, TimeoutKind.JOB_SERVICE, }) @Retention(RetentionPolicy.SOURCE) public @interface TimeoutKind { Loading @@ -53,6 +55,7 @@ public class TimeoutRecord { int CONTENT_PROVIDER = 6; int APP_REGISTERED = 7; int SHORT_FGS_TIMEOUT = 8; int JOB_SERVICE = 9; } /** Kind of timeout, e.g. BROADCAST_RECEIVER, etc. */ Loading Loading @@ -152,4 +155,10 @@ public class TimeoutRecord { public static TimeoutRecord forShortFgsTimeout(String reason) { return TimeoutRecord.endingNow(TimeoutKind.SHORT_FGS_TIMEOUT, reason); } /** Record for a job related timeout. */ @NonNull public static TimeoutRecord forJobService(String reason) { return TimeoutRecord.endingNow(TimeoutKind.JOB_SERVICE, reason); } } services/core/java/com/android/server/am/ActivityManagerService.java +21 −0 Original line number Diff line number Diff line Loading @@ -6811,6 +6811,21 @@ public class ActivityManagerService extends IActivityManager.Stub mAnrHelper.appNotResponding(anrProcess, timeoutRecord); } private void appNotResponding(@NonNull String processName, int uid, @NonNull TimeoutRecord timeoutRecord) { Objects.requireNonNull(processName); Objects.requireNonNull(timeoutRecord); synchronized (this) { final ProcessRecord app = getProcessRecordLocked(processName, uid); if (app == null) { Slog.e(TAG, "Unknown process: " + processName); return; } mAnrHelper.appNotResponding(app, timeoutRecord); } } void startPersistentApps(int matchFlags) { if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return; Loading Loading @@ -18015,6 +18030,12 @@ public class ActivityManagerService extends IActivityManager.Stub } } @Override public void appNotResponding(@NonNull String processName, int uid, @NonNull TimeoutRecord timeoutRecord) { ActivityManagerService.this.appNotResponding(processName, uid, timeoutRecord); } @Override public void killAllBackgroundProcessesExcept(int minTargetSdk, int maxProcState) { synchronized (ActivityManagerService.this) { Loading
apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +52 −9 Original line number Diff line number Diff line Loading @@ -24,7 +24,9 @@ import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import android.annotation.BytesLong; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManagerInternal; import android.app.Notification; import android.app.compat.CompatChanges; import android.app.job.IJobCallback; import android.app.job.IJobService; import android.app.job.JobInfo; Loading @@ -32,6 +34,9 @@ import android.app.job.JobParameters; import android.app.job.JobProtoEnums; import android.app.job.JobWorkItem; import android.app.usage.UsageStatsManagerInternal; import android.compat.annotation.ChangeId; import android.compat.annotation.Disabled; import android.compat.annotation.EnabledAfter; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading @@ -57,6 +62,7 @@ import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; import com.android.internal.os.TimeoutRecord; import com.android.internal.util.FrameworkStatsLog; import com.android.server.EventLogTags; import com.android.server.LocalServices; Loading Loading @@ -87,6 +93,15 @@ public final class JobServiceContext implements ServiceConnection { private static final boolean DEBUG = JobSchedulerService.DEBUG; private static final boolean DEBUG_STANDBY = JobSchedulerService.DEBUG_STANDBY; /** * Whether to trigger an ANR when apps are slow to respond on pre-UDC APIs and functionality. */ @ChangeId @Disabled // TODO(258236856): Enable after test is fixed // @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) private static final long ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES = 258236856L; private static final String TAG = "JobServiceContext"; /** Amount of time the JobScheduler waits for the initial service launch+bind. */ private static final long OP_BIND_TIMEOUT_MILLIS = 18 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; Loading Loading @@ -119,6 +134,7 @@ public final class JobServiceContext implements ServiceConnection { /** Used for service binding, etc. */ private final Context mContext; private final Object mLock; private final ActivityManagerInternal mActivityManagerInternal; private final IBatteryStats mBatteryStats; private final EconomyManagerInternal mEconomyManagerInternal; private final JobPackageTracker mJobPackageTracker; Loading Loading @@ -270,6 +286,7 @@ public final class JobServiceContext implements ServiceConnection { mContext = service.getContext(); mLock = service.getLock(); mService = service; mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mBatteryStats = batteryStats; mEconomyManagerInternal = LocalServices.getService(EconomyManagerInternal.class); mJobPackageTracker = tracker; Loading Loading @@ -1121,23 +1138,31 @@ public final class JobServiceContext implements ServiceConnection { private void handleOpTimeoutLocked() { switch (mVerb) { case VERB_BINDING: Slog.w(TAG, "Time-out while trying to bind " + getRunningJobNameLocked() + ", dropping."); closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while binding"); onSlowAppResponseLocked(/* reschedule */ false, /* updateStopReasons */ true, /* debugReason */ "timed out while binding", /* anrMessage */ "Timed out while trying to bind", CompatChanges.isChangeEnabled(ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES, mRunningJob.getUid())); break; case VERB_STARTING: // Client unresponsive - wedged or failed to respond in time. We don't really // know what happened so let's log it and notify the JobScheduler // FINISHED/NO-RETRY. Slog.w(TAG, "No response from client for onStartJob " + getRunningJobNameLocked()); closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while starting"); onSlowAppResponseLocked(/* reschedule */ false, /* updateStopReasons */ true, /* debugReason */ "timed out while starting", /* anrMessage */ "No response to onStartJob", CompatChanges.isChangeEnabled(ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES, mRunningJob.getUid())); break; case VERB_STOPPING: // At least we got somewhere, so fail but ask the JobScheduler to reschedule. Slog.w(TAG, "No response from client for onStopJob " + getRunningJobNameLocked()); closeAndCleanupJobLocked(true /* needsReschedule */, "timed out while stopping"); // Don't update the stop reasons since we were already stopping the job for some // other reason. onSlowAppResponseLocked(/* reschedule */ true, /* updateStopReasons */ false, /* debugReason */ "timed out while stopping", /* anrMessage */ "No response to onStopJob", CompatChanges.isChangeEnabled(ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES, mRunningJob.getUid())); break; case VERB_EXECUTING: if (mPendingStopReason != JobParameters.STOP_REASON_UNDEFINED) { Loading Loading @@ -1218,6 +1243,24 @@ public final class JobServiceContext implements ServiceConnection { } } @GuardedBy("mLock") private void onSlowAppResponseLocked(boolean reschedule, boolean updateStopReasons, @NonNull String debugReason, @NonNull String anrMessage, boolean triggerAnr) { Slog.w(TAG, anrMessage + " for " + getRunningJobNameLocked()); if (updateStopReasons) { mParams.setStopReason( JobParameters.STOP_REASON_UNDEFINED, JobParameters.INTERNAL_STOP_REASON_ANR, debugReason); } if (triggerAnr) { mActivityManagerInternal.appNotResponding( mRunningJob.serviceProcessName, mRunningJob.getUid(), TimeoutRecord.forJobService(anrMessage)); } closeAndCleanupJobLocked(reschedule, debugReason); } /** * The provided job has finished, either by calling * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)} Loading
core/java/android/app/ActivityManagerInternal.java +6 −0 Original line number Diff line number Diff line Loading @@ -508,6 +508,12 @@ public abstract class ActivityManagerInternal { */ public abstract void broadcastCloseSystemDialogs(String reason); /** * Trigger an ANR for the specified process. */ public abstract void appNotResponding(@NonNull String processName, int uid, @NonNull TimeoutRecord timeoutRecord); /** * Kills all background processes, except those matching any of the specified properties. * Loading
core/java/com/android/internal/os/TimeoutRecord.java +10 −1 Original line number Diff line number Diff line Loading @@ -41,7 +41,9 @@ public class TimeoutRecord { TimeoutKind.SERVICE_EXEC, TimeoutKind.CONTENT_PROVIDER, TimeoutKind.APP_REGISTERED, TimeoutKind.SHORT_FGS_TIMEOUT}) TimeoutKind.SHORT_FGS_TIMEOUT, TimeoutKind.JOB_SERVICE, }) @Retention(RetentionPolicy.SOURCE) public @interface TimeoutKind { Loading @@ -53,6 +55,7 @@ public class TimeoutRecord { int CONTENT_PROVIDER = 6; int APP_REGISTERED = 7; int SHORT_FGS_TIMEOUT = 8; int JOB_SERVICE = 9; } /** Kind of timeout, e.g. BROADCAST_RECEIVER, etc. */ Loading Loading @@ -152,4 +155,10 @@ public class TimeoutRecord { public static TimeoutRecord forShortFgsTimeout(String reason) { return TimeoutRecord.endingNow(TimeoutKind.SHORT_FGS_TIMEOUT, reason); } /** Record for a job related timeout. */ @NonNull public static TimeoutRecord forJobService(String reason) { return TimeoutRecord.endingNow(TimeoutKind.JOB_SERVICE, reason); } }
services/core/java/com/android/server/am/ActivityManagerService.java +21 −0 Original line number Diff line number Diff line Loading @@ -6811,6 +6811,21 @@ public class ActivityManagerService extends IActivityManager.Stub mAnrHelper.appNotResponding(anrProcess, timeoutRecord); } private void appNotResponding(@NonNull String processName, int uid, @NonNull TimeoutRecord timeoutRecord) { Objects.requireNonNull(processName); Objects.requireNonNull(timeoutRecord); synchronized (this) { final ProcessRecord app = getProcessRecordLocked(processName, uid); if (app == null) { Slog.e(TAG, "Unknown process: " + processName); return; } mAnrHelper.appNotResponding(app, timeoutRecord); } } void startPersistentApps(int matchFlags) { if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return; Loading Loading @@ -18015,6 +18030,12 @@ public class ActivityManagerService extends IActivityManager.Stub } } @Override public void appNotResponding(@NonNull String processName, int uid, @NonNull TimeoutRecord timeoutRecord) { ActivityManagerService.this.appNotResponding(processName, uid, timeoutRecord); } @Override public void killAllBackgroundProcessesExcept(int minTargetSdk, int maxProcState) { synchronized (ActivityManagerService.this) {