Loading apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java +12 −3 Original line number Diff line number Diff line Loading @@ -158,7 +158,10 @@ public class JobSchedulerImpl extends JobScheduler { android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) @Override public void registerUserVisibleJobObserver(@NonNull IUserVisibleJobObserver observer) { // TODO(255767350): implement try { mBinder.registerUserVisibleJobObserver(observer); } catch (RemoteException e) { } } @RequiresPermission(allOf = { Loading @@ -166,7 +169,10 @@ public class JobSchedulerImpl extends JobScheduler { android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) @Override public void unregisterUserVisibleJobObserver(@NonNull IUserVisibleJobObserver observer) { // TODO(255767350): implement try { mBinder.unregisterUserVisibleJobObserver(observer); } catch (RemoteException e) { } } @RequiresPermission(allOf = { Loading @@ -174,6 +180,9 @@ public class JobSchedulerImpl extends JobScheduler { android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) @Override public void stopUserVisibleJobsForUser(@NonNull String packageName, int userId) { // TODO(255767350): implement try { mBinder.stopUserVisibleJobsForUser(packageName, userId); } catch (RemoteException e) { } } } apex/jobscheduler/framework/java/android/app/job/IJobScheduler.aidl +7 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.app.job; import android.app.job.IUserVisibleJobObserver; import android.app.job.JobInfo; import android.app.job.JobSnapshot; import android.app.job.JobWorkItem; Loading @@ -38,4 +39,10 @@ interface IJobScheduler { boolean hasRunLongJobsPermission(String packageName, int userId); List<JobInfo> getStartedJobs(); ParceledListSlice getAllJobSnapshots(); @EnforcePermission(allOf={"MANAGE_ACTIVITY_TASKS", "INTERACT_ACROSS_USERS_FULL"}) void registerUserVisibleJobObserver(in IUserVisibleJobObserver observer); @EnforcePermission(allOf={"MANAGE_ACTIVITY_TASKS", "INTERACT_ACROSS_USERS_FULL"}) void unregisterUserVisibleJobObserver(in IUserVisibleJobObserver observer); @EnforcePermission(allOf={"MANAGE_ACTIVITY_TASKS", "INTERACT_ACROSS_USERS_FULL"}) void stopUserVisibleJobsForUser(String packageName, int userId); } apex/jobscheduler/framework/java/android/app/job/JobParameters.java +9 −1 Original line number Diff line number Diff line Loading @@ -98,6 +98,12 @@ public class JobParameters implements Parcelable { */ public static final int INTERNAL_STOP_REASON_SUCCESSFUL_FINISH = JobProtoEnums.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH; // 10. /** * The user stopped the job via some UI (eg. Task Manager). * @hide */ public static final int INTERNAL_STOP_REASON_USER_UI_STOP = JobProtoEnums.INTERNAL_STOP_REASON_USER_UI_STOP; // 11. /** * All the stop reason codes. This should be regarded as an immutable array at runtime. Loading @@ -121,6 +127,7 @@ public class JobParameters implements Parcelable { INTERNAL_STOP_REASON_DATA_CLEARED, INTERNAL_STOP_REASON_RTC_UPDATED, INTERNAL_STOP_REASON_SUCCESSFUL_FINISH, INTERNAL_STOP_REASON_USER_UI_STOP, }; /** Loading @@ -141,6 +148,7 @@ public class JobParameters implements Parcelable { case INTERNAL_STOP_REASON_DATA_CLEARED: return "data_cleared"; case INTERNAL_STOP_REASON_RTC_UPDATED: return "rtc_updated"; case INTERNAL_STOP_REASON_SUCCESSFUL_FINISH: return "successful_finish"; case INTERNAL_STOP_REASON_USER_UI_STOP: return "user_ui_stop"; default: return "unknown:" + reasonCode; } } Loading Loading @@ -230,7 +238,7 @@ public class JobParameters implements Parcelable { public static final int STOP_REASON_APP_STANDBY = 12; /** * The user stopped the job. This can happen either through force-stop, adb shell commands, * or uninstalling. * uninstalling, or some other UI. */ public static final int STOP_REASON_USER = 13; /** The system is doing some processing that requires stopping this job. */ Loading apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java +16 −0 Original line number Diff line number Diff line Loading @@ -1183,6 +1183,22 @@ class JobConcurrencyManager { } } @GuardedBy("mLock") void stopUserVisibleJobsLocked(int userId, @NonNull String packageName, @JobParameters.StopReason int reason, int internalReasonCode) { for (int i = mActiveServices.size() - 1; i >= 0; --i) { final JobServiceContext jsc = mActiveServices.get(i); final JobStatus jobStatus = jsc.getRunningJobLocked(); if (jobStatus != null && userId == jobStatus.getSourceUserId() && jobStatus.getSourcePackageName().equals(packageName) && jobStatus.isUserVisibleJob()) { jsc.cancelExecutingJobLocked(reason, internalReasonCode, JobParameters.getInternalReasonCodeDescription(internalReasonCode)); } } } @GuardedBy("mLock") void stopNonReadyActiveJobsLocked() { for (int i = 0; i < mActiveServices.size(); i++) { Loading apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +105 −0 Original line number Diff line number Diff line Loading @@ -16,11 +16,14 @@ package com.android.server.job; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import android.annotation.EnforcePermission; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; Loading @@ -31,6 +34,7 @@ import android.app.AppGlobals; import android.app.IUidObserver; import android.app.compat.CompatChanges; import android.app.job.IJobScheduler; import android.app.job.IUserVisibleJobObserver; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobProtoEnums; Loading @@ -38,6 +42,7 @@ import android.app.job.JobScheduler; import android.app.job.JobService; import android.app.job.JobSnapshot; import android.app.job.JobWorkItem; import android.app.job.UserVisibleJobSummary; import android.app.usage.UsageStatsManager; import android.app.usage.UsageStatsManagerInternal; import android.compat.annotation.ChangeId; Loading Loading @@ -68,6 +73,7 @@ import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; Loading Loading @@ -248,6 +254,8 @@ public class JobSchedulerService extends com.android.server.SystemService static final int MSG_UID_IDLE = 7; static final int MSG_CHECK_CHANGED_JOB_LIST = 8; static final int MSG_CHECK_MEDIA_EXEMPTION = 9; static final int MSG_INFORM_OBSERVER_OF_ALL_USER_VISIBLE_JOBS = 10; static final int MSG_INFORM_OBSERVERS_OF_USER_VISIBLE_JOB_CHANGE = 11; /** List of controllers that will notify this service of updates to jobs. */ final List<StateController> mControllers; Loading Loading @@ -279,6 +287,9 @@ public class JobSchedulerService extends com.android.server.SystemService @GuardedBy("mLock") private final SparseArray<String> mCloudMediaProviderPackages = new SparseArray<>(); private final RemoteCallbackList<IUserVisibleJobObserver> mUserVisibleJobObservers = new RemoteCallbackList<>(); private final CountQuotaTracker mQuotaTracker; private static final String QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG = ".schedulePersisted()"; private static final String QUOTA_TRACKER_SCHEDULE_LOGGED = Loading Loading @@ -1501,6 +1512,14 @@ public class JobSchedulerService extends com.android.server.SystemService } } private void stopUserVisibleJobsInternal(@NonNull String packageName, int userId) { synchronized (mLock) { mConcurrencyManager.stopUserVisibleJobsLocked(userId, packageName, JobParameters.STOP_REASON_USER, JobParameters.INTERNAL_STOP_REASON_USER_UI_STOP); } } private final Consumer<JobStatus> mCancelJobDueToUserRemovalConsumer = (toRemove) -> { // 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 Loading Loading @@ -2159,6 +2178,7 @@ public class JobSchedulerService extends com.android.server.SystemService } delayMillis = Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS); // TODO(255767350): demote all jobs to regular for user stops so they don't keep privileges JobStatus newJob = new JobStatus(failureToReschedule, elapsedNowMillis + delayMillis, JobStatus.NO_LATEST_RUNTIME, numFailures, numSystemStops, Loading Loading @@ -2509,6 +2529,52 @@ public class JobSchedulerService extends com.android.server.SystemService args.recycle(); break; } case MSG_INFORM_OBSERVER_OF_ALL_USER_VISIBLE_JOBS: { final IUserVisibleJobObserver observer = (IUserVisibleJobObserver) message.obj; synchronized (mLock) { for (int i = mConcurrencyManager.mActiveServices.size() - 1; i >= 0; --i) { JobServiceContext context = mConcurrencyManager.mActiveServices.get(i); final JobStatus jobStatus = context.getRunningJobLocked(); if (jobStatus != null && jobStatus.isUserVisibleJob()) { try { observer.onUserVisibleJobStateChanged( jobStatus.getUserVisibleJobSummary(), /* isRunning */ true); } catch (RemoteException e) { // Will be unregistered automatically by // RemoteCallbackList's dead-object tracking, // so don't need to remove it here. break; } } } } break; } case MSG_INFORM_OBSERVERS_OF_USER_VISIBLE_JOB_CHANGE: { final SomeArgs args = (SomeArgs) message.obj; final JobServiceContext context = (JobServiceContext) args.arg1; final JobStatus jobStatus = (JobStatus) args.arg2; final UserVisibleJobSummary summary = jobStatus.getUserVisibleJobSummary(); final boolean isRunning = args.argi1 == 1; for (int i = mUserVisibleJobObservers.beginBroadcast() - 1; i >= 0; --i) { try { mUserVisibleJobObservers.getBroadcastItem(i) .onUserVisibleJobStateChanged(summary, isRunning); } catch (RemoteException e) { // Will be unregistered automatically by RemoteCallbackList's // dead-object tracking, so nothing we need to do here. } } mUserVisibleJobObservers.finishBroadcast(); args.recycle(); break; } } maybeRunPendingJobsLocked(); } Loading Loading @@ -3022,6 +3088,16 @@ public class JobSchedulerService extends com.android.server.SystemService return adjustJobBias(bias, job); } void informObserversOfUserVisibleJobChange(JobServiceContext context, JobStatus jobStatus, boolean isRunning) { SomeArgs args = SomeArgs.obtain(); args.arg1 = context; args.arg2 = jobStatus; args.argi1 = isRunning ? 1 : 0; mHandler.obtainMessage(MSG_INFORM_OBSERVERS_OF_USER_VISIBLE_JOB_CHANGE, args) .sendToTarget(); } private final class BatteryStateTracker extends BroadcastReceiver { /** * Track whether we're "charging", where charging means that we're ready to commit to Loading Loading @@ -3744,6 +3820,35 @@ public class JobSchedulerService extends com.android.server.SystemService return new ParceledListSlice<>(snapshots); } } @Override @EnforcePermission(allOf = {MANAGE_ACTIVITY_TASKS, INTERACT_ACROSS_USERS_FULL}) public void registerUserVisibleJobObserver(@NonNull IUserVisibleJobObserver observer) { if (observer == null) { throw new NullPointerException("observer"); } mUserVisibleJobObservers.register(observer); mHandler.obtainMessage(MSG_INFORM_OBSERVER_OF_ALL_USER_VISIBLE_JOBS, observer) .sendToTarget(); } @Override @EnforcePermission(allOf = {MANAGE_ACTIVITY_TASKS, INTERACT_ACROSS_USERS_FULL}) public void unregisterUserVisibleJobObserver(@NonNull IUserVisibleJobObserver observer) { if (observer == null) { throw new NullPointerException("observer"); } mUserVisibleJobObservers.unregister(observer); } @Override @EnforcePermission(allOf = {"MANAGE_ACTIVITY_TASKS", "INTERACT_ACROSS_USERS_FULL"}) public void stopUserVisibleJobsForUser(@NonNull String packageName, int userId) { if (packageName == null) { throw new NullPointerException("packageName"); } JobSchedulerService.this.stopUserVisibleJobsInternal(packageName, userId); } } // Shell command infrastructure: run the given job immediately Loading Loading
apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java +12 −3 Original line number Diff line number Diff line Loading @@ -158,7 +158,10 @@ public class JobSchedulerImpl extends JobScheduler { android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) @Override public void registerUserVisibleJobObserver(@NonNull IUserVisibleJobObserver observer) { // TODO(255767350): implement try { mBinder.registerUserVisibleJobObserver(observer); } catch (RemoteException e) { } } @RequiresPermission(allOf = { Loading @@ -166,7 +169,10 @@ public class JobSchedulerImpl extends JobScheduler { android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) @Override public void unregisterUserVisibleJobObserver(@NonNull IUserVisibleJobObserver observer) { // TODO(255767350): implement try { mBinder.unregisterUserVisibleJobObserver(observer); } catch (RemoteException e) { } } @RequiresPermission(allOf = { Loading @@ -174,6 +180,9 @@ public class JobSchedulerImpl extends JobScheduler { android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) @Override public void stopUserVisibleJobsForUser(@NonNull String packageName, int userId) { // TODO(255767350): implement try { mBinder.stopUserVisibleJobsForUser(packageName, userId); } catch (RemoteException e) { } } }
apex/jobscheduler/framework/java/android/app/job/IJobScheduler.aidl +7 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.app.job; import android.app.job.IUserVisibleJobObserver; import android.app.job.JobInfo; import android.app.job.JobSnapshot; import android.app.job.JobWorkItem; Loading @@ -38,4 +39,10 @@ interface IJobScheduler { boolean hasRunLongJobsPermission(String packageName, int userId); List<JobInfo> getStartedJobs(); ParceledListSlice getAllJobSnapshots(); @EnforcePermission(allOf={"MANAGE_ACTIVITY_TASKS", "INTERACT_ACROSS_USERS_FULL"}) void registerUserVisibleJobObserver(in IUserVisibleJobObserver observer); @EnforcePermission(allOf={"MANAGE_ACTIVITY_TASKS", "INTERACT_ACROSS_USERS_FULL"}) void unregisterUserVisibleJobObserver(in IUserVisibleJobObserver observer); @EnforcePermission(allOf={"MANAGE_ACTIVITY_TASKS", "INTERACT_ACROSS_USERS_FULL"}) void stopUserVisibleJobsForUser(String packageName, int userId); }
apex/jobscheduler/framework/java/android/app/job/JobParameters.java +9 −1 Original line number Diff line number Diff line Loading @@ -98,6 +98,12 @@ public class JobParameters implements Parcelable { */ public static final int INTERNAL_STOP_REASON_SUCCESSFUL_FINISH = JobProtoEnums.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH; // 10. /** * The user stopped the job via some UI (eg. Task Manager). * @hide */ public static final int INTERNAL_STOP_REASON_USER_UI_STOP = JobProtoEnums.INTERNAL_STOP_REASON_USER_UI_STOP; // 11. /** * All the stop reason codes. This should be regarded as an immutable array at runtime. Loading @@ -121,6 +127,7 @@ public class JobParameters implements Parcelable { INTERNAL_STOP_REASON_DATA_CLEARED, INTERNAL_STOP_REASON_RTC_UPDATED, INTERNAL_STOP_REASON_SUCCESSFUL_FINISH, INTERNAL_STOP_REASON_USER_UI_STOP, }; /** Loading @@ -141,6 +148,7 @@ public class JobParameters implements Parcelable { case INTERNAL_STOP_REASON_DATA_CLEARED: return "data_cleared"; case INTERNAL_STOP_REASON_RTC_UPDATED: return "rtc_updated"; case INTERNAL_STOP_REASON_SUCCESSFUL_FINISH: return "successful_finish"; case INTERNAL_STOP_REASON_USER_UI_STOP: return "user_ui_stop"; default: return "unknown:" + reasonCode; } } Loading Loading @@ -230,7 +238,7 @@ public class JobParameters implements Parcelable { public static final int STOP_REASON_APP_STANDBY = 12; /** * The user stopped the job. This can happen either through force-stop, adb shell commands, * or uninstalling. * uninstalling, or some other UI. */ public static final int STOP_REASON_USER = 13; /** The system is doing some processing that requires stopping this job. */ Loading
apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java +16 −0 Original line number Diff line number Diff line Loading @@ -1183,6 +1183,22 @@ class JobConcurrencyManager { } } @GuardedBy("mLock") void stopUserVisibleJobsLocked(int userId, @NonNull String packageName, @JobParameters.StopReason int reason, int internalReasonCode) { for (int i = mActiveServices.size() - 1; i >= 0; --i) { final JobServiceContext jsc = mActiveServices.get(i); final JobStatus jobStatus = jsc.getRunningJobLocked(); if (jobStatus != null && userId == jobStatus.getSourceUserId() && jobStatus.getSourcePackageName().equals(packageName) && jobStatus.isUserVisibleJob()) { jsc.cancelExecutingJobLocked(reason, internalReasonCode, JobParameters.getInternalReasonCodeDescription(internalReasonCode)); } } } @GuardedBy("mLock") void stopNonReadyActiveJobsLocked() { for (int i = 0; i < mActiveServices.size(); i++) { Loading
apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +105 −0 Original line number Diff line number Diff line Loading @@ -16,11 +16,14 @@ package com.android.server.job; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import android.annotation.EnforcePermission; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; Loading @@ -31,6 +34,7 @@ import android.app.AppGlobals; import android.app.IUidObserver; import android.app.compat.CompatChanges; import android.app.job.IJobScheduler; import android.app.job.IUserVisibleJobObserver; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobProtoEnums; Loading @@ -38,6 +42,7 @@ import android.app.job.JobScheduler; import android.app.job.JobService; import android.app.job.JobSnapshot; import android.app.job.JobWorkItem; import android.app.job.UserVisibleJobSummary; import android.app.usage.UsageStatsManager; import android.app.usage.UsageStatsManagerInternal; import android.compat.annotation.ChangeId; Loading Loading @@ -68,6 +73,7 @@ import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; Loading Loading @@ -248,6 +254,8 @@ public class JobSchedulerService extends com.android.server.SystemService static final int MSG_UID_IDLE = 7; static final int MSG_CHECK_CHANGED_JOB_LIST = 8; static final int MSG_CHECK_MEDIA_EXEMPTION = 9; static final int MSG_INFORM_OBSERVER_OF_ALL_USER_VISIBLE_JOBS = 10; static final int MSG_INFORM_OBSERVERS_OF_USER_VISIBLE_JOB_CHANGE = 11; /** List of controllers that will notify this service of updates to jobs. */ final List<StateController> mControllers; Loading Loading @@ -279,6 +287,9 @@ public class JobSchedulerService extends com.android.server.SystemService @GuardedBy("mLock") private final SparseArray<String> mCloudMediaProviderPackages = new SparseArray<>(); private final RemoteCallbackList<IUserVisibleJobObserver> mUserVisibleJobObservers = new RemoteCallbackList<>(); private final CountQuotaTracker mQuotaTracker; private static final String QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG = ".schedulePersisted()"; private static final String QUOTA_TRACKER_SCHEDULE_LOGGED = Loading Loading @@ -1501,6 +1512,14 @@ public class JobSchedulerService extends com.android.server.SystemService } } private void stopUserVisibleJobsInternal(@NonNull String packageName, int userId) { synchronized (mLock) { mConcurrencyManager.stopUserVisibleJobsLocked(userId, packageName, JobParameters.STOP_REASON_USER, JobParameters.INTERNAL_STOP_REASON_USER_UI_STOP); } } private final Consumer<JobStatus> mCancelJobDueToUserRemovalConsumer = (toRemove) -> { // 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 Loading Loading @@ -2159,6 +2178,7 @@ public class JobSchedulerService extends com.android.server.SystemService } delayMillis = Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS); // TODO(255767350): demote all jobs to regular for user stops so they don't keep privileges JobStatus newJob = new JobStatus(failureToReschedule, elapsedNowMillis + delayMillis, JobStatus.NO_LATEST_RUNTIME, numFailures, numSystemStops, Loading Loading @@ -2509,6 +2529,52 @@ public class JobSchedulerService extends com.android.server.SystemService args.recycle(); break; } case MSG_INFORM_OBSERVER_OF_ALL_USER_VISIBLE_JOBS: { final IUserVisibleJobObserver observer = (IUserVisibleJobObserver) message.obj; synchronized (mLock) { for (int i = mConcurrencyManager.mActiveServices.size() - 1; i >= 0; --i) { JobServiceContext context = mConcurrencyManager.mActiveServices.get(i); final JobStatus jobStatus = context.getRunningJobLocked(); if (jobStatus != null && jobStatus.isUserVisibleJob()) { try { observer.onUserVisibleJobStateChanged( jobStatus.getUserVisibleJobSummary(), /* isRunning */ true); } catch (RemoteException e) { // Will be unregistered automatically by // RemoteCallbackList's dead-object tracking, // so don't need to remove it here. break; } } } } break; } case MSG_INFORM_OBSERVERS_OF_USER_VISIBLE_JOB_CHANGE: { final SomeArgs args = (SomeArgs) message.obj; final JobServiceContext context = (JobServiceContext) args.arg1; final JobStatus jobStatus = (JobStatus) args.arg2; final UserVisibleJobSummary summary = jobStatus.getUserVisibleJobSummary(); final boolean isRunning = args.argi1 == 1; for (int i = mUserVisibleJobObservers.beginBroadcast() - 1; i >= 0; --i) { try { mUserVisibleJobObservers.getBroadcastItem(i) .onUserVisibleJobStateChanged(summary, isRunning); } catch (RemoteException e) { // Will be unregistered automatically by RemoteCallbackList's // dead-object tracking, so nothing we need to do here. } } mUserVisibleJobObservers.finishBroadcast(); args.recycle(); break; } } maybeRunPendingJobsLocked(); } Loading Loading @@ -3022,6 +3088,16 @@ public class JobSchedulerService extends com.android.server.SystemService return adjustJobBias(bias, job); } void informObserversOfUserVisibleJobChange(JobServiceContext context, JobStatus jobStatus, boolean isRunning) { SomeArgs args = SomeArgs.obtain(); args.arg1 = context; args.arg2 = jobStatus; args.argi1 = isRunning ? 1 : 0; mHandler.obtainMessage(MSG_INFORM_OBSERVERS_OF_USER_VISIBLE_JOB_CHANGE, args) .sendToTarget(); } private final class BatteryStateTracker extends BroadcastReceiver { /** * Track whether we're "charging", where charging means that we're ready to commit to Loading Loading @@ -3744,6 +3820,35 @@ public class JobSchedulerService extends com.android.server.SystemService return new ParceledListSlice<>(snapshots); } } @Override @EnforcePermission(allOf = {MANAGE_ACTIVITY_TASKS, INTERACT_ACROSS_USERS_FULL}) public void registerUserVisibleJobObserver(@NonNull IUserVisibleJobObserver observer) { if (observer == null) { throw new NullPointerException("observer"); } mUserVisibleJobObservers.register(observer); mHandler.obtainMessage(MSG_INFORM_OBSERVER_OF_ALL_USER_VISIBLE_JOBS, observer) .sendToTarget(); } @Override @EnforcePermission(allOf = {MANAGE_ACTIVITY_TASKS, INTERACT_ACROSS_USERS_FULL}) public void unregisterUserVisibleJobObserver(@NonNull IUserVisibleJobObserver observer) { if (observer == null) { throw new NullPointerException("observer"); } mUserVisibleJobObservers.unregister(observer); } @Override @EnforcePermission(allOf = {"MANAGE_ACTIVITY_TASKS", "INTERACT_ACROSS_USERS_FULL"}) public void stopUserVisibleJobsForUser(@NonNull String packageName, int userId) { if (packageName == null) { throw new NullPointerException("packageName"); } JobSchedulerService.this.stopUserVisibleJobsInternal(packageName, userId); } } // Shell command infrastructure: run the given job immediately Loading