Loading apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java +8 −0 Original line number Diff line number Diff line Loading @@ -17,15 +17,23 @@ package com.android.server.job; import android.annotation.Nullable; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.util.proto.ProtoOutputStream; import java.util.List; /** * JobScheduler local system service interface. * {@hide} Only for use within the system server. */ public interface JobSchedulerInternal { /** * Returns a list of jobs scheduled by the system service for itself. */ List<JobInfo> getSystemScheduledOwnJobs(@Nullable String namespace); /** * Cancel the jobs for a given uid (e.g. when app data is cleared) * Loading apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +15 −0 Original line number Diff line number Diff line Loading @@ -3535,6 +3535,21 @@ public class JobSchedulerService extends com.android.server.SystemService final class LocalService implements JobSchedulerInternal { @Override public List<JobInfo> getSystemScheduledOwnJobs(@Nullable String namespace) { synchronized (mLock) { final List<JobInfo> ownJobs = new ArrayList<>(); mJobs.forEachJob(Process.SYSTEM_UID, (job) -> { if (job.getSourceUid() == Process.SYSTEM_UID && Objects.equals(job.getNamespace(), namespace) && "android".equals(job.getSourcePackageName())) { ownJobs.add(job.getJob()); } }); return ownJobs; } } @Override public void cancelJobsForUid(int uid, boolean includeProxiedJobs, @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) { Loading core/proto/android/server/syncstorageengine.proto +1 −0 Original line number Diff line number Diff line Loading @@ -85,4 +85,5 @@ message SyncStatusProto { repeated StatusInfo status = 1; optional bool is_job_namespace_migrated = 2; optional bool is_job_attribution_fixed = 3; } services/core/java/com/android/server/content/SyncManager.java +47 −13 Original line number Diff line number Diff line Loading @@ -488,11 +488,14 @@ public class SyncManager { * migrated already. */ private void migrateSyncJobNamespaceIfNeeded() { if (mSyncStorageEngine.isJobNamespaceMigrated()) { final boolean namespaceMigrated = mSyncStorageEngine.isJobNamespaceMigrated(); final boolean attributionFixed = mSyncStorageEngine.isJobAttributionFixed(); if (namespaceMigrated && attributionFixed) { return; } final JobScheduler jobSchedulerDefaultNamespace = mContext.getSystemService(JobScheduler.class); if (!namespaceMigrated) { final List<JobInfo> pendingJobs = jobSchedulerDefaultNamespace.getAllPendingJobs(); // Wait until we've confirmed that all syncs have been migrated to the new namespace // before we persist successful migration to our status file. This is done to avoid Loading @@ -507,7 +510,8 @@ public class SyncManager { final SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras()); if (op != null) { // This is a sync. Move it over to SyncManager's namespace. mJobScheduler.schedule(job); mJobScheduler.scheduleAsPackage(job, op.owningPackage, op.target.userId, op.wakeLockName()); jobSchedulerDefaultNamespace.cancel(job.getId()); allSyncsMigrated = false; } Loading @@ -515,6 +519,36 @@ public class SyncManager { mSyncStorageEngine.setJobNamespaceMigrated(allSyncsMigrated); } // Fix attribution for any syncs that were previously scheduled using // JobScheduler.schedule() instead of JobScheduler.scheduleAsPackage(). final List<JobInfo> namespacedJobs = LocalServices.getService(JobSchedulerInternal.class) .getSystemScheduledOwnJobs(mJobScheduler.getNamespace()); // Wait until we've confirmed that all syncs have been proper attribution // before we persist attribution state to our status file. This is done to avoid // internal consistency issues if the devices reboots right after SyncManager has // rescheduled the job on its side but before JobScheduler has finished persisting // the updated jobs to disk. If JobScheduler hasn't persisted the update to disk, // then nothing that happened afterwards should have been persisted either, so there's // no concern over activity happening after the migration causing issues. // This case is done to fix issues for a subset of test devices. // TODO: remove this attribution check/fix code boolean allSyncsAttributed = true; for (int i = namespacedJobs.size() - 1; i >= 0; --i) { final JobInfo job = namespacedJobs.get(i); final SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras()); if (op != null) { // This is a sync. Make sure it's properly attributed to the app // instead of the system. // Since the job ID stays the same, scheduleAsPackage will replace the scheduled // job, so we don't need to call cancel as well. mJobScheduler.scheduleAsPackage(job, op.owningPackage, op.target.userId, op.wakeLockName()); allSyncsAttributed = false; } } mSyncStorageEngine.setJobAttributionFixed(allSyncsAttributed); } private synchronized void verifyJobScheduler() { if (mJobScheduler != null) { return; Loading services/core/java/com/android/server/content/SyncStorageEngine.java +20 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,7 @@ public class SyncStorageEngine { private volatile boolean mIsClockValid; private volatile boolean mIsJobNamespaceMigrated; private volatile boolean mIsJobAttributionFixed; static { sAuthorityRenames = new HashMap<String, String>(); Loading Loading @@ -852,6 +853,20 @@ public class SyncStorageEngine { return mIsJobNamespaceMigrated; } void setJobAttributionFixed(boolean fixed) { if (mIsJobAttributionFixed == fixed) { return; } mIsJobAttributionFixed = fixed; // This isn't urgent enough to write synchronously. Post it to the handler thread so // SyncManager can move on with whatever it was doing. mHandler.sendEmptyMessageDelayed(MSG_WRITE_STATUS, WRITE_STATUS_DELAY); } boolean isJobAttributionFixed() { return mIsJobAttributionFixed; } public Pair<Long, Long> getBackoff(EndPoint info) { synchronized (mAuthorities) { AuthorityInfo authority = getAuthorityLocked(info, "getBackoff"); Loading Loading @@ -2120,6 +2135,10 @@ public class SyncStorageEngine { mIsJobNamespaceMigrated = proto.readBoolean(SyncStatusProto.IS_JOB_NAMESPACE_MIGRATED); break; case (int) SyncStatusProto.IS_JOB_ATTRIBUTION_FIXED: mIsJobAttributionFixed = proto.readBoolean(SyncStatusProto.IS_JOB_ATTRIBUTION_FIXED); break; case ProtoInputStream.NO_MORE_FIELDS: return; } Loading Loading @@ -2389,6 +2408,7 @@ public class SyncStorageEngine { } proto.write(SyncStatusProto.IS_JOB_NAMESPACE_MIGRATED, mIsJobNamespaceMigrated); proto.write(SyncStatusProto.IS_JOB_ATTRIBUTION_FIXED, mIsJobAttributionFixed); proto.flush(); } Loading Loading
apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java +8 −0 Original line number Diff line number Diff line Loading @@ -17,15 +17,23 @@ package com.android.server.job; import android.annotation.Nullable; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.util.proto.ProtoOutputStream; import java.util.List; /** * JobScheduler local system service interface. * {@hide} Only for use within the system server. */ public interface JobSchedulerInternal { /** * Returns a list of jobs scheduled by the system service for itself. */ List<JobInfo> getSystemScheduledOwnJobs(@Nullable String namespace); /** * Cancel the jobs for a given uid (e.g. when app data is cleared) * Loading
apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +15 −0 Original line number Diff line number Diff line Loading @@ -3535,6 +3535,21 @@ public class JobSchedulerService extends com.android.server.SystemService final class LocalService implements JobSchedulerInternal { @Override public List<JobInfo> getSystemScheduledOwnJobs(@Nullable String namespace) { synchronized (mLock) { final List<JobInfo> ownJobs = new ArrayList<>(); mJobs.forEachJob(Process.SYSTEM_UID, (job) -> { if (job.getSourceUid() == Process.SYSTEM_UID && Objects.equals(job.getNamespace(), namespace) && "android".equals(job.getSourcePackageName())) { ownJobs.add(job.getJob()); } }); return ownJobs; } } @Override public void cancelJobsForUid(int uid, boolean includeProxiedJobs, @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) { Loading
core/proto/android/server/syncstorageengine.proto +1 −0 Original line number Diff line number Diff line Loading @@ -85,4 +85,5 @@ message SyncStatusProto { repeated StatusInfo status = 1; optional bool is_job_namespace_migrated = 2; optional bool is_job_attribution_fixed = 3; }
services/core/java/com/android/server/content/SyncManager.java +47 −13 Original line number Diff line number Diff line Loading @@ -488,11 +488,14 @@ public class SyncManager { * migrated already. */ private void migrateSyncJobNamespaceIfNeeded() { if (mSyncStorageEngine.isJobNamespaceMigrated()) { final boolean namespaceMigrated = mSyncStorageEngine.isJobNamespaceMigrated(); final boolean attributionFixed = mSyncStorageEngine.isJobAttributionFixed(); if (namespaceMigrated && attributionFixed) { return; } final JobScheduler jobSchedulerDefaultNamespace = mContext.getSystemService(JobScheduler.class); if (!namespaceMigrated) { final List<JobInfo> pendingJobs = jobSchedulerDefaultNamespace.getAllPendingJobs(); // Wait until we've confirmed that all syncs have been migrated to the new namespace // before we persist successful migration to our status file. This is done to avoid Loading @@ -507,7 +510,8 @@ public class SyncManager { final SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras()); if (op != null) { // This is a sync. Move it over to SyncManager's namespace. mJobScheduler.schedule(job); mJobScheduler.scheduleAsPackage(job, op.owningPackage, op.target.userId, op.wakeLockName()); jobSchedulerDefaultNamespace.cancel(job.getId()); allSyncsMigrated = false; } Loading @@ -515,6 +519,36 @@ public class SyncManager { mSyncStorageEngine.setJobNamespaceMigrated(allSyncsMigrated); } // Fix attribution for any syncs that were previously scheduled using // JobScheduler.schedule() instead of JobScheduler.scheduleAsPackage(). final List<JobInfo> namespacedJobs = LocalServices.getService(JobSchedulerInternal.class) .getSystemScheduledOwnJobs(mJobScheduler.getNamespace()); // Wait until we've confirmed that all syncs have been proper attribution // before we persist attribution state to our status file. This is done to avoid // internal consistency issues if the devices reboots right after SyncManager has // rescheduled the job on its side but before JobScheduler has finished persisting // the updated jobs to disk. If JobScheduler hasn't persisted the update to disk, // then nothing that happened afterwards should have been persisted either, so there's // no concern over activity happening after the migration causing issues. // This case is done to fix issues for a subset of test devices. // TODO: remove this attribution check/fix code boolean allSyncsAttributed = true; for (int i = namespacedJobs.size() - 1; i >= 0; --i) { final JobInfo job = namespacedJobs.get(i); final SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras()); if (op != null) { // This is a sync. Make sure it's properly attributed to the app // instead of the system. // Since the job ID stays the same, scheduleAsPackage will replace the scheduled // job, so we don't need to call cancel as well. mJobScheduler.scheduleAsPackage(job, op.owningPackage, op.target.userId, op.wakeLockName()); allSyncsAttributed = false; } } mSyncStorageEngine.setJobAttributionFixed(allSyncsAttributed); } private synchronized void verifyJobScheduler() { if (mJobScheduler != null) { return; Loading
services/core/java/com/android/server/content/SyncStorageEngine.java +20 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,7 @@ public class SyncStorageEngine { private volatile boolean mIsClockValid; private volatile boolean mIsJobNamespaceMigrated; private volatile boolean mIsJobAttributionFixed; static { sAuthorityRenames = new HashMap<String, String>(); Loading Loading @@ -852,6 +853,20 @@ public class SyncStorageEngine { return mIsJobNamespaceMigrated; } void setJobAttributionFixed(boolean fixed) { if (mIsJobAttributionFixed == fixed) { return; } mIsJobAttributionFixed = fixed; // This isn't urgent enough to write synchronously. Post it to the handler thread so // SyncManager can move on with whatever it was doing. mHandler.sendEmptyMessageDelayed(MSG_WRITE_STATUS, WRITE_STATUS_DELAY); } boolean isJobAttributionFixed() { return mIsJobAttributionFixed; } public Pair<Long, Long> getBackoff(EndPoint info) { synchronized (mAuthorities) { AuthorityInfo authority = getAuthorityLocked(info, "getBackoff"); Loading Loading @@ -2120,6 +2135,10 @@ public class SyncStorageEngine { mIsJobNamespaceMigrated = proto.readBoolean(SyncStatusProto.IS_JOB_NAMESPACE_MIGRATED); break; case (int) SyncStatusProto.IS_JOB_ATTRIBUTION_FIXED: mIsJobAttributionFixed = proto.readBoolean(SyncStatusProto.IS_JOB_ATTRIBUTION_FIXED); break; case ProtoInputStream.NO_MORE_FIELDS: return; } Loading Loading @@ -2389,6 +2408,7 @@ public class SyncStorageEngine { } proto.write(SyncStatusProto.IS_JOB_NAMESPACE_MIGRATED, mIsJobNamespaceMigrated); proto.write(SyncStatusProto.IS_JOB_ATTRIBUTION_FIXED, mIsJobAttributionFixed); proto.flush(); } Loading