diff options
| author | 2015-10-29 17:57:11 -0700 | |
|---|---|---|
| committer | 2015-11-16 17:58:32 -0800 | |
| commit | bef28feba57be7fd6a4d14a85a8229154338b2ed (patch) | |
| tree | 3707b23b48eebad74a0ac9a70dcb02a330392b7e | |
| parent | 1653ac43956f74a3a31d76711f9c07348716a3d5 (diff) | |
Initial stab at background check.
Actually, this implementation is more what we want for ephemeral
apps. I am realizing the two are not really the same thing. :(
For this implementation, we now keep track of how long a uid has
been in the background, and after a certain amount of time
(currently 1 minute) we mark it as "idle". Any packages associated
with that uid are then no longer allowed to run in the background.
This means, until the app next goes in the foreground:
- No manifest broadcast receivers in the app will execute.
- No services can be started (binding services is still okay,
as this is outside dependencies on the app that should still
be represented).
- All alarms for the app are cancelled and no more can be set.
- All jobs for the app are cancelled and no more can be scheduled.
- All syncs for the app are cancelled and no more can be requested.
Change-Id: If53714ca4beed35faf2e89f916ce9eaaabd9290d
22 files changed, 917 insertions, 223 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 65de4ca5f59a..00bba2db111b 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -327,12 +327,39 @@ public class ActivityManager { /** @hide Process is being cached for later use and is empty. */ public static final int PROCESS_STATE_CACHED_EMPTY = 16; + /** @hide Should this process state be considered a background state? */ + public static final boolean isProcStateBackground(int procState) { + return procState >= PROCESS_STATE_BACKUP; + } + /** @hide requestType for assist context: only basic information. */ public static final int ASSIST_CONTEXT_BASIC = 0; /** @hide requestType for assist context: generate full AssistStructure. */ public static final int ASSIST_CONTEXT_FULL = 1; + /** @hide Flag for registerUidObserver: report changes in process state. */ + public static final int UID_OBSERVER_PROCSTATE = 1<<0; + + /** @hide Flag for registerUidObserver: report uid gone. */ + public static final int UID_OBSERVER_GONE = 1<<1; + + /** @hide Flag for registerUidObserver: report uid has become idle. */ + public static final int UID_OBSERVER_IDLE = 1<<2; + + /** @hide Flag for registerUidObserver: report uid has become active. */ + public static final int UID_OBSERVER_ACTIVE = 1<<3; + + /** @hide Mode for {@link IActivityManager#getAppStartMode}: normal free-to-run operation. */ + public static final int APP_START_MODE_NORMAL = 0; + + /** @hide Mode for {@link IActivityManager#getAppStartMode}: delay running until later. */ + public static final int APP_START_MODE_DELAYED = 1; + + /** @hide Mode for {@link IActivityManager#getAppStartMode}: disable/cancel pending + * launches. */ + public static final int APP_START_MODE_DISABLED = 2; + /** * Lock task mode is not active. */ diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 4449e4fa8665..e246e620dc72 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -756,7 +756,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } - case MOVE_TOP_ACTIVITY_TO_PINNED_STACK: { + case MOVE_TOP_ACTIVITY_TO_PINNED_STACK_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); final int stackId = data.readInt(); final Rect r = Rect.CREATOR.createFromParcel(data); @@ -2029,7 +2029,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM data.enforceInterface(IActivityManager.descriptor); IUidObserver observer = IUidObserver.Stub.asInterface( data.readStrongBinder()); - registerUidObserver(observer); + int which = data.readInt(); + registerUidObserver(observer, which); return true; } @@ -2698,13 +2699,22 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } - case REMOVE_STACK: { + case REMOVE_STACK_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); final int stackId = data.readInt(); removeStack(stackId); reply.writeNoException(); return true; } + case GET_APP_START_MODE_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + final int uid = data.readInt(); + final String pkg = data.readString(); + int res = getAppStartMode(uid, pkg); + reply.writeNoException(); + reply.writeInt(res); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -3579,7 +3589,7 @@ class ActivityManagerProxy implements IActivityManager data.writeInterfaceToken(IActivityManager.descriptor); data.writeInt(stackId); r.writeToParcel(data, 0); - mRemote.transact(MOVE_TOP_ACTIVITY_TO_PINNED_STACK, data, reply, 0); + mRemote.transact(MOVE_TOP_ACTIVITY_TO_PINNED_STACK_TRANSACTION, data, reply, 0); reply.readException(); final boolean res = reply.readInt() != 0; data.recycle(); @@ -5326,11 +5336,12 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } - public void registerUidObserver(IUidObserver observer) throws RemoteException { + public void registerUidObserver(IUidObserver observer, int which) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(observer != null ? observer.asBinder() : null); + data.writeInt(which); mRemote.transact(REGISTER_UID_OBSERVER_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); @@ -6292,11 +6303,26 @@ class ActivityManagerProxy implements IActivityManager Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeInt(stackId); - mRemote.transact(REMOVE_STACK, data, reply, 0); + mRemote.transact(REMOVE_STACK_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); reply.recycle(); } + @Override + public int getAppStartMode(int uid, String packageName) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeInt(uid); + data.writeString(packageName); + mRemote.transact(GET_APP_START_MODE_TRANSACTION, data, reply, 0); + reply.readException(); + int res = reply.readInt(); + data.recycle(); + reply.recycle(); + return res; + } + private IBinder mRemote; } diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 77a9795bb59f..f0453e9c45cc 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -237,8 +237,10 @@ public class AppOpsManager { public static final int OP_TURN_SCREEN_ON = 61; /** @hide Get device accounts. */ public static final int OP_GET_ACCOUNTS = 62; + /** @hide Control whether an application is allowed to run in the background. */ + public static final int OP_RUN_IN_BACKGROUND = 63; /** @hide */ - public static final int _NUM_OP = 63; + public static final int _NUM_OP = 64; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -409,6 +411,7 @@ public class AppOpsManager { OP_WRITE_EXTERNAL_STORAGE, OP_TURN_SCREEN_ON, OP_GET_ACCOUNTS, + OP_RUN_IN_BACKGROUND, }; /** @@ -478,7 +481,8 @@ public class AppOpsManager { OPSTR_READ_EXTERNAL_STORAGE, OPSTR_WRITE_EXTERNAL_STORAGE, null, - OPSTR_GET_ACCOUNTS + OPSTR_GET_ACCOUNTS, + null, }; /** @@ -549,6 +553,7 @@ public class AppOpsManager { "WRITE_EXTERNAL_STORAGE", "TURN_ON_SCREEN", "GET_ACCOUNTS", + "RUN_IN_BACKGROUND", }; /** @@ -618,7 +623,8 @@ public class AppOpsManager { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, null, // no permission for turning the screen on - Manifest.permission.GET_ACCOUNTS + Manifest.permission.GET_ACCOUNTS, + null, // no permission for running in background }; /** @@ -690,6 +696,7 @@ public class AppOpsManager { null, // WRITE_EXTERNAL_STORAGE null, // TURN_ON_SCREEN null, // GET_ACCOUNTS + null, // RUN_IN_BACKGROUND }; /** @@ -760,6 +767,7 @@ public class AppOpsManager { false, // WRITE_EXTERNAL_STORAGE false, // TURN_ON_SCREEN false, // GET_ACCOUNTS + false, // RUN_IN_BACKGROUND }; /** @@ -829,6 +837,7 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, // OP_TURN_ON_SCREEN AppOpsManager.MODE_ALLOWED, + AppOpsManager.MODE_ALLOWED, // OP_RUN_IN_BACKGROUND }; /** @@ -901,7 +910,8 @@ public class AppOpsManager { false, false, false, - false + false, + false, }; /** @@ -1329,7 +1339,7 @@ public class AppOpsManager { IAppOpsCallback cb = mModeWatchers.get(callback); if (cb == null) { cb = new IAppOpsCallback.Stub() { - public void opChanged(int op, String packageName) { + public void opChanged(int op, int uid, String packageName) { if (callback instanceof OnOpChangedInternalListener) { ((OnOpChangedInternalListener)callback).onOpChanged(op, packageName); } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index b69a4802d6c7..3d0fc92a2603 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -400,7 +400,7 @@ public interface IActivityManager extends IInterface { public void registerProcessObserver(IProcessObserver observer) throws RemoteException; public void unregisterProcessObserver(IProcessObserver observer) throws RemoteException; - public void registerUidObserver(IUidObserver observer) throws RemoteException; + public void registerUidObserver(IUidObserver observer, int which) throws RemoteException; public void unregisterUidObserver(IUidObserver observer) throws RemoteException; public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException; @@ -542,6 +542,8 @@ public interface IActivityManager extends IInterface { public void removeStack(int stackId) throws RemoteException; + public int getAppStartMode(int uid, String packageName) throws RemoteException; + /* * Private non-Binder interfaces */ @@ -899,6 +901,7 @@ public interface IActivityManager extends IInterface { int REPORT_SIZE_CONFIGURATIONS = IBinder.FIRST_CALL_TRANSACTION + 345; int MOVE_TASK_TO_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346; int SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347; - int REMOVE_STACK = IBinder.FIRST_CALL_TRANSACTION + 348; - int MOVE_TOP_ACTIVITY_TO_PINNED_STACK = IBinder.FIRST_CALL_TRANSACTION + 349; + int REMOVE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 348; + int MOVE_TOP_ACTIVITY_TO_PINNED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 349; + int GET_APP_START_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 350; } diff --git a/core/java/android/app/IUidObserver.aidl b/core/java/android/app/IUidObserver.aidl index 308cb945ab45..fa8d0c95e054 100644 --- a/core/java/android/app/IUidObserver.aidl +++ b/core/java/android/app/IUidObserver.aidl @@ -18,6 +18,24 @@ package android.app; /** {@hide} */ oneway interface IUidObserver { + /** + * General report of a state change of an uid. + */ void onUidStateChanged(int uid, int procState); + + /** + * Report that there are no longer any processes running for a uid. + */ void onUidGone(int uid); + + /** + * Report that a uid is now active (no longer idle). + */ + void onUidActive(int uid); + + /** + * Report that a uid is idle -- it has either been running in the background for + * a sufficient period of time, or all of its processes have gone away. + */ + void onUidIdle(int uid); } diff --git a/core/java/com/android/internal/app/IAppOpsCallback.aidl b/core/java/com/android/internal/app/IAppOpsCallback.aidl index afbc6096ede1..5fdc92041c3c 100644 --- a/core/java/com/android/internal/app/IAppOpsCallback.aidl +++ b/core/java/com/android/internal/app/IAppOpsCallback.aidl @@ -19,5 +19,5 @@ package com.android.internal.app; // This interface is also used by native code, so must // be kept in sync with frameworks/native/include/binder/IAppOpsCallback.h oneway interface IAppOpsCallback { - void opChanged(int op, String packageName); + void opChanged(int op, int uid, String packageName); } diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java index 1355635f0631..3164930aa749 100644 --- a/media/java/android/media/SoundPool.java +++ b/media/java/android/media/SoundPool.java @@ -166,7 +166,7 @@ public class SoundPool { updateAppOpsPlayAudio(); // register a callback to monitor whether the OP_PLAY_AUDIO is still allowed mAppOpsCallback = new IAppOpsCallback.Stub() { - public void opChanged(int op, String packageName) { + public void opChanged(int op, int uid, String packageName) { synchronized (mLock) { if (op == AppOpsManager.OP_PLAY_AUDIO) { updateAppOpsPlayAudio(); diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index f9d9950089b6..504a7efab60e 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -25,6 +25,7 @@ import android.app.BroadcastOptions; import android.app.IAlarmCompleteListener; import android.app.IAlarmListener; import android.app.IAlarmManager; +import android.app.IUidObserver; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -41,6 +42,7 @@ import android.os.IBinder; import android.os.Message; import android.os.PowerManager; import android.os.Process; +import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; @@ -459,7 +461,7 @@ class AlarmManagerService extends SystemService { long newStart = 0; // recalculate endpoints as we go long newEnd = Long.MAX_VALUE; int newFlags = 0; - for (int i = 0; i < alarms.size(); ) { + for (int i = alarms.size()-1; i >= 0; i--) { Alarm alarm = alarms.get(i); if (alarm.matches(packageName)) { alarms.remove(i); @@ -475,7 +477,42 @@ class AlarmManagerService extends SystemService { newEnd = alarm.maxWhenElapsed; } newFlags |= alarm.flags; - i++; + } + } + if (didRemove) { + // commit the new batch bounds + start = newStart; + end = newEnd; + flags = newFlags; + } + return didRemove; + } + + boolean removeForStopped(final int uid) { + boolean didRemove = false; + long newStart = 0; // recalculate endpoints as we go + long newEnd = Long.MAX_VALUE; + int newFlags = 0; + for (int i = alarms.size()-1; i >= 0; i--) { + Alarm alarm = alarms.get(i); + try { + if (alarm.uid == uid && ActivityManagerNative.getDefault().getAppStartMode( + uid, alarm.packageName) == ActivityManager.APP_START_MODE_DISABLED) { + alarms.remove(i); + didRemove = true; + if (alarm.alarmClock != null) { + mNextAlarmClockMayChange = true; + } + } else { + if (alarm.whenElapsed > newStart) { + newStart = alarm.whenElapsed; + } + if (alarm.maxWhenElapsed < newEnd) { + newEnd = alarm.maxWhenElapsed; + } + newFlags |= alarm.flags; + } + } catch (RemoteException e) { } } if (didRemove) { @@ -890,6 +927,13 @@ class AlarmManagerService extends SystemService { Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler."); } + try { + ActivityManagerNative.getDefault().registerUidObserver(new UidObserver(), + ActivityManager.UID_OBSERVER_IDLE); + } catch (RemoteException e) { + // ignored; both services live in system_server + } + publishBinderService(Context.ALARM_SERVICE, mService); } @@ -1035,6 +1079,15 @@ class AlarmManagerService extends SystemService { Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval, operation, directReceiver, listenerTag, workSource, flags, alarmClock, callingUid, callingPackage); + try { + if (ActivityManagerNative.getDefault().getAppStartMode(callingUid, callingPackage) + == ActivityManager.APP_START_MODE_DISABLED) { + Slog.w(TAG, "Not setting alarm from " + callingUid + ":" + a + + " -- package not allowed to start"); + return; + } + } catch (RemoteException e) { + } removeLocked(operation, directReceiver); setImplLocked(a, false, doValidate); } @@ -1841,6 +1894,37 @@ class AlarmManagerService extends SystemService { } } + void removeForStoppedLocked(int uid) { + boolean didRemove = false; + for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { + Batch b = mAlarmBatches.get(i); + didRemove |= b.removeForStopped(uid); + if (b.size() == 0) { + mAlarmBatches.remove(i); + } + } + for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) { + final Alarm a = mPendingWhileIdleAlarms.get(i); + try { + if (a.uid == uid && ActivityManagerNative.getDefault().getAppStartMode( + uid, a.packageName) == ActivityManager.APP_START_MODE_DISABLED) { + // Don't set didRemove, since this doesn't impact the scheduled alarms. + mPendingWhileIdleAlarms.remove(i); + } + } catch (RemoteException e) { + } + } + + if (didRemove) { + if (DEBUG_BATCH) { + Slog.v(TAG, "remove(package) changed bounds; rebatching"); + } + rebatchAllAlarmsLocked(true); + rescheduleKernelAlarmsLocked(); + updateNextAlarmClockLocked(); + } + } + void removeUserLocked(int userHandle) { boolean didRemove = false; for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { @@ -2673,7 +2757,22 @@ class AlarmManagerService extends SystemService { } } } - + + final class UidObserver extends IUidObserver.Stub { + @Override public void onUidStateChanged(int uid, int procState) throws RemoteException { + } + + @Override public void onUidGone(int uid) throws RemoteException { + } + + @Override public void onUidActive(int uid) throws RemoteException { + } + + @Override public void onUidIdle(int uid) throws RemoteException { + removeForStoppedLocked(uid); + } + }; + private final BroadcastStats getStatsLocked(PendingIntent pi) { String pkg = pi.getCreatorPackage(); int uid = pi.getCreatorUid(); diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index 96c1e2a5cda7..c131628f2854 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -54,7 +54,6 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Log; -import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; @@ -557,12 +556,12 @@ public class AppOpsService extends IAppOpsService.Stub { ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i); try { if (reportedPackageNames == null) { - callback.mCallback.opChanged(code, null); + callback.mCallback.opChanged(code, uid, null); } else { final int reportedPackageCount = reportedPackageNames.size(); for (int j = 0; j < reportedPackageCount; j++) { String reportedPackageName = reportedPackageNames.valueAt(j); - callback.mCallback.opChanged(code, reportedPackageName); + callback.mCallback.opChanged(code, uid, reportedPackageName); } } } catch (RemoteException e) { @@ -620,7 +619,7 @@ public class AppOpsService extends IAppOpsService.Stub { try { for (int i = 0; i < repCbs.size(); i++) { try { - repCbs.get(i).mCallback.opChanged(code, packageName); + repCbs.get(i).mCallback.opChanged(code, uid, packageName); } catch (RemoteException e) { } } @@ -630,39 +629,51 @@ public class AppOpsService extends IAppOpsService.Stub { } } - private static HashMap<Callback, ArrayList<Pair<String, Integer>>> addCallbacks( - HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks, - String packageName, int op, ArrayList<Callback> cbs) { + private static HashMap<Callback, ArrayList<ChangeRec>> addCallbacks( + HashMap<Callback, ArrayList<ChangeRec>> callbacks, + int op, int uid, String packageName, ArrayList<Callback> cbs) { if (cbs == null) { return callbacks; } if (callbacks == null) { - callbacks = new HashMap<Callback, ArrayList<Pair<String, Integer>>>(); + callbacks = new HashMap<>(); } boolean duplicate = false; for (int i=0; i<cbs.size(); i++) { Callback cb = cbs.get(i); - ArrayList<Pair<String, Integer>> reports = callbacks.get(cb); + ArrayList<ChangeRec> reports = callbacks.get(cb); if (reports == null) { - reports = new ArrayList<Pair<String, Integer>>(); + reports = new ArrayList<>(); callbacks.put(cb, reports); } else { final int reportCount = reports.size(); for (int j = 0; j < reportCount; j++) { - Pair<String, Integer> report = reports.get(j); - if (report.second == op && report.first.equals(packageName)) { + ChangeRec report = reports.get(j); + if (report.op == op && report.pkg.equals(packageName)) { duplicate = true; break; } } } if (!duplicate) { - reports.add(new Pair<>(packageName, op)); + reports.add(new ChangeRec(op, uid, packageName)); } } return callbacks; } + static final class ChangeRec { + final int op; + final int uid; + final String pkg; + + ChangeRec(int _op, int _uid, String _pkg) { + op = _op; + uid = _uid; + pkg = _pkg; + } + } + @Override public void resetAllModes(int reqUserId, String reqPackageName) { final int callingPid = Binder.getCallingPid(); @@ -682,7 +693,7 @@ public class AppOpsService extends IAppOpsService.Stub { } } - HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks = null; + HashMap<Callback, ArrayList<ChangeRec>> callbacks = null; synchronized (this) { boolean changed = false; for (int i = mUidStates.size() - 1; i >= 0; i--) { @@ -699,9 +710,9 @@ public class AppOpsService extends IAppOpsService.Stub { uidState.opModes = null; } for (String packageName : getPackagesForUid(uidState.uid)) { - callbacks = addCallbacks(callbacks, packageName, code, + callbacks = addCallbacks(callbacks, code, uidState.uid, packageName, mOpModeWatchers.get(code)); - callbacks = addCallbacks(callbacks, packageName, code, + callbacks = addCallbacks(callbacks, code, uidState.uid, packageName, mPackageModeWatchers.get(packageName)); } } @@ -734,9 +745,9 @@ public class AppOpsService extends IAppOpsService.Stub { && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) { curOp.mode = AppOpsManager.opToDefaultMode(curOp.op); changed = true; - callbacks = addCallbacks(callbacks, packageName, curOp.op, + callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName, mOpModeWatchers.get(curOp.op)); - callbacks = addCallbacks(callbacks, packageName, curOp.op, + callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName, mPackageModeWatchers.get(packageName)); if (curOp.time == 0 && curOp.rejectTime == 0) { pkgOps.removeAt(j); @@ -757,13 +768,13 @@ public class AppOpsService extends IAppOpsService.Stub { } } if (callbacks != null) { - for (Map.Entry<Callback, ArrayList<Pair<String, Integer>>> ent : callbacks.entrySet()) { + for (Map.Entry<Callback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) { Callback cb = ent.getKey(); - ArrayList<Pair<String, Integer>> reports = ent.getValue(); + ArrayList<ChangeRec> reports = ent.getValue(); for (int i=0; i<reports.size(); i++) { - Pair<String, Integer> rep = reports.get(i); + ChangeRec rep = reports.get(i); try { - cb.mCallback.opChanged(rep.second, rep.first); + cb.mCallback.opChanged(rep.op, rep.uid, rep.pkg); } catch (RemoteException e) { } } @@ -1163,8 +1174,10 @@ public class AppOpsService extends IAppOpsService.Stub { if (pkgUid != uid) { // Oops! The package name is not valid for the uid they are calling // under. Abort. + RuntimeException ex = new RuntimeException("here"); + ex.fillInStackTrace(); Slog.w(TAG, "Bad call: specified package " + packageName - + " under uid " + uid + " but it is really " + pkgUid); + + " under uid " + uid + " but it is really " + pkgUid, ex); return null; } } finally { diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 30565c634124..4d05f9ae9da4 100755 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -168,13 +168,10 @@ public final class ActiveServices { */ class ServiceMap extends Handler { final int mUserId; - final ArrayMap<ComponentName, ServiceRecord> mServicesByName - = new ArrayMap<ComponentName, ServiceRecord>(); - final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent - = new ArrayMap<Intent.FilterComparison, ServiceRecord>(); + final ArrayMap<ComponentName, ServiceRecord> mServicesByName = new ArrayMap<>(); + final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent = new ArrayMap<>(); - final ArrayList<ServiceRecord> mDelayedStartList - = new ArrayList<ServiceRecord>(); + final ArrayList<ServiceRecord> mDelayedStartList = new ArrayList<>(); /* XXX eventually I'd like to have this based on processes instead of services. * That is, if we try to start two services in a row both running in the same * process, this should be one entry in mStartingBackground for that one process @@ -185,8 +182,7 @@ public final class ActiveServices { = new ArrayList<DelayingProcess>(); */ - final ArrayList<ServiceRecord> mStartingBackground - = new ArrayList<ServiceRecord>(); + final ArrayList<ServiceRecord> mStartingBackground = new ArrayList<>(); static final int MSG_BG_START_TIMEOUT = 1; @@ -338,7 +334,7 @@ public final class ActiveServices { ServiceRecord r = res.record; if (!mAm.mUserController.exists(r.userId)) { - Slog.d(TAG, "Trying to start service with non-existent user! " + r.userId); + Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId); return null; } @@ -510,6 +506,35 @@ public final class ActiveServices { return 0; } + void stopInBackgroundLocked(int uid) { + // Stop all services associated with this uid due to it going to the background + // stopped state. + ServiceMap services = mServiceMap.get(UserHandle.getUserId(uid)); + ArrayList<ServiceRecord> stopping = null; + if (services != null) { + for (int i=services.mServicesByName.size()-1; i>=0; i--) { + ServiceRecord service = services.mServicesByName.valueAt(i); + if (service.appInfo.uid == uid && service.startRequested) { + if (mAm.mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, + uid, service.packageName) != AppOpsManager.MODE_ALLOWED) { + if (stopping == null) { + stopping = new ArrayList<>(); + stopping.add(service); + } + } + } + } + if (stopping != null) { + for (int i=stopping.size()-1; i>=0; i--) { + ServiceRecord service = stopping.get(i); + service.delayed = false; + services.ensureNotStartingBackground(service); + stopServiceLocked(service); + } + } + } + } + IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) { ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(), Binder.getCallingUid(), @@ -1069,6 +1094,17 @@ public final class ActiveServices { } r = smap.mServicesByName.get(name); if (r == null && createIfNeeded) { + // Before going further -- if this app is not allowed to run in the background, + // then at this point we aren't going to let it period. + if (!mAm.checkAllowBackgroundLocked(sInfo.applicationInfo.uid, + sInfo.packageName, callingPid)) { + Slog.w(TAG, "Background execution not allowed: service " + + r.intent + " to " + name.flattenToShortString() + + " from pid=" + callingPid + " uid=" + callingUid + + " pkg=" + callingPackage); + return null; + } + Intent.FilterComparison filter = new Intent.FilterComparison(service.cloneFilter()); ServiceRestarter res = new ServiceRestarter(); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 566065c02852..f0bcf0c816e9 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -60,7 +60,6 @@ import android.app.assist.AssistStructure; import android.app.usage.UsageEvents; import android.app.usage.UsageStatsManagerInternal; import android.appwidget.AppWidgetManager; -import android.content.pm.AppsQueryHelper; import android.content.pm.PermissionInfo; import android.content.res.Resources; import android.graphics.Bitmap; @@ -88,6 +87,7 @@ import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.AssistUtils; import com.android.internal.app.DumpHeapActivity; +import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.ProcessMap; @@ -109,15 +109,12 @@ import com.android.server.DeviceIdleController; import com.android.server.IntentResolver; import com.android.server.LocalServices; import com.android.server.ServiceThread; -import com.android.server.SystemConfig; import com.android.server.SystemService; import com.android.server.SystemServiceManager; import com.android.server.Watchdog; import com.android.server.am.ActivityStack.ActivityState; -import com.android.server.am.ActivityStackSupervisor.ActivityDisplay; import com.android.server.firewall.IntentFirewall; import com.android.server.pm.Installer; -import com.android.server.pm.UserManagerService; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.wm.AppTransition; import com.android.server.wm.WindowManagerService; @@ -388,6 +385,10 @@ public final class ActivityManagerService extends ActivityManagerNative // Maximum number of users we allow to be running at a time. static final int MAX_RUNNING_USERS = 3; + // This is the amount of time we allow an app to settle after it goes into the background, + // before we start restricting what it can do. + static final int BACKGROUND_SETTLE_TIME = 1*60*1000; + // How long to wait in getAssistContextExtras for the activity and foreground services // to respond with the result. static final int PENDING_ASSIST_EXTRAS_TIMEOUT = 500; @@ -716,6 +717,12 @@ public final class ActivityManagerService extends ActivityManagerNative final SparseArray<UidRecord> mActiveUids = new SparseArray<>(); /** + * This is for verifying the UID report flow. + */ + static final boolean VALIDATE_UID_STATES = true; + final SparseArray<UidRecord> mValidateUids = new SparseArray<>(); + + /** * Packages that the user has asked to have run in screen size * compatibility mode instead of filling the screen. */ @@ -1310,29 +1317,29 @@ public final class ActivityManagerService extends ActivityManagerNative } } - static final int SHOW_ERROR_MSG = 1; - static final int SHOW_NOT_RESPONDING_MSG = 2; - static final int SHOW_FACTORY_ERROR_MSG = 3; + static final int SHOW_ERROR_UI_MSG = 1; + static final int SHOW_NOT_RESPONDING_UI_MSG = 2; + static final int SHOW_FACTORY_ERROR_UI_MSG = 3; static final int UPDATE_CONFIGURATION_MSG = 4; static final int GC_BACKGROUND_PROCESSES_MSG = 5; - static final int WAIT_FOR_DEBUGGER_MSG = 6; + static final int WAIT_FOR_DEBUGGER_UI_MSG = 6; static final int SERVICE_TIMEOUT_MSG = 12; static final int UPDATE_TIME_ZONE = 13; - static final int SHOW_UID_ERROR_MSG = 14; - static final int SHOW_FINGERPRINT_ERROR_MSG = 15; + static final int SHOW_UID_ERROR_UI_MSG = 14; + static final int SHOW_FINGERPRINT_ERROR_UI_MSG = 15; static final int PROC_START_TIMEOUT_MSG = 20; static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21; static final int KILL_APPLICATION_MSG = 22; static final int FINALIZE_PENDING_INTENT_MSG = 23; static final int POST_HEAVY_NOTIFICATION_MSG = 24; static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25; - static final int SHOW_STRICT_MODE_VIOLATION_MSG = 26; + static final int SHOW_STRICT_MODE_VIOLATION_UI_MSG = 26; static final int CHECK_EXCESSIVE_WAKE_LOCKS_MSG = 27; static final int CLEAR_DNS_CACHE_MSG = 28; static final int UPDATE_HTTP_PROXY_MSG = 29; - static final int SHOW_COMPAT_MODE_DIALOG_MSG = 30; - static final int DISPATCH_PROCESSES_CHANGED = 31; - static final int DISPATCH_PROCESS_DIED = 32; + static final int SHOW_COMPAT_MODE_DIALOG_UI_MSG = 30; + static final int DISPATCH_PROCESSES_CHANGED_UI_MSG = 31; + static final int DISPATCH_PROCESS_DIED_UI_MSG = 32; static final int REPORT_MEM_USAGE_MSG = 33; static final int REPORT_USER_SWITCH_MSG = 34; static final int CONTINUE_USER_SWITCH_MSG = 35; @@ -1346,20 +1353,21 @@ public final class ActivityManagerService extends ActivityManagerNative static final int SYSTEM_USER_CURRENT_MSG = 43; static final int ENTER_ANIMATION_COMPLETE_MSG = 44; static final int FINISH_BOOTING_MSG = 45; - static final int START_USER_SWITCH_MSG = 46; + static final int START_USER_SWITCH_UI_MSG = 46; static final int SEND_LOCALE_TO_MOUNT_DAEMON_MSG = 47; - static final int DISMISS_DIALOG_MSG = 48; + static final int DISMISS_DIALOG_UI_MSG = 48; static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 49; static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 50; static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 51; static final int DELETE_DUMPHEAP_MSG = 52; static final int FOREGROUND_PROFILE_CHANGED_MSG = 53; - static final int DISPATCH_UIDS_CHANGED_MSG = 54; + static final int DISPATCH_UIDS_CHANGED_UI_MSG = 54; static final int REPORT_TIME_TRACKER_MSG = 55; static final int REPORT_USER_SWITCH_COMPLETE_MSG = 56; static final int SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG = 57; static final int APP_BOOST_DEACTIVATE_MSG = 58; static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG = 59; + static final int IDLE_UIDS_MSG = 60; static final int FIRST_ACTIVITY_STACK_MSG = 100; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -1394,7 +1402,7 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public void handleMessage(Message msg) { switch (msg.what) { - case SHOW_ERROR_MSG: { + case SHOW_ERROR_UI_MSG: { HashMap<String, Object> data = (HashMap<String, Object>) msg.obj; boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; @@ -1439,7 +1447,7 @@ public final class ActivityManagerService extends ActivityManagerNative ensureBootCompleted(); } break; - case SHOW_NOT_RESPONDING_MSG: { + case SHOW_NOT_RESPONDING_UI_MSG: { synchronized (ActivityManagerService.this) { HashMap<String, Object> data = (HashMap<String, Object>) msg.obj; ProcessRecord proc = (ProcessRecord)data.get("app"); @@ -1471,7 +1479,7 @@ public final class ActivityManagerService extends ActivityManagerNative ensureBootCompleted(); } break; - case SHOW_STRICT_MODE_VIOLATION_MSG: { + case SHOW_STRICT_MODE_VIOLATION_UI_MSG: { HashMap<String, Object> data = (HashMap<String, Object>) msg.obj; synchronized (ActivityManagerService.this) { ProcessRecord proc = (ProcessRecord) data.get("app"); @@ -1497,13 +1505,13 @@ public final class ActivityManagerService extends ActivityManagerNative } ensureBootCompleted(); } break; - case SHOW_FACTORY_ERROR_MSG: { + case SHOW_FACTORY_ERROR_UI_MSG: { Dialog d = new FactoryErrorDialog( mContext, msg.getData().getCharSequence("msg")); d.show(); ensureBootCompleted(); } break; - case WAIT_FOR_DEBUGGER_MSG: { + case WAIT_FOR_DEBUGGER_UI_MSG: { synchronized (ActivityManagerService.this) { ProcessRecord app = (ProcessRecord)msg.obj; if (msg.arg1 != 0) { @@ -1523,7 +1531,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } } break; - case SHOW_UID_ERROR_MSG: { + case SHOW_UID_ERROR_UI_MSG: { if (mShowDialogs) { AlertDialog d = new BaseErrorDialog(mContext); d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); @@ -1531,11 +1539,11 @@ public final class ActivityManagerService extends ActivityManagerNative d.setTitle(mContext.getText(R.string.android_system_label)); d.setMessage(mContext.getText(R.string.system_error_wipe_data)); d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok), - obtainMessage(DISMISS_DIALOG_MSG, d)); + obtainMessage(DISMISS_DIALOG_UI_MSG, d)); d.show(); } } break; - case SHOW_FINGERPRINT_ERROR_MSG: { + case SHOW_FINGERPRINT_ERROR_UI_MSG: { if (mShowDialogs) { AlertDialog d = new BaseErrorDialog(mContext); d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); @@ -1543,11 +1551,11 @@ public final class ActivityManagerService extends ActivityManagerNative d.setTitle(mContext.getText(R.string.android_system_label)); d.setMessage(mContext.getText(R.string.system_error_manufacturer)); d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok), - obtainMessage(DISMISS_DIALOG_MSG, d)); + obtainMessage(DISMISS_DIALOG_UI_MSG, d)); d.show(); } } break; - case SHOW_COMPAT_MODE_DIALOG_MSG: { + case SHOW_COMPAT_MODE_DIALOG_UI_MSG: { synchronized (ActivityManagerService.this) { ActivityRecord ar = (ActivityRecord) msg.obj; if (mCompatModeDialog != null) { @@ -1575,26 +1583,26 @@ public final class ActivityManagerService extends ActivityManagerNative } break; } - case START_USER_SWITCH_MSG: { + case START_USER_SWITCH_UI_MSG: { mUserController.showUserSwitchDialog(msg.arg1, (String) msg.obj); break; } - case DISMISS_DIALOG_MSG: { + case DISMISS_DIALOG_UI_MSG: { final Dialog d = (Dialog) msg.obj; d.dismiss(); break; } - case DISPATCH_PROCESSES_CHANGED: { + case DISPATCH_PROCESSES_CHANGED_UI_MSG: { dispatchProcessesChanged(); break; } - case DISPATCH_PROCESS_DIED: { + case DISPATCH_PROCESS_DIED_UI_MSG: { final int pid = msg.arg1; final int uid = msg.arg2; dispatchProcessDied(pid, uid); break; } - case DISPATCH_UIDS_CHANGED_MSG: { + case DISPATCH_UIDS_CHANGED_UI_MSG: { dispatchUidsChanged(); } break; } @@ -2046,7 +2054,7 @@ public final class ActivityManagerService extends ActivityManagerNative // it is finished we make sure it is reset to its default. mUserIsMonkey = false; } break; - case APP_BOOST_DEACTIVATE_MSG : { + case APP_BOOST_DEACTIVATE_MSG: { synchronized(ActivityManagerService.this) { if (mIsBoosted) { if (mBoostStartTime < (SystemClock.uptimeMillis() - APP_BOOST_TIMEOUT)) { @@ -2060,6 +2068,9 @@ public final class ActivityManagerService extends ActivityManagerNative } } } break; + case IDLE_UIDS_MSG: { + idleUids(); + } break; } } }; @@ -2352,6 +2363,17 @@ public final class ActivityManagerService extends ActivityManagerNative mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats")); mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"), mHandler); + mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_IN_BACKGROUND, null, + new IAppOpsCallback.Stub() { + @Override public void opChanged(int op, int uid, String packageName) { + if (op == AppOpsManager.OP_RUN_IN_BACKGROUND && packageName != null) { + if (mAppOpsService.checkOperation(op, uid, packageName) + != AppOpsManager.MODE_ALLOWED) { + runInBackgroundDisabled(uid); + } + } + } + }); mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml")); @@ -2766,7 +2788,7 @@ public final class ActivityManagerService extends ActivityManagerNative final void showAskCompatModeDialogLocked(ActivityRecord r) { Message msg = Message.obtain(); - msg.what = SHOW_COMPAT_MODE_DIALOG_MSG; + msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG; msg.obj = r.task.askedCompatMode ? null : r; mUiHandler.sendMessage(msg); } @@ -3797,8 +3819,10 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i=0; i<N; i++) { final UidRecord.ChangeItem change = mPendingUidChanges.get(i); mActiveUidChanges[i] = change; - change.uidRecord.pendingChange = null; - change.uidRecord = null; + if (change.uidRecord != null) { + change.uidRecord.pendingChange = null; + change.uidRecord = null; + } } mPendingUidChanges.clear(); if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, @@ -3808,7 +3832,8 @@ public final class ActivityManagerService extends ActivityManagerNative if (mLocalPowerManager != null) { for (int j=0; j<N; j++) { UidRecord.ChangeItem item = mActiveUidChanges[j]; - if (item.gone) { + if (item.change == UidRecord.CHANGE_GONE + || item.change == UidRecord.CHANGE_GONE_IDLE) { mLocalPowerManager.uidGone(item.uid); } else { mLocalPowerManager.updateUidProcState(item.uid, item.processState); @@ -3820,19 +3845,66 @@ public final class ActivityManagerService extends ActivityManagerNative while (i > 0) { i--; final IUidObserver observer = mUidObservers.getBroadcastItem(i); + final int which = (Integer)mUidObservers.getBroadcastCookie(i); if (observer != null) { try { for (int j=0; j<N; j++) { UidRecord.ChangeItem item = mActiveUidChanges[j]; - if (item.gone) { - if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, - "UID gone uid=" + item.uid); - observer.onUidGone(item.uid); + final int change = item.change; + UidRecord validateUid = null; + if (VALIDATE_UID_STATES && i == 0) { + validateUid = mValidateUids.get(item.uid); + if (validateUid == null && change != UidRecord.CHANGE_GONE + && change != UidRecord.CHANGE_GONE_IDLE) { + validateUid = new UidRecord(item.uid); + mValidateUids.put(item.uid, validateUid); + } + } + if (change == UidRecord.CHANGE_IDLE + || change == UidRecord.CHANGE_GONE_IDLE) { + if ((which & ActivityManager.UID_OBSERVER_IDLE) != 0) { + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "UID idle uid=" + item.uid); + observer.onUidIdle(item.uid); + } + if (VALIDATE_UID_STATES && i == 0) { + if (validateUid != null) { + validateUid.idle = true; + } + } + } else if (change == UidRecord.CHANGE_ACTIVE) { + if ((which & ActivityManager.UID_OBSERVER_ACTIVE) != 0) { + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "UID active uid=" + item.uid); + observer.onUidActive(item.uid); + } + if (VALIDATE_UID_STATES && i == 0) { + validateUid.idle = false; + } + } + if (change == UidRecord.CHANGE_GONE + || change == UidRecord.CHANGE_GONE_IDLE) { + if ((which & ActivityManager.UID_OBSERVER_GONE) != 0) { + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "UID gone uid=" + item.uid); + observer.onUidGone(item.uid); + } + if (VALIDATE_UID_STATES && i == 0) { + if (validateUid != null) { + mValidateUids.remove(item.uid); + } + } } else { - if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, - "UID CHANGED uid=" + item.uid - + ": " + item.processState); - observer.onUidStateChanged(item.uid, item.processState); + if ((which & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) { + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "UID CHANGED uid=" + item.uid + + ": " + item.processState); + observer.onUidStateChanged(item.uid, item.processState); + } + if (VALIDATE_UID_STATES && i == 0) { + validateUid.curProcState = validateUid.setProcState + = item.processState; + } } } } catch (RemoteException e) { @@ -5102,7 +5174,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Bring up the infamous App Not Responding dialog Message msg = Message.obtain(); HashMap<String, Object> map = new HashMap<String, Object>(); - msg.what = SHOW_NOT_RESPONDING_MSG; + msg.what = SHOW_NOT_RESPONDING_UI_MSG; msg.obj = map; msg.arg1 = aboveSystem ? 1 : 0; map.put("app", app); @@ -5881,7 +5953,7 @@ public final class ActivityManagerService extends ActivityManagerNative // No more processes using this uid, tell clients it is gone. if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "No more processes in " + old.uidRecord); - enqueueUidChangeLocked(old.uidRecord, true); + enqueueUidChangeLocked(old.uidRecord, -1, UidRecord.CHANGE_GONE); mActiveUids.remove(uid); } old.uidRecord = null; @@ -5907,7 +5979,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "Creating new process uid: " + uidRec); mActiveUids.put(proc.uid, uidRec); - enqueueUidChangeLocked(uidRec, false); + enqueueUidChangeLocked(uidRec, -1, UidRecord.CHANGE_ACTIVE); } proc.uidRecord = uidRec; uidRec.numProcs++; @@ -6715,9 +6787,11 @@ public final class ActivityManagerService extends ActivityManagerNative if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { activity = ActivityRecord.isInStackLocked(token); if (activity == null) { + Slog.w(TAG, "Failed createPendingResult: activity " + token + " not in any stack"); return null; } if (activity.finishing) { + Slog.w(TAG, "Failed createPendingResult: activity " + activity + " is finishing"); return null; } } @@ -7269,6 +7343,36 @@ public final class ActivityManagerService extends ActivityManagerNative return readMet && writeMet; } + public int getAppStartMode(int uid, String packageName) { + synchronized (this) { + boolean bg = checkAllowBackgroundLocked(uid, packageName, -1); + return bg ? ActivityManager.APP_START_MODE_NORMAL + : ActivityManager.APP_START_MODE_DISABLED; + } + } + + boolean checkAllowBackgroundLocked(int uid, String packageName, int callingPid) { + UidRecord uidRec = mActiveUids.get(uid); + if (uidRec == null || uidRec.idle) { + if (callingPid >= 0) { + ProcessRecord proc; + synchronized (mPidsSelfLocked) { + proc = mPidsSelfLocked.get(callingPid); + } + if (proc != null && proc.curProcState < ActivityManager.PROCESS_STATE_RECEIVER) { + // Whoever is instigating this is in the foreground, so we will allow it + // to go through. + return true; + } + } + if (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, packageName) + != AppOpsManager.MODE_ALLOWED) { + return false; + } + } + return true; + } + private ProviderInfo getProviderInfoLocked(String authority, int userHandle) { ProviderInfo pi = null; ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userHandle); @@ -8268,7 +8372,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (app == null) return; Message msg = Message.obtain(); - msg.what = WAIT_FOR_DEBUGGER_MSG; + msg.what = WAIT_FOR_DEBUGGER_UI_MSG; msg.obj = app; msg.arg1 = waiting ? 1 : 0; mUiHandler.sendMessage(msg); @@ -11213,11 +11317,12 @@ public final class ActivityManagerService extends ActivityManagerNative } } - public void registerUidObserver(IUidObserver observer) { + @Override + public void registerUidObserver(IUidObserver observer, int which) { enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER, "registerUidObserver()"); synchronized (this) { - mUidObservers.register(observer); + mUidObservers.register(observer, which); } } @@ -12056,7 +12161,7 @@ public final class ActivityManagerService extends ActivityManagerNative mTopData = null; mTopComponent = null; Message msg = Message.obtain(); - msg.what = SHOW_FACTORY_ERROR_MSG; + msg.what = SHOW_FACTORY_ERROR_UI_MSG; msg.getData().putCharSequence("msg", errorMsg); mUiHandler.sendMessage(msg); } @@ -12110,14 +12215,14 @@ public final class ActivityManagerService extends ActivityManagerNative if (AppGlobals.getPackageManager().hasSystemUidErrors()) { Slog.e(TAG, "UIDs on the system are inconsistent, you need to wipe your" + " data partition or your device will be unstable."); - mUiHandler.obtainMessage(SHOW_UID_ERROR_MSG).sendToTarget(); + mUiHandler.obtainMessage(SHOW_UID_ERROR_UI_MSG).sendToTarget(); } } catch (RemoteException e) { } if (!Build.isBuildConsistent()) { Slog.e(TAG, "Build fingerprint is not consistent, warning user"); - mUiHandler.obtainMessage(SHOW_FINGERPRINT_ERROR_MSG).sendToTarget(); + mUiHandler.obtainMessage(SHOW_FINGERPRINT_ERROR_UI_MSG).sendToTarget(); } long ident = Binder.clearCallingIdentity(); @@ -12398,7 +12503,7 @@ public final class ActivityManagerService extends ActivityManagerNative final long origId = Binder.clearCallingIdentity(); Message msg = Message.obtain(); - msg.what = SHOW_STRICT_MODE_VIOLATION_MSG; + msg.what = SHOW_STRICT_MODE_VIOLATION_UI_MSG; HashMap<String, Object> data = new HashMap<String, Object>(); data.put("result", result); data.put("app", r); @@ -12855,7 +12960,7 @@ public final class ActivityManagerService extends ActivityManagerNative } Message msg = Message.obtain(); - msg.what = SHOW_ERROR_MSG; + msg.what = SHOW_ERROR_UI_MSG; HashMap data = new HashMap(); data.put("result", result); data.put("app", r); @@ -13484,6 +13589,39 @@ public final class ActivityManagerService extends ActivityManagerNative } } + boolean dumpUids(PrintWriter pw, String dumpPackage, SparseArray<UidRecord> uids, + String header, boolean needSep) { + boolean printed = false; + int whichAppId = -1; + if (dumpPackage != null) { + try { + ApplicationInfo info = mContext.getPackageManager().getApplicationInfo( + dumpPackage, 0); + whichAppId = UserHandle.getAppId(info.uid); + } catch (NameNotFoundException e) { + e.printStackTrace(); + } + } + for (int i=0; i<uids.size(); i++) { + UidRecord uidRec = uids.valueAt(i); + if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) { + continue; + } + if (!printed) { + printed = true; + if (needSep) { + pw.println(); + } + pw.print(" "); + pw.println(header); + needSep = true; + } + pw.print(" UID "); UserHandle.formatUid(pw, uidRec.uid); + pw.print(": "); pw.println(uidRec); + } + return printed; + } + void dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll, String dumpPackage) { boolean needSep = false; @@ -13540,33 +13678,13 @@ public final class ActivityManagerService extends ActivityManagerNative } if (mActiveUids.size() > 0) { - boolean printed = false; - int whichAppId = -1; - if (dumpPackage != null) { - try { - ApplicationInfo info = mContext.getPackageManager().getApplicationInfo( - dumpPackage, 0); - whichAppId = UserHandle.getAppId(info.uid); - } catch (NameNotFoundException e) { - e.printStackTrace(); - } + if (dumpUids(pw, dumpPackage, mActiveUids, "UID states:", needSep)) { + printedAnything = needSep = true; } - for (int i=0; i<mActiveUids.size(); i++) { - UidRecord uidRec = mActiveUids.valueAt(i); - if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) { - continue; - } - if (!printed) { - printed = true; - if (needSep) { - pw.println(); - } - pw.println(" UID states:"); - needSep = true; - printedAnything = true; - } - pw.print(" UID "); UserHandle.formatUid(pw, uidRec.uid); - pw.print(": "); pw.println(uidRec); + } + if (mValidateUids.size() > 0) { + if (dumpUids(pw, dumpPackage, mValidateUids, "UID validation:", needSep)) { + printedAnything = needSep = true; } } @@ -14457,6 +14575,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (object1.first.setAdj != object2.first.setAdj) { return object1.first.setAdj > object2.first.setAdj ? -1 : 1; } + if (object1.first.setProcState != object2.first.setProcState) { + return object1.first.setProcState > object2.first.setProcState ? -1 : 1; + } if (object1.second.intValue() != object2.second.intValue()) { return object1.second.intValue() > object2.second.intValue() ? -1 : 1; } @@ -15829,7 +15950,8 @@ public final class ActivityManagerService extends ActivityManagerNative mAvailProcessChanges.add(item); } } - mUiHandler.obtainMessage(DISPATCH_PROCESS_DIED, app.pid, app.info.uid, null).sendToTarget(); + mUiHandler.obtainMessage(DISPATCH_PROCESS_DIED_UI_MSG, app.pid, app.info.uid, + null).sendToTarget(); // If the caller is restarting this app, then leave it in its // current lists and let the caller take care of it. @@ -19020,7 +19142,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (mPendingProcessChanges.size() == 0) { if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, "*** Enqueueing dispatch processes changed!"); - mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED).sendToTarget(); + mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG).sendToTarget(); } mPendingProcessChanges.add(item); } @@ -19039,29 +19161,46 @@ public final class ActivityManagerService extends ActivityManagerNative return success; } - private final void enqueueUidChangeLocked(UidRecord uidRec, boolean gone) { - if (uidRec.pendingChange == null) { + private final void enqueueUidChangeLocked(UidRecord uidRec, int uid, int change) { + final UidRecord.ChangeItem pendingChange; + if (uidRec == null || uidRec.pendingChange == null) { if (mPendingUidChanges.size() == 0) { if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "*** Enqueueing dispatch uid changed!"); - mUiHandler.obtainMessage(DISPATCH_UIDS_CHANGED_MSG).sendToTarget(); + mUiHandler.obtainMessage(DISPATCH_UIDS_CHANGED_UI_MSG).sendToTarget(); } final int NA = mAvailUidChanges.size(); if (NA > 0) { - uidRec.pendingChange = mAvailUidChanges.remove(NA-1); + pendingChange = mAvailUidChanges.remove(NA-1); if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, - "Retrieving available item: " + uidRec.pendingChange); + "Retrieving available item: " + pendingChange); } else { - uidRec.pendingChange = new UidRecord.ChangeItem(); + pendingChange = new UidRecord.ChangeItem(); if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, - "Allocating new item: " + uidRec.pendingChange); + "Allocating new item: " + pendingChange); + } + if (uidRec != null) { + uidRec.pendingChange = pendingChange; + if (change == UidRecord.CHANGE_GONE && !uidRec.idle) { + // If this uid is going away, and we haven't yet reported it is gone, + // then do so now. + change = UidRecord.CHANGE_GONE_IDLE; + } + } else if (uid < 0) { + throw new IllegalArgumentException("No UidRecord or uid"); + } + pendingChange.uidRecord = uidRec; + pendingChange.uid = uidRec != null ? uidRec.uid : uid; + mPendingUidChanges.add(pendingChange); + } else { + pendingChange = uidRec.pendingChange; + if (change == UidRecord.CHANGE_GONE && pendingChange.change == UidRecord.CHANGE_IDLE) { + change = UidRecord.CHANGE_GONE_IDLE; } - uidRec.pendingChange.uidRecord = uidRec; - uidRec.pendingChange.uid = uidRec.uid; - mPendingUidChanges.add(uidRec.pendingChange); } - uidRec.pendingChange.gone = gone; - uidRec.pendingChange.processState = uidRec.setProcState; + pendingChange.change = change; + pendingChange.processState = uidRec != null + ? uidRec.setProcState : ActivityManager.PROCESS_STATE_NONEXISTENT; } private void maybeUpdateProviderUsageStatsLocked(ProcessRecord app, String providerPkgName, @@ -19608,12 +19747,31 @@ public final class ActivityManagerService extends ActivityManagerNative // Update from any uid changes. for (int i=mActiveUids.size()-1; i>=0; i--) { final UidRecord uidRec = mActiveUids.valueAt(i); + int uidChange = UidRecord.CHANGE_PROCSTATE; if (uidRec.setProcState != uidRec.curProcState) { if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "Changes in " + uidRec + ": proc state from " + uidRec.setProcState + " to " + uidRec.curProcState); + if (ActivityManager.isProcStateBackground(uidRec.curProcState)) { + if (!ActivityManager.isProcStateBackground(uidRec.setProcState)) { + uidRec.lastBackgroundTime = nowElapsed; + if (!mHandler.hasMessages(IDLE_UIDS_MSG)) { + // Note: the background settle time is in elapsed realtime, while + // the handler time base is uptime. All this means is that we may + // stop background uids later than we had intended, but that only + // happens because the device was sleeping so we are okay anyway. + mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG, BACKGROUND_SETTLE_TIME); + } + } + } else { + if (uidRec.idle) { + uidChange = UidRecord.CHANGE_ACTIVE; + uidRec.idle = false; + } + uidRec.lastBackgroundTime = 0; + } uidRec.setProcState = uidRec.curProcState; - enqueueUidChangeLocked(uidRec, false); + enqueueUidChangeLocked(uidRec, -1, uidChange); } } @@ -19638,6 +19796,53 @@ public final class ActivityManagerService extends ActivityManagerNative } } + final void idleUids() { + synchronized (this) { + final long nowElapsed = SystemClock.elapsedRealtime(); + final long maxBgTime = nowElapsed - BACKGROUND_SETTLE_TIME; + long nextTime = 0; + for (int i=mActiveUids.size()-1; i>=0; i--) { + final UidRecord uidRec = mActiveUids.valueAt(i); + final long bgTime = uidRec.lastBackgroundTime; + if (bgTime > 0 && !uidRec.idle) { + if (bgTime <= maxBgTime) { + uidRec.idle = true; + doStopUidLocked(uidRec.uid, uidRec); + } else { + if (nextTime == 0 || nextTime > bgTime) { + nextTime = bgTime; + } + } + } + } + if (nextTime > 0) { + mHandler.removeMessages(IDLE_UIDS_MSG); + mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG, + nextTime + BACKGROUND_SETTLE_TIME - nowElapsed); + } + } + } + + final void runInBackgroundDisabled(int uid) { + synchronized (this) { + UidRecord uidRec = mActiveUids.get(uid); + if (uidRec != null) { + // This uid is actually running... should it be considered background now? + if (uidRec.idle) { + doStopUidLocked(uidRec.uid, uidRec); + } + } else { + // This uid isn't actually running... still send a report about it being "stopped". + doStopUidLocked(uid, null); + } + } + } + + final void doStopUidLocked(int uid, final UidRecord uidRec) { + mServices.stopInBackgroundLocked(uid); + enqueueUidChangeLocked(uidRec, uid, UidRecord.CHANGE_IDLE); + } + final void trimApplications() { synchronized (this) { int i; @@ -19973,8 +20178,9 @@ public final class ActivityManagerService extends ActivityManagerNative userName = userInfo.name; mUserController.setTargetUserIdLocked(userId); } - mUiHandler.removeMessages(START_USER_SWITCH_MSG); - mUiHandler.sendMessage(mUiHandler.obtainMessage(START_USER_SWITCH_MSG, userId, 0, userName)); + mUiHandler.removeMessages(START_USER_SWITCH_UI_MSG); + mUiHandler.sendMessage(mUiHandler.obtainMessage(START_USER_SWITCH_UI_MSG, userId, 0, + userName)); return true; } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index d317791ed30d..fb37edafe44c 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -556,6 +556,17 @@ public final class BroadcastQueue { + " (uid " + r.callingUid + ")"); skip = true; } + if (!skip) { + if (!mService.checkAllowBackgroundLocked(filter.receiverList.uid, filter.packageName, + -1)) { + Slog.w(TAG, "Background execution not allowed: receiving " + + r.intent + + " to " + filter.receiverList.app + + " (pid=" + filter.receiverList.pid + + ", uid=" + filter.receiverList.uid + ")"); + skip = true; + } + } if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, r.callingPid, r.resolvedType, filter.receiverList.uid)) { @@ -938,6 +949,15 @@ public final class BroadcastQueue { skip = true; } if (!skip) { + if (!mService.checkAllowBackgroundLocked(info.activityInfo.applicationInfo.uid, + info.activityInfo.packageName, -1)) { + Slog.w(TAG, "Background execution not allowed: receiving " + + r.intent + " to " + + component.flattenToShortString()); + skip = true; + } + } + if (!skip) { skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid); } diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java index b4efbf011e0a..d24c3a52adba 100644 --- a/services/core/java/com/android/server/am/UidRecord.java +++ b/services/core/java/com/android/server/am/UidRecord.java @@ -17,7 +17,9 @@ package com.android.server.am; import android.app.ActivityManager; +import android.os.SystemClock; import android.os.UserHandle; +import android.util.TimeUtils; /** * Overall information about a uid that has actively running processes. @@ -26,12 +28,20 @@ public final class UidRecord { final int uid; int curProcState; int setProcState = ActivityManager.PROCESS_STATE_NONEXISTENT; + long lastBackgroundTime; + boolean idle; int numProcs; + static final int CHANGE_PROCSTATE = 0; + static final int CHANGE_GONE = 1; + static final int CHANGE_GONE_IDLE = 2; + static final int CHANGE_IDLE = 3; + static final int CHANGE_ACTIVE = 4; + static final class ChangeItem { UidRecord uidRecord; int uid; - boolean gone; + int change; int processState; } @@ -54,9 +64,16 @@ public final class UidRecord { UserHandle.formatUid(sb, uid); sb.append(' '); sb.append(ProcessList.makeProcStateString(curProcState)); - sb.append(" / "); + if (lastBackgroundTime > 0) { + sb.append(" bg:"); + TimeUtils.formatDuration(SystemClock.elapsedRealtime()-lastBackgroundTime, sb); + } + if (idle) { + sb.append(" idle"); + } + sb.append(" procs:"); sb.append(numProcs); - sb.append(" procs}"); + sb.append("}"); return sb.toString(); } } diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index b766894d72b3..75a74c0085b7 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -466,7 +466,7 @@ public final class ContentService extends IContentService.Stub { if (cname == null) { info = new SyncStorageEngine.EndPoint(account, authority, userId); } else { - info = new SyncStorageEngine.EndPoint(cname, userId); + info = new SyncStorageEngine.EndPoint(cname, userId, -1); } syncManager.clearScheduledSyncOperations(info); syncManager.cancelActiveSync(info, null /* all syncs for this adapter */); diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index e2a0f8241479..4f538821958c 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -21,8 +21,10 @@ import android.accounts.AccountAndUser; import android.accounts.AccountManager; import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.AppGlobals; +import android.app.IUidObserver; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -79,6 +81,7 @@ import android.util.EventLog; import android.util.Log; import android.util.Pair; +import android.util.Slog; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IBatteryStats; @@ -237,7 +240,7 @@ public class SyncManager { private final AppIdleMonitor mAppIdleMonitor; - private BroadcastReceiver mStorageIntentReceiver = + private final BroadcastReceiver mStorageIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -260,7 +263,7 @@ public class SyncManager { } }; - private BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() { + private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { boolean idle = mPowerManager.isDeviceIdleMode() || mPowerManager.isLightDeviceIdleMode(); @@ -281,7 +284,7 @@ public class SyncManager { } }; - private BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() { + private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { mBootCompleted = true; @@ -289,7 +292,7 @@ public class SyncManager { } }; - private BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() { + private final BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { updateRunningAccounts(); @@ -300,6 +303,21 @@ public class SyncManager { } }; + private final IUidObserver mUidObserver = new IUidObserver.Stub() { + @Override public void onUidStateChanged(int uid, int procState) throws RemoteException { + } + + @Override public void onUidGone(int uid) throws RemoteException { + } + + @Override public void onUidActive(int uid) throws RemoteException { + } + + @Override public void onUidIdle(int uid) throws RemoteException { + cancelSyncsForUid(uid); + } + }; + private final PowerManager mPowerManager; DeviceIdleController.LocalService mLocalDeviceIdleController; @@ -504,6 +522,13 @@ public class SyncManager { mContext.registerReceiverAsUser( mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null); + try { + ActivityManagerNative.getDefault().registerUidObserver(mUidObserver, + ActivityManager.UID_OBSERVER_IDLE); + } catch (RemoteException e) { + // ignored; both services live in system_server + } + if (!factoryTest) { mNotificationMgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); @@ -661,6 +686,26 @@ public class SyncManager { Log.d(TAG, "one off sync for: " + cname + " " + extras.toString()); } + final android.content.pm.ServiceInfo sinfo; + try { + sinfo = mContext.getPackageManager().getServiceInfo(cname, userId); + } catch (PackageManager.NameNotFoundException e) { + Slog.w(TAG, "Not scheduling sync " + cname + + " -- can't find service for user " + userId); + return; + } + final int sUid = sinfo.applicationInfo.uid; + + try { + if (ActivityManagerNative.getDefault().getAppStartMode(sUid, cname.getPackageName()) + == ActivityManager.APP_START_MODE_DISABLED) { + Slog.w(TAG, "Not scheduling sync " + sUid + ":" + cname + + " -- package not allowed to start"); + return; + } + } catch (RemoteException e) { + } + Boolean expedited = extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false); if (expedited) { runtimeMillis = -1; // this means schedule at the front of the queue @@ -688,7 +733,7 @@ public class SyncManager { } return; } - SyncStorageEngine.EndPoint info = new SyncStorageEngine.EndPoint(cname, userId); + SyncStorageEngine.EndPoint info = new SyncStorageEngine.EndPoint(cname, userId, sUid); Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(info); long delayUntil = mSyncStorageEngine.getDelayUntilTime(info); final long backoffTime = backoff != null ? backoff.first : 0; @@ -702,7 +747,7 @@ public class SyncManager { + ", extras " + extras); } scheduleSyncOperation( - new SyncOperation(cname, userId, uid, source, extras, + new SyncOperation(cname, userId, sUid, cname.getPackageName(), uid, source, extras, runtimeMillis /* runtime */, beforeRunTimeMillis /* flextime */, backoffTime, @@ -837,6 +882,18 @@ public class SyncManager { if (syncAdapterInfo == null) { continue; } + final int owningUid = syncAdapterInfo.uid; + final String owningPackage = syncAdapterInfo.componentName.getPackageName(); + try { + if (ActivityManagerNative.getDefault().getAppStartMode(owningUid, + owningPackage) == ActivityManager.APP_START_MODE_DISABLED) { + Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":" + + syncAdapterInfo.componentName + + " -- package not allowed to start"); + return; + } + } catch (RemoteException e) { + } final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs(); final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable(); if (isSyncable < 0 && isAlwaysSyncable) { @@ -886,7 +943,8 @@ public class SyncManager { + ", extras " + newExtras); } scheduleSyncOperation( - new SyncOperation(account.account, account.userId, reason, source, + new SyncOperation(account.account, account.userId, + owningUid, owningPackage, reason, source, authority, newExtras, 0 /* immediate */, 0 /* No flex time*/, backoffTime, delayUntil, allowParallelSyncs)); } @@ -902,7 +960,8 @@ public class SyncManager { + ", extras " + extras); } scheduleSyncOperation( - new SyncOperation(account.account, account.userId, reason, source, + new SyncOperation(account.account, account.userId, + owningUid, owningPackage, reason, source, authority, extras, runtimeMillis, beforeRuntimeMillis, backoffTime, delayUntil, allowParallelSyncs)); } @@ -1309,6 +1368,14 @@ public class SyncManager { } } + void cancelSyncsForUid(int uid) { + synchronized (mSyncQueue) { + if (mSyncQueue.removeUidIfNeededLocked(uid)) { + sendCheckAlarmsMessage(); + } + } + } + /** * @hide */ @@ -2166,8 +2233,8 @@ public class SyncManager { /** * Stash any messages that come to the handler before boot is complete or before the device * is properly provisioned (i.e. out of set-up wizard). - * {@link #onBootCompleted()} and {@link #onDeviceProvisioned(boolean)} both need to come - * in before we start syncing. + * {@link #onBootCompleted()} and {@link SyncHandler#onDeviceProvisioned} both + * need to come in before we start syncing. * @param msg Message to dispatch at a later point. * @return true if a message was enqueued, false otherwise. This is to avoid losing the * message if we manage to acquire the lock but by the time we do boot has completed. @@ -2503,6 +2570,8 @@ public class SyncManager { } scheduleSyncOperation( new SyncOperation(target.account, target.userId, + syncAdapterInfo.uid, + syncAdapterInfo.componentName.getPackageName(), SyncOperation.REASON_PERIODIC, SyncStorageEngine.SOURCE_PERIODIC, target.provider, extras, @@ -2513,6 +2582,7 @@ public class SyncManager { } else if (target.target_service) { scheduleSyncOperation( new SyncOperation(target.service, target.userId, + target.serviceUid, target.service.getPackageName(), SyncOperation.REASON_PERIODIC, SyncStorageEngine.SOURCE_PERIODIC, extras, @@ -3145,6 +3215,7 @@ public class SyncManager { if (syncResult != null && syncResult.fullSyncRequested) { scheduleSyncOperation( new SyncOperation(info.account, info.userId, + syncOperation.owningUid, syncOperation.owningPackage, syncOperation.reason, syncOperation.syncSource, info.provider, new Bundle(), 0 /* delay */, 0 /* flex */, @@ -3155,6 +3226,7 @@ public class SyncManager { if (syncResult != null && syncResult.fullSyncRequested) { scheduleSyncOperation( new SyncOperation(info.service, info.userId, + syncOperation.owningUid, syncOperation.owningPackage, syncOperation.reason, syncOperation.syncSource, new Bundle(), 0 /* delay */, 0 /* flex */, diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java index 10efe81d0beb..ab777ae74e9c 100644 --- a/services/core/java/com/android/server/content/SyncOperation.java +++ b/services/core/java/com/android/server/content/SyncOperation.java @@ -22,6 +22,7 @@ import android.content.ComponentName; import android.content.ContentResolver; import android.os.Bundle; import android.os.SystemClock; +import android.os.UserHandle; import android.util.Log; /** @@ -62,6 +63,8 @@ public class SyncOperation implements Comparable { /** Identifying info for the target for this operation. */ public final SyncStorageEngine.EndPoint target; + public final int owningUid; + public final String owningPackage; /** Why this sync was kicked off. {@link #REASON_NAMES} */ public final int reason; /** Where this sync was initiated. */ @@ -93,25 +96,28 @@ public class SyncOperation implements Comparable { /** Whether this sync op was recently skipped due to the app being idle */ public boolean appIdle; - public SyncOperation(Account account, int userId, int reason, int source, String provider, - Bundle extras, long runTimeFromNow, long flexTime, long backoff, - long delayUntil, boolean allowParallelSyncs) { - this(new SyncStorageEngine.EndPoint(account, provider, userId), + public SyncOperation(Account account, int userId, int owningUid, String owningPackage, + int reason, int source, String provider, Bundle extras, long runTimeFromNow, + long flexTime, long backoff, long delayUntil, boolean allowParallelSyncs) { + this(new SyncStorageEngine.EndPoint(account, provider, userId), owningUid, owningPackage, reason, source, extras, runTimeFromNow, flexTime, backoff, delayUntil, allowParallelSyncs); } - public SyncOperation(ComponentName service, int userId, int reason, int source, - Bundle extras, long runTimeFromNow, long flexTime, long backoff, + public SyncOperation(ComponentName service, int userId, int owningUid, String owningPackage, + int reason, int source, Bundle extras, long runTimeFromNow, long flexTime, long backoff, long delayUntil) { - this(new SyncStorageEngine.EndPoint(service, userId), reason, source, extras, - runTimeFromNow, flexTime, backoff, delayUntil, true /* allowParallelSyncs */); + this(new SyncStorageEngine.EndPoint(service, userId, owningUid), owningUid, owningPackage, + reason, source, extras, runTimeFromNow, flexTime, backoff, delayUntil, + true /* allowParallelSyncs */); } - private SyncOperation(SyncStorageEngine.EndPoint info, int reason, int source, Bundle extras, - long runTimeFromNow, long flexTime, long backoff, long delayUntil, - boolean allowParallelSyncs) { + private SyncOperation(SyncStorageEngine.EndPoint info, int owningUid, String owningPackage, + int reason, int source, Bundle extras, long runTimeFromNow, long flexTime, + long backoff, long delayUntil, boolean allowParallelSyncs) { this.target = info; + this.owningUid = owningUid; + this.owningPackage = owningPackage; this.reason = reason; this.syncSource = source; this.extras = new Bundle(extras); @@ -142,7 +148,8 @@ public class SyncOperation implements Comparable { /** Used to reschedule a sync at a new point in time. */ public SyncOperation(SyncOperation other, long newRunTimeFromNow) { - this(other.target, other.reason, other.syncSource, new Bundle(other.extras), + this(other.target, other.owningUid, other.owningPackage, other.reason, other.syncSource, + new Bundle(other.extras), newRunTimeFromNow, 0L /* In back-off so no flex */, other.backoff, @@ -228,6 +235,13 @@ public class SyncOperation implements Comparable { } sb.append(", reason: "); sb.append(reasonToString(pm, reason)); + if (!useOneLine) { + sb.append("\n "); + sb.append("owningUid="); + UserHandle.formatUid(sb, owningUid); + sb.append(" owningPackage="); + sb.append(owningPackage); + } if (!useOneLine && !extras.keySet().isEmpty()) { sb.append("\n "); extrasToStringBuilder(extras, sb); diff --git a/services/core/java/com/android/server/content/SyncQueue.java b/services/core/java/com/android/server/content/SyncQueue.java index 587de1c34262..b15d0d8bb868 100644 --- a/services/core/java/com/android/server/content/SyncQueue.java +++ b/services/core/java/com/android/server/content/SyncQueue.java @@ -16,16 +16,20 @@ package com.android.server.content; +import android.app.ActivityManager; +import android.app.ActivityManagerNative; import android.content.pm.PackageManager; import android.content.SyncAdapterType; import android.content.SyncAdaptersCache; import android.content.pm.RegisteredServicesCache.ServiceInfo; import android.os.Bundle; +import android.os.RemoteException; import android.os.SystemClock; import android.text.format.DateUtils; import android.util.Log; import android.util.Pair; +import android.util.Slog; import com.google.android.collect.Maps; import java.util.ArrayList; @@ -74,8 +78,9 @@ public class SyncQueue { continue; } operationToAdd = new SyncOperation( - info.account, info.userId, op.reason, op.syncSource, info.provider, - op.extras, + info.account, info.userId, syncAdapterInfo.uid, + syncAdapterInfo.componentName.getPackageName(), op.reason, + op.syncSource, info.provider, op.extras, op.expedited ? -1 : 0 /* delay */, 0 /* flex */, backoff != null ? backoff.first : 0L, @@ -84,16 +89,24 @@ public class SyncQueue { operationToAdd.pendingOperation = op; add(operationToAdd, op); } else if (info.target_service) { + android.content.pm.ServiceInfo sinfo; try { - mPackageManager.getServiceInfo(info.service, 0); + sinfo = mPackageManager.getServiceInfo(info.service, info.userId); } catch (PackageManager.NameNotFoundException e) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.w(TAG, "Missing sync service for authority " + op.target); } continue; } + if (sinfo == null) { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.w(TAG, "Missing sync service for authority " + op.target); + } + continue; + } operationToAdd = new SyncOperation( - info.service, info.userId, op.reason, op.syncSource, + info.service, info.userId, sinfo.applicationInfo.uid, + info.service.getPackageName(), op.reason, op.syncSource, op.extras, op.expedited ? -1 : 0 /* delay */, 0 /* flex */, @@ -161,9 +174,38 @@ public class SyncQueue { opsToRemove.add(op); } } - for (SyncOperation op : opsToRemove) { - remove(op); + for (SyncOperation op : opsToRemove) { + remove(op); + } + } + + public boolean removeUidIfNeededLocked(int uid) { + ArrayList<SyncOperation> opsToRemove = null; + for (SyncOperation op : mOperationsMap.values()) { + if (op.owningUid != uid) { + continue; + } + try { + if (ActivityManagerNative.getDefault().getAppStartMode(op.owningUid, + op.owningPackage) == ActivityManager.APP_START_MODE_DISABLED) { + Slog.w(TAG, "Removing sync " + op.owningUid + ":" + op + + " -- package not allowed to start"); + continue; + } + } catch (RemoteException e) { + } + if (opsToRemove == null) { + opsToRemove = new ArrayList<SyncOperation>(); } + opsToRemove.add(op); + } + if (opsToRemove == null) { + return false; + } + for (SyncOperation op : opsToRemove) { + remove(op); + } + return true; } /** diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java index cca0c16f805f..8266c08f310f 100644 --- a/services/core/java/com/android/server/content/SyncStorageEngine.java +++ b/services/core/java/com/android/server/content/SyncStorageEngine.java @@ -27,6 +27,7 @@ import android.content.PeriodicSync; import android.content.SyncInfo; import android.content.SyncRequest; import android.content.SyncStatusInfo; +import android.content.pm.PackageManager; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; @@ -42,6 +43,7 @@ import android.os.UserHandle; import android.util.AtomicFile; import android.util.Log; import android.util.Pair; +import android.util.Slog; import android.util.SparseArray; import android.util.ArrayMap; import android.util.Xml; @@ -227,14 +229,16 @@ public class SyncStorageEngine extends Handler { public final static EndPoint USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL = new EndPoint(null, null, UserHandle.USER_ALL); final ComponentName service; + final int serviceUid; // -1 for "any" final Account account; final int userId; final String provider; final boolean target_service; final boolean target_provider; - public EndPoint(ComponentName service, int userId) { + public EndPoint(ComponentName service, int userId, int uid) { this.service = service; + this.serviceUid = uid; this.userId = userId; this.account = null; this.provider = null; @@ -247,6 +251,7 @@ public class SyncStorageEngine extends Handler { this.provider = provider; this.userId = userId; this.service = null; + this.serviceUid = -1; this.target_service = false; this.target_provider = true; } @@ -264,6 +269,11 @@ public class SyncStorageEngine extends Handler { return false; } if (target_service && spec.target_service) { + if (serviceUid != spec.serviceUid + && serviceUid >= 0 + && spec.serviceUid >= 0) { + return false; + } return service.equals(spec.service); } else if (target_provider && spec.target_provider) { boolean accountsMatch; @@ -290,8 +300,9 @@ public class SyncStorageEngine extends Handler { .append("/") .append(provider == null ? "ALL PDRS" : provider); } else if (target_service) { - sb.append(service.getPackageName() + "/") - .append(service.getClassName()); + service.appendShortString(sb); + sb.append(":"); + UserHandle.formatUid(sb,serviceUid); } else { sb.append("invalid target"); } @@ -737,7 +748,7 @@ public class SyncStorageEngine extends Handler { synchronized (mAuthorities) { if (cname != null) { AuthorityInfo authority = getAuthorityLocked( - new EndPoint(cname, userId), + new EndPoint(cname, userId, -1), "get service active"); if (authority == null) { return false; @@ -749,7 +760,7 @@ public class SyncStorageEngine extends Handler { } public void setIsTargetServiceActive(ComponentName cname, int userId, boolean active) { - setSyncableStateForEndPoint(new EndPoint(cname, userId), active ? + setSyncableStateForEndPoint(new EndPoint(cname, userId, -1), active ? AuthorityInfo.SYNCABLE : AuthorityInfo.NOT_SYNCABLE); } @@ -2064,18 +2075,30 @@ public class SyncStorageEngine extends Handler { new Account(accountName, accountType), authorityName, userId); } else { - info = new EndPoint( - new ComponentName(packageName, className), - userId); + final ComponentName cname = new ComponentName(packageName, className); + android.content.pm.ServiceInfo sinfo = null; + try { + sinfo = mContext.getPackageManager().getServiceInfo(cname, userId); + } catch (PackageManager.NameNotFoundException e) { + Slog.w(TAG, "Not restoring sync " + cname + + " -- can't find service for user " + userId); + } + if (sinfo != null) { + info = new EndPoint(cname, userId, sinfo.applicationInfo.uid); + } else { + info = null; + } } - authority = getOrCreateAuthorityLocked(info, id, false); - // If the version is 0 then we are upgrading from a file format that did not - // know about periodic syncs. In that case don't clear the list since we - // want the default, which is a daily periodic sync. - // Otherwise clear out this default list since we will populate it later with - // the periodic sync descriptions that are read from the configuration file. - if (version > 0) { - authority.periodicSyncs.clear(); + if (info != null) { + authority = getOrCreateAuthorityLocked(info, id, false); + // If the version is 0 then we are upgrading from a file format that did not + // know about periodic syncs. In that case don't clear the list since we + // want the default, which is a daily periodic sync. + // Otherwise clear out this default list since we will populate it later with + // the periodic sync descriptions that are read from the configuration file. + if (version > 0) { + authority.periodicSyncs.clear(); + } } } if (authority != null) { diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 759199ce58e6..4d7df9cfba0e 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -23,7 +23,9 @@ import java.util.Iterator; import java.util.List; import android.app.ActivityManager; +import android.app.ActivityManagerNative; import android.app.AppGlobals; +import android.app.IUidObserver; import android.app.job.JobInfo; import android.app.job.JobScheduler; import android.app.job.JobService; @@ -85,6 +87,7 @@ public class JobSchedulerService extends com.android.server.SystemService static final int MSG_JOB_EXPIRED = 0; static final int MSG_CHECK_JOB = 1; + static final int MSG_STOP_JOB = 2; // Policy constants /** @@ -162,7 +165,7 @@ public class JobSchedulerService extends com.android.server.SystemService if (DEBUG) { Slog.d(TAG, "Removing jobs for uid: " + uidRemoved); } - cancelJobsForUid(uidRemoved); + cancelJobsForUid(uidRemoved, true); } } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) { final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); @@ -180,6 +183,21 @@ public class JobSchedulerService extends com.android.server.SystemService } }; + final private IUidObserver mUidObserver = new IUidObserver.Stub() { + @Override public void onUidStateChanged(int uid, int procState) throws RemoteException { + } + + @Override public void onUidGone(int uid) throws RemoteException { + } + + @Override public void onUidActive(int uid) throws RemoteException { + } + + @Override public void onUidIdle(int uid) throws RemoteException { + cancelJobsForUid(uid, false); + } + }; + @Override public void onStartUser(int userHandle) { mStartedUsers.add(userHandle); @@ -202,6 +220,15 @@ public class JobSchedulerService extends com.android.server.SystemService public int schedule(JobInfo job, int uId) { JobStatus jobStatus = new JobStatus(job, uId); cancelJob(uId, job.getId()); + try { + if (ActivityManagerNative.getDefault().getAppStartMode(uId, + job.getService().getPackageName()) == ActivityManager.APP_START_MODE_DISABLED) { + Slog.w(TAG, "Not scheduling job " + uId + ":" + job.toString() + + " -- package not allowed to start"); + return JobScheduler.RESULT_FAILURE; + } + } catch (RemoteException e) { + } startTrackingJob(jobStatus); mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget(); return JobScheduler.RESULT_SUCCESS; @@ -237,14 +264,26 @@ public class JobSchedulerService extends com.android.server.SystemService * This will remove the job from the master list, and cancel the job if it was staged for * execution or being executed. * @param uid Uid to check against for removal of a job. + * @param forceAll If true, all jobs for the uid will be canceled; if false, only those + * whose apps are stopped. */ - public void cancelJobsForUid(int uid) { + public void cancelJobsForUid(int uid, boolean forceAll) { List<JobStatus> jobsForUid; synchronized (mJobs) { jobsForUid = mJobs.getJobsByUid(uid); } for (int i=0; i<jobsForUid.size(); i++) { JobStatus toRemove = jobsForUid.get(i); + if (!forceAll) { + String packageName = toRemove.getServiceComponent().getPackageName(); + try { + if (ActivityManagerNative.getDefault().getAppStartMode(uid, packageName) + != ActivityManager.APP_START_MODE_DISABLED) { + continue; + } + } catch (RemoteException e) { + } + } cancelJobImpl(toRemove); } } @@ -384,6 +423,12 @@ public class JobSchedulerService extends com.android.server.SystemService getContext().registerReceiverAsUser( mBroadcastReceiver, UserHandle.ALL, userFilter, null, null); mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE); + try { + ActivityManagerNative.getDefault().registerUidObserver(mUidObserver, + ActivityManager.UID_OBSERVER_IDLE); + } catch (RemoteException e) { + // ignored; both services live in system_server + } } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { synchronized (mJobs) { // Let's go! @@ -635,6 +680,9 @@ public class JobSchedulerService extends com.android.server.SystemService maybeQueueReadyJobsForExecutionLockedH(); } break; + case MSG_STOP_JOB: + cancelJobImpl((JobStatus)message.obj); + break; } maybeRunPendingJobsH(); // Don't remove JOB_EXPIRED in case one came along while processing the queue. @@ -686,11 +734,22 @@ public class JobSchedulerService extends com.android.server.SystemService int idleCount = 0; int backoffCount = 0; int connectivityCount = 0; - List<JobStatus> runnableJobs = new ArrayList<JobStatus>(); + List<JobStatus> runnableJobs = null; ArraySet<JobStatus> jobs = mJobs.getJobs(); for (int i=0; i<jobs.size(); i++) { JobStatus job = jobs.valueAt(i); if (isReadyToBeExecutedLocked(job)) { + try { + if (ActivityManagerNative.getDefault().getAppStartMode(job.getUid(), + job.getJob().getService().getPackageName()) + == ActivityManager.APP_START_MODE_DISABLED) { + Slog.w(TAG, "Aborting job " + job.getUid() + ":" + + job.getJob().toString() + " -- package not allowed to start"); + mHandler.obtainMessage(MSG_STOP_JOB, job).sendToTarget(); + continue; + } + } catch (RemoteException e) { + } if (job.getNumFailures() > 0) { backoffCount++; } @@ -703,6 +762,9 @@ public class JobSchedulerService extends com.android.server.SystemService if (job.hasChargingConstraint()) { chargingCount++; } + if (runnableJobs == null) { + runnableJobs = new ArrayList<>(); + } runnableJobs.add(job); } else if (isReadyToBeCancelledLocked(job)) { stopJobOnServiceContextLocked(job); @@ -712,7 +774,7 @@ public class JobSchedulerService extends com.android.server.SystemService idleCount >= MIN_IDLE_COUNT || connectivityCount >= MIN_CONNECTIVITY_COUNT || chargingCount >= MIN_CHARGING_COUNT || - runnableJobs.size() >= MIN_READY_JOBS_COUNT) { + (runnableJobs != null && runnableJobs.size() >= MIN_READY_JOBS_COUNT)) { if (DEBUG) { Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Running jobs."); } @@ -908,7 +970,7 @@ public class JobSchedulerService extends com.android.server.SystemService long ident = Binder.clearCallingIdentity(); try { - JobSchedulerService.this.cancelJobsForUid(uid); + JobSchedulerService.this.cancelJobsForUid(uid, true); } finally { Binder.restoreCallingIdentity(ident); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 41aea040cdc5..2ac0ba6fe765 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -459,7 +459,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { updateScreenOn(); try { - mActivityManager.registerUidObserver(mUidObserver); + mActivityManager.registerUidObserver(mUidObserver, + ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE); mNetworkManager.registerObserver(mAlertObserver); } catch (RemoteException e) { // ignored; both services live in system_server @@ -541,6 +542,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { removeUidStateLocked(uid); } } + + @Override public void onUidActive(int uid) throws RemoteException { + } + + @Override public void onUidIdle(int uid) throws RemoteException { + } }; final private BroadcastReceiver mPowerSaveWhitelistReceiver = new BroadcastReceiver() { diff --git a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java index b0296a0c1126..c174a92e74f2 100644 --- a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java +++ b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java @@ -61,7 +61,7 @@ public class SyncOperationTest extends AndroidTestCase { b2.putBoolean("b2", true); SyncOperation op1 = new SyncOperation(account1, 0, - 1, + 1, "foo", 0, SyncOperation.REASON_PERIODIC, "authority1", b1, @@ -73,7 +73,7 @@ public class SyncOperationTest extends AndroidTestCase { // Same as op1 but different time infos SyncOperation op2 = new SyncOperation(account1, 0, - 1, + 1, "foo", 0, SyncOperation.REASON_PERIODIC, "authority1", b1, @@ -85,7 +85,7 @@ public class SyncOperationTest extends AndroidTestCase { // Same as op1 but different authority SyncOperation op3 = new SyncOperation(account1, 0, - 1, + 1, "foo", 0, SyncOperation.REASON_PERIODIC, "authority2", b1, @@ -97,7 +97,7 @@ public class SyncOperationTest extends AndroidTestCase { // Same as op1 but different account SyncOperation op4 = new SyncOperation(account2, 0, - 1, + 1, "foo", 0, SyncOperation.REASON_PERIODIC, "authority1", b1, @@ -109,7 +109,7 @@ public class SyncOperationTest extends AndroidTestCase { // Same as op1 but different bundle SyncOperation op5 = new SyncOperation(account1, 0, - 1, + 1, "foo", 0, SyncOperation.REASON_PERIODIC, "authority1", b2, @@ -131,21 +131,21 @@ public class SyncOperationTest extends AndroidTestCase { long soonFlex = 50; long after = 1500; long afterFlex = 100; - SyncOperation op1 = new SyncOperation(mDummy, 0, 0, SyncOperation.REASON_PERIODIC, + SyncOperation op1 = new SyncOperation(mDummy, 0, 0, "foo", 0, SyncOperation.REASON_PERIODIC, "authority1", mEmpty, soon, soonFlex, mUnimportantLong, mUnimportantLong, true); // Interval disjoint from and after op1. - SyncOperation op2 = new SyncOperation(mDummy, 0, 0, SyncOperation.REASON_PERIODIC, + SyncOperation op2 = new SyncOperation(mDummy, 0, 0, "foo", 0, SyncOperation.REASON_PERIODIC, "authority1", mEmpty, after, afterFlex, mUnimportantLong, mUnimportantLong, true); // Interval equivalent to op1, but expedited. Bundle b2 = new Bundle(); b2.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); - SyncOperation op3 = new SyncOperation(mDummy, 0, 0, 0, + SyncOperation op3 = new SyncOperation(mDummy, 0, 0, "foo", 0, 0, "authority1", b2, -1, soonFlex, mUnimportantLong, mUnimportantLong, true); // Interval overlaps but not equivalent to op1. - SyncOperation op4 = new SyncOperation(mDummy, 0, 0, SyncOperation.REASON_PERIODIC, + SyncOperation op4 = new SyncOperation(mDummy, 0, 0, "foo", 0, SyncOperation.REASON_PERIODIC, "authority1", mEmpty, soon + 100, soonFlex + 100, mUnimportantLong, mUnimportantLong, true); assertTrue(op1.compareTo(op2) == -1); @@ -165,7 +165,8 @@ public class SyncOperationTest extends AndroidTestCase { Bundle withExpedited = new Bundle(); withExpedited.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); - SyncOperation op = new SyncOperation(mDummy, 0, 0, SyncOperation.REASON_USER_START, + SyncOperation op = new SyncOperation(mDummy, 0, 0, "foo", 0, + SyncOperation.REASON_USER_START, mAuthority, withExpedited, fiveSecondsFromNow, twoSecondsFlex, eightSeconds /* backoff */, fourSeconds /* delayUntil */, true); // Create another sync op to be rerun in 5 minutes. diff --git a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java index ae1967e424bd..b22eb5394296 100644 --- a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java +++ b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java @@ -41,8 +41,6 @@ import java.io.File; import java.io.FileOutputStream; import java.util.List; -import com.android.server.content.SyncStorageEngine.EndPoint; - public class SyncStorageEngineTest extends AndroidTestCase { protected Account account1; @@ -96,7 +94,7 @@ public class SyncStorageEngineTest extends AndroidTestCase { SyncStorageEngine engine = SyncStorageEngine.newTestInstance( new TestContext(mockResolver, getContext())); long time0 = 1000; - SyncOperation op = new SyncOperation(account, 0, + SyncOperation op = new SyncOperation(account, 0, 0, "foo", SyncOperation.REASON_PERIODIC, SyncStorageEngine.SOURCE_LOCAL, authority, @@ -112,7 +110,7 @@ public class SyncStorageEngineTest extends AndroidTestCase { @MediumTest public void testAppendPending() throws Exception { SyncOperation sop = new SyncOperation(account1, - DEFAULT_USER, + DEFAULT_USER, 0, "foo", SyncOperation.REASON_PERIODIC, SyncStorageEngine.SOURCE_LOCAL, authority1, Bundle.EMPTY, 0 /* runtime */, 0 /* flex */, 0 /* backoff */, 0 /* delayuntil */, @@ -140,19 +138,19 @@ public class SyncStorageEngineTest extends AndroidTestCase { */ public void testWritePendingOperationsLocked() throws Exception { SyncOperation sop = new SyncOperation(account1, - DEFAULT_USER, + DEFAULT_USER, 0, "foo", SyncOperation.REASON_IS_SYNCABLE, SyncStorageEngine.SOURCE_LOCAL, authority1, Bundle.EMPTY, 1000L /* runtime */, 57L /* flex */, 0 /* backoff */, 0 /* delayuntil */, true /* expedited */); SyncOperation sop1 = new SyncOperation(account2, - DEFAULT_USER, + DEFAULT_USER, 0, "foo", SyncOperation.REASON_PERIODIC, SyncStorageEngine.SOURCE_LOCAL, authority1, defaultBundle, 0 /* runtime */, 0 /* flex */, 20L /* backoff */, 100L /* delayuntil */, false /* expedited */); SyncOperation deleted = new SyncOperation(account2, - DEFAULT_USER, + DEFAULT_USER, 0, "foo", SyncOperation.REASON_SYNC_AUTO, SyncStorageEngine.SOURCE_LOCAL, authority1, Bundle.EMPTY, 0 /* runtime */, 0 /* flex */, 20L /* backoff */, 100L /* delayuntil */, @@ -456,14 +454,14 @@ public class SyncStorageEngineTest extends AndroidTestCase { // Test service component read List<PeriodicSync> syncs = engine.getPeriodicSyncs( - new SyncStorageEngine.EndPoint(syncService1, 0)); + new SyncStorageEngine.EndPoint(syncService1, 0, 0)); assertEquals(1, syncs.size()); assertEquals(true, engine.getIsTargetServiceActive(syncService1, 0)); } @SmallTest public void testComponentSettings() throws Exception { - EndPoint target1 = new EndPoint(syncService1, 0); + EndPoint target1 = new EndPoint(syncService1, 0, 0); engine.updateOrAddPeriodicSync(target1, dayPoll, dayFuzz, Bundle.EMPTY); engine.setIsTargetServiceActive(target1.service, 0, true); |