Loading services/core/java/com/android/server/content/AppIdleMonitor.java 0 → 100644 +89 −0 Original line number Diff line number Diff line /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.content; import android.app.usage.UsageStatsManagerInternal; import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.BatteryManager; import android.os.UserHandle; import com.android.server.LocalServices; /** * Helper to listen for app idle and charging status changes and restart backed off * sync operations. */ class AppIdleMonitor implements AppIdleStateChangeListener { private final SyncManager mSyncManager; private final UsageStatsManagerInternal mUsageStats; final BatteryManager mBatteryManager; /** Is the device currently plugged into power. */ private boolean mPluggedIn; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { onPluggedIn(mBatteryManager.isCharging()); } }; AppIdleMonitor(SyncManager syncManager, Context context) { mSyncManager = syncManager; mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class); mUsageStats.addAppIdleStateChangeListener(this); mBatteryManager = context.getSystemService(BatteryManager.class); mPluggedIn = isPowered(); registerReceivers(context); } private void registerReceivers(Context context) { // Monitor battery charging state IntentFilter filter = new IntentFilter(BatteryManager.ACTION_CHARGING); filter.addAction(BatteryManager.ACTION_DISCHARGING); context.registerReceiver(mReceiver, filter); } private boolean isPowered() { return mBatteryManager.isCharging(); } void onPluggedIn(boolean pluggedIn) { if (mPluggedIn == pluggedIn) { return; } mPluggedIn = pluggedIn; if (mPluggedIn) { mSyncManager.onAppNotIdle(null, UserHandle.USER_ALL); } } boolean isAppIdle(String packageName, int userId) { return !mPluggedIn && mUsageStats.isAppIdle(packageName, userId); } @Override public void onAppIdleStateChanged(String packageName, int userId, boolean idle) { // Don't care if the app is becoming idle if (idle) return; mSyncManager.onAppNotIdle(packageName, userId); } } services/core/java/com/android/server/content/SyncManager.java +64 −1 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.util.IndentingPrintWriter; import com.android.server.accounts.AccountManagerService; import com.android.server.content.SyncStorageEngine.AuthorityInfo; import com.android.server.content.SyncStorageEngine.EndPoint; import com.android.server.content.SyncStorageEngine.OnSyncRequestListener; import com.google.android.collect.Lists; import com.google.android.collect.Maps; Loading @@ -107,7 +108,7 @@ import java.util.Set; * @hide */ public class SyncManager { private static final String TAG = "SyncManager"; static final String TAG = "SyncManager"; /** Delay a sync due to local changes this long. In milliseconds */ private static final long LOCAL_SYNC_DELAY; Loading Loading @@ -199,6 +200,8 @@ public class SyncManager { protected SyncAdaptersCache mSyncAdapters; private final AppIdleMonitor mAppIdleMonitor; private BroadcastReceiver mStorageIntentReceiver = new BroadcastReceiver() { @Override Loading Loading @@ -427,6 +430,8 @@ public class SyncManager { mSyncAlarmIntent = PendingIntent.getBroadcast( mContext, 0 /* ignored */, new Intent(ACTION_SYNC_ALARM), 0); mAppIdleMonitor = new AppIdleMonitor(this, mContext); IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); context.registerReceiver(mConnectivityIntentReceiver, intentFilter); Loading Loading @@ -1168,6 +1173,36 @@ public class SyncManager { } } /** * Clear backoff on operations in the sync queue that match the packageName and userId. * @param packageName The package that just became active. Can be null to indicate that all * packages are now considered active due to being plugged in. * @param userId The user for which the package has become active. Can be USER_ALL if * the device just plugged in. */ void onAppNotIdle(String packageName, int userId) { synchronized (mSyncQueue) { // For all sync operations in sync queue, if marked as idle, compare with package name // and unmark. And clear backoff for the operation. final Iterator<SyncOperation> operationIterator = mSyncQueue.getOperations().iterator(); boolean changed = false; while (operationIterator.hasNext()) { final SyncOperation op = operationIterator.next(); if (op.appIdle && getPackageName(op.target).equals(packageName) && (userId == UserHandle.USER_ALL || op.target.userId == userId)) { op.appIdle = false; clearBackoffSetting(op); changed = true; } } if (changed) { sendCheckAlarmsMessage(); } } } /** * @hide */ Loading Loading @@ -2447,6 +2482,19 @@ public class SyncManager { } continue; } String packageName = getPackageName(op.target); // If app is considered idle, then skip for now and backoff if (packageName != null && mAppIdleMonitor.isAppIdle(packageName, op.target.userId)) { increaseBackoffSetting(op); op.appIdle = true; if (isLoggable) { Log.v(TAG, "Sync backing off idle app " + packageName); } continue; } else { op.appIdle = false; } // Add this sync to be run. operations.add(op); } Loading Loading @@ -3194,6 +3242,21 @@ public class SyncManager { } } String getPackageName(EndPoint endpoint) { if (endpoint.target_service) { return endpoint.service.getPackageName(); } else { SyncAdapterType syncAdapterType = SyncAdapterType.newKey(endpoint.provider, endpoint.account.type); final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo; syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, endpoint.userId); if (syncAdapterInfo == null) { return null; } return syncAdapterInfo.componentName.getPackageName(); } } private boolean isSyncStillActive(ActiveSyncContext activeSyncContext) { for (ActiveSyncContext sync : mActiveSyncContexts) { if (sync == activeSyncContext) { Loading services/core/java/com/android/server/content/SyncOperation.java +3 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,9 @@ public class SyncOperation implements Comparable { /** Descriptive string key for this operation */ public String wakeLockName; /** 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) { Loading services/usage/java/com/android/server/usage/UsageStatsService.java +4 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ import android.util.SparseArray; import com.android.internal.os.BackgroundThread; import com.android.internal.util.IndentingPrintWriter; import com.android.server.SystemConfig; import com.android.server.SystemService; import java.io.File; Loading Loading @@ -383,6 +384,9 @@ public class UsageStatsService extends SystemService implements } boolean isAppIdle(String packageName, int userId) { if (SystemConfig.getInstance().getAllowInPowerSave().contains(packageName)) { return false; } final long lastUsed = getLastPackageAccessTime(packageName, userId); return hasPassedIdleDuration(lastUsed); } Loading Loading
services/core/java/com/android/server/content/AppIdleMonitor.java 0 → 100644 +89 −0 Original line number Diff line number Diff line /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.content; import android.app.usage.UsageStatsManagerInternal; import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.BatteryManager; import android.os.UserHandle; import com.android.server.LocalServices; /** * Helper to listen for app idle and charging status changes and restart backed off * sync operations. */ class AppIdleMonitor implements AppIdleStateChangeListener { private final SyncManager mSyncManager; private final UsageStatsManagerInternal mUsageStats; final BatteryManager mBatteryManager; /** Is the device currently plugged into power. */ private boolean mPluggedIn; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { onPluggedIn(mBatteryManager.isCharging()); } }; AppIdleMonitor(SyncManager syncManager, Context context) { mSyncManager = syncManager; mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class); mUsageStats.addAppIdleStateChangeListener(this); mBatteryManager = context.getSystemService(BatteryManager.class); mPluggedIn = isPowered(); registerReceivers(context); } private void registerReceivers(Context context) { // Monitor battery charging state IntentFilter filter = new IntentFilter(BatteryManager.ACTION_CHARGING); filter.addAction(BatteryManager.ACTION_DISCHARGING); context.registerReceiver(mReceiver, filter); } private boolean isPowered() { return mBatteryManager.isCharging(); } void onPluggedIn(boolean pluggedIn) { if (mPluggedIn == pluggedIn) { return; } mPluggedIn = pluggedIn; if (mPluggedIn) { mSyncManager.onAppNotIdle(null, UserHandle.USER_ALL); } } boolean isAppIdle(String packageName, int userId) { return !mPluggedIn && mUsageStats.isAppIdle(packageName, userId); } @Override public void onAppIdleStateChanged(String packageName, int userId, boolean idle) { // Don't care if the app is becoming idle if (idle) return; mSyncManager.onAppNotIdle(packageName, userId); } }
services/core/java/com/android/server/content/SyncManager.java +64 −1 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.util.IndentingPrintWriter; import com.android.server.accounts.AccountManagerService; import com.android.server.content.SyncStorageEngine.AuthorityInfo; import com.android.server.content.SyncStorageEngine.EndPoint; import com.android.server.content.SyncStorageEngine.OnSyncRequestListener; import com.google.android.collect.Lists; import com.google.android.collect.Maps; Loading @@ -107,7 +108,7 @@ import java.util.Set; * @hide */ public class SyncManager { private static final String TAG = "SyncManager"; static final String TAG = "SyncManager"; /** Delay a sync due to local changes this long. In milliseconds */ private static final long LOCAL_SYNC_DELAY; Loading Loading @@ -199,6 +200,8 @@ public class SyncManager { protected SyncAdaptersCache mSyncAdapters; private final AppIdleMonitor mAppIdleMonitor; private BroadcastReceiver mStorageIntentReceiver = new BroadcastReceiver() { @Override Loading Loading @@ -427,6 +430,8 @@ public class SyncManager { mSyncAlarmIntent = PendingIntent.getBroadcast( mContext, 0 /* ignored */, new Intent(ACTION_SYNC_ALARM), 0); mAppIdleMonitor = new AppIdleMonitor(this, mContext); IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); context.registerReceiver(mConnectivityIntentReceiver, intentFilter); Loading Loading @@ -1168,6 +1173,36 @@ public class SyncManager { } } /** * Clear backoff on operations in the sync queue that match the packageName and userId. * @param packageName The package that just became active. Can be null to indicate that all * packages are now considered active due to being plugged in. * @param userId The user for which the package has become active. Can be USER_ALL if * the device just plugged in. */ void onAppNotIdle(String packageName, int userId) { synchronized (mSyncQueue) { // For all sync operations in sync queue, if marked as idle, compare with package name // and unmark. And clear backoff for the operation. final Iterator<SyncOperation> operationIterator = mSyncQueue.getOperations().iterator(); boolean changed = false; while (operationIterator.hasNext()) { final SyncOperation op = operationIterator.next(); if (op.appIdle && getPackageName(op.target).equals(packageName) && (userId == UserHandle.USER_ALL || op.target.userId == userId)) { op.appIdle = false; clearBackoffSetting(op); changed = true; } } if (changed) { sendCheckAlarmsMessage(); } } } /** * @hide */ Loading Loading @@ -2447,6 +2482,19 @@ public class SyncManager { } continue; } String packageName = getPackageName(op.target); // If app is considered idle, then skip for now and backoff if (packageName != null && mAppIdleMonitor.isAppIdle(packageName, op.target.userId)) { increaseBackoffSetting(op); op.appIdle = true; if (isLoggable) { Log.v(TAG, "Sync backing off idle app " + packageName); } continue; } else { op.appIdle = false; } // Add this sync to be run. operations.add(op); } Loading Loading @@ -3194,6 +3242,21 @@ public class SyncManager { } } String getPackageName(EndPoint endpoint) { if (endpoint.target_service) { return endpoint.service.getPackageName(); } else { SyncAdapterType syncAdapterType = SyncAdapterType.newKey(endpoint.provider, endpoint.account.type); final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo; syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, endpoint.userId); if (syncAdapterInfo == null) { return null; } return syncAdapterInfo.componentName.getPackageName(); } } private boolean isSyncStillActive(ActiveSyncContext activeSyncContext) { for (ActiveSyncContext sync : mActiveSyncContexts) { if (sync == activeSyncContext) { Loading
services/core/java/com/android/server/content/SyncOperation.java +3 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,9 @@ public class SyncOperation implements Comparable { /** Descriptive string key for this operation */ public String wakeLockName; /** 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) { Loading
services/usage/java/com/android/server/usage/UsageStatsService.java +4 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ import android.util.SparseArray; import com.android.internal.os.BackgroundThread; import com.android.internal.util.IndentingPrintWriter; import com.android.server.SystemConfig; import com.android.server.SystemService; import java.io.File; Loading Loading @@ -383,6 +384,9 @@ public class UsageStatsService extends SystemService implements } boolean isAppIdle(String packageName, int userId) { if (SystemConfig.getInstance().getAllowInPowerSave().contains(packageName)) { return false; } final long lastUsed = getLastPackageAccessTime(packageName, userId); return hasPassedIdleDuration(lastUsed); } Loading