Merge "Add concurrency restriction at the USER level" into sc-dev
This commit is contained in:
@@ -16,33 +16,43 @@
|
|||||||
|
|
||||||
package com.android.server.job;
|
package com.android.server.job;
|
||||||
|
|
||||||
|
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
|
||||||
|
|
||||||
import android.annotation.IntDef;
|
import android.annotation.IntDef;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
|
import android.app.ActivityManagerInternal;
|
||||||
|
import android.app.UserSwitchObserver;
|
||||||
import android.app.job.JobInfo;
|
import android.app.job.JobInfo;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
import android.content.pm.UserInfo;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
import android.os.UserHandle;
|
||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.IndentingPrintWriter;
|
import android.util.IndentingPrintWriter;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
|
import android.util.SparseLongArray;
|
||||||
import android.util.TimeUtils;
|
import android.util.TimeUtils;
|
||||||
import android.util.proto.ProtoOutputStream;
|
import android.util.proto.ProtoOutputStream;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.app.procstats.ProcessStats;
|
import com.android.internal.app.procstats.ProcessStats;
|
||||||
import com.android.internal.util.StatLogger;
|
import com.android.internal.util.StatLogger;
|
||||||
import com.android.server.JobSchedulerBackgroundThread;
|
import com.android.server.JobSchedulerBackgroundThread;
|
||||||
|
import com.android.server.LocalServices;
|
||||||
import com.android.server.job.controllers.JobStatus;
|
import com.android.server.job.controllers.JobStatus;
|
||||||
import com.android.server.job.controllers.StateController;
|
import com.android.server.job.controllers.StateController;
|
||||||
|
import com.android.server.pm.UserManagerInternal;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
@@ -66,12 +76,14 @@ class JobConcurrencyManager {
|
|||||||
static final int WORK_TYPE_NONE = 0;
|
static final int WORK_TYPE_NONE = 0;
|
||||||
static final int WORK_TYPE_TOP = 1 << 0;
|
static final int WORK_TYPE_TOP = 1 << 0;
|
||||||
static final int WORK_TYPE_BG = 1 << 1;
|
static final int WORK_TYPE_BG = 1 << 1;
|
||||||
private static final int NUM_WORK_TYPES = 2;
|
static final int WORK_TYPE_BGUSER = 1 << 2;
|
||||||
|
private static final int NUM_WORK_TYPES = 3;
|
||||||
|
|
||||||
@IntDef(prefix = {"WORK_TYPE_"}, flag = true, value = {
|
@IntDef(prefix = {"WORK_TYPE_"}, flag = true, value = {
|
||||||
WORK_TYPE_NONE,
|
WORK_TYPE_NONE,
|
||||||
WORK_TYPE_TOP,
|
WORK_TYPE_TOP,
|
||||||
WORK_TYPE_BG
|
WORK_TYPE_BG,
|
||||||
|
WORK_TYPE_BGUSER
|
||||||
})
|
})
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface WorkType {
|
public @interface WorkType {
|
||||||
@@ -98,22 +110,26 @@ class JobConcurrencyManager {
|
|||||||
// defaultMin
|
// defaultMin
|
||||||
List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 2)),
|
List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 2)),
|
||||||
// defaultMax
|
// defaultMax
|
||||||
List.of(Pair.create(WORK_TYPE_BG, 6))),
|
List.of(Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 4))
|
||||||
|
),
|
||||||
new WorkTypeConfig("screen_on_moderate", 8,
|
new WorkTypeConfig("screen_on_moderate", 8,
|
||||||
// defaultMin
|
// defaultMin
|
||||||
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 2)),
|
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 2)),
|
||||||
// defaultMax
|
// defaultMax
|
||||||
List.of(Pair.create(WORK_TYPE_BG, 4))),
|
List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2))
|
||||||
|
),
|
||||||
new WorkTypeConfig("screen_on_low", 5,
|
new WorkTypeConfig("screen_on_low", 5,
|
||||||
// defaultMin
|
// defaultMin
|
||||||
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
|
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
|
||||||
// defaultMax
|
// defaultMax
|
||||||
List.of(Pair.create(WORK_TYPE_BG, 1))),
|
List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
|
||||||
|
),
|
||||||
new WorkTypeConfig("screen_on_critical", 5,
|
new WorkTypeConfig("screen_on_critical", 5,
|
||||||
// defaultMin
|
// defaultMin
|
||||||
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
|
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
|
||||||
// defaultMax
|
// defaultMax
|
||||||
List.of(Pair.create(WORK_TYPE_BG, 1)))
|
List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
|
||||||
|
)
|
||||||
);
|
);
|
||||||
private static final WorkConfigLimitsPerMemoryTrimLevel CONFIG_LIMITS_SCREEN_OFF =
|
private static final WorkConfigLimitsPerMemoryTrimLevel CONFIG_LIMITS_SCREEN_OFF =
|
||||||
new WorkConfigLimitsPerMemoryTrimLevel(
|
new WorkConfigLimitsPerMemoryTrimLevel(
|
||||||
@@ -121,22 +137,26 @@ class JobConcurrencyManager {
|
|||||||
// defaultMin
|
// defaultMin
|
||||||
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 2)),
|
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 2)),
|
||||||
// defaultMax
|
// defaultMax
|
||||||
List.of(Pair.create(WORK_TYPE_BG, 6))),
|
List.of(Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 4))
|
||||||
|
),
|
||||||
new WorkTypeConfig("screen_off_moderate", 10,
|
new WorkTypeConfig("screen_off_moderate", 10,
|
||||||
// defaultMin
|
// defaultMin
|
||||||
List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 2)),
|
List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 2)),
|
||||||
// defaultMax
|
// defaultMax
|
||||||
List.of(Pair.create(WORK_TYPE_BG, 4))),
|
List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2))
|
||||||
|
),
|
||||||
new WorkTypeConfig("screen_off_low", 5,
|
new WorkTypeConfig("screen_off_low", 5,
|
||||||
// defaultMin
|
// defaultMin
|
||||||
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
|
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
|
||||||
// defaultMax
|
// defaultMax
|
||||||
List.of(Pair.create(WORK_TYPE_BG, 1))),
|
List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
|
||||||
|
),
|
||||||
new WorkTypeConfig("screen_off_critical", 5,
|
new WorkTypeConfig("screen_off_critical", 5,
|
||||||
// defaultMin
|
// defaultMin
|
||||||
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
|
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
|
||||||
// defaultMax
|
// defaultMax
|
||||||
List.of(Pair.create(WORK_TYPE_BG, 1)))
|
List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -171,6 +191,10 @@ class JobConcurrencyManager {
|
|||||||
"assignJobsToContexts",
|
"assignJobsToContexts",
|
||||||
"refreshSystemState",
|
"refreshSystemState",
|
||||||
});
|
});
|
||||||
|
@VisibleForTesting
|
||||||
|
GracePeriodObserver mGracePeriodObserver;
|
||||||
|
@VisibleForTesting
|
||||||
|
boolean mShouldRestrictBgUser;
|
||||||
|
|
||||||
interface Stats {
|
interface Stats {
|
||||||
int ASSIGN_JOBS_TO_CONTEXTS = 0;
|
int ASSIGN_JOBS_TO_CONTEXTS = 0;
|
||||||
@@ -182,9 +206,13 @@ class JobConcurrencyManager {
|
|||||||
JobConcurrencyManager(JobSchedulerService service) {
|
JobConcurrencyManager(JobSchedulerService service) {
|
||||||
mService = service;
|
mService = service;
|
||||||
mLock = mService.mLock;
|
mLock = mService.mLock;
|
||||||
mContext = service.getContext();
|
mContext = service.getTestableContext();
|
||||||
|
|
||||||
mHandler = JobSchedulerBackgroundThread.getHandler();
|
mHandler = JobSchedulerBackgroundThread.getHandler();
|
||||||
|
|
||||||
|
mGracePeriodObserver = new GracePeriodObserver(mContext);
|
||||||
|
mShouldRestrictBgUser = mContext.getResources().getBoolean(
|
||||||
|
R.bool.config_jobSchedulerRestrictBackgroundUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onSystemReady() {
|
public void onSystemReady() {
|
||||||
@@ -193,10 +221,18 @@ class JobConcurrencyManager {
|
|||||||
final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
|
final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
|
||||||
filter.addAction(Intent.ACTION_SCREEN_OFF);
|
filter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||||
mContext.registerReceiver(mReceiver, filter);
|
mContext.registerReceiver(mReceiver, filter);
|
||||||
|
try {
|
||||||
|
ActivityManager.getService().registerUserSwitchObserver(mGracePeriodObserver, TAG);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
}
|
||||||
|
|
||||||
onInteractiveStateChanged(mPowerManager.isInteractive());
|
onInteractiveStateChanged(mPowerManager.isInteractive());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onUserRemoved(int userId) {
|
||||||
|
mGracePeriodObserver.onUserRemoved(userId);
|
||||||
|
}
|
||||||
|
|
||||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
@@ -224,7 +260,7 @@ class JobConcurrencyManager {
|
|||||||
Slog.d(TAG, "Interactive: " + interactive);
|
Slog.d(TAG, "Interactive: " + interactive);
|
||||||
}
|
}
|
||||||
|
|
||||||
final long nowRealtime = JobSchedulerService.sElapsedRealtimeClock.millis();
|
final long nowRealtime = sElapsedRealtimeClock.millis();
|
||||||
if (interactive) {
|
if (interactive) {
|
||||||
mLastScreenOnRealtime = nowRealtime;
|
mLastScreenOnRealtime = nowRealtime;
|
||||||
mEffectiveInteractiveState = true;
|
mEffectiveInteractiveState = true;
|
||||||
@@ -261,7 +297,7 @@ class JobConcurrencyManager {
|
|||||||
if (mLastScreenOnRealtime > mLastScreenOffRealtime) {
|
if (mLastScreenOnRealtime > mLastScreenOffRealtime) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
|
final long now = sElapsedRealtimeClock.millis();
|
||||||
if ((mLastScreenOffRealtime + mScreenOffAdjustmentDelayMs) > now) {
|
if ((mLastScreenOffRealtime + mScreenOffAdjustmentDelayMs) > now) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -723,6 +759,10 @@ class JobConcurrencyManager {
|
|||||||
pw.print(mLastMemoryTrimLevel);
|
pw.print(mLastMemoryTrimLevel);
|
||||||
pw.println();
|
pw.println();
|
||||||
|
|
||||||
|
pw.print("User Grace Period: ");
|
||||||
|
pw.print(mGracePeriodObserver.mGracePeriodExpiration);
|
||||||
|
pw.println();
|
||||||
|
|
||||||
mStatLogger.dump(pw);
|
mStatLogger.dump(pw);
|
||||||
} finally {
|
} finally {
|
||||||
pw.decreaseIndent();
|
pw.decreaseIndent();
|
||||||
@@ -748,14 +788,44 @@ class JobConcurrencyManager {
|
|||||||
proto.end(token);
|
proto.end(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decides whether a job is from the current foreground user or the equivalent.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
boolean shouldRunAsFgUserJob(JobStatus job) {
|
||||||
|
if (!mShouldRestrictBgUser) return true;
|
||||||
|
int userId = job.getSourceUserId();
|
||||||
|
UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
|
||||||
|
UserInfo userInfo = um.getUserInfo(userId);
|
||||||
|
|
||||||
|
// If the user has a parent user (e.g. a work profile of another user), the user should be
|
||||||
|
// treated equivalent as its parent user.
|
||||||
|
if (userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
|
||||||
|
&& userInfo.profileGroupId != userId) {
|
||||||
|
userId = userInfo.profileGroupId;
|
||||||
|
userInfo = um.getUserInfo(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
int currentUser = LocalServices.getService(ActivityManagerInternal.class)
|
||||||
|
.getCurrentUserId();
|
||||||
|
// A user is treated as foreground user if any of the followings is true:
|
||||||
|
// 1. The user is current user
|
||||||
|
// 2. The user is primary user
|
||||||
|
// 3. The user's grace period has not expired
|
||||||
|
return currentUser == userId || userInfo.isPrimary()
|
||||||
|
|| mGracePeriodObserver.isWithinGracePeriodForUser(userId);
|
||||||
|
}
|
||||||
|
|
||||||
int getJobWorkTypes(@NonNull JobStatus js) {
|
int getJobWorkTypes(@NonNull JobStatus js) {
|
||||||
int classification = 0;
|
int classification = 0;
|
||||||
// TODO(171305774): create dedicated work type for EJ and FGS
|
// TODO(171305774): create dedicated work type for EJ and FGS
|
||||||
if (js.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP
|
if (js.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP
|
||||||
|| js.shouldTreatAsExpeditedJob()) {
|
|| js.shouldTreatAsExpeditedJob()) {
|
||||||
classification |= WORK_TYPE_TOP;
|
classification |= WORK_TYPE_TOP;
|
||||||
} else {
|
} else if (shouldRunAsFgUserJob(js)) {
|
||||||
classification |= WORK_TYPE_BG;
|
classification |= WORK_TYPE_BG;
|
||||||
|
} else {
|
||||||
|
classification |= WORK_TYPE_BGUSER;
|
||||||
}
|
}
|
||||||
return classification;
|
return classification;
|
||||||
}
|
}
|
||||||
@@ -766,8 +836,12 @@ class JobConcurrencyManager {
|
|||||||
CONFIG_KEY_PREFIX_CONCURRENCY + "max_total_";
|
CONFIG_KEY_PREFIX_CONCURRENCY + "max_total_";
|
||||||
private static final String KEY_PREFIX_MAX_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "max_top_";
|
private static final String KEY_PREFIX_MAX_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "max_top_";
|
||||||
private static final String KEY_PREFIX_MAX_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "max_bg_";
|
private static final String KEY_PREFIX_MAX_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "max_bg_";
|
||||||
|
private static final String KEY_PREFIX_MAX_BGUSER =
|
||||||
|
CONFIG_KEY_PREFIX_CONCURRENCY + "max_bguser_";
|
||||||
private static final String KEY_PREFIX_MIN_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "min_top_";
|
private static final String KEY_PREFIX_MIN_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "min_top_";
|
||||||
private static final String KEY_PREFIX_MIN_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "min_bg_";
|
private static final String KEY_PREFIX_MIN_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "min_bg_";
|
||||||
|
private static final String KEY_PREFIX_MIN_BGUSER =
|
||||||
|
CONFIG_KEY_PREFIX_CONCURRENCY + "min_bguser_";
|
||||||
private final String mConfigIdentifier;
|
private final String mConfigIdentifier;
|
||||||
|
|
||||||
private int mMaxTotal;
|
private int mMaxTotal;
|
||||||
@@ -815,6 +889,10 @@ class JobConcurrencyManager {
|
|||||||
properties.getInt(KEY_PREFIX_MAX_BG + mConfigIdentifier,
|
properties.getInt(KEY_PREFIX_MAX_BG + mConfigIdentifier,
|
||||||
mDefaultMaxAllowedSlots.get(WORK_TYPE_BG, mMaxTotal))));
|
mDefaultMaxAllowedSlots.get(WORK_TYPE_BG, mMaxTotal))));
|
||||||
mMaxAllowedSlots.put(WORK_TYPE_BG, maxBg);
|
mMaxAllowedSlots.put(WORK_TYPE_BG, maxBg);
|
||||||
|
final int maxBgUser = Math.max(1, Math.min(mMaxTotal,
|
||||||
|
properties.getInt(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier,
|
||||||
|
mDefaultMaxAllowedSlots.get(WORK_TYPE_BGUSER, mMaxTotal))));
|
||||||
|
mMaxAllowedSlots.put(WORK_TYPE_BGUSER, maxBgUser);
|
||||||
|
|
||||||
int remaining = mMaxTotal;
|
int remaining = mMaxTotal;
|
||||||
mMinReservedSlots.clear();
|
mMinReservedSlots.clear();
|
||||||
@@ -829,6 +907,12 @@ class JobConcurrencyManager {
|
|||||||
properties.getInt(KEY_PREFIX_MIN_BG + mConfigIdentifier,
|
properties.getInt(KEY_PREFIX_MIN_BG + mConfigIdentifier,
|
||||||
mDefaultMinReservedSlots.get(WORK_TYPE_BG))));
|
mDefaultMinReservedSlots.get(WORK_TYPE_BG))));
|
||||||
mMinReservedSlots.put(WORK_TYPE_BG, minBg);
|
mMinReservedSlots.put(WORK_TYPE_BG, minBg);
|
||||||
|
remaining -= minBg;
|
||||||
|
// Ensure bg user is in the range [0, min(maxBgUser, remaining)]
|
||||||
|
final int minBgUser = Math.max(0, Math.min(Math.min(maxBgUser, remaining),
|
||||||
|
properties.getInt(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier,
|
||||||
|
mDefaultMinReservedSlots.get(WORK_TYPE_BGUSER, 0))));
|
||||||
|
mMinReservedSlots.put(WORK_TYPE_BGUSER, minBgUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getMaxTotal() {
|
int getMaxTotal() {
|
||||||
@@ -853,6 +937,10 @@ class JobConcurrencyManager {
|
|||||||
.println();
|
.println();
|
||||||
pw.print(KEY_PREFIX_MAX_BG + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_BG))
|
pw.print(KEY_PREFIX_MAX_BG + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_BG))
|
||||||
.println();
|
.println();
|
||||||
|
pw.print(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier,
|
||||||
|
mMinReservedSlots.get(WORK_TYPE_BGUSER)).println();
|
||||||
|
pw.print(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier,
|
||||||
|
mMaxAllowedSlots.get(WORK_TYPE_BGUSER)).println();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -872,6 +960,58 @@ class JobConcurrencyManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class keeps the track of when a user's grace period expires.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
static class GracePeriodObserver extends UserSwitchObserver {
|
||||||
|
// Key is UserId and Value is the time when grace period expires
|
||||||
|
@VisibleForTesting
|
||||||
|
final SparseLongArray mGracePeriodExpiration = new SparseLongArray();
|
||||||
|
private int mCurrentUserId;
|
||||||
|
@VisibleForTesting
|
||||||
|
int mGracePeriod;
|
||||||
|
private final UserManagerInternal mUserManagerInternal;
|
||||||
|
final Object mLock = new Object();
|
||||||
|
|
||||||
|
|
||||||
|
GracePeriodObserver(Context context) {
|
||||||
|
mCurrentUserId = LocalServices.getService(ActivityManagerInternal.class)
|
||||||
|
.getCurrentUserId();
|
||||||
|
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
|
||||||
|
mGracePeriod = Math.max(0, context.getResources().getInteger(
|
||||||
|
R.integer.config_jobSchedulerUserGracePeriod));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUserSwitchComplete(int newUserId) {
|
||||||
|
final long expiration = sElapsedRealtimeClock.millis() + mGracePeriod;
|
||||||
|
synchronized (mLock) {
|
||||||
|
if (mCurrentUserId != UserHandle.USER_NULL
|
||||||
|
&& mUserManagerInternal.exists(mCurrentUserId)) {
|
||||||
|
mGracePeriodExpiration.append(mCurrentUserId, expiration);
|
||||||
|
}
|
||||||
|
mGracePeriodExpiration.delete(newUserId);
|
||||||
|
mCurrentUserId = newUserId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onUserRemoved(int userId) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
mGracePeriodExpiration.delete(userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public boolean isWithinGracePeriodForUser(int userId) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
return userId == mCurrentUserId
|
||||||
|
|| sElapsedRealtimeClock.millis()
|
||||||
|
< mGracePeriodExpiration.get(userId, Long.MAX_VALUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class decides, taking into account the current {@link WorkTypeConfig} and how many jobs
|
* This class decides, taking into account the current {@link WorkTypeConfig} and how many jobs
|
||||||
* are running/pending, how many more job can start.
|
* are running/pending, how many more job can start.
|
||||||
@@ -900,12 +1040,16 @@ class JobConcurrencyManager {
|
|||||||
mConfigNumReservedSlots.put(WORK_TYPE_TOP,
|
mConfigNumReservedSlots.put(WORK_TYPE_TOP,
|
||||||
workTypeConfig.getMinReserved(WORK_TYPE_TOP));
|
workTypeConfig.getMinReserved(WORK_TYPE_TOP));
|
||||||
mConfigNumReservedSlots.put(WORK_TYPE_BG, workTypeConfig.getMinReserved(WORK_TYPE_BG));
|
mConfigNumReservedSlots.put(WORK_TYPE_BG, workTypeConfig.getMinReserved(WORK_TYPE_BG));
|
||||||
|
mConfigNumReservedSlots.put(WORK_TYPE_BGUSER,
|
||||||
|
workTypeConfig.getMinReserved(WORK_TYPE_BGUSER));
|
||||||
mConfigAbsoluteMaxSlots.put(WORK_TYPE_TOP, workTypeConfig.getMax(WORK_TYPE_TOP));
|
mConfigAbsoluteMaxSlots.put(WORK_TYPE_TOP, workTypeConfig.getMax(WORK_TYPE_TOP));
|
||||||
mConfigAbsoluteMaxSlots.put(WORK_TYPE_BG, workTypeConfig.getMax(WORK_TYPE_BG));
|
mConfigAbsoluteMaxSlots.put(WORK_TYPE_BG, workTypeConfig.getMax(WORK_TYPE_BG));
|
||||||
|
mConfigAbsoluteMaxSlots.put(WORK_TYPE_BGUSER, workTypeConfig.getMax(WORK_TYPE_BGUSER));
|
||||||
|
|
||||||
mNumUnspecialized = mConfigMaxTotal;
|
mNumUnspecialized = mConfigMaxTotal;
|
||||||
mNumUnspecialized -= mConfigNumReservedSlots.get(WORK_TYPE_TOP);
|
mNumUnspecialized -= mConfigNumReservedSlots.get(WORK_TYPE_TOP);
|
||||||
mNumUnspecialized -= mConfigNumReservedSlots.get(WORK_TYPE_BG);
|
mNumUnspecialized -= mConfigNumReservedSlots.get(WORK_TYPE_BG);
|
||||||
|
mNumUnspecialized -= mConfigNumReservedSlots.get(WORK_TYPE_BGUSER);
|
||||||
mNumUnspecializedRemaining = mConfigMaxTotal;
|
mNumUnspecializedRemaining = mConfigMaxTotal;
|
||||||
for (int i = mNumRunningJobs.size() - 1; i >= 0; --i) {
|
for (int i = mNumRunningJobs.size() - 1; i >= 0; --i) {
|
||||||
mNumUnspecializedRemaining -= Math.max(mNumRunningJobs.valueAt(i),
|
mNumUnspecializedRemaining -= Math.max(mNumRunningJobs.valueAt(i),
|
||||||
@@ -937,6 +1081,9 @@ class JobConcurrencyManager {
|
|||||||
if ((workTypes & WORK_TYPE_BG) == WORK_TYPE_BG) {
|
if ((workTypes & WORK_TYPE_BG) == WORK_TYPE_BG) {
|
||||||
mNumPendingJobs.put(WORK_TYPE_BG, mNumPendingJobs.get(WORK_TYPE_BG) + 1);
|
mNumPendingJobs.put(WORK_TYPE_BG, mNumPendingJobs.get(WORK_TYPE_BG) + 1);
|
||||||
}
|
}
|
||||||
|
if ((workTypes & WORK_TYPE_BGUSER) == WORK_TYPE_BGUSER) {
|
||||||
|
mNumPendingJobs.put(WORK_TYPE_BGUSER, mNumPendingJobs.get(WORK_TYPE_BGUSER) + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void stageJob(@WorkType int workType) {
|
void stageJob(@WorkType int workType) {
|
||||||
@@ -1029,6 +1176,11 @@ class JobConcurrencyManager {
|
|||||||
int resBg = Math.min(mConfigNumReservedSlots.get(WORK_TYPE_BG), numBg);
|
int resBg = Math.min(mConfigNumReservedSlots.get(WORK_TYPE_BG), numBg);
|
||||||
mNumActuallyReservedSlots.put(WORK_TYPE_BG, resBg);
|
mNumActuallyReservedSlots.put(WORK_TYPE_BG, resBg);
|
||||||
mNumUnspecialized -= resBg;
|
mNumUnspecialized -= resBg;
|
||||||
|
final int numBgUser = mNumRunningJobs.get(WORK_TYPE_BGUSER)
|
||||||
|
+ mNumPendingJobs.get(WORK_TYPE_BGUSER);
|
||||||
|
int resBgUser = Math.min(mConfigNumReservedSlots.get(WORK_TYPE_BGUSER), numBgUser);
|
||||||
|
mNumActuallyReservedSlots.put(WORK_TYPE_BGUSER, resBgUser);
|
||||||
|
mNumUnspecialized -= resBgUser;
|
||||||
|
|
||||||
mNumUnspecializedRemaining = mNumUnspecialized;
|
mNumUnspecializedRemaining = mNumUnspecialized;
|
||||||
// Account for already running jobs after we've assigned the minimum number of slots.
|
// Account for already running jobs after we've assigned the minimum number of slots.
|
||||||
@@ -1048,6 +1200,14 @@ class JobConcurrencyManager {
|
|||||||
resBg += unspecializedAssigned;
|
resBg += unspecializedAssigned;
|
||||||
mNumUnspecializedRemaining -= extraRunning;
|
mNumUnspecializedRemaining -= extraRunning;
|
||||||
}
|
}
|
||||||
|
extraRunning = (mNumRunningJobs.get(WORK_TYPE_BGUSER) - resBgUser);
|
||||||
|
if (extraRunning > 0) {
|
||||||
|
unspecializedAssigned = Math.max(0,
|
||||||
|
Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BGUSER) - resBgUser,
|
||||||
|
extraRunning));
|
||||||
|
resBgUser += unspecializedAssigned;
|
||||||
|
mNumUnspecializedRemaining -= extraRunning;
|
||||||
|
}
|
||||||
|
|
||||||
// Assign remaining unspecialized based on ranking.
|
// Assign remaining unspecialized based on ranking.
|
||||||
unspecializedAssigned = Math.max(0,
|
unspecializedAssigned = Math.max(0,
|
||||||
@@ -1060,6 +1220,12 @@ class JobConcurrencyManager {
|
|||||||
Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG), numBg) - resBg));
|
Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG), numBg) - resBg));
|
||||||
mNumActuallyReservedSlots.put(WORK_TYPE_BG, resBg + unspecializedAssigned);
|
mNumActuallyReservedSlots.put(WORK_TYPE_BG, resBg + unspecializedAssigned);
|
||||||
mNumUnspecializedRemaining -= unspecializedAssigned;
|
mNumUnspecializedRemaining -= unspecializedAssigned;
|
||||||
|
unspecializedAssigned = Math.max(0,
|
||||||
|
Math.min(mNumUnspecializedRemaining,
|
||||||
|
Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BGUSER), numBgUser)
|
||||||
|
- resBgUser));
|
||||||
|
mNumActuallyReservedSlots.put(WORK_TYPE_BGUSER, resBgUser + unspecializedAssigned);
|
||||||
|
mNumUnspecializedRemaining -= unspecializedAssigned;
|
||||||
}
|
}
|
||||||
|
|
||||||
int canJobStart(int workTypes) {
|
int canJobStart(int workTypes) {
|
||||||
@@ -1081,6 +1247,16 @@ class JobConcurrencyManager {
|
|||||||
return WORK_TYPE_BG;
|
return WORK_TYPE_BG;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ((workTypes & WORK_TYPE_BGUSER) == WORK_TYPE_BGUSER) {
|
||||||
|
final int maxAllowed = Math.min(
|
||||||
|
mConfigAbsoluteMaxSlots.get(WORK_TYPE_BGUSER),
|
||||||
|
mNumActuallyReservedSlots.get(WORK_TYPE_BGUSER)
|
||||||
|
+ mNumUnspecializedRemaining);
|
||||||
|
if (mNumRunningJobs.get(WORK_TYPE_BGUSER) + mNumStartingJobs.get(WORK_TYPE_BGUSER)
|
||||||
|
< maxAllowed) {
|
||||||
|
return WORK_TYPE_BGUSER;
|
||||||
|
}
|
||||||
|
}
|
||||||
return WORK_TYPE_NONE;
|
return WORK_TYPE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -743,6 +743,7 @@ public class JobSchedulerService extends com.android.server.SystemService
|
|||||||
mControllers.get(c).onUserRemovedLocked(userId);
|
mControllers.get(c).onUserRemovedLocked(userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mConcurrencyManager.onUserRemoved(userId);
|
||||||
} else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
|
} else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
|
||||||
// Has this package scheduled any jobs, such that we will take action
|
// Has this package scheduled any jobs, such that we will take action
|
||||||
// if it were to be force-stopped?
|
// if it were to be force-stopped?
|
||||||
|
|||||||
@@ -3477,6 +3477,11 @@
|
|||||||
<!-- The alarm window (in milliseconds) that JobScheduler uses to enter the idle state -->
|
<!-- The alarm window (in milliseconds) that JobScheduler uses to enter the idle state -->
|
||||||
<integer name="config_jobSchedulerIdleWindowSlop">300000</integer>
|
<integer name="config_jobSchedulerIdleWindowSlop">300000</integer>
|
||||||
|
|
||||||
|
<!-- If true, jobs from background user will be restricted -->
|
||||||
|
<bool name="config_jobSchedulerRestrictBackgroundUser">false</bool>
|
||||||
|
<!-- The length of grace period after user becomes background user -->
|
||||||
|
<integer name="config_jobSchedulerUserGracePeriod">60000</integer>
|
||||||
|
|
||||||
<!-- If true, all guest users created on the device will be ephemeral. -->
|
<!-- If true, all guest users created on the device will be ephemeral. -->
|
||||||
<bool name="config_guestUserEphemeral">false</bool>
|
<bool name="config_guestUserEphemeral">false</bool>
|
||||||
|
|
||||||
|
|||||||
@@ -2680,6 +2680,8 @@
|
|||||||
|
|
||||||
<java-symbol type="integer" name="config_jobSchedulerInactivityIdleThreshold" />
|
<java-symbol type="integer" name="config_jobSchedulerInactivityIdleThreshold" />
|
||||||
<java-symbol type="integer" name="config_jobSchedulerIdleWindowSlop" />
|
<java-symbol type="integer" name="config_jobSchedulerIdleWindowSlop" />
|
||||||
|
<java-symbol type="bool" name="config_jobSchedulerRestrictBackgroundUser" />
|
||||||
|
<java-symbol type="integer" name="config_jobSchedulerUserGracePeriod" />
|
||||||
|
|
||||||
<java-symbol type="style" name="Animation.ImmersiveModeConfirmation" />
|
<java-symbol type="style" name="Animation.ImmersiveModeConfirmation" />
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server.job;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.ActivityManagerInternal;
|
||||||
|
import android.app.job.JobInfo;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.UserInfo;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
|
import com.android.server.LocalServices;
|
||||||
|
import com.android.server.job.JobConcurrencyManager.GracePeriodObserver;
|
||||||
|
import com.android.server.job.controllers.JobStatus;
|
||||||
|
import com.android.server.pm.UserManagerInternal;
|
||||||
|
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public final class JobConcurrencyManagerTest {
|
||||||
|
private static final int UNAVAILABLE_USER = 0;
|
||||||
|
private JobConcurrencyManager mJobConcurrencyManager;
|
||||||
|
private UserManagerInternal mUserManagerInternal;
|
||||||
|
private ActivityManagerInternal mActivityManagerInternal;
|
||||||
|
private int mNextUserId;
|
||||||
|
private GracePeriodObserver mGracePeriodObserver;
|
||||||
|
private Context mContext;
|
||||||
|
private Resources mResources;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpOnce() {
|
||||||
|
LocalServices.addService(UserManagerInternal.class, mock(UserManagerInternal.class));
|
||||||
|
LocalServices.addService(
|
||||||
|
ActivityManagerInternal.class, mock(ActivityManagerInternal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDownOnce() {
|
||||||
|
LocalServices.removeServiceForTest(UserManagerInternal.class);
|
||||||
|
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
final JobSchedulerService jobSchedulerService = mock(JobSchedulerService.class);
|
||||||
|
mContext = mock(Context.class);
|
||||||
|
mResources = mock(Resources.class);
|
||||||
|
doReturn(true).when(mResources).getBoolean(
|
||||||
|
R.bool.config_jobSchedulerRestrictBackgroundUser);
|
||||||
|
when(mContext.getResources()).thenReturn(mResources);
|
||||||
|
doReturn(mContext).when(jobSchedulerService).getTestableContext();
|
||||||
|
mJobConcurrencyManager = new JobConcurrencyManager(jobSchedulerService);
|
||||||
|
mGracePeriodObserver = mock(GracePeriodObserver.class);
|
||||||
|
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
|
||||||
|
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
|
||||||
|
mNextUserId = 10;
|
||||||
|
mJobConcurrencyManager.mGracePeriodObserver = mGracePeriodObserver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShouldRunAsFgUserJob_currentUser() {
|
||||||
|
assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
|
||||||
|
createJob(createCurrentUser(false))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShouldRunAsFgUserJob_currentProfile() {
|
||||||
|
assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
|
||||||
|
createJob(createCurrentUser(true))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShouldRunAsFgUserJob_primaryUser() {
|
||||||
|
assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
|
||||||
|
createJob(createPrimaryUser(false))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShouldRunAsFgUserJob_primaryProfile() {
|
||||||
|
assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
|
||||||
|
createJob(createPrimaryUser(true))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShouldRunAsFgUserJob_UnexpiredUser() {
|
||||||
|
assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
|
||||||
|
createJob(createUnexpiredUser(false))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShouldRunAsFgUserJob_UnexpiredProfile() {
|
||||||
|
assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
|
||||||
|
createJob(createUnexpiredUser(true))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShouldRunAsFgUserJob_restrictedUser() {
|
||||||
|
assertFalse(mJobConcurrencyManager.shouldRunAsFgUserJob(
|
||||||
|
createJob(createRestrictedUser(false))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShouldRunAsFgUserJob_restrictedProfile() {
|
||||||
|
assertFalse(mJobConcurrencyManager.shouldRunAsFgUserJob(
|
||||||
|
createJob(createRestrictedUser(true))));
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserInfo createCurrentUser(boolean isProfile) {
|
||||||
|
final UserInfo ui = createNewUser();
|
||||||
|
doReturn(ui.id).when(mActivityManagerInternal).getCurrentUserId();
|
||||||
|
return isProfile ? createNewProfile(ui) : ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserInfo createPrimaryUser(boolean isProfile) {
|
||||||
|
final UserInfo ui = createNewUser();
|
||||||
|
doReturn(true).when(ui).isPrimary();
|
||||||
|
return isProfile ? createNewProfile(ui) : ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserInfo createUnexpiredUser(boolean isProfile) {
|
||||||
|
final UserInfo ui = createNewUser();
|
||||||
|
doReturn(true).when(mGracePeriodObserver).isWithinGracePeriodForUser(ui.id);
|
||||||
|
return isProfile ? createNewProfile(ui) : ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserInfo createRestrictedUser(boolean isProfile) {
|
||||||
|
final UserInfo ui = createNewUser();
|
||||||
|
doReturn(UNAVAILABLE_USER).when(mActivityManagerInternal).getCurrentUserId();
|
||||||
|
doReturn(false).when(ui).isPrimary();
|
||||||
|
doReturn(false).when(mGracePeriodObserver).isWithinGracePeriodForUser(ui.id);
|
||||||
|
return isProfile ? createNewProfile(ui) : ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserInfo createNewProfile(UserInfo parent) {
|
||||||
|
final UserInfo ui = createNewUser();
|
||||||
|
parent.profileGroupId = parent.id;
|
||||||
|
ui.profileGroupId = parent.id;
|
||||||
|
doReturn(true).when(ui).isProfile();
|
||||||
|
return ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserInfo createNewUser() {
|
||||||
|
final UserInfo ui = mock(UserInfo.class);
|
||||||
|
ui.id = mNextUserId++;
|
||||||
|
doReturn(ui).when(mUserManagerInternal).getUserInfo(ui.id);
|
||||||
|
ui.profileGroupId = UserInfo.NO_PROFILE_GROUP_ID;
|
||||||
|
return ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JobStatus createJob(UserInfo userInfo) {
|
||||||
|
JobStatus jobStatus = JobStatus.createFromJobInfo(
|
||||||
|
new JobInfo.Builder(1, new ComponentName("foo", "bar")).build(),
|
||||||
|
userInfo.id * UserHandle.PER_USER_RANGE,
|
||||||
|
null, userInfo.id, "JobConcurrencyManagerTest");
|
||||||
|
return jobStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server.job;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
import android.app.ActivityManagerInternal;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.server.LocalServices;
|
||||||
|
import com.android.server.job.JobConcurrencyManager.GracePeriodObserver;
|
||||||
|
import com.android.server.pm.UserManagerInternal;
|
||||||
|
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.time.Clock;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public final class GracePeriodObserverTest {
|
||||||
|
private GracePeriodObserver mGracePeriodObserver;
|
||||||
|
private UserManagerInternal mUserManagerInternal;
|
||||||
|
private static final int FIRST_USER = 0;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpOnce() {
|
||||||
|
UserManagerInternal userManagerInternal = mock(UserManagerInternal.class);
|
||||||
|
LocalServices.addService(UserManagerInternal.class, userManagerInternal);
|
||||||
|
ActivityManagerInternal activityManagerInternal = mock(ActivityManagerInternal.class);
|
||||||
|
LocalServices.addService(ActivityManagerInternal.class, activityManagerInternal);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDownOnce() {
|
||||||
|
LocalServices.removeServiceForTest(UserManagerInternal.class);
|
||||||
|
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
JobSchedulerService.sElapsedRealtimeClock =
|
||||||
|
Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC);
|
||||||
|
doReturn(FIRST_USER)
|
||||||
|
.when(LocalServices.getService(ActivityManagerInternal.class)).getCurrentUserId();
|
||||||
|
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
|
||||||
|
doReturn(true).when(mUserManagerInternal).exists(FIRST_USER);
|
||||||
|
mGracePeriodObserver = new GracePeriodObserver(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGracePeriod() throws RemoteException {
|
||||||
|
final int oldUser = FIRST_USER;
|
||||||
|
final int newUser = 10;
|
||||||
|
doReturn(true).when(mUserManagerInternal).exists(newUser);
|
||||||
|
mGracePeriodObserver.onUserSwitchComplete(newUser);
|
||||||
|
assertTrue(mGracePeriodObserver.isWithinGracePeriodForUser(oldUser));
|
||||||
|
JobSchedulerService.sElapsedRealtimeClock =
|
||||||
|
Clock.offset(JobSchedulerService.sElapsedRealtimeClock,
|
||||||
|
Duration.ofMillis(mGracePeriodObserver.mGracePeriod));
|
||||||
|
assertFalse(mGracePeriodObserver.isWithinGracePeriodForUser(oldUser));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCleanUp() throws RemoteException {
|
||||||
|
final int removedUser = FIRST_USER;
|
||||||
|
final int newUser = 10;
|
||||||
|
mGracePeriodObserver.onUserSwitchComplete(newUser);
|
||||||
|
|
||||||
|
final int sizeBefore = mGracePeriodObserver.mGracePeriodExpiration.size();
|
||||||
|
doReturn(false).when(mUserManagerInternal).exists(removedUser);
|
||||||
|
|
||||||
|
mGracePeriodObserver.onUserRemoved(removedUser);
|
||||||
|
assertEquals(sizeBefore - 1, mGracePeriodObserver.mGracePeriodExpiration.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.android.server.job;
|
package com.android.server.job;
|
||||||
|
|
||||||
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
|
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
|
||||||
|
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER;
|
||||||
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE;
|
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE;
|
||||||
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP;
|
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP;
|
||||||
|
|
||||||
@@ -63,17 +64,27 @@ public class WorkCountTrackerTest {
|
|||||||
public final SparseIntArray running = new SparseIntArray();
|
public final SparseIntArray running = new SparseIntArray();
|
||||||
public final SparseIntArray pending = new SparseIntArray();
|
public final SparseIntArray pending = new SparseIntArray();
|
||||||
|
|
||||||
public void maybeEnqueueJobs(double startRatio, double fgJobRatio) {
|
public void maybeEnqueueJobs(double startRatio, double fgJobRatio, double fgUserJobRatio) {
|
||||||
|
// fgUserJobRatio should always be at least fgJobRatio, otherwise no WORK_TYPE_BG will
|
||||||
|
// be enqueued.
|
||||||
while (mRandom.nextDouble() < startRatio) {
|
while (mRandom.nextDouble() < startRatio) {
|
||||||
if (mRandom.nextDouble() < fgJobRatio) {
|
final double random = mRandom.nextDouble();
|
||||||
|
if (random < fgJobRatio) {
|
||||||
pending.put(WORK_TYPE_TOP, pending.get(WORK_TYPE_TOP) + 1);
|
pending.put(WORK_TYPE_TOP, pending.get(WORK_TYPE_TOP) + 1);
|
||||||
} else {
|
} else if (random < fgUserJobRatio) {
|
||||||
pending.put(WORK_TYPE_BG, pending.get(WORK_TYPE_BG) + 1);
|
pending.put(WORK_TYPE_BG, pending.get(WORK_TYPE_BG) + 1);
|
||||||
|
} else {
|
||||||
|
pending.put(WORK_TYPE_BGUSER, pending.get(WORK_TYPE_BGUSER) + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void maybeFinishJobs(double stopRatio) {
|
public void maybeFinishJobs(double stopRatio) {
|
||||||
|
for (int i = running.get(WORK_TYPE_BGUSER); i > 0; i--) {
|
||||||
|
if (mRandom.nextDouble() < stopRatio) {
|
||||||
|
running.put(WORK_TYPE_BGUSER, running.get(WORK_TYPE_BGUSER) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
for (int i = running.get(WORK_TYPE_BG); i > 0; i--) {
|
for (int i = running.get(WORK_TYPE_BG); i > 0; i--) {
|
||||||
if (mRandom.nextDouble() < stopRatio) {
|
if (mRandom.nextDouble() < stopRatio) {
|
||||||
running.put(WORK_TYPE_BG, running.get(WORK_TYPE_BG) - 1);
|
running.put(WORK_TYPE_BG, running.get(WORK_TYPE_BG) - 1);
|
||||||
@@ -120,8 +131,11 @@ public class WorkCountTrackerTest {
|
|||||||
while ((jobs.pending.get(WORK_TYPE_TOP) > 0
|
while ((jobs.pending.get(WORK_TYPE_TOP) > 0
|
||||||
&& mWorkCountTracker.canJobStart(WORK_TYPE_TOP) != WORK_TYPE_NONE)
|
&& mWorkCountTracker.canJobStart(WORK_TYPE_TOP) != WORK_TYPE_NONE)
|
||||||
|| (jobs.pending.get(WORK_TYPE_BG) > 0
|
|| (jobs.pending.get(WORK_TYPE_BG) > 0
|
||||||
&& mWorkCountTracker.canJobStart(WORK_TYPE_BG) != WORK_TYPE_NONE)) {
|
&& mWorkCountTracker.canJobStart(WORK_TYPE_BG) != WORK_TYPE_NONE)
|
||||||
|
|| (jobs.pending.get(WORK_TYPE_BGUSER) > 0
|
||||||
|
&& mWorkCountTracker.canJobStart(WORK_TYPE_BGUSER) != WORK_TYPE_NONE)) {
|
||||||
final boolean isStartingFg = mRandom.nextBoolean();
|
final boolean isStartingFg = mRandom.nextBoolean();
|
||||||
|
final boolean isStartingFgUser = mRandom.nextBoolean();
|
||||||
|
|
||||||
if (isStartingFg) {
|
if (isStartingFg) {
|
||||||
if (jobs.pending.get(WORK_TYPE_TOP) > 0
|
if (jobs.pending.get(WORK_TYPE_TOP) > 0
|
||||||
@@ -131,7 +145,7 @@ public class WorkCountTrackerTest {
|
|||||||
mWorkCountTracker.stageJob(WORK_TYPE_TOP);
|
mWorkCountTracker.stageJob(WORK_TYPE_TOP);
|
||||||
mWorkCountTracker.onJobStarted(WORK_TYPE_TOP);
|
mWorkCountTracker.onJobStarted(WORK_TYPE_TOP);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (isStartingFgUser) {
|
||||||
if (jobs.pending.get(WORK_TYPE_BG) > 0
|
if (jobs.pending.get(WORK_TYPE_BG) > 0
|
||||||
&& mWorkCountTracker.canJobStart(WORK_TYPE_BG) != WORK_TYPE_NONE) {
|
&& mWorkCountTracker.canJobStart(WORK_TYPE_BG) != WORK_TYPE_NONE) {
|
||||||
jobs.pending.put(WORK_TYPE_BG, jobs.pending.get(WORK_TYPE_BG) - 1);
|
jobs.pending.put(WORK_TYPE_BG, jobs.pending.get(WORK_TYPE_BG) - 1);
|
||||||
@@ -139,6 +153,14 @@ public class WorkCountTrackerTest {
|
|||||||
mWorkCountTracker.stageJob(WORK_TYPE_BG);
|
mWorkCountTracker.stageJob(WORK_TYPE_BG);
|
||||||
mWorkCountTracker.onJobStarted(WORK_TYPE_BG);
|
mWorkCountTracker.onJobStarted(WORK_TYPE_BG);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (jobs.pending.get(WORK_TYPE_BGUSER) > 0
|
||||||
|
&& mWorkCountTracker.canJobStart(WORK_TYPE_BGUSER) != WORK_TYPE_NONE) {
|
||||||
|
jobs.pending.put(WORK_TYPE_BGUSER, jobs.pending.get(WORK_TYPE_BGUSER) - 1);
|
||||||
|
jobs.running.put(WORK_TYPE_BGUSER, jobs.running.get(WORK_TYPE_BGUSER) + 1);
|
||||||
|
mWorkCountTracker.stageJob(WORK_TYPE_BGUSER);
|
||||||
|
mWorkCountTracker.onJobStarted(WORK_TYPE_BGUSER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,10 +171,10 @@ public class WorkCountTrackerTest {
|
|||||||
private void checkRandom(Jobs jobs, int numTests, int totalMax,
|
private void checkRandom(Jobs jobs, int numTests, int totalMax,
|
||||||
@NonNull List<Pair<Integer, Integer>> minLimits,
|
@NonNull List<Pair<Integer, Integer>> minLimits,
|
||||||
@NonNull List<Pair<Integer, Integer>> maxLimits,
|
@NonNull List<Pair<Integer, Integer>> maxLimits,
|
||||||
double startRatio, double fgJobRatio, double stopRatio) {
|
double startRatio, double fgJobRatio, double fgUserJobRatio, double stopRatio) {
|
||||||
for (int i = 0; i < numTests; i++) {
|
for (int i = 0; i < numTests; i++) {
|
||||||
jobs.maybeFinishJobs(stopRatio);
|
jobs.maybeFinishJobs(stopRatio);
|
||||||
jobs.maybeEnqueueJobs(startRatio, fgJobRatio);
|
jobs.maybeEnqueueJobs(startRatio, fgJobRatio, fgUserJobRatio);
|
||||||
|
|
||||||
recount(jobs, totalMax, minLimits, maxLimits);
|
recount(jobs, totalMax, minLimits, maxLimits);
|
||||||
startPendingJobs(jobs);
|
startPendingJobs(jobs);
|
||||||
@@ -182,14 +204,21 @@ public class WorkCountTrackerTest {
|
|||||||
|
|
||||||
final int numTests = 5000;
|
final int numTests = 5000;
|
||||||
final int totalMax = 6;
|
final int totalMax = 6;
|
||||||
final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
|
final List<Pair<Integer, Integer>> maxLimits =
|
||||||
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
|
List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
|
||||||
|
final List<Pair<Integer, Integer>> minLimits =
|
||||||
|
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
|
||||||
final double stopRatio = 0.1;
|
final double stopRatio = 0.1;
|
||||||
|
// WorkType probabilities:
|
||||||
|
// WORK_TYPE_TOP -- 50%
|
||||||
|
// WORK_TYPE_BG -- 50%
|
||||||
|
// WORK_TYPE_BGUSER -- 0%
|
||||||
final double fgJobRatio = 0.5;
|
final double fgJobRatio = 0.5;
|
||||||
|
final double fgUserJobRatio = 1;
|
||||||
final double startRatio = 0.1;
|
final double startRatio = 0.1;
|
||||||
|
|
||||||
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
||||||
startRatio, fgJobRatio, stopRatio);
|
startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -198,14 +227,20 @@ public class WorkCountTrackerTest {
|
|||||||
|
|
||||||
final int numTests = 5000;
|
final int numTests = 5000;
|
||||||
final int totalMax = 2;
|
final int totalMax = 2;
|
||||||
final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
|
final List<Pair<Integer, Integer>> maxLimits =
|
||||||
|
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
|
||||||
final List<Pair<Integer, Integer>> minLimits = List.of();
|
final List<Pair<Integer, Integer>> minLimits = List.of();
|
||||||
final double stopRatio = 0.5;
|
final double stopRatio = 0.5;
|
||||||
|
// WorkType probabilities:
|
||||||
|
// WORK_TYPE_TOP -- 50%
|
||||||
|
// WORK_TYPE_BG -- 50%
|
||||||
|
// WORK_TYPE_BGUSER -- 0%
|
||||||
final double fgJobRatio = 0.5;
|
final double fgJobRatio = 0.5;
|
||||||
|
final double fgUserJobRatio = 1;
|
||||||
final double startRatio = 0.5;
|
final double startRatio = 0.5;
|
||||||
|
|
||||||
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
||||||
startRatio, fgJobRatio, stopRatio);
|
startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -214,14 +249,20 @@ public class WorkCountTrackerTest {
|
|||||||
|
|
||||||
final int numTests = 5000;
|
final int numTests = 5000;
|
||||||
final int totalMax = 2;
|
final int totalMax = 2;
|
||||||
final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
|
final List<Pair<Integer, Integer>> maxLimits =
|
||||||
|
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
|
||||||
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
|
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
|
||||||
final double stopRatio = 0.5;
|
final double stopRatio = 0.5;
|
||||||
final double fgJobRatio = 0.5;
|
// WorkType probabilities:
|
||||||
|
// WORK_TYPE_TOP -- 33%
|
||||||
|
// WORK_TYPE_BG -- 33%
|
||||||
|
// WORK_TYPE_BGUSER -- 33%
|
||||||
|
final double fgJobRatio = 1 / 3.0;
|
||||||
|
final double fgUserJobRatio = 2 / 3.0;
|
||||||
final double startRatio = 0.5;
|
final double startRatio = 0.5;
|
||||||
|
|
||||||
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
||||||
startRatio, fgJobRatio, stopRatio);
|
startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -230,14 +271,20 @@ public class WorkCountTrackerTest {
|
|||||||
|
|
||||||
final int numTests = 5000;
|
final int numTests = 5000;
|
||||||
final int totalMax = 10;
|
final int totalMax = 10;
|
||||||
final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
|
final List<Pair<Integer, Integer>> maxLimits =
|
||||||
|
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
|
||||||
final List<Pair<Integer, Integer>> minLimits = List.of();
|
final List<Pair<Integer, Integer>> minLimits = List.of();
|
||||||
final double stopRatio = 0.5;
|
final double stopRatio = 0.5;
|
||||||
final double fgJobRatio = 0.5;
|
// WorkType probabilities:
|
||||||
|
// WORK_TYPE_TOP -- 33%
|
||||||
|
// WORK_TYPE_BG -- 33%
|
||||||
|
// WORK_TYPE_BGUSER -- 33%
|
||||||
|
final double fgJobRatio = 1 / 3.0;
|
||||||
|
final double fgUserJobRatio = 2 / 3.0;
|
||||||
final double startRatio = 0.5;
|
final double startRatio = 0.5;
|
||||||
|
|
||||||
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
||||||
startRatio, fgJobRatio, stopRatio);
|
startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -246,14 +293,20 @@ public class WorkCountTrackerTest {
|
|||||||
|
|
||||||
final int numTests = 5000;
|
final int numTests = 5000;
|
||||||
final int totalMax = 6;
|
final int totalMax = 6;
|
||||||
final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
|
final List<Pair<Integer, Integer>> maxLimits =
|
||||||
|
List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
|
||||||
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
|
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
|
||||||
final double stopRatio = 0.5;
|
final double stopRatio = 0.5;
|
||||||
|
// WorkType probabilities:
|
||||||
|
// WORK_TYPE_TOP -- 10%
|
||||||
|
// WORK_TYPE_BG -- 80%
|
||||||
|
// WORK_TYPE_BGUSER -- 10%
|
||||||
final double fgJobRatio = 0.1;
|
final double fgJobRatio = 0.1;
|
||||||
|
final double fgUserJobRatio = 0.9;
|
||||||
final double startRatio = 0.5;
|
final double startRatio = 0.5;
|
||||||
|
|
||||||
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
||||||
startRatio, fgJobRatio, stopRatio);
|
startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -262,14 +315,20 @@ public class WorkCountTrackerTest {
|
|||||||
|
|
||||||
final int numTests = 5000;
|
final int numTests = 5000;
|
||||||
final int totalMax = 6;
|
final int totalMax = 6;
|
||||||
final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
|
final List<Pair<Integer, Integer>> maxLimits =
|
||||||
|
List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
|
||||||
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
|
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
|
||||||
final double stopRatio = 0.5;
|
final double stopRatio = 0.5;
|
||||||
|
// WorkType probabilities:
|
||||||
|
// WORK_TYPE_TOP -- 90%
|
||||||
|
// WORK_TYPE_BG -- 10%
|
||||||
|
// WORK_TYPE_BGUSER -- 0%
|
||||||
final double fgJobRatio = 0.9;
|
final double fgJobRatio = 0.9;
|
||||||
|
final double fgUserJobRatio = 1;
|
||||||
final double startRatio = 0.5;
|
final double startRatio = 0.5;
|
||||||
|
|
||||||
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
||||||
startRatio, fgJobRatio, stopRatio);
|
startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -278,14 +337,20 @@ public class WorkCountTrackerTest {
|
|||||||
|
|
||||||
final int numTests = 5000;
|
final int numTests = 5000;
|
||||||
final int totalMax = 6;
|
final int totalMax = 6;
|
||||||
final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
|
final List<Pair<Integer, Integer>> maxLimits =
|
||||||
|
List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
|
||||||
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
|
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
|
||||||
final double stopRatio = 0.4;
|
final double stopRatio = 0.4;
|
||||||
|
// WorkType probabilities:
|
||||||
|
// WORK_TYPE_TOP -- 10%
|
||||||
|
// WORK_TYPE_BG -- 10%
|
||||||
|
// WORK_TYPE_BGUSER -- 80%
|
||||||
final double fgJobRatio = 0.1;
|
final double fgJobRatio = 0.1;
|
||||||
|
final double fgUserJobRatio = 0.2;
|
||||||
final double startRatio = 0.5;
|
final double startRatio = 0.5;
|
||||||
|
|
||||||
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
||||||
startRatio, fgJobRatio, stopRatio);
|
startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -294,14 +359,90 @@ public class WorkCountTrackerTest {
|
|||||||
|
|
||||||
final int numTests = 5000;
|
final int numTests = 5000;
|
||||||
final int totalMax = 6;
|
final int totalMax = 6;
|
||||||
final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
|
final List<Pair<Integer, Integer>> maxLimits =
|
||||||
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
|
List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
|
||||||
|
final List<Pair<Integer, Integer>> minLimits =
|
||||||
|
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
|
||||||
final double stopRatio = 0.4;
|
final double stopRatio = 0.4;
|
||||||
|
// WorkType probabilities:
|
||||||
|
// WORK_TYPE_TOP -- 90%
|
||||||
|
// WORK_TYPE_BG -- 5%
|
||||||
|
// WORK_TYPE_BGUSER -- 5%
|
||||||
final double fgJobRatio = 0.9;
|
final double fgJobRatio = 0.9;
|
||||||
|
final double fgUserJobRatio = 0.95;
|
||||||
final double startRatio = 0.5;
|
final double startRatio = 0.5;
|
||||||
|
|
||||||
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
||||||
startRatio, fgJobRatio, stopRatio);
|
startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRandom9() {
|
||||||
|
final Jobs jobs = new Jobs();
|
||||||
|
|
||||||
|
final int numTests = 5000;
|
||||||
|
final int totalMax = 6;
|
||||||
|
final List<Pair<Integer, Integer>> maxLimits =
|
||||||
|
List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
|
||||||
|
final List<Pair<Integer, Integer>> minLimits =
|
||||||
|
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
|
||||||
|
final double stopRatio = 0.5;
|
||||||
|
// WorkType probabilities:
|
||||||
|
// WORK_TYPE_TOP -- 0%
|
||||||
|
// WORK_TYPE_BG -- 50%
|
||||||
|
// WORK_TYPE_BGUSER -- 50%
|
||||||
|
final double fgJobRatio = 0;
|
||||||
|
final double fgUserJobRatio = 0.5;
|
||||||
|
final double startRatio = 0.5;
|
||||||
|
|
||||||
|
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
||||||
|
startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRandom10() {
|
||||||
|
final Jobs jobs = new Jobs();
|
||||||
|
|
||||||
|
final int numTests = 5000;
|
||||||
|
final int totalMax = 6;
|
||||||
|
final List<Pair<Integer, Integer>> maxLimits =
|
||||||
|
List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
|
||||||
|
final List<Pair<Integer, Integer>> minLimits =
|
||||||
|
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
|
||||||
|
final double stopRatio = 0.5;
|
||||||
|
// WorkType probabilities:
|
||||||
|
// WORK_TYPE_TOP -- 0%
|
||||||
|
// WORK_TYPE_BG -- 10%
|
||||||
|
// WORK_TYPE_BGUSER -- 90%
|
||||||
|
final double fgJobRatio = 0;
|
||||||
|
final double fgUserJobRatio = 0.1;
|
||||||
|
final double startRatio = 0.5;
|
||||||
|
|
||||||
|
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
||||||
|
startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRandom11() {
|
||||||
|
final Jobs jobs = new Jobs();
|
||||||
|
|
||||||
|
final int numTests = 5000;
|
||||||
|
final int totalMax = 6;
|
||||||
|
final List<Pair<Integer, Integer>> maxLimits =
|
||||||
|
List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
|
||||||
|
final List<Pair<Integer, Integer>> minLimits =
|
||||||
|
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
|
||||||
|
final double stopRatio = 0.5;
|
||||||
|
// WorkType probabilities:
|
||||||
|
// WORK_TYPE_TOP -- 0%
|
||||||
|
// WORK_TYPE_BG -- 90%
|
||||||
|
// WORK_TYPE_BGUSER -- 10%
|
||||||
|
final double fgJobRatio = 0;
|
||||||
|
final double fgUserJobRatio = 0.9;
|
||||||
|
final double startRatio = 0.5;
|
||||||
|
|
||||||
|
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
|
||||||
|
startRatio, fgJobRatio, fgUserJobRatio, stopRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Used by the following tests */
|
/** Used by the following tests */
|
||||||
@@ -337,7 +478,7 @@ public class WorkCountTrackerTest {
|
|||||||
public void testBasic() {
|
public void testBasic() {
|
||||||
checkSimple(6,
|
checkSimple(6,
|
||||||
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
||||||
/* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
|
/* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
|
||||||
/* run */ List.of(),
|
/* run */ List.of(),
|
||||||
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 1)),
|
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 1)),
|
||||||
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 1)),
|
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 1)),
|
||||||
@@ -345,7 +486,7 @@ public class WorkCountTrackerTest {
|
|||||||
|
|
||||||
checkSimple(6,
|
checkSimple(6,
|
||||||
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
||||||
/* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
|
/* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
|
||||||
/* run */ List.of(),
|
/* run */ List.of(),
|
||||||
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10)),
|
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10)),
|
||||||
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 6)),
|
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 6)),
|
||||||
@@ -354,7 +495,7 @@ public class WorkCountTrackerTest {
|
|||||||
// When there are BG jobs pending, 2 (min-BG) jobs should run.
|
// When there are BG jobs pending, 2 (min-BG) jobs should run.
|
||||||
checkSimple(6,
|
checkSimple(6,
|
||||||
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
||||||
/* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
|
/* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
|
||||||
/* run */ List.of(),
|
/* run */ List.of(),
|
||||||
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 1)),
|
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 1)),
|
||||||
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 1)),
|
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 1)),
|
||||||
@@ -383,6 +524,16 @@ public class WorkCountTrackerTest {
|
|||||||
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 6)),
|
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 6)),
|
||||||
/* resPen */ List.of(Pair.create(WORK_TYPE_BG, 47)));
|
/* resPen */ List.of(Pair.create(WORK_TYPE_BG, 47)));
|
||||||
|
|
||||||
|
checkSimple(8,
|
||||||
|
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
||||||
|
/* max */ List.of(Pair.create(WORK_TYPE_BG, 6)),
|
||||||
|
/* run */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 4)),
|
||||||
|
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 49), Pair.create(WORK_TYPE_BG, 49)),
|
||||||
|
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 4)),
|
||||||
|
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 47), Pair.create(WORK_TYPE_BG, 49))
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
checkSimple(8,
|
checkSimple(8,
|
||||||
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
||||||
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 6)),
|
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 6)),
|
||||||
@@ -407,6 +558,14 @@ public class WorkCountTrackerTest {
|
|||||||
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 6)),
|
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 6)),
|
||||||
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 8), Pair.create(WORK_TYPE_BG, 49)));
|
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 8), Pair.create(WORK_TYPE_BG, 49)));
|
||||||
|
|
||||||
|
checkSimple(8,
|
||||||
|
/* min */ List.of(Pair.create(WORK_TYPE_BG, 1)),
|
||||||
|
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 2)),
|
||||||
|
/* run */ List.of(Pair.create(WORK_TYPE_BG, 6)),
|
||||||
|
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 49)),
|
||||||
|
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 6)),
|
||||||
|
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 8), Pair.create(WORK_TYPE_BG, 49)));
|
||||||
|
|
||||||
checkSimple(6,
|
checkSimple(6,
|
||||||
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
||||||
/* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
|
/* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
|
||||||
@@ -425,6 +584,38 @@ public class WorkCountTrackerTest {
|
|||||||
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)),
|
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)),
|
||||||
/* resRun */ List.of(Pair.create(WORK_TYPE_BG, 6)),
|
/* resRun */ List.of(Pair.create(WORK_TYPE_BG, 6)),
|
||||||
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)));
|
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)));
|
||||||
|
|
||||||
|
checkSimple(6,
|
||||||
|
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
||||||
|
/* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
|
||||||
|
/* run */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
||||||
|
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10),
|
||||||
|
Pair.create(WORK_TYPE_BG, 3),
|
||||||
|
Pair.create(WORK_TYPE_BGUSER, 3)),
|
||||||
|
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 2)),
|
||||||
|
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 6),
|
||||||
|
Pair.create(WORK_TYPE_BG, 3),
|
||||||
|
Pair.create(WORK_TYPE_BGUSER, 3)));
|
||||||
|
|
||||||
|
checkSimple(6,
|
||||||
|
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
||||||
|
/* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 3)),
|
||||||
|
/* run */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
||||||
|
/* pen */ List.of(Pair.create(WORK_TYPE_BG, 3), Pair.create(WORK_TYPE_BGUSER, 3)),
|
||||||
|
/* resRun */ List.of(
|
||||||
|
Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
|
||||||
|
/* resPen */ List.of(
|
||||||
|
Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1)));
|
||||||
|
|
||||||
|
checkSimple(6,
|
||||||
|
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
||||||
|
/* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 1)),
|
||||||
|
/* run */ List.of(Pair.create(WORK_TYPE_BG, 2)),
|
||||||
|
/* pen */ List.of(Pair.create(WORK_TYPE_BG, 3), Pair.create(WORK_TYPE_BGUSER, 3)),
|
||||||
|
/* resRun */ List.of(
|
||||||
|
Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 1)),
|
||||||
|
/* resPen */ List.of(
|
||||||
|
Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Tests that the counter updates properly when jobs are stopped. */
|
/** Tests that the counter updates properly when jobs are stopped. */
|
||||||
|
|||||||
@@ -16,8 +16,10 @@
|
|||||||
package com.android.server.job;
|
package com.android.server.job;
|
||||||
|
|
||||||
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
|
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
|
||||||
|
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER;
|
||||||
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP;
|
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
@@ -31,7 +33,6 @@ import androidx.test.runner.AndroidJUnit4;
|
|||||||
import com.android.server.job.JobConcurrencyManager.WorkTypeConfig;
|
import com.android.server.job.JobConcurrencyManager.WorkTypeConfig;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
@@ -44,8 +45,10 @@ public class WorkTypeConfigTest {
|
|||||||
private static final String KEY_MAX_TOTAL = "concurrency_max_total_test";
|
private static final String KEY_MAX_TOTAL = "concurrency_max_total_test";
|
||||||
private static final String KEY_MAX_TOP = "concurrency_max_top_test";
|
private static final String KEY_MAX_TOP = "concurrency_max_top_test";
|
||||||
private static final String KEY_MAX_BG = "concurrency_max_bg_test";
|
private static final String KEY_MAX_BG = "concurrency_max_bg_test";
|
||||||
|
private static final String KEY_MAX_BGUSER = "concurrency_max_bguser_test";
|
||||||
private static final String KEY_MIN_TOP = "concurrency_min_top_test";
|
private static final String KEY_MIN_TOP = "concurrency_min_top_test";
|
||||||
private static final String KEY_MIN_BG = "concurrency_min_bg_test";
|
private static final String KEY_MIN_BG = "concurrency_min_bg_test";
|
||||||
|
private static final String KEY_MIN_BGUSER = "concurrency_min_bguser_test";
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
@@ -57,17 +60,21 @@ public class WorkTypeConfigTest {
|
|||||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOTAL, "", false);
|
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOTAL, "", false);
|
||||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOP, "", false);
|
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOP, "", false);
|
||||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BG, "", false);
|
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BG, "", false);
|
||||||
|
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BGUSER, "", false);
|
||||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_TOP, "", false);
|
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_TOP, "", false);
|
||||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BG, "", false);
|
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BG, "", false);
|
||||||
|
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BGUSER, "", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void check(@Nullable DeviceConfig.Properties config,
|
private void check(@Nullable DeviceConfig.Properties config,
|
||||||
int defaultTotal,
|
int defaultTotal,
|
||||||
@Nullable Pair<Integer, Integer> defaultTopLimits,
|
@Nullable Pair<Integer, Integer> defaultTopLimits,
|
||||||
@Nullable Pair<Integer, Integer> defaultBgLimits,
|
@Nullable Pair<Integer, Integer> defaultBgLimits,
|
||||||
|
@Nullable Pair<Integer, Integer> defaultBgUserLimits,
|
||||||
boolean expectedValid, int expectedTotal,
|
boolean expectedValid, int expectedTotal,
|
||||||
@NonNull Pair<Integer, Integer> expectedTopLimits,
|
@NonNull Pair<Integer, Integer> expectedTopLimits,
|
||||||
@NonNull Pair<Integer, Integer> expectedBgLimits) throws Exception {
|
@NonNull Pair<Integer, Integer> expectedBgLimits,
|
||||||
|
@NonNull Pair<Integer, Integer> expectedBgUserLimits) throws Exception {
|
||||||
resetConfig();
|
resetConfig();
|
||||||
if (config != null) {
|
if (config != null) {
|
||||||
DeviceConfig.setProperties(config);
|
DeviceConfig.setProperties(config);
|
||||||
@@ -92,6 +99,14 @@ public class WorkTypeConfigTest {
|
|||||||
defaultMax.add(Pair.create(WORK_TYPE_BG, val));
|
defaultMax.add(Pair.create(WORK_TYPE_BG, val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (defaultBgUserLimits != null) {
|
||||||
|
if ((val = defaultBgUserLimits.first) != null) {
|
||||||
|
defaultMin.add(Pair.create(WORK_TYPE_BGUSER, val));
|
||||||
|
}
|
||||||
|
if ((val = defaultBgUserLimits.second) != null) {
|
||||||
|
defaultMax.add(Pair.create(WORK_TYPE_BGUSER, val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final WorkTypeConfig counts;
|
final WorkTypeConfig counts;
|
||||||
try {
|
try {
|
||||||
@@ -112,40 +127,45 @@ public class WorkTypeConfigTest {
|
|||||||
|
|
||||||
counts.update(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_JOB_SCHEDULER));
|
counts.update(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_JOB_SCHEDULER));
|
||||||
|
|
||||||
Assert.assertEquals(expectedTotal, counts.getMaxTotal());
|
assertEquals(expectedTotal, counts.getMaxTotal());
|
||||||
Assert.assertEquals((int) expectedTopLimits.first, counts.getMinReserved(WORK_TYPE_TOP));
|
assertEquals((int) expectedTopLimits.first, counts.getMinReserved(WORK_TYPE_TOP));
|
||||||
Assert.assertEquals((int) expectedTopLimits.second, counts.getMax(WORK_TYPE_TOP));
|
assertEquals((int) expectedTopLimits.second, counts.getMax(WORK_TYPE_TOP));
|
||||||
Assert.assertEquals((int) expectedBgLimits.first, counts.getMinReserved(WORK_TYPE_BG));
|
assertEquals((int) expectedBgLimits.first, counts.getMinReserved(WORK_TYPE_BG));
|
||||||
Assert.assertEquals((int) expectedBgLimits.second, counts.getMax(WORK_TYPE_BG));
|
assertEquals((int) expectedBgLimits.second, counts.getMax(WORK_TYPE_BG));
|
||||||
|
assertEquals((int) expectedBgUserLimits.first, counts.getMinReserved(WORK_TYPE_BGUSER));
|
||||||
|
assertEquals((int) expectedBgUserLimits.second, counts.getMax(WORK_TYPE_BGUSER));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() throws Exception {
|
public void test() throws Exception {
|
||||||
// Tests with various combinations.
|
// Tests with various combinations.
|
||||||
check(null, /*default*/ 5, Pair.create(4, null), Pair.create(0, 1),
|
check(null, /*default*/ 5, Pair.create(4, null), Pair.create(0, 1), Pair.create(0, 1),
|
||||||
/*expected*/ true, 5, Pair.create(4, 5), Pair.create(0, 1));
|
/*expected*/ true, 5, Pair.create(4, 5), Pair.create(0, 1), Pair.create(0, 1));
|
||||||
check(null, /*default*/ 5, Pair.create(5, null), Pair.create(0, 0),
|
check(null, /*default*/ 5, Pair.create(5, null), Pair.create(0, 0), Pair.create(0, 0),
|
||||||
/*expected*/ true, 5, Pair.create(5, 5), Pair.create(0, 1));
|
/*expected*/ true, 5, Pair.create(5, 5), Pair.create(0, 1), Pair.create(0, 1));
|
||||||
check(null, /*default*/ 0, Pair.create(5, null), Pair.create(0, 0),
|
check(null, /*default*/ 0, Pair.create(5, null), Pair.create(0, 0), Pair.create(0, 0),
|
||||||
/*expected*/ false, 1, Pair.create(1, 1), Pair.create(0, 1));
|
/*expected*/ false, 1, Pair.create(1, 1), Pair.create(0, 1), Pair.create(0, 1));
|
||||||
check(null, /*default*/ -1, null, Pair.create(-1, -1),
|
check(null, /*default*/ -1, null, Pair.create(-1, -1), Pair.create(-1, -1),
|
||||||
/*expected*/ false, 1, Pair.create(1, 1), Pair.create(0, 1));
|
/*expected*/ false, 1, Pair.create(1, 1), Pair.create(0, 1), Pair.create(0, 1));
|
||||||
check(null, /*default*/ 5, null, Pair.create(5, 5),
|
check(null, /*default*/ 5, null, Pair.create(5, 5), Pair.create(0, 5),
|
||||||
/*expected*/ true, 5, Pair.create(1, 5), Pair.create(4, 5));
|
/*expected*/ true, 5, Pair.create(1, 5), Pair.create(4, 5), Pair.create(0, 5));
|
||||||
check(null, /*default*/ 6, Pair.create(1, null), Pair.create(6, 5),
|
check(null, /*default*/ 6, Pair.create(1, null), Pair.create(6, 5), Pair.create(2, 1),
|
||||||
/*expected*/ false, 6, Pair.create(1, 6), Pair.create(5, 5));
|
/*expected*/ false, 6, Pair.create(1, 6), Pair.create(5, 5), Pair.create(0, 1));
|
||||||
check(null, /*default*/ 4, null, Pair.create(6, 5),
|
check(null, /*default*/ 4, null, Pair.create(6, 5), Pair.create(6, 5),
|
||||||
/*expected*/ false, 4, Pair.create(1, 4), Pair.create(3, 4));
|
/*expected*/ false, 4, Pair.create(1, 4), Pair.create(3, 4), Pair.create(0, 4));
|
||||||
check(null, /*default*/ 5, Pair.create(4, null), Pair.create(1, 1),
|
check(null, /*default*/ 5, Pair.create(4, null), Pair.create(1, 1), Pair.create(0, 5),
|
||||||
/*expected*/ true, 5, Pair.create(4, 5), Pair.create(1, 1));
|
/*expected*/ true, 5, Pair.create(4, 5), Pair.create(1, 1), Pair.create(0, 5));
|
||||||
check(null, /*default*/ 15, null, Pair.create(15, 15),
|
check(null, /*default*/ 5, Pair.create(4, null), Pair.create(0, 1), Pair.create(1, 5),
|
||||||
/*expected*/ true, 15, Pair.create(1, 15), Pair.create(14, 15));
|
/*expected*/ true, 5, Pair.create(4, 5), Pair.create(0, 1), Pair.create(1, 5));
|
||||||
check(null, /*default*/ 16, null, Pair.create(16, 16),
|
check(null, /*default*/ 15, null, Pair.create(15, 15), Pair.create(0, 15),
|
||||||
/*expected*/ true, 16, Pair.create(1, 16), Pair.create(15, 16));
|
/*expected*/ true, 15, Pair.create(1, 15), Pair.create(14, 15), Pair.create(0, 15));
|
||||||
check(null, /*default*/ 20, null, Pair.create(20, 20),
|
check(null, /*default*/ 16, null, Pair.create(16, 16), Pair.create(0, 16),
|
||||||
/*expected*/ false, 16, Pair.create(1, 16), Pair.create(15, 16));
|
/*expected*/ true, 16, Pair.create(1, 16), Pair.create(15, 16), Pair.create(0, 16));
|
||||||
check(null, /*default*/ 20, null, Pair.create(16, 16),
|
check(null, /*default*/ 20, null, Pair.create(20, 20), Pair.create(10, 20),
|
||||||
/*expected*/ true, 16, Pair.create(1, 16), Pair.create(15, 16));
|
/*expected*/ false, 16,
|
||||||
|
Pair.create(1, 16), Pair.create(15, 16), Pair.create(0, 16));
|
||||||
|
check(null, /*default*/ 20, null, Pair.create(16, 16), Pair.create(0, 16),
|
||||||
|
/*expected*/ true, 16, Pair.create(1, 16), Pair.create(15, 16), Pair.create(0, 16));
|
||||||
|
|
||||||
// Test for overriding with a setting string.
|
// Test for overriding with a setting string.
|
||||||
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
|
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
|
||||||
@@ -153,26 +173,26 @@ public class WorkTypeConfigTest {
|
|||||||
.setInt(KEY_MAX_BG, 4)
|
.setInt(KEY_MAX_BG, 4)
|
||||||
.setInt(KEY_MIN_BG, 3)
|
.setInt(KEY_MIN_BG, 3)
|
||||||
.build(),
|
.build(),
|
||||||
/*default*/ 9, null, Pair.create(9, 9),
|
/*default*/ 9, null, Pair.create(9, 9), Pair.create(0, 2),
|
||||||
/*expected*/ true, 5, Pair.create(1, 5), Pair.create(3, 4));
|
/*expected*/ true, 5, Pair.create(1, 5), Pair.create(3, 4), Pair.create(0, 2));
|
||||||
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
|
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
|
||||||
.setInt(KEY_MAX_TOTAL, 5).build(),
|
.setInt(KEY_MAX_TOTAL, 5).build(),
|
||||||
/*default*/ 9, null, Pair.create(9, 9),
|
/*default*/ 9, null, Pair.create(9, 9), Pair.create(0, 0),
|
||||||
/*expected*/ true, 5, Pair.create(1, 5), Pair.create(4, 5));
|
/*expected*/ true, 5, Pair.create(1, 5), Pair.create(4, 5), Pair.create(0, 1));
|
||||||
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
|
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
|
||||||
.setInt(KEY_MAX_BG, 4).build(),
|
.setInt(KEY_MAX_BG, 4).build(),
|
||||||
/*default*/ 9, null, Pair.create(9, 9),
|
/*default*/ 9, null, Pair.create(9, 9), Pair.create(0, 9),
|
||||||
/*expected*/ true, 9, Pair.create(1, 9), Pair.create(4, 4));
|
/*expected*/ true, 9, Pair.create(1, 9), Pair.create(4, 4), Pair.create(0, 9));
|
||||||
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
|
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
|
||||||
.setInt(KEY_MIN_BG, 3).build(),
|
.setInt(KEY_MIN_BG, 3).build(),
|
||||||
/*default*/ 9, null, Pair.create(9, 9),
|
/*default*/ 9, null, Pair.create(9, 9), Pair.create(0, 6),
|
||||||
/*expected*/ true, 9, Pair.create(1, 9), Pair.create(3, 9));
|
/*expected*/ true, 9, Pair.create(1, 9), Pair.create(3, 9), Pair.create(0, 6));
|
||||||
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
|
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
|
||||||
.setInt(KEY_MAX_TOTAL, 20)
|
.setInt(KEY_MAX_TOTAL, 20)
|
||||||
.setInt(KEY_MAX_BG, 20)
|
.setInt(KEY_MAX_BG, 20)
|
||||||
.setInt(KEY_MIN_BG, 8)
|
.setInt(KEY_MIN_BG, 8)
|
||||||
.build(),
|
.build(),
|
||||||
/*default*/ 9, null, Pair.create(9, 9),
|
/*default*/ 9, null, Pair.create(9, 9), Pair.create(0, 8),
|
||||||
/*expected*/ true, 16, Pair.create(1, 16), Pair.create(8, 16));
|
/*expected*/ true, 16, Pair.create(1, 16), Pair.create(8, 16), Pair.create(0, 8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user