diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 7bcc0385c13ac..8a31390dbf260 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -53,6 +53,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.
*/
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 057001ca3ff30..d37dda049b6cf 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;
@@ -1935,6 +1937,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
*
This method requires the caller to hold the permission
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index 9998f08ff54cb..8b471a04f25b5 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 8bb3ee7f178bf..6704b75dff7f3 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
private static final String ATTRIBUTES_NAME = "sync-adapter";
private static final MySerializer sSerializer = new MySerializer();
+ @GuardedBy("mServicesLock")
+ private SparseArray> 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
}
}
+ @Override
+ protected void onServicesChangedLocked(int userId) {
+ synchronized (mServicesLock) {
+ ArrayMap adapterMap = mAuthorityToSyncAdapters.get(userId);
+ if (adapterMap != null) {
+ adapterMap.clear();
+ }
+ }
+
+ super.onServicesChangedLocked(userId);
+ }
+
+ public String[] getSyncAdapterPackagesForAuthority(String authority, int userId) {
+ synchronized (mServicesLock) {
+ ArrayMap 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> serviceInfos;
+ serviceInfos = getAllServices(userId);
+ ArrayList packages = new ArrayList<>();
+ for (RegisteredServicesCache.ServiceInfo 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 {
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 0bd2a3b84f067..b293e2a834000 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 {
private final String mAttributesName;
private final XmlSerializerAndParser mSerializerAndParser;
- private final Object mServicesLock = new Object();
+ protected final Object mServicesLock = new Object();
@GuardedBy("mServicesLock")
private final SparseArray> mUserServices = new SparseArray>(2);
@@ -232,6 +232,7 @@ public abstract class RegisteredServicesCache {
synchronized (mServicesLock) {
final UserServices user = findOrCreateUserLocked(userId);
user.services = null;
+ onServicesChangedLocked(userId);
}
}
@@ -489,11 +490,16 @@ public abstract class RegisteredServicesCache {
}
}
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 {
@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 8297e14bc972e..4d7ca1b9c88dd 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 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 mStartedUsers = new SparseArray<>();
+ final SparseArray mStartedUsers = new SparseArray<>();
/**
* LRU list of history of current users. Most recently current is at the end.
@@ -1782,15 +1782,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: {
@@ -2310,7 +2310,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();
@@ -6306,9 +6306,9 @@ public final class ActivityManagerService extends ActivityManagerNative
SystemProperties.set("dev.bootcomplete", "1");
}
for (int i=0; i 0) {
@@ -19828,21 +19847,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) {
moveUserToForegroundLocked(uss, oldUserId, newUserId);
@@ -19852,7 +19871,7 @@ public final class ActivityManagerService extends ActivityManagerNative
completeSwitchAndInitalize(uss, newUserId, true, false);
}
- void moveUserToForegroundLocked(UserStartedState uss, int oldUserId, int newUserId) {
+ void moveUserToForegroundLocked(UserState uss, int oldUserId, int newUserId) {
boolean homeInFront = mStackSupervisor.switchUserLocked(newUserId, uss);
if (homeInFront) {
startHomeActivityLocked(newUserId, "moveUserToFroreground");
@@ -19871,11 +19890,11 @@ public final class ActivityManagerService extends ActivityManagerNative
updateConfigurationLocked(configuration, null, false);
}
- 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) {
@@ -19912,10 +19931,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);
@@ -19956,11 +19975,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);
@@ -19973,7 +19992,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- void finishUserSwitch(UserStartedState uss) {
+ void finishUserSwitch(UserState uss) {
synchronized (this) {
finishUserBoot(uss);
@@ -19983,15 +20002,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++;
@@ -20036,7 +20055,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.
@@ -20058,9 +20077,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();
@@ -20088,11 +20107,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,
@@ -20116,7 +20135,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 callbacks;
@@ -20124,7 +20143,7 @@ public final class ActivityManagerService extends ActivityManagerNative
callbacks = new ArrayList(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;
@@ -20198,15 +20217,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
@@ -20228,19 +20247,19 @@ public final class ActivityManagerService extends ActivityManagerNative
private void updateStartedUserArrayLocked() {
int num = 0;
for (int i=0; i mGoingToSleepActivities = new ArrayList<>();
/** Used on user changes */
- final ArrayList mStartingUsers = new ArrayList<>();
+ final ArrayList mStartingUsers = new ArrayList<>();
/** Used to queue up any background users being started */
- final ArrayList mStartingBackgroundUsers = new ArrayList<>();
+ final ArrayList mStartingBackgroundUsers = new ArrayList<>();
/** Set to indicate whether to issue an onUserLeaving callback when a newly launched activity
* is being brought in front of us. */
@@ -2376,7 +2376,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
ArrayList stops = null;
ArrayList finishes = null;
- ArrayList startingUsers = null;
+ ArrayList startingUsers = null;
int NS = 0;
int NF = 0;
boolean booting = false;
@@ -2473,7 +2473,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
// Complete starting up of background users
if (mStartingBackgroundUsers.size() > 0) {
- startingUsers = new ArrayList(mStartingBackgroundUsers);
+ startingUsers = new ArrayList(mStartingBackgroundUsers);
mStartingBackgroundUsers.clear();
for (int i = 0; i < startingUsers.size(); i++) {
mService.finishUserBoot(startingUsers.get(i));
@@ -3235,7 +3235,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;
@@ -3276,7 +3276,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
similarity index 85%
rename from services/core/java/com/android/server/am/UserStartedState.java
rename to services/core/java/com/android/server/am/UserState.java
index d3e73d5222a45..b3d82bca2de8c 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 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 ea461e52947ff..93ed2ee0c7a2a 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -505,6 +505,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 2eb8797916679..cd9c7fe0b9bb1 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 3767fce183d9e..3b7ed91306053 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;
@@ -1176,6 +1212,16 @@ public class UsageStatsService extends SystemService implements
mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
}
+ @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);