summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmith Yamasani <yamasani@google.com>2015-06-17 13:25:42 -0700
committerAmith Yamasani <yamasani@google.com>2015-06-19 15:04:58 -0700
commit37a40c24deb02bca3868a8085069afae112f22e4 (patch)
tree7e38587e99825bf5234c1f130bcf1972271b0795
parentb0ff3a6cb37aa45add4b0c5135bd978442fcc441 (diff)
downloadframeworks_base-37a40c24deb02bca3868a8085069afae112f22e4.zip
frameworks_base-37a40c24deb02bca3868a8085069afae112f22e4.tar.gz
frameworks_base-37a40c24deb02bca3868a8085069afae112f22e4.tar.bz2
App Standby : Association between content providers and their sync adapter
Set sync adapters to active if the associated content providers are used at foreground process state. Minimize how frequently published content providers are reported by keeping track of last reported time. Also cache sync adapters associated with an authority in SyncManager. Bug: 21785111 Change-Id: Ic2c8cb6a27f005d1a1d0aad21d36b1510160753a
-rw-r--r--core/java/android/app/usage/UsageStatsManagerInternal.java8
-rw-r--r--core/java/android/content/ContentResolver.java15
-rw-r--r--core/java/android/content/IContentService.aidl2
-rw-r--r--core/java/android/content/SyncAdaptersCache.java62
-rw-r--r--core/java/android/content/pm/RegisteredServicesCache.java12
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java121
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java12
-rw-r--r--services/core/java/com/android/server/am/UserState.java (renamed from services/core/java/com/android/server/am/UserStartedState.java)11
-rw-r--r--services/core/java/com/android/server/content/ContentService.java15
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java4
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java48
11 files changed, 248 insertions, 62 deletions
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 7bcc038..8a31390 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -54,6 +54,14 @@ public abstract class UsageStatsManagerInternal {
public abstract void reportConfigurationChange(Configuration config, int userId);
/**
+ * Reports that a content provider has been accessed by a foreground app.
+ * @param name The authority of the content provider
+ * @param pkgName The package name of the content provider
+ * @param userId The user in which the content provider was accessed.
+ */
+ public abstract void reportContentProviderUsage(String name, String pkgName, int userId);
+
+ /**
* Prepares the UsageStatsService for shutdown.
*/
public abstract void prepareShutdown();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 057001c..d37dda0 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -48,6 +48,7 @@ import android.util.Log;
import dalvik.system.CloseGuard;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
import java.io.File;
@@ -57,6 +58,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Random;
@@ -1936,6 +1938,19 @@ public abstract class ContentResolver {
}
/**
+ * @hide
+ * Returns the package names of syncadapters that match a given user and authority.
+ */
+ public static String[] getSyncAdapterPackagesForAuthorityAsUser(String authority,
+ int userId) {
+ try {
+ return getContentService().getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
+ } catch (RemoteException e) {
+ }
+ return ArrayUtils.emptyArray(String.class);
+ }
+
+ /**
* Check if the provider should be synced when a network tickle is received
* <p>This method requires the caller to hold the permission
* {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index 9998f08..8b471a0 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -143,6 +143,8 @@ interface IContentService {
SyncAdapterType[] getSyncAdapterTypes();
SyncAdapterType[] getSyncAdapterTypesAsUser(int userId);
+ String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId);
+
/**
* Returns true if there is currently a operation for the given account/authority or service
* actively being processed.
diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java
index 8bb3ee7..6704b75 100644
--- a/core/java/android/content/SyncAdaptersCache.java
+++ b/core/java/android/content/SyncAdaptersCache.java
@@ -20,12 +20,19 @@ import android.content.pm.RegisteredServicesCache;
import android.content.pm.XmlSerializerAndParser;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.util.ArrayMap;
import android.util.AttributeSet;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
/**
* A cache of services that export the {@link android.content.ISyncAdapter} interface.
@@ -39,6 +46,10 @@ public class SyncAdaptersCache extends RegisteredServicesCache<SyncAdapterType>
private static final String ATTRIBUTES_NAME = "sync-adapter";
private static final MySerializer sSerializer = new MySerializer();
+ @GuardedBy("mServicesLock")
+ private SparseArray<ArrayMap<String,String[]>> mAuthorityToSyncAdapters
+ = new SparseArray<>();
+
public SyncAdaptersCache(Context context) {
super(context, SERVICE_INTERFACE, SERVICE_META_DATA, ATTRIBUTES_NAME, sSerializer);
}
@@ -76,6 +87,57 @@ public class SyncAdaptersCache extends RegisteredServicesCache<SyncAdapterType>
}
}
+ @Override
+ protected void onServicesChangedLocked(int userId) {
+ synchronized (mServicesLock) {
+ ArrayMap<String,String[]> adapterMap = mAuthorityToSyncAdapters.get(userId);
+ if (adapterMap != null) {
+ adapterMap.clear();
+ }
+ }
+
+ super.onServicesChangedLocked(userId);
+ }
+
+ public String[] getSyncAdapterPackagesForAuthority(String authority, int userId) {
+ synchronized (mServicesLock) {
+ ArrayMap<String,String[]> adapterMap = mAuthorityToSyncAdapters.get(userId);
+ if (adapterMap == null) {
+ adapterMap = new ArrayMap<>();
+ mAuthorityToSyncAdapters.put(userId, adapterMap);
+ }
+ // If the mapping exists, return it
+ if (adapterMap.containsKey(authority)) {
+ return adapterMap.get(authority);
+ }
+ // Create the mapping and cache it
+ String[] syncAdapterPackages;
+ final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos;
+ serviceInfos = getAllServices(userId);
+ ArrayList<String> packages = new ArrayList<>();
+ for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) {
+ if (authority.equals(serviceInfo.type.authority)
+ && serviceInfo.componentName != null) {
+ packages.add(serviceInfo.componentName.getPackageName());
+ }
+ }
+ syncAdapterPackages = new String[packages.size()];
+ packages.toArray(syncAdapterPackages);
+ adapterMap.put(authority, syncAdapterPackages);
+
+ return syncAdapterPackages;
+ }
+ }
+
+ @Override
+ protected void onUserRemoved(int userId) {
+ synchronized (mServicesLock) {
+ mAuthorityToSyncAdapters.remove(userId);
+ }
+
+ super.onUserRemoved(userId);
+ }
+
static class MySerializer implements XmlSerializerAndParser<SyncAdapterType> {
public void writeAsXml(SyncAdapterType item, XmlSerializer out) throws IOException {
out.attribute(null, "authority", item.authority);
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 0bd2a3b..b293e2a 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -84,7 +84,7 @@ public abstract class RegisteredServicesCache<V> {
private final String mAttributesName;
private final XmlSerializerAndParser<V> mSerializerAndParser;
- private final Object mServicesLock = new Object();
+ protected final Object mServicesLock = new Object();
@GuardedBy("mServicesLock")
private final SparseArray<UserServices<V>> mUserServices = new SparseArray<UserServices<V>>(2);
@@ -232,6 +232,7 @@ public abstract class RegisteredServicesCache<V> {
synchronized (mServicesLock) {
final UserServices<V> user = findOrCreateUserLocked(userId);
user.services = null;
+ onServicesChangedLocked(userId);
}
}
@@ -489,11 +490,16 @@ public abstract class RegisteredServicesCache<V> {
}
}
if (changed) {
+ onServicesChangedLocked(userId);
writePersistentServicesLocked(user, userId);
}
}
}
+ protected void onServicesChangedLocked(int userId) {
+ // Feel free to override
+ }
+
/**
* Returns true if the list of changed uids is null (wildcard) or the specified uid
* is contained in the list of changed uids.
@@ -687,7 +693,9 @@ public abstract class RegisteredServicesCache<V> {
@VisibleForTesting
protected void onUserRemoved(int userId) {
- mUserServices.remove(userId);
+ synchronized (mServicesLock) {
+ mUserServices.remove(userId);
+ }
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c4f460e..1120b6b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -676,9 +676,9 @@ public final class ActivityManagerService extends ActivityManagerNative
final SparseArray<UidRecord> mActiveUids = new SparseArray<>();
/**
- * Which uses have been started, so are allowed to run code.
+ * Which users have been started, so are allowed to run code.
*/
- final SparseArray<UserStartedState> mStartedUsers = new SparseArray<>();
+ final SparseArray<UserState> mStartedUsers = new SparseArray<>();
/**
* LRU list of history of current users. Most recently current is at the end.
@@ -1781,15 +1781,15 @@ public final class ActivityManagerService extends ActivityManagerNative
break;
}
case REPORT_USER_SWITCH_MSG: {
- dispatchUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);
+ dispatchUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
break;
}
case CONTINUE_USER_SWITCH_MSG: {
- continueUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);
+ continueUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
break;
}
case USER_SWITCH_TIMEOUT_MSG: {
- timeoutUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);
+ timeoutUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
break;
}
case IMMERSIVE_MODE_LOCK_MSG: {
@@ -2309,7 +2309,7 @@ public final class ActivityManagerService extends ActivityManagerNative
mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));
// User 0 is the first and only user that runs at boot.
- mStartedUsers.put(UserHandle.USER_OWNER, new UserStartedState(UserHandle.OWNER, true));
+ mStartedUsers.put(UserHandle.USER_OWNER, new UserState(UserHandle.OWNER, true));
mUserLru.add(UserHandle.USER_OWNER);
updateStartedUserArrayLocked();
@@ -6313,9 +6313,9 @@ public final class ActivityManagerService extends ActivityManagerNative
SystemProperties.set("dev.bootcomplete", "1");
}
for (int i=0; i<mStartedUsers.size(); i++) {
- UserStartedState uss = mStartedUsers.valueAt(i);
- if (uss.mState == UserStartedState.STATE_BOOTING) {
- uss.mState = UserStartedState.STATE_RUNNING;
+ UserState uss = mStartedUsers.valueAt(i);
+ if (uss.mState == UserState.STATE_BOOTING) {
+ uss.mState = UserState.STATE_RUNNING;
final int userId = mStartedUsers.keyAt(i);
Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
@@ -9442,6 +9442,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
boolean success = updateOomAdjLocked(cpr.proc);
+ maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
// NOTE: there is still a race here where a signal could be
@@ -9831,6 +9832,8 @@ public final class ActivityManagerService extends ActivityManagerNative
dst.notifyAll();
}
updateOomAdjLocked(r);
+ maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
+ src.info.authority);
}
}
@@ -13343,7 +13346,7 @@ public final class ActivityManagerService extends ActivityManagerNative
needSep = false;
pw.println(" mStartedUsers:");
for (int i=0; i<mStartedUsers.size(); i++) {
- UserStartedState uss = mStartedUsers.valueAt(i);
+ UserState uss = mStartedUsers.valueAt(i);
pw.print(" User #"); pw.print(uss.mHandle.getIdentifier());
pw.print(": "); uss.dump("", pw);
}
@@ -18615,6 +18618,22 @@ public final class ActivityManagerService extends ActivityManagerNative
uidRec.pendingChange.processState = uidRec.setProcState;
}
+ private void maybeUpdateProviderUsageStatsLocked(ProcessRecord app, String providerPkgName,
+ String authority) {
+ if (app == null) return;
+ if (app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+ UserState userState = mStartedUsers.get(app.userId);
+ if (userState == null) return;
+ final long now = SystemClock.elapsedRealtime();
+ Long lastReported = userState.mProviderLastReportedFg.get(authority);
+ if (lastReported == null || lastReported < now - 60 * 1000L) {
+ mUsageStatsService.reportContentProviderUsage(
+ authority, providerPkgName, app.userId);
+ userState.mProviderLastReportedFg.put(authority, now);
+ }
+ }
+ }
+
private void maybeUpdateUsageStatsLocked(ProcessRecord app) {
if (DEBUG_USAGE_STATS) {
Slog.d(TAG, "Checking proc [" + Arrays.toString(app.getPackageList())
@@ -19602,7 +19621,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// If the user we are switching to is not currently started, then
// we need to start it now.
if (mStartedUsers.get(userId) == null) {
- mStartedUsers.put(userId, new UserStartedState(new UserHandle(userId), false));
+ mStartedUsers.put(userId, new UserState(new UserHandle(userId), false));
updateStartedUserArrayLocked();
needStart = true;
}
@@ -19627,26 +19646,26 @@ public final class ActivityManagerService extends ActivityManagerNative
mUserLru.add(currentUserIdInt);
}
- final UserStartedState uss = mStartedUsers.get(userId);
+ final UserState uss = mStartedUsers.get(userId);
// Make sure user is in the started state. If it is currently
// stopping, we need to knock that off.
- if (uss.mState == UserStartedState.STATE_STOPPING) {
+ if (uss.mState == UserState.STATE_STOPPING) {
// If we are stopping, we haven't sent ACTION_SHUTDOWN,
// so we can just fairly silently bring the user back from
// the almost-dead.
- uss.mState = UserStartedState.STATE_RUNNING;
+ uss.mState = UserState.STATE_RUNNING;
updateStartedUserArrayLocked();
needStart = true;
- } else if (uss.mState == UserStartedState.STATE_SHUTDOWN) {
+ } else if (uss.mState == UserState.STATE_SHUTDOWN) {
// This means ACTION_SHUTDOWN has been sent, so we will
// need to treat this as a new boot of the user.
- uss.mState = UserStartedState.STATE_BOOTING;
+ uss.mState = UserState.STATE_BOOTING;
updateStartedUserArrayLocked();
needStart = true;
}
- if (uss.mState == UserStartedState.STATE_BOOTING) {
+ if (uss.mState == UserState.STATE_BOOTING) {
// Booting up a new user, need to tell system services about it.
// Note that this is on the same handler as scheduling of broadcasts,
// which is important because it needs to go first.
@@ -19784,7 +19803,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- void dispatchUserSwitch(final UserStartedState uss, final int oldUserId,
+ void dispatchUserSwitch(final UserState uss, final int oldUserId,
final int newUserId) {
final int N = mUserSwitchObservers.beginBroadcast();
if (N > 0) {
@@ -19821,21 +19840,21 @@ public final class ActivityManagerService extends ActivityManagerNative
mUserSwitchObservers.finishBroadcast();
}
- void timeoutUserSwitch(UserStartedState uss, int oldUserId, int newUserId) {
+ void timeoutUserSwitch(UserState uss, int oldUserId, int newUserId) {
synchronized (this) {
Slog.w(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId);
sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
}
}
- void sendContinueUserSwitchLocked(UserStartedState uss, int oldUserId, int newUserId) {
+ void sendContinueUserSwitchLocked(UserState uss, int oldUserId, int newUserId) {
mCurUserSwitchCallback = null;
mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
mHandler.sendMessage(mHandler.obtainMessage(CONTINUE_USER_SWITCH_MSG,
oldUserId, newUserId, uss));
}
- void onUserInitialized(UserStartedState uss, boolean foreground, int oldUserId, int newUserId) {
+ void onUserInitialized(UserState uss, boolean foreground, int oldUserId, int newUserId) {
synchronized (this) {
if (foreground) {
moveUserToForeground(uss, oldUserId, newUserId);
@@ -19845,7 +19864,7 @@ public final class ActivityManagerService extends ActivityManagerNative
completeSwitchAndInitalize(uss, newUserId, true, false);
}
- void moveUserToForeground(UserStartedState uss, int oldUserId, int newUserId) {
+ void moveUserToForeground(UserState uss, int oldUserId, int newUserId) {
boolean homeInFront = mStackSupervisor.switchUserLocked(newUserId, uss);
if (homeInFront) {
startHomeActivityLocked(newUserId, "moveUserToFroreground");
@@ -19857,11 +19876,11 @@ public final class ActivityManagerService extends ActivityManagerNative
sendUserSwitchBroadcastsLocked(oldUserId, newUserId);
}
- void continueUserSwitch(UserStartedState uss, int oldUserId, int newUserId) {
+ void continueUserSwitch(UserState uss, int oldUserId, int newUserId) {
completeSwitchAndInitalize(uss, newUserId, false, true);
}
- void completeSwitchAndInitalize(UserStartedState uss, int newUserId,
+ void completeSwitchAndInitalize(UserState uss, int newUserId,
boolean clearInitializing, boolean clearSwitching) {
boolean unfrozen = false;
synchronized (this) {
@@ -19898,10 +19917,10 @@ public final class ActivityManagerService extends ActivityManagerNative
final int num = mUserLru.size();
for (int i = 0; i < num; i++) {
Integer oldUserId = mUserLru.get(i);
- UserStartedState oldUss = mStartedUsers.get(oldUserId);
+ UserState oldUss = mStartedUsers.get(oldUserId);
if (oldUserId == UserHandle.USER_OWNER || oldUserId == mCurrentUserId
- || oldUss.mState == UserStartedState.STATE_STOPPING
- || oldUss.mState == UserStartedState.STATE_SHUTDOWN) {
+ || oldUss.mState == UserState.STATE_STOPPING
+ || oldUss.mState == UserState.STATE_SHUTDOWN) {
continue;
}
UserInfo userInfo = mUserManager.getUserInfo(oldUserId);
@@ -19942,11 +19961,11 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- void finishUserBoot(UserStartedState uss) {
+ void finishUserBoot(UserState uss) {
synchronized (this) {
- if (uss.mState == UserStartedState.STATE_BOOTING
+ if (uss.mState == UserState.STATE_BOOTING
&& mStartedUsers.get(uss.mHandle.getIdentifier()) == uss) {
- uss.mState = UserStartedState.STATE_RUNNING;
+ uss.mState = UserState.STATE_RUNNING;
final int userId = uss.mHandle.getIdentifier();
Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
@@ -19959,7 +19978,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- void finishUserSwitch(UserStartedState uss) {
+ void finishUserSwitch(UserState uss) {
synchronized (this) {
finishUserBoot(uss);
@@ -19969,15 +19988,15 @@ public final class ActivityManagerService extends ActivityManagerNative
int i = 0;
while (num > MAX_RUNNING_USERS && i < mUserLru.size()) {
Integer oldUserId = mUserLru.get(i);
- UserStartedState oldUss = mStartedUsers.get(oldUserId);
+ UserState oldUss = mStartedUsers.get(oldUserId);
if (oldUss == null) {
// Shouldn't happen, but be sane if it does.
mUserLru.remove(i);
num--;
continue;
}
- if (oldUss.mState == UserStartedState.STATE_STOPPING
- || oldUss.mState == UserStartedState.STATE_SHUTDOWN) {
+ if (oldUss.mState == UserState.STATE_STOPPING
+ || oldUss.mState == UserState.STATE_SHUTDOWN) {
// This user is already stopping, doesn't count.
num--;
i++;
@@ -20022,7 +20041,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return ActivityManager.USER_OP_IS_CURRENT;
}
- final UserStartedState uss = mStartedUsers.get(userId);
+ final UserState uss = mStartedUsers.get(userId);
if (uss == null) {
// User is not started, nothing to do... but we do need to
// callback if requested.
@@ -20044,9 +20063,9 @@ public final class ActivityManagerService extends ActivityManagerNative
uss.mStopCallbacks.add(callback);
}
- if (uss.mState != UserStartedState.STATE_STOPPING
- && uss.mState != UserStartedState.STATE_SHUTDOWN) {
- uss.mState = UserStartedState.STATE_STOPPING;
+ if (uss.mState != UserState.STATE_STOPPING
+ && uss.mState != UserState.STATE_SHUTDOWN) {
+ uss.mState = UserState.STATE_STOPPING;
updateStartedUserArrayLocked();
long ident = Binder.clearCallingIdentity();
@@ -20074,11 +20093,11 @@ public final class ActivityManagerService extends ActivityManagerNative
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
// On to the next.
synchronized (ActivityManagerService.this) {
- if (uss.mState != UserStartedState.STATE_STOPPING) {
+ if (uss.mState != UserState.STATE_STOPPING) {
// Whoops, we are being started back up. Abort, abort!
return;
}
- uss.mState = UserStartedState.STATE_SHUTDOWN;
+ uss.mState = UserState.STATE_SHUTDOWN;
}
mBatteryStatsService.noteEvent(
BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH,
@@ -20102,7 +20121,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return ActivityManager.USER_OP_SUCCESS;
}
- void finishUserStop(UserStartedState uss) {
+ void finishUserStop(UserState uss) {
final int userId = uss.mHandle.getIdentifier();
boolean stopped;
ArrayList<IStopUserCallback> callbacks;
@@ -20110,7 +20129,7 @@ public final class ActivityManagerService extends ActivityManagerNative
callbacks = new ArrayList<IStopUserCallback>(uss.mStopCallbacks);
if (mStartedUsers.get(userId) != uss) {
stopped = false;
- } else if (uss.mState != UserStartedState.STATE_SHUTDOWN) {
+ } else if (uss.mState != UserState.STATE_SHUTDOWN) {
stopped = false;
} else {
stopped = true;
@@ -20184,15 +20203,15 @@ public final class ActivityManagerService extends ActivityManagerNative
}
boolean isUserRunningLocked(int userId, boolean orStopped) {
- UserStartedState state = mStartedUsers.get(userId);
+ UserState state = mStartedUsers.get(userId);
if (state == null) {
return false;
}
if (orStopped) {
return true;
}
- return state.mState != UserStartedState.STATE_STOPPING
- && state.mState != UserStartedState.STATE_SHUTDOWN;
+ return state.mState != UserState.STATE_STOPPING
+ && state.mState != UserState.STATE_SHUTDOWN;
}
@Override
@@ -20214,19 +20233,19 @@ public final class ActivityManagerService extends ActivityManagerNative
private void updateStartedUserArrayLocked() {
int num = 0;
for (int i=0; i<mStartedUsers.size(); i++) {
- UserStartedState uss = mStartedUsers.valueAt(i);
+ UserState uss = mStartedUsers.valueAt(i);
// This list does not include stopping users.
- if (uss.mState != UserStartedState.STATE_STOPPING
- && uss.mState != UserStartedState.STATE_SHUTDOWN) {
+ if (uss.mState != UserState.STATE_STOPPING
+ && uss.mState != UserState.STATE_SHUTDOWN) {
num++;
}
}
mStartedUserArray = new int[num];
num = 0;
for (int i=0; i<mStartedUsers.size(); i++) {
- UserStartedState uss = mStartedUsers.valueAt(i);
- if (uss.mState != UserStartedState.STATE_STOPPING
- && uss.mState != UserStartedState.STATE_SHUTDOWN) {
+ UserState uss = mStartedUsers.valueAt(i);
+ if (uss.mState != UserState.STATE_STOPPING
+ && uss.mState != UserState.STATE_SHUTDOWN) {
mStartedUserArray[num] = mStartedUsers.keyAt(i);
num++;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 9e33f2a..4d0e1fa 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -233,10 +233,10 @@ public final class ActivityStackSupervisor implements DisplayListener {
final ArrayList<ActivityRecord> mGoingToSleepActivities = new ArrayList<>();
/** Used on user changes */
- final ArrayList<UserStartedState> mStartingUsers = new ArrayList<>();
+ final ArrayList<UserState> mStartingUsers = new ArrayList<>();
/** Used to queue up any background users being started */
- final ArrayList<UserStartedState> mStartingBackgroundUsers = new ArrayList<>();
+ final ArrayList<UserState> mStartingBackgroundUsers = new ArrayList<>();
/** Set to indicate whether to issue an onUserLeaving callback when a newly launched activity
* is being brought in front of us. */
@@ -2371,7 +2371,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
ArrayList<ActivityRecord> stops = null;
ArrayList<ActivityRecord> finishes = null;
- ArrayList<UserStartedState> startingUsers = null;
+ ArrayList<UserState> startingUsers = null;
int NS = 0;
int NF = 0;
boolean booting = false;
@@ -2468,7 +2468,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
// Complete starting up of background users
if (mStartingBackgroundUsers.size() > 0) {
- startingUsers = new ArrayList<UserStartedState>(mStartingBackgroundUsers);
+ startingUsers = new ArrayList<UserState>(mStartingBackgroundUsers);
mStartingBackgroundUsers.clear();
for (int i = 0; i < startingUsers.size(); i++) {
mService.finishUserBoot(startingUsers.get(i));
@@ -3230,7 +3230,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
}
- boolean switchUserLocked(int userId, UserStartedState uss) {
+ boolean switchUserLocked(int userId, UserState uss) {
mUserStackInFront.put(mCurrentUser, mFocusedStack.getStackId());
final int restoreStackId = mUserStackInFront.get(userId, HOME_STACK_ID);
mCurrentUser = userId;
@@ -3271,7 +3271,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
* @param userId The user being started in the background
* @param uss The state object for the user.
*/
- public void startBackgroundUserLocked(int userId, UserStartedState uss) {
+ public void startBackgroundUserLocked(int userId, UserState uss) {
mStartingBackgroundUsers.add(uss);
}
diff --git a/services/core/java/com/android/server/am/UserStartedState.java b/services/core/java/com/android/server/am/UserState.java
index d3e73d5..b3d82bc 100644
--- a/services/core/java/com/android/server/am/UserStartedState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -21,8 +21,9 @@ import java.util.ArrayList;
import android.app.IStopUserCallback;
import android.os.UserHandle;
+import android.util.ArrayMap;
-public final class UserStartedState {
+public final class UserState {
// User is first coming up.
public final static int STATE_BOOTING = 0;
// User is in the normal running state.
@@ -40,7 +41,13 @@ public final class UserStartedState {
public boolean switching;
public boolean initializing;
- public UserStartedState(UserHandle handle, boolean initial) {
+ /**
+ * The last time that a provider was reported to usage stats as being brought to important
+ * foreground procstate.
+ */
+ public final ArrayMap<String,Long> mProviderLastReportedFg = new ArrayMap<>();
+
+ public UserState(UserHandle handle, boolean initial) {
mHandle = handle;
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index ea461e5..93ed2ee 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -506,6 +506,21 @@ public final class ContentService extends IContentService.Stub {
}
@Override
+ public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) {
+ enforceCrossUserPermission(userId,
+ "no permission to read sync settings for user " + userId);
+ // This makes it so that future permission checks will be in the context of this
+ // process rather than the caller's process. We will restore this before returning.
+ final long identityToken = clearCallingIdentity();
+ try {
+ SyncManager syncManager = getSyncManager();
+ return syncManager.getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ @Override
public boolean getSyncAutomatically(Account account, String providerName) {
return getSyncAutomaticallyAsUser(account, providerName, UserHandle.getCallingUserId());
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 2eb8797..cd9c7fe 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -908,6 +908,10 @@ public class SyncManager {
return types;
}
+ public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) {
+ return mSyncAdapters.getSyncAdapterPackagesForAuthority(authority, userId);
+ }
+
private void sendSyncAlarmMessage() {
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "sending MESSAGE_SYNC_ALARM");
mSyncHandler.sendEmptyMessage(SyncHandler.MESSAGE_SYNC_ALARM);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 3767fce..3b7ed91 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -31,9 +31,12 @@ import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.SyncAdapterType;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
@@ -69,6 +72,7 @@ import android.view.Display;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.os.SomeArgs;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.DeviceIdleController;
import com.android.server.SystemService;
@@ -117,6 +121,7 @@ public class UsageStatsService extends SystemService implements
static final int MSG_CHECK_IDLE_STATES = 5;
static final int MSG_CHECK_PAROLE_TIMEOUT = 6;
static final int MSG_PAROLE_END_TIMEOUT = 7;
+ static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
private final Object mLock = new Object();
Handler mHandler;
@@ -583,6 +588,29 @@ public class UsageStatsService extends SystemService implements
}
}
+ void reportContentProviderUsage(String authority, String providerPkgName, int userId) {
+ // Get sync adapters for the authority
+ String[] packages = ContentResolver.getSyncAdapterPackagesForAuthorityAsUser(
+ authority, userId);
+ for (String packageName: packages) {
+ // Only force the sync adapters to active if the provider is not in the same package and
+ // the sync adapter is a system package.
+ try {
+ PackageInfo pi = AppGlobals.getPackageManager().getPackageInfo(
+ packageName, 0, userId);
+ if (pi == null || pi.applicationInfo == null
+ || !pi.applicationInfo.isSystemApp()) {
+ continue;
+ }
+ if (!packageName.equals(providerPkgName)) {
+ forceIdleState(packageName, userId, false);
+ }
+ } catch (RemoteException re) {
+ // Shouldn't happen
+ }
+ }
+ }
+
/**
* Forces the app's beginIdleTime and lastUsedTime to reflect idle or active. If idle,
* then it rolls back the beginIdleTime and lastUsedTime to a point in time that's behind
@@ -605,7 +633,7 @@ public class UsageStatsService extends SystemService implements
timeNow - (idle ? mAppIdleWallclockThresholdMillis : 0) - 5000);
// Inform listeners if necessary
if (previouslyIdle != idle) {
- // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
+ // Slog.d(TAG, "Informing listeners of out-of-idle " + packageName);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
/* idle = */ idle ? 1 : 0, packageName));
if (!idle) {
@@ -916,6 +944,14 @@ public class UsageStatsService extends SystemService implements
setAppIdleParoled(false);
break;
+ case MSG_REPORT_CONTENT_PROVIDER_USAGE:
+ SomeArgs args = (SomeArgs) msg.obj;
+ reportContentProviderUsage((String) args.arg1, // authority name
+ (String) args.arg2, // package name
+ (int) args.arg3); // userId
+ args.recycle();
+ break;
+
default:
super.handleMessage(msg);
break;
@@ -1177,6 +1213,16 @@ public class UsageStatsService extends SystemService implements
}
@Override
+ public void reportContentProviderUsage(String name, String packageName, int userId) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = name;
+ args.arg2 = packageName;
+ args.arg3 = userId;
+ mHandler.obtainMessage(MSG_REPORT_CONTENT_PROVIDER_USAGE, args)
+ .sendToTarget();
+ }
+
+ @Override
public boolean isAppIdle(String packageName, int userId) {
return UsageStatsService.this.isAppIdleFiltered(packageName, userId, -1);
}