summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/UserHandle.java3
-rw-r--r--services/core/java/android/app/usage/UsageStatsManagerInternal.java4
-rw-r--r--services/core/java/com/android/server/backup/SystemBackupAgent.java4
-rw-r--r--services/core/java/com/android/server/backup/UsageStatsBackupHelper.java22
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java2
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsIdleService.java69
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java69
7 files changed, 94 insertions, 79 deletions
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index dca722e649bc..4ce9184f0b96 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -123,6 +123,9 @@ public final class UserHandle implements Parcelable {
@TestApi
public static final int MIN_SECONDARY_USER_ID = 10;
+ /** @hide */
+ public static final int MAX_SECONDARY_USER_ID = Integer.MAX_VALUE / UserHandle.PER_USER_RANGE;
+
/**
* (Arbitrary) user handle cache size.
* {@link #CACHED_USER_HANDLES} caches user handles in the range of
diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
index a35aa7c74ee5..70eeb7fecc8f 100644
--- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -329,11 +329,11 @@ public abstract class UsageStatsManagerInternal {
* when the user is first unlocked to update the usage stats package mappings data that might
* be stale or have existed from a restore and belongs to packages that are not installed for
* this user anymore.
- * Note: this is only executed for the system user.
*
+ * @param userId The user to update
* @return {@code true} if the updating was successful, {@code false} otherwise
*/
- public abstract boolean updatePackageMappingsData();
+ public abstract boolean updatePackageMappingsData(@UserIdInt int userId);
/**
* Listener interface for usage events.
diff --git a/services/core/java/com/android/server/backup/SystemBackupAgent.java b/services/core/java/com/android/server/backup/SystemBackupAgent.java
index b18be3cc094e..08dcccfe405b 100644
--- a/services/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/services/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -86,7 +86,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
private static final Set<String> sEligibleForMultiUser = Sets.newArraySet(
PERMISSION_HELPER, NOTIFICATION_HELPER, SYNC_SETTINGS_HELPER, APP_LOCALES_HELPER,
- ACCOUNT_MANAGER_HELPER);
+ ACCOUNT_MANAGER_HELPER, USAGE_STATS_HELPER);
private int mUserId = UserHandle.USER_SYSTEM;
@@ -100,7 +100,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper(mUserId));
addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(mUserId));
addHelper(PERMISSION_HELPER, new PermissionBackupHelper(mUserId));
- addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
+ addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(mUserId));
addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper(mUserId));
addHelper(SLICES_HELPER, new SliceBackupHelper(this));
diff --git a/services/core/java/com/android/server/backup/UsageStatsBackupHelper.java b/services/core/java/com/android/server/backup/UsageStatsBackupHelper.java
index d6a70d369cdc..4098c1a9cff9 100644
--- a/services/core/java/com/android/server/backup/UsageStatsBackupHelper.java
+++ b/services/core/java/com/android/server/backup/UsageStatsBackupHelper.java
@@ -1,9 +1,9 @@
package com.android.server.backup;
+import android.annotation.UserIdInt;
import android.app.backup.BlobBackupHelper;
import android.app.usage.UsageStatsManagerInternal;
-import android.content.Context;
import android.os.UserHandle;
import android.util.Log;
@@ -26,8 +26,16 @@ public class UsageStatsBackupHelper extends BlobBackupHelper {
// same as UsageStatsDatabase.KEY_USAGE_STATS
static final String KEY_USAGE_STATS = "usage_stats";
- public UsageStatsBackupHelper(Context context) {
+ private final @UserIdInt int mUserId;
+
+ /**
+ * Marshall/unmarshall the usagestats data for the given user
+ *
+ * @param userId The userId to backup/restore
+ */
+ public UsageStatsBackupHelper(@UserIdInt int userId) {
super(BLOB_VERSION, KEY_USAGE_STATS);
+ mUserId = userId;
}
@Override
@@ -38,8 +46,11 @@ public class UsageStatsBackupHelper extends BlobBackupHelper {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(baos);
try {
+ // Note: Write 0 here deliberately so that a backup from a secondary user
+ // can still be restored to an older OS where the restore was always to user 0
+ // Writing the actual userId here would result in restores not working on pre-U.
out.writeInt(UserHandle.USER_SYSTEM);
- out.write(localUsageStatsManager.getBackupPayload(UserHandle.USER_SYSTEM, key));
+ out.write(localUsageStatsManager.getBackupPayload(mUserId, key));
} catch (IOException ioe) {
if (DEBUG) Log.e(TAG, "Failed to backup Usage Stats", ioe);
baos.reset();
@@ -49,7 +60,6 @@ public class UsageStatsBackupHelper extends BlobBackupHelper {
return null;
}
-
@Override
protected void applyRestoredPayload(String key, byte[] payload) {
if (KEY_USAGE_STATS.equals(key)) {
@@ -57,10 +67,10 @@ public class UsageStatsBackupHelper extends BlobBackupHelper {
LocalServices.getService(UsageStatsManagerInternal.class);
DataInputStream in = new DataInputStream(new ByteArrayInputStream(payload));
try {
- int user = in.readInt();
+ in.readInt(); // Legacy userId parameter, read and ignore
byte[] restoreData = new byte[payload.length - 4];
in.read(restoreData, 0, restoreData.length);
- localUsageStatsManager.applyRestoredPayload(user, key, restoreData);
+ localUsageStatsManager.applyRestoredPayload(mUserId, key, restoreData);
} catch (IOException ioe) {
if (DEBUG) Log.e(TAG, "Failed to restore Usage Stats", ioe);
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 1c838803fe21..762d1f665653 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -262,7 +262,7 @@ public class UserManagerService extends IUserManager.Stub {
// We need to keep process uid within Integer.MAX_VALUE.
@VisibleForTesting
- static final int MAX_USER_ID = Integer.MAX_VALUE / UserHandle.PER_USER_RANGE;
+ static final int MAX_USER_ID = UserHandle.MAX_SECONDARY_USER_ID;
// Max size of the queue of recently removed users
@VisibleForTesting
diff --git a/services/usage/java/com/android/server/usage/UsageStatsIdleService.java b/services/usage/java/com/android/server/usage/UsageStatsIdleService.java
index 316382028677..20f03d8c1b2a 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsIdleService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsIdleService.java
@@ -15,6 +15,7 @@
*/
package com.android.server.usage;
+import android.annotation.UserIdInt;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
@@ -35,65 +36,71 @@ import java.util.concurrent.TimeUnit;
public class UsageStatsIdleService extends JobService {
/**
- * Base job ID for the pruning job - must be unique within the system server uid.
+ * Namespace for prune job
*/
- private static final int PRUNE_JOB_ID = 546357475;
+ private static final String PRUNE_JOB_NS = "usagestats_prune";
+
/**
- * Job ID for the update mappings job - must be unique within the system server uid.
- * Incrementing PRUNE_JOB_ID by 21475 (MAX_USER_ID) to ensure there is no overlap in job ids.
+ * Namespace for update mappings job
*/
- private static final int UPDATE_MAPPINGS_JOB_ID = 546378950;
+ private static final String UPDATE_MAPPINGS_JOB_NS = "usagestats_mapping";
private static final String USER_ID_KEY = "user_id";
- static void scheduleJob(Context context, int userId) {
- final int userJobId = PRUNE_JOB_ID + userId; // unique job id per user
+ /** Schedule a prune job */
+ static void schedulePruneJob(Context context, @UserIdInt int userId) {
final ComponentName component = new ComponentName(context.getPackageName(),
UsageStatsIdleService.class.getName());
final PersistableBundle bundle = new PersistableBundle();
bundle.putInt(USER_ID_KEY, userId);
- final JobInfo pruneJob = new JobInfo.Builder(userJobId, component)
+ final JobInfo pruneJob = new JobInfo.Builder(userId, component)
.setRequiresDeviceIdle(true)
.setExtras(bundle)
.setPersisted(true)
.build();
- scheduleJobInternal(context, pruneJob, userJobId);
+ scheduleJobInternal(context, pruneJob, PRUNE_JOB_NS, userId);
}
- static void scheduleUpdateMappingsJob(Context context) {
+ static void scheduleUpdateMappingsJob(Context context, @UserIdInt int userId) {
final ComponentName component = new ComponentName(context.getPackageName(),
UsageStatsIdleService.class.getName());
- final JobInfo updateMappingsJob = new JobInfo.Builder(UPDATE_MAPPINGS_JOB_ID, component)
+ final PersistableBundle bundle = new PersistableBundle();
+ bundle.putInt(USER_ID_KEY, userId);
+ final JobInfo updateMappingsJob = new JobInfo.Builder(userId, component)
.setPersisted(true)
.setMinimumLatency(TimeUnit.DAYS.toMillis(1))
.setOverrideDeadline(TimeUnit.DAYS.toMillis(2))
+ .setExtras(bundle)
.build();
- scheduleJobInternal(context, updateMappingsJob, UPDATE_MAPPINGS_JOB_ID);
+ scheduleJobInternal(context, updateMappingsJob, UPDATE_MAPPINGS_JOB_NS, userId);
}
- private static void scheduleJobInternal(Context context, JobInfo pruneJob, int jobId) {
- final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
- final JobInfo pendingPruneJob = jobScheduler.getPendingJob(jobId);
- // only schedule a new prune job if one doesn't exist already for this user
- if (!pruneJob.equals(pendingPruneJob)) {
- jobScheduler.cancel(jobId); // cancel any previously scheduled prune job
- jobScheduler.schedule(pruneJob);
+ private static void scheduleJobInternal(Context context, JobInfo jobInfo,
+ String namespace, int jobId) {
+ JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+ jobScheduler = jobScheduler.forNamespace(namespace);
+ final JobInfo pendingJob = jobScheduler.getPendingJob(jobId);
+ // only schedule a new job if one doesn't exist already for this user
+ if (!jobInfo.equals(pendingJob)) {
+ jobScheduler.cancel(jobId); // cancel any previously scheduled job
+ jobScheduler.schedule(jobInfo);
}
}
- static void cancelJob(Context context, int userId) {
- cancelJobInternal(context, PRUNE_JOB_ID + userId);
+ static void cancelPruneJob(Context context, @UserIdInt int userId) {
+ cancelJobInternal(context, PRUNE_JOB_NS, userId);
}
- static void cancelUpdateMappingsJob(Context context) {
- cancelJobInternal(context, UPDATE_MAPPINGS_JOB_ID);
+ static void cancelUpdateMappingsJob(Context context, @UserIdInt int userId) {
+ cancelJobInternal(context, UPDATE_MAPPINGS_JOB_NS, userId);
}
- private static void cancelJobInternal(Context context, int jobId) {
- final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+ private static void cancelJobInternal(Context context, String namespace, int jobId) {
+ JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
if (jobScheduler != null) {
+ jobScheduler = jobScheduler.forNamespace(namespace);
jobScheduler.cancel(jobId);
}
}
@@ -102,15 +109,19 @@ public class UsageStatsIdleService extends JobService {
public boolean onStartJob(JobParameters params) {
final PersistableBundle bundle = params.getExtras();
final int userId = bundle.getInt(USER_ID_KEY, -1);
- if (userId == -1 && params.getJobId() != UPDATE_MAPPINGS_JOB_ID) {
+
+ if (userId == -1) { // legacy job
return false;
}
+ // Do async
AsyncTask.execute(() -> {
final UsageStatsManagerInternal usageStatsManagerInternal = LocalServices.getService(
UsageStatsManagerInternal.class);
- if (params.getJobId() == UPDATE_MAPPINGS_JOB_ID) {
- final boolean jobFinished = usageStatsManagerInternal.updatePackageMappingsData();
+ final String jobNs = params.getJobNamespace();
+ if (UPDATE_MAPPINGS_JOB_NS.equals(jobNs)) {
+ final boolean jobFinished =
+ usageStatsManagerInternal.updatePackageMappingsData(userId);
jobFinished(params, !jobFinished); // reschedule if data was not updated
} else {
final boolean jobFinished =
@@ -118,6 +129,8 @@ public class UsageStatsIdleService extends JobService {
jobFinished(params, !jobFinished); // reschedule if data was not pruned
}
});
+
+ // Job is running asynchronously
return true;
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index b3a1f2b85f63..7ff5b4a28f1b 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -433,11 +433,9 @@ public class UsageStatsService extends SystemService implements
private void onUserUnlocked(int userId) {
// fetch the installed packages outside the lock so it doesn't block package manager.
final HashMap<String, Long> installedPackages = getInstalledPackages(userId);
- // delay updating of package mappings for user 0 since their data is not likely to be stale.
- // this also makes it less likely for restored data to be erased on unexpected reboots.
- if (userId == UserHandle.USER_SYSTEM) {
- UsageStatsIdleService.scheduleUpdateMappingsJob(getContext());
- }
+
+ UsageStatsIdleService.scheduleUpdateMappingsJob(getContext(), userId);
+
final boolean deleteObsoleteData = shouldDeleteObsoleteData(UserHandle.of(userId));
synchronized (mLock) {
// This should be safe to add this early. Other than reportEventOrAddToQueue and
@@ -1261,8 +1259,8 @@ public class UsageStatsService extends SystemService implements
}
mAppStandby.onUserRemoved(userId);
// Cancel any scheduled jobs for this user since the user is being removed.
- UsageStatsIdleService.cancelJob(getContext(), userId);
- UsageStatsIdleService.cancelUpdateMappingsJob(getContext());
+ UsageStatsIdleService.cancelPruneJob(getContext(), userId);
+ UsageStatsIdleService.cancelUpdateMappingsJob(getContext(), userId);
}
/**
@@ -1300,7 +1298,7 @@ public class UsageStatsService extends SystemService implements
// Schedule a job to prune any data related to this package.
if (tokenRemoved != PackagesTokenData.UNASSIGNED_TOKEN) {
- UsageStatsIdleService.scheduleJob(getContext(), userId);
+ UsageStatsIdleService.schedulePruneJob(getContext(), userId);
}
}
@@ -1325,19 +1323,19 @@ public class UsageStatsService extends SystemService implements
/**
* Called by the Binder stub.
*/
- private boolean updatePackageMappingsData() {
+ private boolean updatePackageMappingsData(@UserIdInt int userId) {
// don't update the mappings if a profile user is defined
- if (!shouldDeleteObsoleteData(UserHandle.SYSTEM)) {
+ if (!shouldDeleteObsoleteData(UserHandle.of(userId))) {
return true; // return true so job scheduler doesn't reschedule the job
}
// fetch the installed packages outside the lock so it doesn't block package manager.
- final HashMap<String, Long> installedPkgs = getInstalledPackages(UserHandle.USER_SYSTEM);
+ final HashMap<String, Long> installedPkgs = getInstalledPackages(userId);
synchronized (mLock) {
- if (!mUserUnlockedStates.contains(UserHandle.USER_SYSTEM)) {
+ if (!mUserUnlockedStates.contains(userId)) {
return false; // user is no longer unlocked
}
- final UserUsageStatsService userService = mUserState.get(UserHandle.USER_SYSTEM);
+ final UserUsageStatsService userService = mUserState.get(userId);
if (userService == null) {
return false; // user was stopped or removed
}
@@ -3055,44 +3053,35 @@ public class UsageStatsService extends SystemService implements
}
@Override
- public byte[] getBackupPayload(int user, String key) {
- if (!mUserUnlockedStates.contains(user)) {
- Slog.w(TAG, "Failed to get backup payload for locked user " + user);
+ public byte[] getBackupPayload(@UserIdInt int userId, String key) {
+ if (!mUserUnlockedStates.contains(userId)) {
+ Slog.w(TAG, "Failed to get backup payload for locked user " + userId);
return null;
}
synchronized (mLock) {
- // Check to ensure that only user 0's data is b/r for now
- // Note: if backup and restore is enabled for users other than the system user, the
- // #onUserUnlocked logic, specifically when the update mappings job is scheduled via
- // UsageStatsIdleService.scheduleUpdateMappingsJob, will have to be updated.
- if (user == UserHandle.USER_SYSTEM) {
- final UserUsageStatsService userStats = getUserUsageStatsServiceLocked(user);
- if (userStats == null) {
- return null; // user was stopped or removed
- }
- return userStats.getBackupPayload(key);
- } else {
- return null;
+ final UserUsageStatsService userStats = getUserUsageStatsServiceLocked(userId);
+ if (userStats == null) {
+ return null; // user was stopped or removed
}
+ Slog.i(TAG, "Returning backup payload for u=" + userId);
+ return userStats.getBackupPayload(key);
}
}
@Override
- public void applyRestoredPayload(int user, String key, byte[] payload) {
+ public void applyRestoredPayload(@UserIdInt int userId, String key, byte[] payload) {
synchronized (mLock) {
- if (!mUserUnlockedStates.contains(user)) {
- Slog.w(TAG, "Failed to apply restored payload for locked user " + user);
+ if (!mUserUnlockedStates.contains(userId)) {
+ Slog.w(TAG, "Failed to apply restored payload for locked user " + userId);
return;
}
- if (user == UserHandle.USER_SYSTEM) {
- final UserUsageStatsService userStats = getUserUsageStatsServiceLocked(user);
- if (userStats == null) {
- return; // user was stopped or removed
- }
- final Set<String> restoredApps = userStats.applyRestoredPayload(key, payload);
- mAppStandby.restoreAppsToRare(restoredApps, user);
+ final UserUsageStatsService userStats = getUserUsageStatsServiceLocked(userId);
+ if (userStats == null) {
+ return; // user was stopped or removed
}
+ final Set<String> restoredApps = userStats.applyRestoredPayload(key, payload);
+ mAppStandby.restoreAppsToRare(restoredApps, userId);
}
}
@@ -3165,8 +3154,8 @@ public class UsageStatsService extends SystemService implements
}
@Override
- public boolean updatePackageMappingsData() {
- return UsageStatsService.this.updatePackageMappingsData();
+ public boolean updatePackageMappingsData(@UserIdInt int userId) {
+ return UsageStatsService.this.updatePackageMappingsData(userId);
}
/**