Loading cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java +13 −10 Original line number Diff line number Diff line Loading @@ -29,23 +29,21 @@ public class RequestSync { private String[] mArgs; private int mNextArg; private String mCurArgData; private boolean mIsForegroundRequest; private int mExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE; enum Operation { REQUEST_SYNC { @Override void invoke(RequestSync caller) { if (caller.mIsForegroundRequest) { caller.mExtras.putBoolean( ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC, true); } else { caller.mExtras.putBoolean( ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC, true); final int flag = caller.mExemptionFlag; caller.mExtras.putInt(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG, flag); if (flag == ContentResolver.SYNC_EXEMPTION_NONE) { System.out.println( "Making a sync request as a background app.\n" + "Note: request may be throttled by App Standby.\n" + "To override this behavior and run a sync immediately," + " pass a -f option.\n"); + " pass a -f or -F option (use -h for help).\n"); } final SyncRequest request = new SyncRequest.Builder() Loading Loading @@ -213,7 +211,10 @@ public class RequestSync { mExtras.putBoolean(key, Boolean.valueOf(value)); } else if (opt.equals("-f") || opt.equals("--foreground")) { mIsForegroundRequest = true; mExemptionFlag = ContentResolver.SYNC_EXEMPTION_ACTIVE; } else if (opt.equals("-F") || opt.equals("--top")) { mExemptionFlag = ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP; } else { System.err.println("Error: Unknown option: " + opt); Loading Loading @@ -293,7 +294,9 @@ public class RequestSync { " -a|--authority <AUTHORITY>\n" + " App-standby related options\n" + "\n" + " -f|--foreground (Exempt a sync from app standby)\n" + " -f|--foreground (cause WORKING_SET, FREQUENT sync adapters" + " to run immediately)\n" + " -F|--top (cause even RARE sync adapters to run immediately)\n" + " ContentResolver extra options:\n" + " --is|--ignore-settings: Add SYNC_EXTRAS_IGNORE_SETTINGS\n" + " --ib|--ignore-backoff: Add SYNC_EXTRAS_IGNORE_BACKOFF\n" + Loading core/java/android/app/usage/UsageStatsManager.java +6 −0 Original line number Diff line number Diff line Loading @@ -183,10 +183,13 @@ public final class UsageStatsManager { public static final int REASON_SUB_USAGE_SLICE_PINNED = 0x0009; /** @hide */ public static final int REASON_SUB_USAGE_SLICE_PINNED_PRIV = 0x000A; /** @hide */ public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_START = 0x000B; /** @hide */ public static final int REASON_SUB_PREDICTED_RESTORED = 0x0001; /** @hide */ @IntDef(flag = false, prefix = { "STANDBY_BUCKET_" }, value = { STANDBY_BUCKET_EXEMPTED, Loading Loading @@ -665,6 +668,9 @@ public final class UsageStatsManager { case REASON_SUB_USAGE_SLICE_PINNED_PRIV: sb.append("slpp"); break; case REASON_SUB_USAGE_EXEMPTED_SYNC_START: sb.append("es"); break; } break; } Loading core/java/android/app/usage/UsageStatsManagerInternal.java +8 −0 Original line number Diff line number Diff line Loading @@ -243,4 +243,12 @@ public abstract class UsageStatsManagerInternal { */ public abstract void reportAppJobState(String packageName, @UserIdInt int userId, int numDeferredJobs, long timeSinceLastJobRun); /** * Report a sync that was scheduled by an active app is about to be executed. * * @param packageName name of the package that owns the sync adapter. * @param userId which user the app is associated with */ public abstract void reportExemptedSyncStart(String packageName, @UserIdInt int userId); } core/java/android/content/ContentResolver.java +34 −13 Original line number Diff line number Diff line Loading @@ -166,24 +166,13 @@ public abstract class ContentResolver { public static final String SYNC_EXTRAS_DISALLOW_METERED = "allow_metered"; /** * {@hide} Flag only used by the requestsync command to treat a request as if it was made by * a foreground app. * {@hide} Integer extra containing a SyncExemption flag. * * Only the system and the shell user can set it. * * This extra is "virtual". Once passed to the system server, it'll be removed from the bundle. */ public static final String SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC = "force_fg_sync"; /** * {@hide} Flag only used by the requestsync command to treat a request as if it was made by * a background app. * * Only the system and the shell user can set it. * * This extra is "virtual". Once passed to the system server, it'll be removed from the bundle. */ public static final String SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC = "force_bg_sync"; public static final String SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG = "v_exemption"; /** * Set by the SyncManager to request that the SyncAdapter initialize itself for Loading Loading @@ -525,6 +514,38 @@ public abstract class ContentResolver { */ public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 1<<1; /** * No exception, throttled by app standby normally. * @hide */ public static final int SYNC_EXEMPTION_NONE = 0; /** * When executing a sync with this exemption, we'll put the target app in the ACTIVE bucket * for 10 minutes. This will allow the sync adapter to schedule/run further syncs and jobs. * * Note this will still *not* let RARE apps to run syncs, because they still won't get network * connection. * @hide */ public static final int SYNC_EXEMPTION_ACTIVE = 1; /** * In addition to {@link #SYNC_EXEMPTION_ACTIVE}, we put the sync adapter app in the * temp whitelist for 10 minutes, so that even RARE apps can run syncs right away. * @hide */ public static final int SYNC_EXEMPTION_ACTIVE_WITH_TEMP = 2; /** @hide */ @IntDef(flag = false, prefix = { "SYNC_EXEMPTION_" }, value = { SYNC_EXEMPTION_NONE, SYNC_EXEMPTION_ACTIVE, SYNC_EXEMPTION_ACTIVE_WITH_TEMP, }) @Retention(RetentionPolicy.SOURCE) public @interface SyncExemption {} // Always log queries which take 500ms+; shorter queries are // sampled accordingly. private static final boolean ENABLE_CONTENT_SAMPLE = false; Loading services/core/java/com/android/server/content/ContentService.java +39 −38 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.app.job.JobInfo; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentResolver.SyncExemption; import android.content.Context; import android.content.IContentService; import android.content.ISyncStatusObserver; Loading Loading @@ -78,7 +79,7 @@ import java.util.List; */ public final class ContentService extends IContentService.Stub { static final String TAG = "ContentService"; static final boolean DEBUG = false; static final boolean DEBUG = true; public static class Lifecycle extends SystemService { private ContentService mService; Loading Loading @@ -451,7 +452,7 @@ public final class ContentService extends IContentService.Stub { SyncManager syncManager = getSyncManager(); if (syncManager != null) { syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid, uri.getAuthority(), /*isAppStandbyExempted=*/ isUidInForeground(uid)); uri.getAuthority(), getSyncExemptionForCaller(uid)); } } Loading Loading @@ -508,7 +509,7 @@ public final class ContentService extends IContentService.Stub { int uId = Binder.getCallingUid(); validateExtras(uId, extras); final boolean isForegroundSyncRequest = isForegroundSyncRequest(uId, extras); final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(uId, extras); // This makes it so that future permission checks will be in the context of this // process rather than the caller's process. We will restore this before returning. Loading @@ -518,7 +519,7 @@ public final class ContentService extends IContentService.Stub { if (syncManager != null) { syncManager.scheduleSync(account, userId, uId, authority, extras, SyncStorageEngine.AuthorityInfo.UNDEFINED, /*isAppStandbyExempted=*/ isForegroundSyncRequest); syncExemption); } } finally { restoreCallingIdentity(identityToken); Loading Loading @@ -561,7 +562,7 @@ public final class ContentService extends IContentService.Stub { final Bundle extras = request.getBundle(); validateExtras(callerUid, extras); final boolean isForegroundSyncRequest = isForegroundSyncRequest(callerUid, extras); final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callerUid, extras); // This makes it so that future permission checks will be in the context of this // process rather than the caller's process. We will restore this before returning. Loading Loading @@ -589,7 +590,7 @@ public final class ContentService extends IContentService.Stub { syncManager.scheduleSync( request.getAccount(), userId, callerUid, request.getProvider(), extras, SyncStorageEngine.AuthorityInfo.UNDEFINED, /*isAppStandbyExempted=*/ isForegroundSyncRequest); syncExemption); } } finally { restoreCallingIdentity(identityToken); Loading Loading @@ -777,13 +778,15 @@ public final class ContentService extends IContentService.Stub { "no permission to write the sync settings"); enforceCrossUserPermission(userId, "no permission to modify the sync settings for user " + userId); final int callingUid = Binder.getCallingUid(); final int syncExemptionFlag = getSyncExemptionForCaller(callingUid); long identityToken = clearCallingIdentity(); try { SyncManager syncManager = getSyncManager(); if (syncManager != null) { syncManager.getSyncStorageEngine().setSyncAutomatically(account, userId, providerName, sync); providerName, sync, syncExemptionFlag); } } finally { restoreCallingIdentity(identityToken); Loading Loading @@ -964,11 +967,14 @@ public final class ContentService extends IContentService.Stub { mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, "no permission to write the sync settings"); final int callingUid = Binder.getCallingUid(); long identityToken = clearCallingIdentity(); try { SyncManager syncManager = getSyncManager(); if (syncManager != null) { syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId); syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId, getSyncExemptionForCaller(callingUid)); } } finally { restoreCallingIdentity(identityToken); Loading Loading @@ -1263,9 +1269,7 @@ public final class ContentService extends IContentService.Stub { } private void validateExtras(int callingUid, Bundle extras) { if (extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC) || extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC) ) { if (extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG)) { switch (callingUid) { case Process.ROOT_UID: case Process.SHELL_UID: Loading @@ -1277,39 +1281,36 @@ public final class ContentService extends IContentService.Stub { } } private boolean isForegroundSyncRequest(int callingUid, Bundle extras) { final boolean isForegroundRequest; if (extras.getBoolean(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC)) { isForegroundRequest = true; } else if (extras.getBoolean(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC)) { isForegroundRequest = false; } else { isForegroundRequest = isUidInForeground(callingUid); @SyncExemption private int getSyncExemptionForCaller(int callingUid) { return getSyncExemptionAndCleanUpExtrasForCaller(callingUid, null); } extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC); extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC); return isForegroundRequest; } @SyncExemption private int getSyncExemptionAndCleanUpExtrasForCaller(int callingUid, Bundle extras) { if (extras != null) { final int exemption = extras.getInt(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG, -1); private boolean isUidInForeground(int uid) { // If the caller is ADB, we assume it's a background request by default, because // that's also the default of requests from the requestsync command. // The requestsync command will always set either SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC or // SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC (for non-periodic sync requests), // so it shouldn't matter in practice. switch (uid) { case Process.SHELL_UID: case Process.ROOT_UID: return false; // Need to remove the virtual extra. extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG); if (exemption != -1) { return exemption; } } final ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class); if (ami != null) { return ami.getUidProcessState(uid) <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; final int procState = (ami != null) ? ami.getUidProcessState(callingUid) : ActivityManager.PROCESS_STATE_NONEXISTENT; if (procState <= ActivityManager.PROCESS_STATE_TOP) { return ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP; } return false; if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { return ContentResolver.SYNC_EXEMPTION_ACTIVE; } return ContentResolver.SYNC_EXEMPTION_NONE; } /** Loading Loading
cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java +13 −10 Original line number Diff line number Diff line Loading @@ -29,23 +29,21 @@ public class RequestSync { private String[] mArgs; private int mNextArg; private String mCurArgData; private boolean mIsForegroundRequest; private int mExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE; enum Operation { REQUEST_SYNC { @Override void invoke(RequestSync caller) { if (caller.mIsForegroundRequest) { caller.mExtras.putBoolean( ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC, true); } else { caller.mExtras.putBoolean( ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC, true); final int flag = caller.mExemptionFlag; caller.mExtras.putInt(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG, flag); if (flag == ContentResolver.SYNC_EXEMPTION_NONE) { System.out.println( "Making a sync request as a background app.\n" + "Note: request may be throttled by App Standby.\n" + "To override this behavior and run a sync immediately," + " pass a -f option.\n"); + " pass a -f or -F option (use -h for help).\n"); } final SyncRequest request = new SyncRequest.Builder() Loading Loading @@ -213,7 +211,10 @@ public class RequestSync { mExtras.putBoolean(key, Boolean.valueOf(value)); } else if (opt.equals("-f") || opt.equals("--foreground")) { mIsForegroundRequest = true; mExemptionFlag = ContentResolver.SYNC_EXEMPTION_ACTIVE; } else if (opt.equals("-F") || opt.equals("--top")) { mExemptionFlag = ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP; } else { System.err.println("Error: Unknown option: " + opt); Loading Loading @@ -293,7 +294,9 @@ public class RequestSync { " -a|--authority <AUTHORITY>\n" + " App-standby related options\n" + "\n" + " -f|--foreground (Exempt a sync from app standby)\n" + " -f|--foreground (cause WORKING_SET, FREQUENT sync adapters" + " to run immediately)\n" + " -F|--top (cause even RARE sync adapters to run immediately)\n" + " ContentResolver extra options:\n" + " --is|--ignore-settings: Add SYNC_EXTRAS_IGNORE_SETTINGS\n" + " --ib|--ignore-backoff: Add SYNC_EXTRAS_IGNORE_BACKOFF\n" + Loading
core/java/android/app/usage/UsageStatsManager.java +6 −0 Original line number Diff line number Diff line Loading @@ -183,10 +183,13 @@ public final class UsageStatsManager { public static final int REASON_SUB_USAGE_SLICE_PINNED = 0x0009; /** @hide */ public static final int REASON_SUB_USAGE_SLICE_PINNED_PRIV = 0x000A; /** @hide */ public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_START = 0x000B; /** @hide */ public static final int REASON_SUB_PREDICTED_RESTORED = 0x0001; /** @hide */ @IntDef(flag = false, prefix = { "STANDBY_BUCKET_" }, value = { STANDBY_BUCKET_EXEMPTED, Loading Loading @@ -665,6 +668,9 @@ public final class UsageStatsManager { case REASON_SUB_USAGE_SLICE_PINNED_PRIV: sb.append("slpp"); break; case REASON_SUB_USAGE_EXEMPTED_SYNC_START: sb.append("es"); break; } break; } Loading
core/java/android/app/usage/UsageStatsManagerInternal.java +8 −0 Original line number Diff line number Diff line Loading @@ -243,4 +243,12 @@ public abstract class UsageStatsManagerInternal { */ public abstract void reportAppJobState(String packageName, @UserIdInt int userId, int numDeferredJobs, long timeSinceLastJobRun); /** * Report a sync that was scheduled by an active app is about to be executed. * * @param packageName name of the package that owns the sync adapter. * @param userId which user the app is associated with */ public abstract void reportExemptedSyncStart(String packageName, @UserIdInt int userId); }
core/java/android/content/ContentResolver.java +34 −13 Original line number Diff line number Diff line Loading @@ -166,24 +166,13 @@ public abstract class ContentResolver { public static final String SYNC_EXTRAS_DISALLOW_METERED = "allow_metered"; /** * {@hide} Flag only used by the requestsync command to treat a request as if it was made by * a foreground app. * {@hide} Integer extra containing a SyncExemption flag. * * Only the system and the shell user can set it. * * This extra is "virtual". Once passed to the system server, it'll be removed from the bundle. */ public static final String SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC = "force_fg_sync"; /** * {@hide} Flag only used by the requestsync command to treat a request as if it was made by * a background app. * * Only the system and the shell user can set it. * * This extra is "virtual". Once passed to the system server, it'll be removed from the bundle. */ public static final String SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC = "force_bg_sync"; public static final String SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG = "v_exemption"; /** * Set by the SyncManager to request that the SyncAdapter initialize itself for Loading Loading @@ -525,6 +514,38 @@ public abstract class ContentResolver { */ public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 1<<1; /** * No exception, throttled by app standby normally. * @hide */ public static final int SYNC_EXEMPTION_NONE = 0; /** * When executing a sync with this exemption, we'll put the target app in the ACTIVE bucket * for 10 minutes. This will allow the sync adapter to schedule/run further syncs and jobs. * * Note this will still *not* let RARE apps to run syncs, because they still won't get network * connection. * @hide */ public static final int SYNC_EXEMPTION_ACTIVE = 1; /** * In addition to {@link #SYNC_EXEMPTION_ACTIVE}, we put the sync adapter app in the * temp whitelist for 10 minutes, so that even RARE apps can run syncs right away. * @hide */ public static final int SYNC_EXEMPTION_ACTIVE_WITH_TEMP = 2; /** @hide */ @IntDef(flag = false, prefix = { "SYNC_EXEMPTION_" }, value = { SYNC_EXEMPTION_NONE, SYNC_EXEMPTION_ACTIVE, SYNC_EXEMPTION_ACTIVE_WITH_TEMP, }) @Retention(RetentionPolicy.SOURCE) public @interface SyncExemption {} // Always log queries which take 500ms+; shorter queries are // sampled accordingly. private static final boolean ENABLE_CONTENT_SAMPLE = false; Loading
services/core/java/com/android/server/content/ContentService.java +39 −38 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.app.job.JobInfo; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentResolver.SyncExemption; import android.content.Context; import android.content.IContentService; import android.content.ISyncStatusObserver; Loading Loading @@ -78,7 +79,7 @@ import java.util.List; */ public final class ContentService extends IContentService.Stub { static final String TAG = "ContentService"; static final boolean DEBUG = false; static final boolean DEBUG = true; public static class Lifecycle extends SystemService { private ContentService mService; Loading Loading @@ -451,7 +452,7 @@ public final class ContentService extends IContentService.Stub { SyncManager syncManager = getSyncManager(); if (syncManager != null) { syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid, uri.getAuthority(), /*isAppStandbyExempted=*/ isUidInForeground(uid)); uri.getAuthority(), getSyncExemptionForCaller(uid)); } } Loading Loading @@ -508,7 +509,7 @@ public final class ContentService extends IContentService.Stub { int uId = Binder.getCallingUid(); validateExtras(uId, extras); final boolean isForegroundSyncRequest = isForegroundSyncRequest(uId, extras); final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(uId, extras); // This makes it so that future permission checks will be in the context of this // process rather than the caller's process. We will restore this before returning. Loading @@ -518,7 +519,7 @@ public final class ContentService extends IContentService.Stub { if (syncManager != null) { syncManager.scheduleSync(account, userId, uId, authority, extras, SyncStorageEngine.AuthorityInfo.UNDEFINED, /*isAppStandbyExempted=*/ isForegroundSyncRequest); syncExemption); } } finally { restoreCallingIdentity(identityToken); Loading Loading @@ -561,7 +562,7 @@ public final class ContentService extends IContentService.Stub { final Bundle extras = request.getBundle(); validateExtras(callerUid, extras); final boolean isForegroundSyncRequest = isForegroundSyncRequest(callerUid, extras); final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callerUid, extras); // This makes it so that future permission checks will be in the context of this // process rather than the caller's process. We will restore this before returning. Loading Loading @@ -589,7 +590,7 @@ public final class ContentService extends IContentService.Stub { syncManager.scheduleSync( request.getAccount(), userId, callerUid, request.getProvider(), extras, SyncStorageEngine.AuthorityInfo.UNDEFINED, /*isAppStandbyExempted=*/ isForegroundSyncRequest); syncExemption); } } finally { restoreCallingIdentity(identityToken); Loading Loading @@ -777,13 +778,15 @@ public final class ContentService extends IContentService.Stub { "no permission to write the sync settings"); enforceCrossUserPermission(userId, "no permission to modify the sync settings for user " + userId); final int callingUid = Binder.getCallingUid(); final int syncExemptionFlag = getSyncExemptionForCaller(callingUid); long identityToken = clearCallingIdentity(); try { SyncManager syncManager = getSyncManager(); if (syncManager != null) { syncManager.getSyncStorageEngine().setSyncAutomatically(account, userId, providerName, sync); providerName, sync, syncExemptionFlag); } } finally { restoreCallingIdentity(identityToken); Loading Loading @@ -964,11 +967,14 @@ public final class ContentService extends IContentService.Stub { mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, "no permission to write the sync settings"); final int callingUid = Binder.getCallingUid(); long identityToken = clearCallingIdentity(); try { SyncManager syncManager = getSyncManager(); if (syncManager != null) { syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId); syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId, getSyncExemptionForCaller(callingUid)); } } finally { restoreCallingIdentity(identityToken); Loading Loading @@ -1263,9 +1269,7 @@ public final class ContentService extends IContentService.Stub { } private void validateExtras(int callingUid, Bundle extras) { if (extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC) || extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC) ) { if (extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG)) { switch (callingUid) { case Process.ROOT_UID: case Process.SHELL_UID: Loading @@ -1277,39 +1281,36 @@ public final class ContentService extends IContentService.Stub { } } private boolean isForegroundSyncRequest(int callingUid, Bundle extras) { final boolean isForegroundRequest; if (extras.getBoolean(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC)) { isForegroundRequest = true; } else if (extras.getBoolean(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC)) { isForegroundRequest = false; } else { isForegroundRequest = isUidInForeground(callingUid); @SyncExemption private int getSyncExemptionForCaller(int callingUid) { return getSyncExemptionAndCleanUpExtrasForCaller(callingUid, null); } extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC); extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC); return isForegroundRequest; } @SyncExemption private int getSyncExemptionAndCleanUpExtrasForCaller(int callingUid, Bundle extras) { if (extras != null) { final int exemption = extras.getInt(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG, -1); private boolean isUidInForeground(int uid) { // If the caller is ADB, we assume it's a background request by default, because // that's also the default of requests from the requestsync command. // The requestsync command will always set either SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC or // SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC (for non-periodic sync requests), // so it shouldn't matter in practice. switch (uid) { case Process.SHELL_UID: case Process.ROOT_UID: return false; // Need to remove the virtual extra. extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG); if (exemption != -1) { return exemption; } } final ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class); if (ami != null) { return ami.getUidProcessState(uid) <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; final int procState = (ami != null) ? ami.getUidProcessState(callingUid) : ActivityManager.PROCESS_STATE_NONEXISTENT; if (procState <= ActivityManager.PROCESS_STATE_TOP) { return ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP; } return false; if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { return ContentResolver.SYNC_EXEMPTION_ACTIVE; } return ContentResolver.SYNC_EXEMPTION_NONE; } /** Loading