Loading core/java/android/app/ActivityManagerNative.java +20 −0 Original line number Original line Diff line number Diff line Loading @@ -1540,6 +1540,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; return true; } } case GET_MEMORY_TRIM_LEVEL_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); int level = getMemoryTrimLevel(); reply.writeNoException(); reply.writeInt(level); return true; } case ENTER_SAFE_MODE_TRANSACTION: { case ENTER_SAFE_MODE_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); data.enforceInterface(IActivityManager.descriptor); enterSafeMode(); enterSafeMode(); Loading Loading @@ -4874,6 +4882,18 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); data.recycle(); reply.recycle(); reply.recycle(); } } public int getMemoryTrimLevel() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); mRemote.transact(GET_MEMORY_TRIM_LEVEL_TRANSACTION, data, reply, 0); reply.readException(); int level = reply.readInt(); data.recycle(); reply.recycle(); return level; } public void enterSafeMode() throws RemoteException { public void enterSafeMode() throws RemoteException { Parcel data = Parcel.obtain(); Parcel data = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeInterfaceToken(IActivityManager.descriptor); Loading core/java/android/app/IActivityManager.java +2 −0 Original line number Original line Diff line number Diff line Loading @@ -308,6 +308,7 @@ public interface IActivityManager extends IInterface { public void setActivityController(IActivityController watcher) public void setActivityController(IActivityController watcher) throws RemoteException; throws RemoteException; public void setLenientBackgroundCheck(boolean enabled) throws RemoteException; public void setLenientBackgroundCheck(boolean enabled) throws RemoteException; public int getMemoryTrimLevel() throws RemoteException; public void enterSafeMode() throws RemoteException; public void enterSafeMode() throws RemoteException; Loading Loading @@ -980,4 +981,5 @@ public interface IActivityManager extends IInterface { int NOTIFY_PINNED_STACK_ANIMATION_ENDED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 366; int NOTIFY_PINNED_STACK_ANIMATION_ENDED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 366; int REMOVE_STACK = IBinder.FIRST_CALL_TRANSACTION + 367; int REMOVE_STACK = IBinder.FIRST_CALL_TRANSACTION + 367; int SET_LENIENT_BACKGROUND_CHECK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+368; int SET_LENIENT_BACKGROUND_CHECK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+368; int GET_MEMORY_TRIM_LEVEL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+369; } } core/java/android/app/job/JobInfo.java +8 −1 Original line number Original line Diff line number Diff line Loading @@ -102,12 +102,19 @@ public class JobInfo implements Parcelable { public static final int PRIORITY_SYNC_INITIALIZATION = 20; public static final int PRIORITY_SYNC_INITIALIZATION = 20; /** /** * Value of {@link #getPriority} for the current foreground app (overrides the supplied * Value of {@link #getPriority} for a foreground app (overrides the supplied * JobInfo priority if it is smaller). * JobInfo priority if it is smaller). * @hide * @hide */ */ public static final int PRIORITY_FOREGROUND_APP = 30; public static final int PRIORITY_FOREGROUND_APP = 30; /** * Value of {@link #getPriority} for the current top app (overrides the supplied * JobInfo priority if it is smaller). * @hide */ public static final int PRIORITY_TOP_APP = 40; private final int jobId; private final int jobId; private final PersistableBundle extras; private final PersistableBundle extras; private final ComponentName service; private final ComponentName service; Loading services/core/java/com/android/server/am/ActivityManagerService.java +8 −0 Original line number Original line Diff line number Diff line Loading @@ -13394,6 +13394,14 @@ public final class ActivityManagerService extends ActivityManagerNative } } } } @Override public int getMemoryTrimLevel() { enforceNotIsolatedCaller("getMyMemoryState"); synchronized (this) { return mLastMemoryLevel; } } @Override @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ResultReceiver resultReceiver) { FileDescriptor err, String[] args, ResultReceiver resultReceiver) { services/core/java/com/android/server/job/JobSchedulerService.java +110 −58 Original line number Original line Diff line number Diff line Loading @@ -53,9 +53,11 @@ import android.os.UserHandle; import android.util.Slog; import android.util.Slog; import android.util.SparseArray; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.TimeUtils; import com.android.internal.app.IBatteryStats; import com.android.internal.app.IBatteryStats; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.app.ProcessStats; import com.android.server.DeviceIdleController; import com.android.server.DeviceIdleController; import com.android.server.LocalServices; import com.android.server.LocalServices; import com.android.server.job.JobStore.JobStatusFunctor; import com.android.server.job.JobStore.JobStatusFunctor; Loading Loading @@ -87,9 +89,8 @@ public final class JobSchedulerService extends com.android.server.SystemService static final String TAG = "JobSchedulerService"; static final String TAG = "JobSchedulerService"; public static final boolean DEBUG = false; public static final boolean DEBUG = false; /** The number of concurrent jobs we run at one time. */ /** The maximum number of concurrent jobs we run at one time. */ private static final int MAX_JOB_CONTEXTS_COUNT private static final int MAX_JOB_CONTEXTS_COUNT = 8; = ActivityManager.isLowRamDeviceStatic() ? 3 : 6; /** Enforce a per-app limit on scheduled jobs? */ /** Enforce a per-app limit on scheduled jobs? */ private static final boolean ENFORCE_MAX_JOBS = false; private static final boolean ENFORCE_MAX_JOBS = false; /** The maximum number of jobs that we allow an unprivileged app to schedule */ /** The maximum number of jobs that we allow an unprivileged app to schedule */ Loading Loading @@ -170,10 +171,34 @@ public final class JobSchedulerService extends com.android.server.SystemService */ */ boolean mReportedActive; boolean mReportedActive; /** * Current limit on the number of concurrent JobServiceContext entries we want to * keep actively running a job. */ int mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - 2; /** /** * Which uids are currently in the foreground. * Which uids are currently in the foreground. */ */ final SparseBooleanArray mForegroundUids = new SparseBooleanArray(); final SparseIntArray mUidPriorityOverride = new SparseIntArray(); // -- Pre-allocated temporaries only for use in assignJobsToContextsLocked -- /** * This array essentially stores the state of mActiveServices array. * The ith index stores the job present on the ith JobServiceContext. * We manipulate this array until we arrive at what jobs should be running on * what JobServiceContext. */ JobStatus[] mTmpAssignContextIdToJobMap = new JobStatus[MAX_JOB_CONTEXTS_COUNT]; /** * Indicates whether we need to act on this jobContext id */ boolean[] mTmpAssignAct = new boolean[MAX_JOB_CONTEXTS_COUNT]; /** * The uid whose jobs we would like to assign to a context. */ int[] mTmpAssignPreferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT]; /** /** * Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we * Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we Loading Loading @@ -376,19 +401,15 @@ public final class JobSchedulerService extends com.android.server.SystemService void updateUidState(int uid, int procState) { void updateUidState(int uid, int procState) { synchronized (mLock) { synchronized (mLock) { boolean foreground = procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; if (procState == ActivityManager.PROCESS_STATE_TOP) { boolean changed = false; // Only use this if we are exactly the top app. All others can live if (foreground) { // with just the foreground priority. This means that persistent processes if (!mForegroundUids.get(uid)) { // can never be the top app priority... that is fine. changed = true; mUidPriorityOverride.put(uid, JobInfo.PRIORITY_TOP_APP); mForegroundUids.put(uid, true); } else if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) { } mUidPriorityOverride.put(uid, JobInfo.PRIORITY_FOREGROUND_APP); } else { } else { int index = mForegroundUids.indexOfKey(uid); mUidPriorityOverride.delete(uid); if (index >= 0) { mForegroundUids.removeAt(index); changed = true; } } } } } } } Loading Loading @@ -1007,8 +1028,9 @@ public final class JobSchedulerService extends com.android.server.SystemService if (priority >= JobInfo.PRIORITY_FOREGROUND_APP) { if (priority >= JobInfo.PRIORITY_FOREGROUND_APP) { return priority; return priority; } } if (mForegroundUids.get(job.getSourceUid())) { int override = mUidPriorityOverride.get(job.getSourceUid(), 0); return JobInfo.PRIORITY_FOREGROUND_APP; if (override != 0) { return override; } } return priority; return priority; } } Loading @@ -1024,24 +1046,44 @@ public final class JobSchedulerService extends com.android.server.SystemService Slog.d(TAG, printPendingQueue()); Slog.d(TAG, printPendingQueue()); } } // This array essentially stores the state of mActiveServices array. int memLevel; // ith index stores the job present on the ith JobServiceContext. try { // We manipulate this array until we arrive at what jobs should be running on memLevel = ActivityManagerNative.getDefault().getMemoryTrimLevel(); // what JobServiceContext. } catch (RemoteException e) { JobStatus[] contextIdToJobMap = new JobStatus[MAX_JOB_CONTEXTS_COUNT]; memLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL; // Indicates whether we need to act on this jobContext id } boolean[] act = new boolean[MAX_JOB_CONTEXTS_COUNT]; switch (memLevel) { int[] preferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT]; case ProcessStats.ADJ_MEM_FACTOR_MODERATE: for (int i=0; i<mActiveServices.size(); i++) { mMaxActiveJobs = ((MAX_JOB_CONTEXTS_COUNT - 2) * 2) / 3; contextIdToJobMap[i] = mActiveServices.get(i).getRunningJob(); break; preferredUidForContext[i] = mActiveServices.get(i).getPreferredUid(); case ProcessStats.ADJ_MEM_FACTOR_LOW: mMaxActiveJobs = (MAX_JOB_CONTEXTS_COUNT - 2) / 3; break; case ProcessStats.ADJ_MEM_FACTOR_CRITICAL: mMaxActiveJobs = 1; break; default: mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - 2; break; } JobStatus[] contextIdToJobMap = mTmpAssignContextIdToJobMap; boolean[] act = mTmpAssignAct; int[] preferredUidForContext = mTmpAssignPreferredUidForContext; int numActive = 0; for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) { final JobServiceContext js = mActiveServices.get(i); if ((contextIdToJobMap[i] = js.getRunningJob()) != null) { numActive++; } act[i] = false; preferredUidForContext[i] = js.getPreferredUid(); } } if (DEBUG) { if (DEBUG) { Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs initial")); Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs initial")); } } Iterator<JobStatus> it = mPendingJobs.iterator(); for (int i=0; i<mPendingJobs.size(); i++) { while (it.hasNext()) { JobStatus nextPending = mPendingJobs.get(i); JobStatus nextPending = it.next(); // If job is already running, go to next job. // If job is already running, go to next job. int jobRunningContext = findJobContextIdFromMap(nextPending, contextIdToJobMap); int jobRunningContext = findJobContextIdFromMap(nextPending, contextIdToJobMap); Loading @@ -1049,24 +1091,30 @@ public final class JobSchedulerService extends com.android.server.SystemService continue; continue; } } nextPending.lastEvaluatedPriority = evaluateJobPriorityLocked(nextPending); final int priority = evaluateJobPriorityLocked(nextPending); nextPending.lastEvaluatedPriority = priority; // Find a context for nextPending. The context should be available OR // Find a context for nextPending. The context should be available OR // it should have lowest priority among all running jobs // it should have lowest priority among all running jobs // (sharing the same Uid as nextPending) // (sharing the same Uid as nextPending) int minPriority = Integer.MAX_VALUE; int minPriority = Integer.MAX_VALUE; int minPriorityContextId = -1; int minPriorityContextId = -1; for (int i=0; i<mActiveServices.size(); i++) { for (int j=0; j<MAX_JOB_CONTEXTS_COUNT; j++) { JobStatus job = contextIdToJobMap[i]; JobStatus job = contextIdToJobMap[j]; int preferredUid = preferredUidForContext[i]; int preferredUid = preferredUidForContext[j]; if (job == null && (preferredUid == nextPending.getUid() || if (job == null) { if ((numActive < mMaxActiveJobs || priority >= JobInfo.PRIORITY_TOP_APP) && (preferredUid == nextPending.getUid() || preferredUid == JobServiceContext.NO_PREFERRED_UID)) { preferredUid == JobServiceContext.NO_PREFERRED_UID)) { minPriorityContextId = i; // This slot is free, and we haven't yet hit the limit on // concurrent jobs... we can just throw the job in to here. minPriorityContextId = j; numActive++; break; break; } } if (job == null) { // No job on this context, but nextPending can't run here because // No job on this context, but nextPending can't run here because // the context has a preferred Uid. // the context has a preferred Uid or we have reached the limit on // concurrent jobs. continue; continue; } } if (job.getUid() != nextPending.getUid()) { if (job.getUid() != nextPending.getUid()) { Loading @@ -1077,7 +1125,7 @@ public final class JobSchedulerService extends com.android.server.SystemService } } if (minPriority > nextPending.lastEvaluatedPriority) { if (minPriority > nextPending.lastEvaluatedPriority) { minPriority = nextPending.lastEvaluatedPriority; minPriority = nextPending.lastEvaluatedPriority; minPriorityContextId = i; minPriorityContextId = j; } } } } if (minPriorityContextId != -1) { if (minPriorityContextId != -1) { Loading @@ -1088,7 +1136,7 @@ public final class JobSchedulerService extends com.android.server.SystemService if (DEBUG) { if (DEBUG) { Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs final")); Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs final")); } } for (int i=0; i<mActiveServices.size(); i++) { for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) { boolean preservePreferredUid = false; boolean preservePreferredUid = false; if (act[i]) { if (act[i]) { JobStatus js = mActiveServices.get(i).getRunningJob(); JobStatus js = mActiveServices.get(i).getRunningJob(); Loading Loading @@ -1329,7 +1377,7 @@ public final class JobSchedulerService extends com.android.server.SystemService public void process(JobStatus job) { public void process(JobStatus job) { pw.print(" Job #"); pw.print(index++); pw.print(": "); pw.print(" Job #"); pw.print(index++); pw.print(": "); pw.println(job.toShortString()); pw.println(job.toShortString()); job.dump(pw, " "); job.dump(pw, " ", true); pw.print(" Ready: "); pw.print(" Ready: "); pw.print(mHandler.isReadyToBeExecutedLocked(job)); pw.print(mHandler.isReadyToBeExecutedLocked(job)); pw.print(" (job="); pw.print(" (job="); Loading @@ -1351,9 +1399,10 @@ public final class JobSchedulerService extends com.android.server.SystemService mControllers.get(i).dumpControllerStateLocked(pw); mControllers.get(i).dumpControllerStateLocked(pw); } } pw.println(); pw.println(); pw.println("Foreground uids:"); pw.println("Uid priority overrides:"); for (int i=0; i<mForegroundUids.size(); i++) { for (int i=0; i< mUidPriorityOverride.size(); i++) { pw.print(" "); pw.println(UserHandle.formatUid(mForegroundUids.keyAt(i))); pw.print(" "); pw.print(UserHandle.formatUid(mUidPriorityOverride.keyAt(i))); pw.print(": "); pw.println(mUidPriorityOverride.valueAt(i)); } } pw.println(); pw.println(); pw.println("Pending queue:"); pw.println("Pending queue:"); Loading @@ -1361,6 +1410,7 @@ public final class JobSchedulerService extends com.android.server.SystemService JobStatus job = mPendingJobs.get(i); JobStatus job = mPendingJobs.get(i); pw.print(" Pending #"); pw.print(i); pw.print(": "); pw.print(" Pending #"); pw.print(i); pw.print(": "); pw.println(job.toShortString()); pw.println(job.toShortString()); job.dump(pw, " ", false); int priority = evaluateJobPriorityLocked(job); int priority = evaluateJobPriorityLocked(job); if (priority != JobInfo.PRIORITY_DEFAULT) { if (priority != JobInfo.PRIORITY_DEFAULT) { pw.print(" Evaluated priority: "); pw.println(priority); pw.print(" Evaluated priority: "); pw.println(priority); Loading @@ -1371,17 +1421,18 @@ public final class JobSchedulerService extends com.android.server.SystemService pw.println("Active jobs:"); pw.println("Active jobs:"); for (int i=0; i<mActiveServices.size(); i++) { for (int i=0; i<mActiveServices.size(); i++) { JobServiceContext jsc = mActiveServices.get(i); JobServiceContext jsc = mActiveServices.get(i); pw.print(" Slot #"); pw.print(i); pw.print(": "); if (jsc.getRunningJob() == null) { if (jsc.getRunningJob() == null) { pw.println("inactive"); continue; continue; } else { } else { final long timeout = jsc.getTimeoutElapsed(); pw.println(jsc.getRunningJob().toShortString()); pw.print(" Running for: "); pw.print(" Running for: "); pw.print((now - jsc.getExecutionStartTimeElapsed())/1000); TimeUtils.formatDuration(now - jsc.getExecutionStartTimeElapsed(), pw); pw.print("s timeout="); pw.print(", timeout at: "); pw.print(timeout); TimeUtils.formatDuration(jsc.getTimeoutElapsed() - now, pw); pw.print(" fromnow="); pw.println(); pw.println(timeout-now); jsc.getRunningJob().dump(pw, " ", false); jsc.getRunningJob().dump(pw, " "); int priority = evaluateJobPriorityLocked(jsc.getRunningJob()); int priority = evaluateJobPriorityLocked(jsc.getRunningJob()); if (priority != JobInfo.PRIORITY_DEFAULT) { if (priority != JobInfo.PRIORITY_DEFAULT) { pw.print(" Evaluated priority: "); pw.println(priority); pw.print(" Evaluated priority: "); pw.println(priority); Loading @@ -1392,6 +1443,7 @@ public final class JobSchedulerService extends com.android.server.SystemService pw.print("mReadyToRock="); pw.println(mReadyToRock); pw.print("mReadyToRock="); pw.println(mReadyToRock); pw.print("mDeviceIdleMode="); pw.println(mDeviceIdleMode); pw.print("mDeviceIdleMode="); pw.println(mDeviceIdleMode); pw.print("mReportedActive="); pw.println(mReportedActive); pw.print("mReportedActive="); pw.println(mReportedActive); pw.print("mMaxActiveJobs="); pw.println(mMaxActiveJobs); } } pw.println(); pw.println(); } } Loading Loading
core/java/android/app/ActivityManagerNative.java +20 −0 Original line number Original line Diff line number Diff line Loading @@ -1540,6 +1540,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; return true; } } case GET_MEMORY_TRIM_LEVEL_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); int level = getMemoryTrimLevel(); reply.writeNoException(); reply.writeInt(level); return true; } case ENTER_SAFE_MODE_TRANSACTION: { case ENTER_SAFE_MODE_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); data.enforceInterface(IActivityManager.descriptor); enterSafeMode(); enterSafeMode(); Loading Loading @@ -4874,6 +4882,18 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); data.recycle(); reply.recycle(); reply.recycle(); } } public int getMemoryTrimLevel() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); mRemote.transact(GET_MEMORY_TRIM_LEVEL_TRANSACTION, data, reply, 0); reply.readException(); int level = reply.readInt(); data.recycle(); reply.recycle(); return level; } public void enterSafeMode() throws RemoteException { public void enterSafeMode() throws RemoteException { Parcel data = Parcel.obtain(); Parcel data = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeInterfaceToken(IActivityManager.descriptor); Loading
core/java/android/app/IActivityManager.java +2 −0 Original line number Original line Diff line number Diff line Loading @@ -308,6 +308,7 @@ public interface IActivityManager extends IInterface { public void setActivityController(IActivityController watcher) public void setActivityController(IActivityController watcher) throws RemoteException; throws RemoteException; public void setLenientBackgroundCheck(boolean enabled) throws RemoteException; public void setLenientBackgroundCheck(boolean enabled) throws RemoteException; public int getMemoryTrimLevel() throws RemoteException; public void enterSafeMode() throws RemoteException; public void enterSafeMode() throws RemoteException; Loading Loading @@ -980,4 +981,5 @@ public interface IActivityManager extends IInterface { int NOTIFY_PINNED_STACK_ANIMATION_ENDED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 366; int NOTIFY_PINNED_STACK_ANIMATION_ENDED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 366; int REMOVE_STACK = IBinder.FIRST_CALL_TRANSACTION + 367; int REMOVE_STACK = IBinder.FIRST_CALL_TRANSACTION + 367; int SET_LENIENT_BACKGROUND_CHECK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+368; int SET_LENIENT_BACKGROUND_CHECK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+368; int GET_MEMORY_TRIM_LEVEL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+369; } }
core/java/android/app/job/JobInfo.java +8 −1 Original line number Original line Diff line number Diff line Loading @@ -102,12 +102,19 @@ public class JobInfo implements Parcelable { public static final int PRIORITY_SYNC_INITIALIZATION = 20; public static final int PRIORITY_SYNC_INITIALIZATION = 20; /** /** * Value of {@link #getPriority} for the current foreground app (overrides the supplied * Value of {@link #getPriority} for a foreground app (overrides the supplied * JobInfo priority if it is smaller). * JobInfo priority if it is smaller). * @hide * @hide */ */ public static final int PRIORITY_FOREGROUND_APP = 30; public static final int PRIORITY_FOREGROUND_APP = 30; /** * Value of {@link #getPriority} for the current top app (overrides the supplied * JobInfo priority if it is smaller). * @hide */ public static final int PRIORITY_TOP_APP = 40; private final int jobId; private final int jobId; private final PersistableBundle extras; private final PersistableBundle extras; private final ComponentName service; private final ComponentName service; Loading
services/core/java/com/android/server/am/ActivityManagerService.java +8 −0 Original line number Original line Diff line number Diff line Loading @@ -13394,6 +13394,14 @@ public final class ActivityManagerService extends ActivityManagerNative } } } } @Override public int getMemoryTrimLevel() { enforceNotIsolatedCaller("getMyMemoryState"); synchronized (this) { return mLastMemoryLevel; } } @Override @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ResultReceiver resultReceiver) { FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
services/core/java/com/android/server/job/JobSchedulerService.java +110 −58 Original line number Original line Diff line number Diff line Loading @@ -53,9 +53,11 @@ import android.os.UserHandle; import android.util.Slog; import android.util.Slog; import android.util.SparseArray; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.TimeUtils; import com.android.internal.app.IBatteryStats; import com.android.internal.app.IBatteryStats; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.app.ProcessStats; import com.android.server.DeviceIdleController; import com.android.server.DeviceIdleController; import com.android.server.LocalServices; import com.android.server.LocalServices; import com.android.server.job.JobStore.JobStatusFunctor; import com.android.server.job.JobStore.JobStatusFunctor; Loading Loading @@ -87,9 +89,8 @@ public final class JobSchedulerService extends com.android.server.SystemService static final String TAG = "JobSchedulerService"; static final String TAG = "JobSchedulerService"; public static final boolean DEBUG = false; public static final boolean DEBUG = false; /** The number of concurrent jobs we run at one time. */ /** The maximum number of concurrent jobs we run at one time. */ private static final int MAX_JOB_CONTEXTS_COUNT private static final int MAX_JOB_CONTEXTS_COUNT = 8; = ActivityManager.isLowRamDeviceStatic() ? 3 : 6; /** Enforce a per-app limit on scheduled jobs? */ /** Enforce a per-app limit on scheduled jobs? */ private static final boolean ENFORCE_MAX_JOBS = false; private static final boolean ENFORCE_MAX_JOBS = false; /** The maximum number of jobs that we allow an unprivileged app to schedule */ /** The maximum number of jobs that we allow an unprivileged app to schedule */ Loading Loading @@ -170,10 +171,34 @@ public final class JobSchedulerService extends com.android.server.SystemService */ */ boolean mReportedActive; boolean mReportedActive; /** * Current limit on the number of concurrent JobServiceContext entries we want to * keep actively running a job. */ int mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - 2; /** /** * Which uids are currently in the foreground. * Which uids are currently in the foreground. */ */ final SparseBooleanArray mForegroundUids = new SparseBooleanArray(); final SparseIntArray mUidPriorityOverride = new SparseIntArray(); // -- Pre-allocated temporaries only for use in assignJobsToContextsLocked -- /** * This array essentially stores the state of mActiveServices array. * The ith index stores the job present on the ith JobServiceContext. * We manipulate this array until we arrive at what jobs should be running on * what JobServiceContext. */ JobStatus[] mTmpAssignContextIdToJobMap = new JobStatus[MAX_JOB_CONTEXTS_COUNT]; /** * Indicates whether we need to act on this jobContext id */ boolean[] mTmpAssignAct = new boolean[MAX_JOB_CONTEXTS_COUNT]; /** * The uid whose jobs we would like to assign to a context. */ int[] mTmpAssignPreferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT]; /** /** * Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we * Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we Loading Loading @@ -376,19 +401,15 @@ public final class JobSchedulerService extends com.android.server.SystemService void updateUidState(int uid, int procState) { void updateUidState(int uid, int procState) { synchronized (mLock) { synchronized (mLock) { boolean foreground = procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; if (procState == ActivityManager.PROCESS_STATE_TOP) { boolean changed = false; // Only use this if we are exactly the top app. All others can live if (foreground) { // with just the foreground priority. This means that persistent processes if (!mForegroundUids.get(uid)) { // can never be the top app priority... that is fine. changed = true; mUidPriorityOverride.put(uid, JobInfo.PRIORITY_TOP_APP); mForegroundUids.put(uid, true); } else if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) { } mUidPriorityOverride.put(uid, JobInfo.PRIORITY_FOREGROUND_APP); } else { } else { int index = mForegroundUids.indexOfKey(uid); mUidPriorityOverride.delete(uid); if (index >= 0) { mForegroundUids.removeAt(index); changed = true; } } } } } } } Loading Loading @@ -1007,8 +1028,9 @@ public final class JobSchedulerService extends com.android.server.SystemService if (priority >= JobInfo.PRIORITY_FOREGROUND_APP) { if (priority >= JobInfo.PRIORITY_FOREGROUND_APP) { return priority; return priority; } } if (mForegroundUids.get(job.getSourceUid())) { int override = mUidPriorityOverride.get(job.getSourceUid(), 0); return JobInfo.PRIORITY_FOREGROUND_APP; if (override != 0) { return override; } } return priority; return priority; } } Loading @@ -1024,24 +1046,44 @@ public final class JobSchedulerService extends com.android.server.SystemService Slog.d(TAG, printPendingQueue()); Slog.d(TAG, printPendingQueue()); } } // This array essentially stores the state of mActiveServices array. int memLevel; // ith index stores the job present on the ith JobServiceContext. try { // We manipulate this array until we arrive at what jobs should be running on memLevel = ActivityManagerNative.getDefault().getMemoryTrimLevel(); // what JobServiceContext. } catch (RemoteException e) { JobStatus[] contextIdToJobMap = new JobStatus[MAX_JOB_CONTEXTS_COUNT]; memLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL; // Indicates whether we need to act on this jobContext id } boolean[] act = new boolean[MAX_JOB_CONTEXTS_COUNT]; switch (memLevel) { int[] preferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT]; case ProcessStats.ADJ_MEM_FACTOR_MODERATE: for (int i=0; i<mActiveServices.size(); i++) { mMaxActiveJobs = ((MAX_JOB_CONTEXTS_COUNT - 2) * 2) / 3; contextIdToJobMap[i] = mActiveServices.get(i).getRunningJob(); break; preferredUidForContext[i] = mActiveServices.get(i).getPreferredUid(); case ProcessStats.ADJ_MEM_FACTOR_LOW: mMaxActiveJobs = (MAX_JOB_CONTEXTS_COUNT - 2) / 3; break; case ProcessStats.ADJ_MEM_FACTOR_CRITICAL: mMaxActiveJobs = 1; break; default: mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - 2; break; } JobStatus[] contextIdToJobMap = mTmpAssignContextIdToJobMap; boolean[] act = mTmpAssignAct; int[] preferredUidForContext = mTmpAssignPreferredUidForContext; int numActive = 0; for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) { final JobServiceContext js = mActiveServices.get(i); if ((contextIdToJobMap[i] = js.getRunningJob()) != null) { numActive++; } act[i] = false; preferredUidForContext[i] = js.getPreferredUid(); } } if (DEBUG) { if (DEBUG) { Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs initial")); Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs initial")); } } Iterator<JobStatus> it = mPendingJobs.iterator(); for (int i=0; i<mPendingJobs.size(); i++) { while (it.hasNext()) { JobStatus nextPending = mPendingJobs.get(i); JobStatus nextPending = it.next(); // If job is already running, go to next job. // If job is already running, go to next job. int jobRunningContext = findJobContextIdFromMap(nextPending, contextIdToJobMap); int jobRunningContext = findJobContextIdFromMap(nextPending, contextIdToJobMap); Loading @@ -1049,24 +1091,30 @@ public final class JobSchedulerService extends com.android.server.SystemService continue; continue; } } nextPending.lastEvaluatedPriority = evaluateJobPriorityLocked(nextPending); final int priority = evaluateJobPriorityLocked(nextPending); nextPending.lastEvaluatedPriority = priority; // Find a context for nextPending. The context should be available OR // Find a context for nextPending. The context should be available OR // it should have lowest priority among all running jobs // it should have lowest priority among all running jobs // (sharing the same Uid as nextPending) // (sharing the same Uid as nextPending) int minPriority = Integer.MAX_VALUE; int minPriority = Integer.MAX_VALUE; int minPriorityContextId = -1; int minPriorityContextId = -1; for (int i=0; i<mActiveServices.size(); i++) { for (int j=0; j<MAX_JOB_CONTEXTS_COUNT; j++) { JobStatus job = contextIdToJobMap[i]; JobStatus job = contextIdToJobMap[j]; int preferredUid = preferredUidForContext[i]; int preferredUid = preferredUidForContext[j]; if (job == null && (preferredUid == nextPending.getUid() || if (job == null) { if ((numActive < mMaxActiveJobs || priority >= JobInfo.PRIORITY_TOP_APP) && (preferredUid == nextPending.getUid() || preferredUid == JobServiceContext.NO_PREFERRED_UID)) { preferredUid == JobServiceContext.NO_PREFERRED_UID)) { minPriorityContextId = i; // This slot is free, and we haven't yet hit the limit on // concurrent jobs... we can just throw the job in to here. minPriorityContextId = j; numActive++; break; break; } } if (job == null) { // No job on this context, but nextPending can't run here because // No job on this context, but nextPending can't run here because // the context has a preferred Uid. // the context has a preferred Uid or we have reached the limit on // concurrent jobs. continue; continue; } } if (job.getUid() != nextPending.getUid()) { if (job.getUid() != nextPending.getUid()) { Loading @@ -1077,7 +1125,7 @@ public final class JobSchedulerService extends com.android.server.SystemService } } if (minPriority > nextPending.lastEvaluatedPriority) { if (minPriority > nextPending.lastEvaluatedPriority) { minPriority = nextPending.lastEvaluatedPriority; minPriority = nextPending.lastEvaluatedPriority; minPriorityContextId = i; minPriorityContextId = j; } } } } if (minPriorityContextId != -1) { if (minPriorityContextId != -1) { Loading @@ -1088,7 +1136,7 @@ public final class JobSchedulerService extends com.android.server.SystemService if (DEBUG) { if (DEBUG) { Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs final")); Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs final")); } } for (int i=0; i<mActiveServices.size(); i++) { for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) { boolean preservePreferredUid = false; boolean preservePreferredUid = false; if (act[i]) { if (act[i]) { JobStatus js = mActiveServices.get(i).getRunningJob(); JobStatus js = mActiveServices.get(i).getRunningJob(); Loading Loading @@ -1329,7 +1377,7 @@ public final class JobSchedulerService extends com.android.server.SystemService public void process(JobStatus job) { public void process(JobStatus job) { pw.print(" Job #"); pw.print(index++); pw.print(": "); pw.print(" Job #"); pw.print(index++); pw.print(": "); pw.println(job.toShortString()); pw.println(job.toShortString()); job.dump(pw, " "); job.dump(pw, " ", true); pw.print(" Ready: "); pw.print(" Ready: "); pw.print(mHandler.isReadyToBeExecutedLocked(job)); pw.print(mHandler.isReadyToBeExecutedLocked(job)); pw.print(" (job="); pw.print(" (job="); Loading @@ -1351,9 +1399,10 @@ public final class JobSchedulerService extends com.android.server.SystemService mControllers.get(i).dumpControllerStateLocked(pw); mControllers.get(i).dumpControllerStateLocked(pw); } } pw.println(); pw.println(); pw.println("Foreground uids:"); pw.println("Uid priority overrides:"); for (int i=0; i<mForegroundUids.size(); i++) { for (int i=0; i< mUidPriorityOverride.size(); i++) { pw.print(" "); pw.println(UserHandle.formatUid(mForegroundUids.keyAt(i))); pw.print(" "); pw.print(UserHandle.formatUid(mUidPriorityOverride.keyAt(i))); pw.print(": "); pw.println(mUidPriorityOverride.valueAt(i)); } } pw.println(); pw.println(); pw.println("Pending queue:"); pw.println("Pending queue:"); Loading @@ -1361,6 +1410,7 @@ public final class JobSchedulerService extends com.android.server.SystemService JobStatus job = mPendingJobs.get(i); JobStatus job = mPendingJobs.get(i); pw.print(" Pending #"); pw.print(i); pw.print(": "); pw.print(" Pending #"); pw.print(i); pw.print(": "); pw.println(job.toShortString()); pw.println(job.toShortString()); job.dump(pw, " ", false); int priority = evaluateJobPriorityLocked(job); int priority = evaluateJobPriorityLocked(job); if (priority != JobInfo.PRIORITY_DEFAULT) { if (priority != JobInfo.PRIORITY_DEFAULT) { pw.print(" Evaluated priority: "); pw.println(priority); pw.print(" Evaluated priority: "); pw.println(priority); Loading @@ -1371,17 +1421,18 @@ public final class JobSchedulerService extends com.android.server.SystemService pw.println("Active jobs:"); pw.println("Active jobs:"); for (int i=0; i<mActiveServices.size(); i++) { for (int i=0; i<mActiveServices.size(); i++) { JobServiceContext jsc = mActiveServices.get(i); JobServiceContext jsc = mActiveServices.get(i); pw.print(" Slot #"); pw.print(i); pw.print(": "); if (jsc.getRunningJob() == null) { if (jsc.getRunningJob() == null) { pw.println("inactive"); continue; continue; } else { } else { final long timeout = jsc.getTimeoutElapsed(); pw.println(jsc.getRunningJob().toShortString()); pw.print(" Running for: "); pw.print(" Running for: "); pw.print((now - jsc.getExecutionStartTimeElapsed())/1000); TimeUtils.formatDuration(now - jsc.getExecutionStartTimeElapsed(), pw); pw.print("s timeout="); pw.print(", timeout at: "); pw.print(timeout); TimeUtils.formatDuration(jsc.getTimeoutElapsed() - now, pw); pw.print(" fromnow="); pw.println(); pw.println(timeout-now); jsc.getRunningJob().dump(pw, " ", false); jsc.getRunningJob().dump(pw, " "); int priority = evaluateJobPriorityLocked(jsc.getRunningJob()); int priority = evaluateJobPriorityLocked(jsc.getRunningJob()); if (priority != JobInfo.PRIORITY_DEFAULT) { if (priority != JobInfo.PRIORITY_DEFAULT) { pw.print(" Evaluated priority: "); pw.println(priority); pw.print(" Evaluated priority: "); pw.println(priority); Loading @@ -1392,6 +1443,7 @@ public final class JobSchedulerService extends com.android.server.SystemService pw.print("mReadyToRock="); pw.println(mReadyToRock); pw.print("mReadyToRock="); pw.println(mReadyToRock); pw.print("mDeviceIdleMode="); pw.println(mDeviceIdleMode); pw.print("mDeviceIdleMode="); pw.println(mDeviceIdleMode); pw.print("mReportedActive="); pw.println(mReportedActive); pw.print("mReportedActive="); pw.println(mReportedActive); pw.print("mMaxActiveJobs="); pw.println(mMaxActiveJobs); } } pw.println(); pw.println(); } } Loading