diff options
52 files changed, 759 insertions, 158 deletions
diff --git a/api/current.txt b/api/current.txt index e295a63..4b36adc 100644 --- a/api/current.txt +++ b/api/current.txt @@ -106,6 +106,7 @@ package android { field public static final java.lang.String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH"; field public static final java.lang.String RECORD_AUDIO = "android.permission.RECORD_AUDIO"; field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS"; + field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES"; field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES"; field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE"; @@ -26444,6 +26445,7 @@ package android.provider { field public static final java.lang.String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS"; field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS"; field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS"; + field public static final java.lang.String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS"; field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS"; field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS"; diff --git a/api/system-current.txt b/api/system-current.txt index 8b9af5e..36cd869 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -180,6 +180,7 @@ package android { field public static final java.lang.String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION"; field public static final java.lang.String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES"; field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS"; + field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES"; field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES"; field public static final java.lang.String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT"; @@ -28502,6 +28503,7 @@ package android.provider { field public static final java.lang.String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS"; field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS"; field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS"; + field public static final java.lang.String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS"; field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS"; field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS"; diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index 6fca0de..689283c 100644 --- a/core/java/android/app/backup/BackupAgent.java +++ b/core/java/android/app/backup/BackupAgent.java @@ -605,6 +605,13 @@ public abstract class BackupAgent extends ContextWrapper { public void onRestoreFile(ParcelFileDescriptor data, long size, File destination, int type, long mode, long mtime) throws IOException { + + final boolean accept = isFileEligibleForRestore(destination); + // If we don't accept the file, consume the bytes from the pipe anyway. + FullBackup.restoreFile(data, size, type, mode, mtime, accept ? destination : null); + } + + private boolean isFileEligibleForRestore(File destination) throws IOException { FullBackup.BackupScheme bs = FullBackup.getBackupScheme(this); if (!bs.isFullBackupContentEnabled()) { if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) { @@ -612,8 +619,9 @@ public abstract class BackupAgent extends ContextWrapper { "onRestoreFile \"" + destination.getCanonicalPath() + "\" : fullBackupContent not enabled for " + getPackageName()); } - return; + return false; } + Map<String, Set<String>> includes = null; ArraySet<String> excludes = null; final String destinationCanonicalPath = destination.getCanonicalPath(); @@ -627,7 +635,7 @@ public abstract class BackupAgent extends ContextWrapper { + "\" : Exception trying to parse fullBackupContent xml file!" + " Aborting onRestoreFile.", e); } - return; + return false; } if (excludes != null && @@ -637,7 +645,7 @@ public abstract class BackupAgent extends ContextWrapper { "onRestoreFile: \"" + destinationCanonicalPath + "\": listed in" + " excludes; skipping."); } - return; + return false; } if (includes != null && !includes.isEmpty()) { @@ -657,10 +665,10 @@ public abstract class BackupAgent extends ContextWrapper { + destinationCanonicalPath + "\" but it isn't specified" + " in the included files; skipping."); } - return; + return false; } } - FullBackup.restoreFile(data, size, type, mode, mtime, destination); + return true; } /** diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java index 9113426..948ea1e 100644 --- a/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -77,6 +77,13 @@ public abstract class UsageStatsManagerInternal { public abstract boolean isAppIdle(String packageName, int userId); /** + * Returns all of the uids for a given user where all packages associating with that uid + * are in the app idle state -- there are no associated apps that are not idle. This means + * all of the returned uids can be safely considered app idle. + */ + public abstract int[] getIdleUidsForUser(int userId); + + /** * @return True if currently app idle parole mode is on. This means all idle apps are allow to * run for a short period of time. */ diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java index d514513..9da2ba9 100644 --- a/core/java/android/content/pm/PermissionInfo.java +++ b/core/java/android/content/pm/PermissionInfo.java @@ -145,6 +145,13 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { public static final int FLAG_COSTS_MONEY = 1<<0; /** + * Flag for {@link #flags}, corresponding to <code>hidden</code> + * value of {@link android.R.attr#permissionFlags}. + * @hide + */ + public static final int FLAG_HIDDEN = 1<<1; + + /** * Flag for {@link #flags}, indicating that this permission has been * installed into the system's globally defined permissions. */ diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 605acb0..ff6dd32 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1414,8 +1414,9 @@ public class ConnectivityManager { context.enforceCallingOrSelfPermission( android.Manifest.permission.CONNECTIVITY_INTERNAL, "ConnectivityService"); } else { - context.enforceCallingOrSelfPermission( - android.Manifest.permission.CHANGE_NETWORK_STATE, "ConnectivityService"); + int uid = Binder.getCallingUid(); + Settings.checkAndNoteChangeNetworkStateOperation(context, uid, Settings + .getPackageNameForUid(context, uid), true); } } diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java index 46f7194..29daf35 100644 --- a/core/java/android/net/NetworkScorerAppManager.java +++ b/core/java/android/net/NetworkScorerAppManager.java @@ -23,6 +23,7 @@ import android.app.AppOpsManager; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.UserHandle; @@ -54,6 +55,9 @@ public final class NetworkScorerAppManager { /** Package name of this scorer app. */ public final String mPackageName; + /** UID of the scorer app. */ + public final int mPackageUid; + /** Name of this scorer app for display. */ public final CharSequence mScorerName; @@ -64,10 +68,11 @@ public final class NetworkScorerAppManager { */ public final String mConfigurationActivityClassName; - public NetworkScorerAppData(String packageName, CharSequence scorerName, + public NetworkScorerAppData(String packageName, int packageUid, CharSequence scorerName, @Nullable String configurationActivityClassName) { mScorerName = scorerName; mPackageName = packageName; + mPackageUid = packageUid; mConfigurationActivityClassName = configurationActivityClassName; } } @@ -125,7 +130,8 @@ public final class NetworkScorerAppManager { // NOTE: loadLabel will attempt to load the receiver's label and fall back to the app // label if none is present. scorers.add(new NetworkScorerAppData(receiverInfo.packageName, - receiverInfo.loadLabel(pm), configurationActivityClassName)); + receiverInfo.applicationInfo.uid, receiverInfo.loadLabel(pm), + configurationActivityClassName)); } return scorers; @@ -187,13 +193,9 @@ public final class NetworkScorerAppManager { if (defaultApp == null) { return false; } - AppOpsManager appOpsMgr = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); - try { - appOpsMgr.checkPackage(callingUid, defaultApp.mPackageName); - } catch (SecurityException e) { + if (callingUid != defaultApp.mPackageUid) { return false; } - // To be extra safe, ensure the caller holds the SCORE_NETWORKS permission. It always // should, since it couldn't become the active scorer otherwise, but this can't hurt. return context.checkCallingPermission(Manifest.permission.SCORE_NETWORKS) == diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl index d3eec1e..f55883a 100644 --- a/core/java/android/os/IDeviceIdleController.aidl +++ b/core/java/android/os/IDeviceIdleController.aidl @@ -22,10 +22,14 @@ import android.os.UserHandle; interface IDeviceIdleController { void addPowerSaveWhitelistApp(String name); void removePowerSaveWhitelistApp(String name); + String[] getSystemPowerWhitelistExceptIdle(); String[] getSystemPowerWhitelist(); + String[] getFullPowerWhitelistExceptIdle(); String[] getFullPowerWhitelist(); + int[] getAppIdWhitelistExceptIdle(); int[] getAppIdWhitelist(); int[] getAppIdTempWhitelist(); + boolean isPowerSaveWhitelistExceptIdleApp(String name); boolean isPowerSaveWhitelistApp(String name); void addPowerSaveTempWhitelistApp(String name, long duration, int userId, String reason); long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index bb09b05..fe95864 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -616,20 +616,46 @@ public final class Settings { /** * Activity Action: Show screen for controlling which apps can ignore battery optimizations. * <p> - * Input: Optionally, the Intent's data URI specifies the application package name - * to be shown, with the "package" scheme. That is "package:com.my.app". + * Input: Nothing. * <p> * Output: Nothing. * <p> * You can use {@link android.os.PowerManager#isIgnoringBatteryOptimizations * PowerManager.isIgnoringBatteryOptimizations()} to determine if an application is - * already ignoring optimizations. + * already ignoring optimizations. You can use + * {@link #ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS} to ask the user to put you + * on this list. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS = "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS"; /** + * Activity Action: Ask the user to allow an to ignore battery optimizations (that is, + * put them on the whitelist of apps shown by + * {@link #ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS}). For an app to use this, it also + * must hold the {@link android.Manifest.permission#REQUEST_IGNORE_BATTERY_OPTIMIZATIONS} + * permission. + * <p><b>Note:</b> most applications should <em>not</em> use this; there are many facilities + * provided by the platform for applications to operate correctly in the various power + * saving mode. This is only for unusual applications that need to deeply control their own + * execution, at the potential expense of the user's battery life. Note that these applications + * greatly run the risk of showing to the user has how power consumers on their device.</p> + * <p> + * Input: The Intent's data URI must specify the application package name + * to be shown, with the "package" scheme. That is "package:com.my.app". + * <p> + * Output: Nothing. + * <p> + * You can use {@link android.os.PowerManager#isIgnoringBatteryOptimizations + * PowerManager.isIgnoringBatteryOptimizations()} to determine if an application is + * already ignoring optimizations. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = + "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; + + /** * @hide * Activity Action: Show the "app ops" settings screen. * <p> @@ -1408,6 +1434,25 @@ public final class Settings { } /** + * An app can use this method to check if it is currently allowed to change the network + * state. In order to be allowed to do so, an app must first declare either the + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} or + * {@link android.Manifest.permission#WRITE_SETTINGS} permission in its manifest. If it + * is currently disallowed, it can prompt the user to grant it this capability through a + * management UI by sending an Intent with action + * {@link android.provider.Settings#ACTION_MANAGE_WRITE_SETTINGS}. + * + * @param context A context + * @return true if the calling app can change the state of network, false otherwise. + * @hide + */ + public static boolean canChangeNetworkState(Context context) { + int uid = Binder.getCallingUid(); + return Settings.isCallingPackageAllowedToChangeNetworkState(context, uid, Settings + .getPackageNameForUid(context, uid), false); + } + + /** * System settings, containing miscellaneous system preferences. This * table holds simple name/value pairs. There are convenience * functions for accessing individual settings entries. @@ -8252,6 +8297,17 @@ public final class Settings { return "android-" + Long.toHexString(androidId); } + private static final String[] PM_WRITE_SETTINGS = { + android.Manifest.permission.WRITE_SETTINGS + }; + private static final String[] PM_CHANGE_NETWORK_STATE = { + android.Manifest.permission.CHANGE_NETWORK_STATE, + android.Manifest.permission.WRITE_SETTINGS + }; + private static final String[] PM_SYSTEM_ALERT_WINDOW = { + android.Manifest.permission.SYSTEM_ALERT_WINDOW + }; + /** * Performs a strict and comprehensive check of whether a calling package is allowed to * write/modify system settings, as the condition differs for pre-M, M+, and @@ -8263,14 +8319,15 @@ public final class Settings { String callingPackage, boolean throwException) { return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid, callingPackage, throwException, AppOpsManager.OP_WRITE_SETTINGS, - android.Manifest.permission.WRITE_SETTINGS, false); + PM_WRITE_SETTINGS, false); } /** * Performs a strict and comprehensive check of whether a calling package is allowed to * write/modify system settings, as the condition differs for pre-M, M+, and * privileged/preinstalled apps. If the provided uid does not match the - * callingPackage, a negative result will be returned. + * callingPackage, a negative result will be returned. The caller is expected to have + * either WRITE_SETTINGS or CHANGE_NETWORK_STATE permission declared. * * Note: if the check is successful, the operation of this app will be updated to the * current time. @@ -8280,7 +8337,40 @@ public final class Settings { String callingPackage, boolean throwException) { return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid, callingPackage, throwException, AppOpsManager.OP_WRITE_SETTINGS, - android.Manifest.permission.WRITE_SETTINGS, true); + PM_WRITE_SETTINGS, true); + } + + /** + * Performs a strict and comprehensive check of whether a calling package is allowed to + * change the state of network, as the condition differs for pre-M, M+, and + * privileged/preinstalled apps. If the provided uid does not match the + * callingPackage, a negative result will be returned. The caller is expected to have + * either of CHANGE_NETWORK_STATE or WRITE_SETTINGS permission declared. + * @hide + */ + public static boolean isCallingPackageAllowedToChangeNetworkState(Context context, int uid, + String callingPackage, boolean throwException) { + return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid, + callingPackage, throwException, AppOpsManager.OP_WRITE_SETTINGS, + PM_CHANGE_NETWORK_STATE, false); + } + + /** + * Performs a strict and comprehensive check of whether a calling package is allowed to + * change the state of network, as the condition differs for pre-M, M+, and + * privileged/preinstalled apps. If the provided uid does not match the + * callingPackage, a negative result will be returned. The caller is expected to have + * either CHANGE_NETWORK_STATE or WRITE_SETTINGS permission declared. + * + * Note: if the check is successful, the operation of this app will be updated to the + * current time. + * @hide + */ + public static boolean checkAndNoteChangeNetworkStateOperation(Context context, int uid, + String callingPackage, boolean throwException) { + return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid, + callingPackage, throwException, AppOpsManager.OP_WRITE_SETTINGS, + PM_CHANGE_NETWORK_STATE, true); } /** @@ -8294,7 +8384,7 @@ public final class Settings { String callingPackage, boolean throwException) { return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid, callingPackage, throwException, AppOpsManager.OP_SYSTEM_ALERT_WINDOW, - android.Manifest.permission.SYSTEM_ALERT_WINDOW, false); + PM_SYSTEM_ALERT_WINDOW, false); } /** @@ -8311,7 +8401,7 @@ public final class Settings { callingPackage, boolean throwException) { return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid, callingPackage, throwException, AppOpsManager.OP_SYSTEM_ALERT_WINDOW, - android.Manifest.permission.SYSTEM_ALERT_WINDOW, true); + PM_SYSTEM_ALERT_WINDOW, true); } /** @@ -8321,8 +8411,8 @@ public final class Settings { * @hide */ public static boolean isCallingPackageAllowedToPerformAppOpsProtectedOperation(Context context, - int uid, String callingPackage, boolean throwException, int appOpsOpCode, String - permissionName, boolean makeNote) { + int uid, String callingPackage, boolean throwException, int appOpsOpCode, String[] + permissions, boolean makeNote) { if (callingPackage == null) { return false; } @@ -8338,20 +8428,41 @@ public final class Settings { switch (mode) { case AppOpsManager.MODE_ALLOWED: return true; + case AppOpsManager.MODE_DEFAULT: // this is the default operating mode after an app's installation - if(context.checkCallingOrSelfPermission(permissionName) == PackageManager - .PERMISSION_GRANTED) { - return true; + // In this case we will check all associated static permission to see + // if it is granted during install time. + for (String permission : permissions) { + if (context.checkCallingOrSelfPermission(permission) == PackageManager + .PERMISSION_GRANTED) { + // if either of the permissions are granted, we will allow it + return true; + } } + default: // this is for all other cases trickled down here... if (!throwException) { return false; } } - throw new SecurityException(callingPackage + " was not granted " - + permissionName + " permission"); + + // prepare string to throw SecurityException + StringBuilder exceptionMessage = new StringBuilder(); + exceptionMessage.append(callingPackage); + exceptionMessage.append(" was not granted "); + if (permissions.length > 1) { + exceptionMessage.append(" either of these permissions: "); + } else { + exceptionMessage.append(" this permission: "); + } + for (int i = 0; i < permissions.length; i++) { + exceptionMessage.append(permissions[i]); + exceptionMessage.append((i == permissions.length - 1) ? "." : ", "); + } + + throw new SecurityException(exceptionMessage.toString()); } /** diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java index 2b85a21..e5c729d 100644 --- a/core/java/android/util/SparseIntArray.java +++ b/core/java/android/util/SparseIntArray.java @@ -184,6 +184,14 @@ public class SparseIntArray implements Cloneable { } /** + * Directly set the value at a particular index. + * @hide + */ + public void setValueAt(int index, int value) { + mValues[index] = value; + } + + /** * Returns the index for which {@link #keyAt} would return the * specified key, or a negative number if the specified * key is not mapped. diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index 3b9aca8..584deff 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -314,8 +314,7 @@ public final class WebViewFactory { if (path.contains("!/")) { String[] split = TextUtils.split(path, "!/"); if (split.length == 2) { - try { - ZipFile z = new ZipFile(split[0]); + try (ZipFile z = new ZipFile(split[0])) { ZipEntry e = z.getEntry(split[1]); if (e != null && e.getMethod() == ZipEntry.STORED) { newVmSize = Math.max(newVmSize, e.getSize()); @@ -355,8 +354,7 @@ public final class WebViewFactory { String[] abiList, String nativeLibFileName) { // Search the APK for a native library conforming to a listed ABI. - try { - ZipFile z = new ZipFile(apkPath); + try (ZipFile z = new ZipFile(apkPath)) { for (String abi : abiList) { final String entry = "lib/" + abi + "/" + nativeLibFileName; ZipEntry e = z.getEntry(entry); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 699e113..629d14b 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -599,7 +599,6 @@ --> <permission android:name="android.permission.ACCESS_IMS_CALL_SERVICE" android:permissionGroup="android.permission-group.PHONE" - android:permissionFlags="hide" android:label="@string/permlab_accessImsCallService" android:description="@string/permdesc_accessImsCallService" android:protectionLevel="signature|system" /> @@ -760,32 +759,32 @@ <!-- @hide We need to keep this around for backwards compatibility --> <permission android:name="android.permission.READ_PROFILE" android:protectionLevel="normal" - android:permissionFlags="hide"/> + android:permissionFlags="hidden"/> <!-- @hide We need to keep this around for backwards compatibility --> <permission android:name="android.permission.WRITE_PROFILE" android:protectionLevel="normal" - android:permissionFlags="hide"/> + android:permissionFlags="hidden"/> <!-- @hide We need to keep this around for backwards compatibility --> <permission android:name="android.permission.READ_SOCIAL_STREAM" android:protectionLevel="normal" - android:permissionFlags="hide"/> + android:permissionFlags="hidden"/> <!-- @hide We need to keep this around for backwards compatibility --> <permission android:name="android.permission.WRITE_SOCIAL_STREAM" android:protectionLevel="normal" - android:permissionFlags="hide"/> + android:permissionFlags="hidden"/> <!-- @hide We need to keep this around for backwards compatibility --> <permission android:name="android.permission.READ_USER_DICTIONARY" android:protectionLevel="normal" - android:permissionFlags="hide"/> + android:permissionFlags="hidden"/> <!-- @hide We need to keep this around for backwards compatibility --> <permission android:name="android.permission.WRITE_USER_DICTIONARY" android:protectionLevel="normal" - android:permissionFlags="hide"/> + android:permissionFlags="hidden"/> <!-- ====================================================================== --> <!-- INSTALL PERMISSIONS --> @@ -1660,7 +1659,7 @@ <permission android:name="android.permission.CHANGE_NETWORK_STATE" android:description="@string/permdesc_changeNetworkState" android:label="@string/permlab_changeNetworkState" - android:protectionLevel="normal" /> + android:protectionLevel="signature|preinstalled|appop|pre23" /> <!-- Allows an application to clear the caches of all installed applications on the device. @@ -2258,6 +2257,13 @@ <permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" android:protectionLevel="system|signature" /> + <!-- Permission an application must hold in order to use + {@link android.provider.Settings#ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}. + This is a normal permission: an app requesting it will always be granted the + permission, without the user needing to approve or see it. --> + <permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" + android:protectionLevel="normal" /> + <!-- @SystemApi Allows an application to collect battery statistics --> <permission android:name="android.permission.BATTERY_STATS" android:protectionLevel="signature|privileged|development" /> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index de16f20..1a45b3a 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -250,7 +250,7 @@ <flag name="costsMoney" value="0x0001" /> <!-- Additional flag from base permission type: this permission is hidden and should not show in the UI. --> - <flag name="hide" value="0x2" /> + <flag name="hidden" value="0x2" /> </attr> <!-- Specified the name of a group that this permission is associated diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java index 9bb44d0..605f067 100644 --- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java +++ b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java @@ -57,16 +57,19 @@ public class NetworkScorerAppManagerTest extends InstrumentationTestCase { public void testGetAllValidScorers() throws Exception { // Package 1 - Valid scorer. - Pair<ResolveInfo, ResolveInfo> package1 = buildResolveInfo("package1", true, true, false); + Pair<ResolveInfo, ResolveInfo> package1 = buildResolveInfo("package1", 1, true, true, + false); // Package 2 - Receiver does not have BROADCAST_NETWORK_PRIVILEGED permission. - Pair<ResolveInfo, ResolveInfo> package2 = buildResolveInfo("package2", false, true, false); + Pair<ResolveInfo, ResolveInfo> package2 = buildResolveInfo("package2", 2, false, true, + false); // Package 3 - App does not have SCORE_NETWORKS permission. - Pair<ResolveInfo, ResolveInfo> package3 = buildResolveInfo("package3", true, false, false); + Pair<ResolveInfo, ResolveInfo> package3 = buildResolveInfo("package3", 3, true, false, + false); // Package 4 - Valid scorer w/ optional config activity. - Pair<ResolveInfo, ResolveInfo> package4 = buildResolveInfo("package4", true, true, true); + Pair<ResolveInfo, ResolveInfo> package4 = buildResolveInfo("package4", 4, true, true, true); List<Pair<ResolveInfo, ResolveInfo>> scorers = new ArrayList<>(); scorers.add(package1); @@ -81,11 +84,13 @@ public class NetworkScorerAppManagerTest extends InstrumentationTestCase { assertTrue(result.hasNext()); NetworkScorerAppData next = result.next(); assertEquals("package1", next.mPackageName); + assertEquals(1, next.mPackageUid); assertNull(next.mConfigurationActivityClassName); assertTrue(result.hasNext()); next = result.next(); assertEquals("package4", next.mPackageName); + assertEquals(4, next.mPackageUid); assertEquals(".ConfigActivity", next.mConfigurationActivityClassName); assertFalse(result.hasNext()); @@ -122,7 +127,7 @@ public class NetworkScorerAppManagerTest extends InstrumentationTestCase { .thenReturn(receivers); } - private Pair<ResolveInfo, ResolveInfo> buildResolveInfo(String packageName, + private Pair<ResolveInfo, ResolveInfo> buildResolveInfo(String packageName, int packageUid, boolean hasReceiverPermission, boolean hasScorePermission, boolean hasConfigActivity) throws Exception { Mockito.when(mMockPm.checkPermission(permission.SCORE_NETWORKS, packageName)) @@ -133,6 +138,7 @@ public class NetworkScorerAppManagerTest extends InstrumentationTestCase { resolveInfo.activityInfo = new ActivityInfo(); resolveInfo.activityInfo.packageName = packageName; resolveInfo.activityInfo.applicationInfo = new ApplicationInfo(); + resolveInfo.activityInfo.applicationInfo.uid = packageUid; if (hasReceiverPermission) { resolveInfo.activityInfo.permission = permission.BROADCAST_NETWORK_PRIVILEGED; } diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 579d2df..350310c 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -141,6 +141,6 @@ <!-- These are the standard packages that are white-listed to always have internet access while in power save mode, even if they aren't in the foreground. --> - <allow-in-power-save package="com.android.providers.downloads" /> + <allow-in-power-save-except-idle package="com.android.providers.downloads" /> </permissions> diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index fef65ee..7f22b8a 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -111,14 +111,6 @@ public final class AudioDeviceInfo { * A device type connected over IP. */ public static final int TYPE_IP = 20; - /** - * @hide - * A remote-submix device. - * We need this for CTS, but it is not part of the external API. - * FIXME It has been suggested that CTS should only be testing public APIs. - * Consider this for a public API. - */ - public static final int TYPE_REMOTE_SUBMIX = 0x7FFF; private final AudioDevicePort mPort; @@ -286,7 +278,6 @@ public final class AudioDeviceInfo { INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_FM, TYPE_FM); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_AUX_LINE, TYPE_AUX_LINE); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_IP, TYPE_IP); - INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, TYPE_BUILTIN_MIC); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO); @@ -304,7 +295,10 @@ public final class AudioDeviceInfo { INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_SPDIF, TYPE_LINE_DIGITAL); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, TYPE_BLUETOOTH_A2DP); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_IP, TYPE_IP); - INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX); + + // not covered here, legacy + //AudioSystem.DEVICE_OUT_REMOTE_SUBMIX + //AudioSystem.DEVICE_IN_REMOTE_SUBMIX // privileges mapping to output device EXT_TO_INT_DEVICE_MAPPING = new SparseIntArray(); diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 5290cac..875e716 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -3757,6 +3757,12 @@ public class AudioManager { port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0; } + private static boolean checkTypes(AudioDevicePort port) { + return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) != + AudioDeviceInfo.TYPE_UNKNOWN && + port.type() != AudioSystem.DEVICE_IN_BACK_MIC; + } + /** * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices * currently connected to the system and meeting the criteria specified in the @@ -3779,7 +3785,7 @@ public class AudioManager { // figure out how many AudioDeviceInfo we need space for... int numRecs = 0; for (AudioDevicePort port : ports) { - if (checkFlags(port, flags)) { + if (checkTypes(port) && checkFlags(port, flags)) { numRecs++; } } @@ -3788,7 +3794,7 @@ public class AudioManager { AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs]; int slot = 0; for (AudioDevicePort port : ports) { - if (checkFlags(port, flags)) { + if (checkTypes(port) && checkFlags(port, flags)) { deviceList[slot++] = new AudioDeviceInfo(port); } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index e74334b..b9a9c24 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -148,7 +148,10 @@ public class SettingsBackupAgent extends BackupAgentHelper { private WifiManager mWfm; private static String mWifiConfigFile; + // Chain of asynchronous operations used when rewriting the wifi supplicant config file + WifiDisableRunnable mWifiDisable = null; WifiRestoreRunnable mWifiRestore = null; + int mRetainedWifiState; // used only during config file rewrite // Class for capturing a network definition from the wifi supplicant config file static class Network { @@ -407,9 +410,47 @@ public class SettingsBackupAgent extends BackupAgentHelper { writeNewChecksums(stateChecksums, newState); } + class WifiDisableRunnable implements Runnable { + final WifiRestoreRunnable mNextPhase; + + public WifiDisableRunnable(WifiRestoreRunnable next) { + mNextPhase = next; + } + + @Override + public void run() { + if (DEBUG_BACKUP) { + Log.v(TAG, "Disabling wifi during restore"); + } + final ContentResolver cr = getContentResolver(); + final int scanAlways = Settings.Global.getInt(cr, + Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0); + final int retainedWifiState = enableWifi(false); + if (scanAlways != 0) { + Settings.Global.putInt(cr, + Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0); + } + + // Tell the final stage how to clean up after itself + mNextPhase.setPriorState(retainedWifiState, scanAlways); + + // And run it after a modest pause to give broadcasts and content + // observers time an opportunity to run on this looper thread, so + // that the wifi stack actually goes all the way down. + new Handler(getMainLooper()).postDelayed(mNextPhase, 2500); + } + } + class WifiRestoreRunnable implements Runnable { private byte[] restoredSupplicantData; private byte[] restoredWifiConfigFile; + private int retainedWifiState; // provided by disable stage + private int scanAlways; // provided by disable stage + + void setPriorState(int retainedState, int always) { + retainedWifiState = retainedState; + scanAlways = always; + } void incorporateWifiSupplicant(BackupDataInput data) { restoredSupplicantData = new byte[data.getDataSize()]; @@ -437,20 +478,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { public void run() { if (restoredSupplicantData != null || restoredWifiConfigFile != null) { if (DEBUG_BACKUP) { - Log.v(TAG, "Starting deferred restore of wifi data"); - } - final ContentResolver cr = getContentResolver(); - final int scanAlways = Settings.Global.getInt(cr, - Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0); - final int retainedWifiState = enableWifi(false); - if (scanAlways != 0) { - Settings.Global.putInt(cr, - Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0); + Log.v(TAG, "Applying restored wifi data"); } - // !!! Give the wifi stack a moment to quiesce. We've observed the - // response to disabling WIFI_SCAN_ALWAYS_AVAILABLE taking more - // than 1500ms, so we wait a generous 2500 here before proceeding. - try { Thread.sleep(2500); } catch (InterruptedException e) {} if (restoredSupplicantData != null) { restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, restoredSupplicantData, restoredSupplicantData.length); @@ -465,7 +494,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { } // restore the previous WIFI state. if (scanAlways != 0) { - Settings.Global.putInt(cr, + Settings.Global.putInt(getContentResolver(), Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, scanAlways); } enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED || @@ -479,6 +508,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { void initWifiRestoreIfNecessary() { if (mWifiRestore == null) { mWifiRestore = new WifiRestoreRunnable(); + mWifiDisable = new WifiDisableRunnable(mWifiRestore); } } @@ -518,13 +548,16 @@ public class SettingsBackupAgent extends BackupAgentHelper { } // If we have wifi data to restore, post a runnable to perform the - // bounce-and-update operation a little ways in the future. + // bounce-and-update operation a little ways in the future. The + // 'disable' runnable brings down the stack and remembers its state, + // and in turn schedules the 'restore' runnable to do the rewrite + // and cleanup operations. if (mWifiRestore != null) { long wifiBounceDelayMillis = Settings.Global.getLong( getContentResolver(), Settings.Global.WIFI_BOUNCE_DELAY_OVERRIDE_MS, WIFI_BOUNCE_DELAY_MILLIS); - new Handler(getMainLooper()).postDelayed(mWifiRestore, wifiBounceDelayMillis); + new Handler(getMainLooper()).postDelayed(mWifiDisable, wifiBounceDelayMillis); } } diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png Binary files differindex d2760bb..aa9f6d4 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png Binary files differindex 5cbf418..151caea 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png Binary files differindex df43e21..613afce 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png Binary files differindex 6fab1d6..eb80426 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png Binary files differindex 1d8c3af..34a11df 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png Binary files differindex 47c6ebd..1c1e78c 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png Binary files differindex 66de0ec..7c25fc5 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png Binary files differindex 30c65f5..1ee9cf5 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png Binary files differindex a356285..987aac5 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png Binary files differindex 42893ff..433e5a74 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png Binary files differindex ba2d0b2..0e2a14d 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png Binary files differindex 94a74b1..f810704 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png Binary files differindex 29da099..be03cbe 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png Binary files differindex ada2879..b6b1615 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png Binary files differindex 59b32f2..f16aa48 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png Binary files differindex ba66d27..109aeed 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back.png Binary files differnew file mode 100644 index 0000000..a059704 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime.png Binary files differnew file mode 100644 index 0000000..8f00a64 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home.png Binary files differnew file mode 100644 index 0000000..194d39f --- /dev/null +++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent.png Binary files differnew file mode 100644 index 0000000..046d850 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 6627360..42a2f90 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -29,6 +29,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Configuration; +import android.hardware.fingerprint.FingerprintManager; import android.os.AsyncTask; import android.os.Bundle; import android.os.IBinder; @@ -601,6 +602,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } private final BroadcastReceiver mDevicePolicyReceiver = new BroadcastReceiver() { + @Override public void onReceive(Context context, Intent intent) { post(new Runnable() { @Override @@ -671,7 +673,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL @Override public void onFingerprintError(int msgId, String errString) { - if (!KeyguardUpdateMonitor.getInstance(mContext).isUnlockingWithFingerprintAllowed()) { + if (!KeyguardUpdateMonitor.getInstance(mContext).isUnlockingWithFingerprintAllowed() + || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) { return; } // TODO: Go to bouncer if this is "too many attempts" (lockout) error. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index ed1dca3..b65bf43 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -88,8 +88,10 @@ public class MobileSignalController extends SignalController< mapIconSets(); - mLastState.networkName = mCurrentState.networkName = mNetworkNameDefault; - mLastState.networkNameData = mCurrentState.networkNameData = mNetworkNameDefault; + String networkName = info.getCarrierName() != null ? info.getCarrierName().toString() + : mNetworkNameDefault; + mLastState.networkName = mCurrentState.networkName = networkName; + mLastState.networkNameData = mCurrentState.networkNameData = networkName; mLastState.enabled = mCurrentState.enabled = hasMobileData; mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons; // Get initial data sim state. diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index 45c020c..56ebed6 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -1245,6 +1245,7 @@ public class AppOpsService extends IAppOpsService.Stub { return; } boolean success = false; + mUidStates.clear(); try { XmlPullParser parser = Xml.newPullParser(); parser.setInput(stream, StandardCharsets.UTF_8.name()); @@ -1448,7 +1449,7 @@ public class AppOpsService extends IAppOpsService.Stub { XmlSerializer out = new FastXmlSerializer(); out.setOutput(stream, StandardCharsets.UTF_8.name()); out.startDocument(null, true); - out.startTag(null, "app"); + out.startTag(null, "app-ops"); final int uidStateCount = mUidStates.size(); for (int i = 0; i < uidStateCount; i++) { @@ -1541,6 +1542,17 @@ public class AppOpsService extends IAppOpsService.Stub { } } + private void dumpHelp(PrintWriter pw) { + pw.println("AppOps service (appops) dump options:"); + pw.println(" [-h] [CMD]"); + pw.println(" -h: print this help text."); + pw.println("Commands:"); + pw.println(" write-settings"); + pw.println(" Immediately write pending changes to storage."); + pw.println(" read-settings"); + pw.println(" Read the last written settings, replacing current state in RAM."); + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) @@ -1551,6 +1563,43 @@ public class AppOpsService extends IAppOpsService.Stub { return; } + if (args != null) { + for (int i=0; i<args.length; i++) { + String arg = args[i]; + if ("-h".equals(arg)) { + dumpHelp(pw); + return; + } else if ("write-settings".equals(arg)) { + long token = Binder.clearCallingIdentity(); + try { + synchronized (this) { + mHandler.removeCallbacks(mWriteRunner); + } + writeState(); + pw.println("Current settings written."); + } finally { + Binder.restoreCallingIdentity(token); + } + return; + } else if ("read-settings".equals(arg)) { + long token = Binder.clearCallingIdentity(); + try { + readState(); + pw.println("Last settings read."); + } finally { + Binder.restoreCallingIdentity(token); + } + return; + } else if (arg.length() > 0 && arg.charAt(0) == '-'){ + pw.println("Unknown option: " + arg); + return; + } else { + pw.println("Unknown command: " + arg); + return; + } + } + } + synchronized (this) { pw.println("Current AppOps Service state:"); final long now = System.currentTimeMillis(); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 0802d30..6e0c37f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1432,9 +1432,10 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void enforceChangePermission() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.CHANGE_NETWORK_STATE, - "ConnectivityService"); + int uid = Binder.getCallingUid(); + Settings.checkAndNoteChangeNetworkStateOperation(mContext, uid, Settings + .getPackageNameForUid(mContext, uid), true); + } private void enforceTetherAccessPermission() { diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 7561c7d..e678bbc 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -113,6 +113,7 @@ public class DeviceIdleController extends SystemService private Display mCurDisplay; private AnyMotionDetector mAnyMotionDetector; private boolean mEnabled; + private boolean mForceIdle; private boolean mScreenOn; private boolean mCharging; private boolean mSigMotionActive; @@ -151,7 +152,14 @@ public class DeviceIdleController extends SystemService public final AtomicFile mConfigFile; /** - * Package names the system has white-listed to opt out of power save restrictions. + * Package names the system has white-listed to opt out of power save restrictions, + * except for device idle mode. + */ + private final ArrayMap<String, Integer> mPowerSaveWhitelistAppsExceptIdle = new ArrayMap<>(); + + /** + * Package names the system has white-listed to opt out of power save restrictions for + * all modes. */ private final ArrayMap<String, Integer> mPowerSaveWhitelistApps = new ArrayMap<>(); @@ -161,11 +169,30 @@ public class DeviceIdleController extends SystemService private final ArrayMap<String, Integer> mPowerSaveWhitelistUserApps = new ArrayMap<>(); /** + * App IDs of built-in system apps that have been white-listed except for idle modes. + */ + private final SparseBooleanArray mPowerSaveWhitelistSystemAppIdsExceptIdle + = new SparseBooleanArray(); + + /** * App IDs of built-in system apps that have been white-listed. */ private final SparseBooleanArray mPowerSaveWhitelistSystemAppIds = new SparseBooleanArray(); /** + * App IDs that have been white-listed to opt out of power save restrictions, except + * for device idle modes. + */ + private final SparseBooleanArray mPowerSaveWhitelistExceptIdleAppIds = new SparseBooleanArray(); + + /** + * Current app IDs that are in the complete power save white list, but shouldn't be + * excluded from idle modes. This array can be shared with others because it will not be + * modified once set. + */ + private int[] mPowerSaveWhitelistExceptIdleAppIdArray = new int[0]; + + /** * App IDs that have been white-listed to opt out of power save restrictions. */ private final SparseBooleanArray mPowerSaveWhitelistAllAppIds = new SparseBooleanArray(); @@ -583,14 +610,26 @@ public class DeviceIdleController extends SystemService removePowerSaveWhitelistAppInternal(name); } + @Override public String[] getSystemPowerWhitelistExceptIdle() { + return getSystemPowerWhitelistExceptIdleInternal(); + } + @Override public String[] getSystemPowerWhitelist() { return getSystemPowerWhitelistInternal(); } + @Override public String[] getFullPowerWhitelistExceptIdle() { + return getFullPowerWhitelistExceptIdleInternal(); + } + @Override public String[] getFullPowerWhitelist() { return getFullPowerWhitelistInternal(); } + @Override public int[] getAppIdWhitelistExceptIdle() { + return getAppIdWhitelistExceptIdleInternal(); + } + @Override public int[] getAppIdWhitelist() { return getAppIdWhitelistInternal(); } @@ -599,6 +638,10 @@ public class DeviceIdleController extends SystemService return getAppIdTempWhitelistInternal(); } + @Override public boolean isPowerSaveWhitelistExceptIdleApp(String name) { + return isPowerSaveWhitelistExceptIdleAppInternal(name); + } + @Override public boolean isPowerSaveWhitelistApp(String name) { return isPowerSaveWhitelistAppInternal(name); } @@ -679,6 +722,19 @@ public class DeviceIdleController extends SystemService mEnabled = getContext().getResources().getBoolean( com.android.internal.R.bool.config_enableAutoPowerModes); SystemConfig sysConfig = SystemConfig.getInstance(); + ArraySet<String> allowPowerExceptIdle = sysConfig.getAllowInPowerSaveExceptIdle(); + for (int i=0; i<allowPowerExceptIdle.size(); i++) { + String pkg = allowPowerExceptIdle.valueAt(i); + try { + ApplicationInfo ai = pm.getApplicationInfo(pkg, 0); + if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { + int appid = UserHandle.getAppId(ai.uid); + mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid); + mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true); + } + } catch (PackageManager.NameNotFoundException e) { + } + } ArraySet<String> allowPower = sysConfig.getAllowInPowerSave(); for (int i=0; i<allowPower.size(); i++) { String pkg = allowPower.valueAt(i); @@ -686,6 +742,10 @@ public class DeviceIdleController extends SystemService ApplicationInfo ai = pm.getApplicationInfo(pkg, 0); if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { int appid = UserHandle.getAppId(ai.uid); + // These apps are on both the whitelist-except-idle as well + // as the full whitelist, so they apply in all cases. + mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid); + mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true); mPowerSaveWhitelistApps.put(ai.packageName, appid); mPowerSaveWhitelistSystemAppIds.put(appid, true); } @@ -783,17 +843,45 @@ public class DeviceIdleController extends SystemService return false; } + public String[] getSystemPowerWhitelistExceptIdleInternal() { + synchronized (this) { + int size = mPowerSaveWhitelistAppsExceptIdle.size(); + String[] apps = new String[size]; + for (int i = 0; i < size; i++) { + apps[i] = mPowerSaveWhitelistAppsExceptIdle.keyAt(i); + } + return apps; + } + } + public String[] getSystemPowerWhitelistInternal() { synchronized (this) { int size = mPowerSaveWhitelistApps.size(); String[] apps = new String[size]; - for (int i = 0; i < mPowerSaveWhitelistApps.size(); i++) { + for (int i = 0; i < size; i++) { apps[i] = mPowerSaveWhitelistApps.keyAt(i); } return apps; } } + public String[] getFullPowerWhitelistExceptIdleInternal() { + synchronized (this) { + int size = mPowerSaveWhitelistAppsExceptIdle.size() + mPowerSaveWhitelistUserApps.size(); + String[] apps = new String[size]; + int cur = 0; + for (int i = 0; i < mPowerSaveWhitelistAppsExceptIdle.size(); i++) { + apps[cur] = mPowerSaveWhitelistAppsExceptIdle.keyAt(i); + cur++; + } + for (int i = 0; i < mPowerSaveWhitelistUserApps.size(); i++) { + apps[cur] = mPowerSaveWhitelistUserApps.keyAt(i); + cur++; + } + return apps; + } + } + public String[] getFullPowerWhitelistInternal() { synchronized (this) { int size = mPowerSaveWhitelistApps.size() + mPowerSaveWhitelistUserApps.size(); @@ -811,6 +899,13 @@ public class DeviceIdleController extends SystemService } } + public boolean isPowerSaveWhitelistExceptIdleAppInternal(String packageName) { + synchronized (this) { + return mPowerSaveWhitelistAppsExceptIdle.containsKey(packageName) + || mPowerSaveWhitelistUserApps.containsKey(packageName); + } + } + public boolean isPowerSaveWhitelistAppInternal(String packageName) { synchronized (this) { return mPowerSaveWhitelistApps.containsKey(packageName) @@ -818,6 +913,12 @@ public class DeviceIdleController extends SystemService } } + public int[] getAppIdWhitelistExceptIdleInternal() { + synchronized (this) { + return mPowerSaveWhitelistExceptIdleAppIdArray; + } + } + public int[] getAppIdWhitelistInternal() { synchronized (this) { return mPowerSaveWhitelistAllAppIdArray; @@ -921,6 +1022,9 @@ public class DeviceIdleController extends SystemService Slog.d(TAG, "Removing UID " + uid + " from temp whitelist"); } updateTempWhitelistAppIdsLocked(); + if (mNetworkPolicyTempWhitelistCallback != null) { + mHandler.post(mNetworkPolicyTempWhitelistCallback); + } reportTempWhitelistChangedLocked(); try { mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_TEMP_WHITELIST_FINISH, @@ -949,10 +1053,14 @@ public class DeviceIdleController extends SystemService if (DEBUG) Slog.d(TAG, "updateDisplayLocked: screenOn=" + screenOn); if (!screenOn && mScreenOn) { mScreenOn = false; - becomeInactiveIfAppropriateLocked(); + if (!mForceIdle) { + becomeInactiveIfAppropriateLocked(); + } } else if (screenOn) { mScreenOn = true; - becomeActiveLocked("screen", Process.myUid()); + if (!mForceIdle) { + becomeActiveLocked("screen", Process.myUid()); + } } } @@ -960,10 +1068,14 @@ public class DeviceIdleController extends SystemService if (DEBUG) Slog.i(TAG, "updateChargingLocked: charging=" + charging); if (!charging && mCharging) { mCharging = false; - becomeInactiveIfAppropriateLocked(); + if (!mForceIdle) { + becomeInactiveIfAppropriateLocked(); + } } else if (charging) { mCharging = charging; - becomeActiveLocked("charging", Process.myUid()); + if (!mForceIdle) { + becomeActiveLocked("charging", Process.myUid()); + } } } @@ -989,7 +1101,7 @@ public class DeviceIdleController extends SystemService void becomeInactiveIfAppropriateLocked() { if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()"); - if (!mScreenOn && !mCharging && mEnabled && mState == STATE_ACTIVE) { + if (((!mScreenOn && !mCharging) || mForceIdle) && mEnabled && mState == STATE_ACTIVE) { // Screen has turned off; we are now going to become inactive and start // waiting to see if we will ultimately go idle. mState = STATE_INACTIVE; @@ -1010,6 +1122,15 @@ public class DeviceIdleController extends SystemService becomeInactiveIfAppropriateLocked(); } + void exitForceIdleLocked() { + if (mForceIdle) { + mForceIdle = false; + if (mScreenOn || mCharging) { + becomeActiveLocked("exit-force-idle", Process.myUid()); + } + } + } + void stepIdleStateLocked() { if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState); EventLogTags.writeDeviceIdleStep(); @@ -1138,20 +1259,28 @@ public class DeviceIdleController extends SystemService mNextAlarmTime, mSensingAlarmIntent); } - private void updateWhitelistAppIdsLocked() { - mPowerSaveWhitelistAllAppIds.clear(); - for (int i=0; i<mPowerSaveWhitelistApps.size(); i++) { - mPowerSaveWhitelistAllAppIds.put(mPowerSaveWhitelistApps.valueAt(i), true); + private static int[] buildAppIdArray(ArrayMap<String, Integer> systemApps, + ArrayMap<String, Integer> userApps, SparseBooleanArray outAppIds) { + outAppIds.clear(); + for (int i=0; i<systemApps.size(); i++) { + outAppIds.put(systemApps.valueAt(i), true); } - for (int i=0; i<mPowerSaveWhitelistUserApps.size(); i++) { - mPowerSaveWhitelistAllAppIds.put(mPowerSaveWhitelistUserApps.valueAt(i), true); + for (int i=0; i<userApps.size(); i++) { + outAppIds.put(userApps.valueAt(i), true); } - int size = mPowerSaveWhitelistAllAppIds.size(); + int size = outAppIds.size(); int[] appids = new int[size]; for (int i = 0; i < size; i++) { - appids[i] = mPowerSaveWhitelistAllAppIds.keyAt(i); + appids[i] = outAppIds.keyAt(i); } - mPowerSaveWhitelistAllAppIdArray = appids; + return appids; + } + + private void updateWhitelistAppIdsLocked() { + mPowerSaveWhitelistExceptIdleAppIdArray = buildAppIdArray(mPowerSaveWhitelistAppsExceptIdle, + mPowerSaveWhitelistUserApps, mPowerSaveWhitelistExceptIdleAppIds); + mPowerSaveWhitelistAllAppIdArray = buildAppIdArray(mPowerSaveWhitelistApps, + mPowerSaveWhitelistUserApps, mPowerSaveWhitelistAllAppIds); if (mLocalPowerManager != null) { if (DEBUG) { Slog.d(TAG, "Setting wakelock whitelist to " @@ -1320,6 +1449,9 @@ public class DeviceIdleController extends SystemService pw.println("Commands:"); pw.println(" step"); pw.println(" Immediately step to next state, without waiting for alarm."); + pw.println(" force-idle"); + pw.println(" Force directly into idle mode, regardless of other device state."); + pw.println(" Use \"step\" to get out."); pw.println(" disable"); pw.println(" Completely disable device idle mode."); pw.println(" enable"); @@ -1362,6 +1494,7 @@ public class DeviceIdleController extends SystemService synchronized (this) { long token = Binder.clearCallingIdentity(); try { + exitForceIdleLocked(); stepIdleStateLocked(); pw.print("Stepped to: "); pw.println(stateToString(mState)); } finally { @@ -1369,6 +1502,33 @@ public class DeviceIdleController extends SystemService } } return; + } else if ("force-idle".equals(arg)) { + synchronized (this) { + long token = Binder.clearCallingIdentity(); + try { + if (!mEnabled) { + pw.println("Unable to go idle; not enabled"); + return; + } + mForceIdle = true; + becomeInactiveIfAppropriateLocked(); + int curState = mState; + while (curState != STATE_IDLE) { + stepIdleStateLocked(); + if (curState == mState) { + pw.print("Unable to go idle; stopped at "); + pw.println(stateToString(mState)); + exitForceIdleLocked(); + return; + } + curState = mState; + } + pw.println("Now forced in to idle mode"); + } finally { + Binder.restoreCallingIdentity(token); + } + } + return; } else if ("disable".equals(arg)) { synchronized (this) { long token = Binder.clearCallingIdentity(); @@ -1387,6 +1547,7 @@ public class DeviceIdleController extends SystemService synchronized (this) { long token = Binder.clearCallingIdentity(); try { + exitForceIdleLocked(); if (!mEnabled) { mEnabled = true; becomeInactiveIfAppropriateLocked(); @@ -1431,6 +1592,12 @@ public class DeviceIdleController extends SystemService } } else { synchronized (this) { + for (int j=0; j<mPowerSaveWhitelistAppsExceptIdle.size(); j++) { + pw.print("system-excidle,"); + pw.print(mPowerSaveWhitelistAppsExceptIdle.keyAt(j)); + pw.print(","); + pw.println(mPowerSaveWhitelistAppsExceptIdle.valueAt(j)); + } for (int j=0; j<mPowerSaveWhitelistApps.size(); j++) { pw.print("system,"); pw.print(mPowerSaveWhitelistApps.keyAt(j)); @@ -1481,7 +1648,15 @@ public class DeviceIdleController extends SystemService synchronized (this) { mConstants.dump(pw); - int size = mPowerSaveWhitelistApps.size(); + int size = mPowerSaveWhitelistAppsExceptIdle.size(); + if (size > 0) { + pw.println(" Whitelist (except idle) system apps:"); + for (int i = 0; i < size; i++) { + pw.print(" "); + pw.println(mPowerSaveWhitelistAppsExceptIdle.keyAt(i)); + } + } + size = mPowerSaveWhitelistApps.size(); if (size > 0) { pw.println(" Whitelist system apps:"); for (int i = 0; i < size; i++) { @@ -1497,6 +1672,15 @@ public class DeviceIdleController extends SystemService pw.println(mPowerSaveWhitelistUserApps.keyAt(i)); } } + size = mPowerSaveWhitelistExceptIdleAppIds.size(); + if (size > 0) { + pw.println(" Whitelist (except idle) all app ids:"); + for (int i = 0; i < size; i++) { + pw.print(" "); + pw.print(mPowerSaveWhitelistExceptIdleAppIds.keyAt(i)); + pw.println(); + } + } size = mPowerSaveWhitelistAllAppIds.size(); if (size > 0) { pw.println(" Whitelist all app ids:"); @@ -1531,6 +1715,7 @@ public class DeviceIdleController extends SystemService } pw.print(" mEnabled="); pw.println(mEnabled); + pw.print(" mForceIdle="); pw.println(mForceIdle); pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor); pw.print(" mCurDisplay="); pw.println(mCurDisplay); pw.print(" mScreenOn="); pw.println(mScreenOn); diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java index ad5406c..cd61347 100644 --- a/services/core/java/com/android/server/SystemConfig.java +++ b/services/core/java/com/android/server/SystemConfig.java @@ -84,6 +84,11 @@ public class SystemConfig { final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>(); // These are the packages that are white-listed to be able to run in the + // background while in power save mode (but not whitelisted from device idle modes), + // as read from the configuration files. + final ArraySet<String> mAllowInPowerSaveExceptIdle = new ArraySet<>(); + + // These are the packages that are white-listed to be able to run in the // background while in power save mode, as read from the configuration files. final ArraySet<String> mAllowInPowerSave = new ArraySet<>(); @@ -123,6 +128,10 @@ public class SystemConfig { return mPermissions; } + public ArraySet<String> getAllowInPowerSaveExceptIdle() { + return mAllowInPowerSaveExceptIdle; + } + public ArraySet<String> getAllowInPowerSave() { return mAllowInPowerSave; } @@ -329,6 +338,17 @@ public class SystemConfig { XmlUtils.skipCurrentTag(parser); continue; + } else if ("allow-in-power-save-except-idle".equals(name) && !onlyFeatures) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<allow-in-power-save-except-idle> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mAllowInPowerSaveExceptIdle.add(pkgname); + } + XmlUtils.skipCurrentTag(parser); + continue; + } else if ("allow-in-power-save".equals(name) && !onlyFeatures) { String pkgname = parser.getAttributeValue(null, "package"); if (pkgname == null) { diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 83e8db0..aab6374 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -2604,7 +2604,8 @@ public class AccountManagerService // Prune the list down to just the requested type. visibleAccountTypes = new ArrayList<>(); visibleAccountTypes.add(type); - } // else aggregate all the visible accounts (it won't matter if the list is empty). + } // else aggregate all the visible accounts (it won't matter if the + // list is empty). long identityToken = clearCallingIdentity(); try { @@ -3788,8 +3789,15 @@ public class AccountManagerService private List<String> getTypesForCaller( int callingUid, int userId, boolean isOtherwisePermitted) { List<String> managedAccountTypes = new ArrayList<>(); + long identityToken = Binder.clearCallingIdentity(); + Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos; + try { + serviceInfos = mAuthenticatorCache.getAllServices(userId); + } finally { + Binder.restoreCallingIdentity(identityToken); + } for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo : - mAuthenticatorCache.getAllServices(userId)) { + serviceInfos) { final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid); if (isOtherwisePermitted || sigChk == PackageManager.SIGNATURE_MATCH) { managedAccountTypes.add(serviceInfo.type.type); diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java index 8e2ca18..92df851 100644 --- a/services/core/java/com/android/server/job/controllers/IdleController.java +++ b/services/core/java/com/android/server/job/controllers/IdleController.java @@ -108,6 +108,7 @@ public class IdleController extends StateController { private AlarmManager mAlarm; private PendingIntent mIdleTriggerIntent; boolean mIdle; + boolean mScreenOn; public IdlenessTracker() { mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); @@ -120,6 +121,7 @@ public class IdleController extends StateController { // At boot we presume that the user has just "interacted" with the // device in some meaningful way. mIdle = false; + mScreenOn = true; } public boolean isIdle() { @@ -149,12 +151,14 @@ public class IdleController extends StateController { if (action.equals(Intent.ACTION_SCREEN_ON) || action.equals(Intent.ACTION_DREAMING_STOPPED)) { - // possible transition to not-idle + if (DEBUG) { + Slog.v(TAG,"exiting idle : " + action); + } + mScreenOn = true; + //cancel the alarm + mAlarm.cancel(mIdleTriggerIntent); if (mIdle) { - if (DEBUG) { - Slog.v(TAG, "exiting idle : " + action); - } - mAlarm.cancel(mIdleTriggerIntent); + // possible transition to not-idle mIdle = false; reportNewIdleState(mIdle); } @@ -169,11 +173,12 @@ public class IdleController extends StateController { Slog.v(TAG, "Scheduling idle : " + action + " now:" + nowElapsed + " when=" + when); } + mScreenOn = false; mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, IDLE_WINDOW_SLOP, mIdleTriggerIntent); } else if (action.equals(ACTION_TRIGGER_IDLE)) { - // idle time starts now - if (!mIdle) { + // idle time starts now. Do not set mIdle if screen is on. + if (!mIdle && !mScreenOn) { if (DEBUG) { Slog.v(TAG, "Idle trigger fired @ " + SystemClock.elapsedRealtime()); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 46bda8c..c0d0d13 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -39,6 +39,7 @@ import static android.net.NetworkPolicy.WARNING_DISABLED; import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY; +import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW; import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY; import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE; @@ -46,7 +47,6 @@ import static android.net.NetworkPolicyManager.POLICY_NONE; import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; -import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; import static android.net.NetworkPolicyManager.computeLastCycleBoundary; import static android.net.NetworkPolicyManager.dumpPolicy; import static android.net.NetworkPolicyManager.dumpRules; @@ -284,6 +284,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** * UIDs that have been white-listed to always be able to have network access + * in power save mode, except device idle (doze) still applies. + * TODO: An int array might be sufficient + */ + private final SparseBooleanArray mPowerSaveWhitelistExceptIdleAppIds = new SparseBooleanArray(); + + /** + * UIDs that have been white-listed to always be able to have network access * in power save mode. * TODO: An int array might be sufficient */ @@ -302,9 +309,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** Foreground at UID granularity. */ final SparseIntArray mUidState = new SparseIntArray(); - /** The current maximum process state that we are considering to be foreground. */ - private int mCurForegroundState = ActivityManager.PROCESS_STATE_TOP; - private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<>(); @@ -365,7 +369,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { void updatePowerSaveWhitelistLocked() { try { - final int[] whitelist = mDeviceIdleController.getAppIdWhitelist(); + int[] whitelist = mDeviceIdleController.getAppIdWhitelistExceptIdle(); + mPowerSaveWhitelistExceptIdleAppIds.clear(); + if (whitelist != null) { + for (int uid : whitelist) { + mPowerSaveWhitelistExceptIdleAppIds.put(uid, true); + } + } + whitelist = mDeviceIdleController.getAppIdWhitelist(); mPowerSaveWhitelistAppIds.clear(); if (whitelist != null) { for (int uid : whitelist) { @@ -425,7 +436,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (mRestrictPower != enabled) { mRestrictPower = enabled; updateRulesForGlobalChangeLocked(true); - updateRulesForTempWhitelistChangeLocked(); } } } @@ -437,9 +447,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { readPolicyLocked(); if (mRestrictBackground || mRestrictPower || mDeviceIdleMode) { - updateRulesForGlobalChangeLocked(true); - updateRulesForTempWhitelistChangeLocked(); + updateRulesForGlobalChangeLocked(false); updateNotificationsLocked(); + } else { + // If we are not in any special mode, we just need to make sure the current + // app idle state is updated. + updateRulesForAppIdleLocked(); } } @@ -1907,7 +1920,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.print("Restrict background: "); fout.println(mRestrictBackground); fout.print("Restrict power: "); fout.println(mRestrictPower); fout.print("Device idle: "); fout.println(mDeviceIdleMode); - fout.print("Current foreground state: "); fout.println(mCurForegroundState); fout.println("Network policies:"); fout.increaseIndent(); for (int i = 0; i < mNetworkPolicy.size(); i++) { @@ -1931,6 +1943,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } fout.decreaseIndent(); + size = mPowerSaveWhitelistExceptIdleAppIds.size(); + if (size > 0) { + fout.println("Power save whitelist (except idle) app ids:"); + fout.increaseIndent(); + for (int i = 0; i < size; i++) { + fout.print("UID="); + fout.print(mPowerSaveWhitelistExceptIdleAppIds.keyAt(i)); + fout.print(": "); + fout.print(mPowerSaveWhitelistExceptIdleAppIds.valueAt(i)); + fout.println(); + } + fout.decreaseIndent(); + } + size = mPowerSaveWhitelistAppIds.size(); if (size > 0) { fout.println("Power save whitelist app ids:"); @@ -1960,7 +1986,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { int state = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); fout.print(" state="); fout.print(state); - fout.print(state <= mCurForegroundState ? " (fg)" : " (bg)"); + fout.print(state <= ActivityManager.PROCESS_STATE_TOP ? " (fg)" : " (bg)"); fout.print(" rules="); final int rulesIndex = mUidRules.indexOfKey(uid); @@ -1988,7 +2014,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { boolean isUidForegroundLocked(int uid) { // only really in foreground when screen is also on return mScreenOn && mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY) - <= mCurForegroundState; + <= ActivityManager.PROCESS_STATE_TOP; } /** @@ -2024,8 +2050,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } void updateRulesForUidStateChangeLocked(int uid, int oldUidState, int newUidState) { - final boolean oldForeground = oldUidState <= mCurForegroundState; - final boolean newForeground = newUidState <= mCurForegroundState; + final boolean oldForeground = oldUidState <= ActivityManager.PROCESS_STATE_TOP; + final boolean newForeground = newUidState <= ActivityManager.PROCESS_STATE_TOP; if (oldForeground != newForeground) { updateRulesForUidLocked(uid); } @@ -2049,7 +2075,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // only update rules for anyone with foreground activities final int size = mUidState.size(); for (int i = 0; i < size; i++) { - if (mUidState.valueAt(i) <= mCurForegroundState) { + if (mUidState.valueAt(i) <= ActivityManager.PROCESS_STATE_TOP) { final int uid = mUidState.keyAt(i); updateRulesForUidLocked(uid); } @@ -2069,9 +2095,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { for (int ui = users.size() - 1; ui >= 0; ui--) { UserInfo user = users.get(ui); for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) { - int appId = mPowerSaveTempWhitelistAppIds.keyAt(i); - int uid = UserHandle.getUid(user.id, appId); - uidRules.put(uid, FIREWALL_RULE_ALLOW); + if (mPowerSaveTempWhitelistAppIds.valueAt(i)) { + int appId = mPowerSaveTempWhitelistAppIds.keyAt(i); + int uid = UserHandle.getUid(user.id, appId); + uidRules.put(uid, FIREWALL_RULE_ALLOW); + } } for (int i = mPowerSaveWhitelistAppIds.size() - 1; i >= 0; i--) { int appId = mPowerSaveWhitelistAppIds.keyAt(i); @@ -2089,6 +2117,45 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { enableFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode); } + void updateRuleForDeviceIdleLocked(int uid) { + if (mDeviceIdleMode) { + int appId = UserHandle.getAppId(uid); + if (mPowerSaveTempWhitelistAppIds.get(appId) || mPowerSaveWhitelistAppIds.get(appId) + || isProcStateAllowedWhileIdle(mUidState.get(uid))) { + setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_ALLOW); + } else { + setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT); + } + } + } + + void updateRulesForAppIdleLocked() { + // Fully update the app idle firewall chain. + SparseIntArray uidRules = new SparseIntArray(); + final List<UserInfo> users = mUserManager.getUsers(); + for (int ui = users.size() - 1; ui >= 0; ui--) { + UserInfo user = users.get(ui); + int[] idleUids = mUsageStats.getIdleUidsForUser(user.id); + for (int uid : idleUids) { + if (!mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid), false)) { + uidRules.put(uid, FIREWALL_RULE_DENY); + } + } + } + setUidFirewallRules(FIREWALL_CHAIN_STANDBY, uidRules); + } + + void updateRuleForAppIdleLocked(int uid) { + if (!isUidValidForRules(uid)) return; + + int appId = UserHandle.getAppId(uid); + if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid)) { + setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DENY); + } else { + setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT); + } + } + void updateRulesForAppIdleParoleLocked() { boolean enableChain = !mUsageStats.isAppIdleParoleOn(); enableFirewallChainLocked(FIREWALL_CHAIN_STANDBY, enableChain); @@ -2101,14 +2168,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { void updateRulesForGlobalChangeLocked(boolean restrictedNetworksChanged) { final PackageManager pm = mContext.getPackageManager(); - // If we are in restrict power mode, we allow all important apps - // to have data access. Otherwise, we restrict data access to only - // the top apps. - mCurForegroundState = (!mRestrictBackground && mRestrictPower) - ? ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE - : ActivityManager.PROCESS_STATE_TOP; - updateRulesForDeviceIdleLocked(); + updateRulesForAppIdleLocked(); // update rules for all installed applications final List<UserInfo> users = mUserManager.getUsers(); @@ -2138,10 +2199,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { for (UserInfo user : users) { for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) { int appId = mPowerSaveTempWhitelistAppIds.keyAt(i); - boolean isAllow = mPowerSaveTempWhitelistAppIds.valueAt(i); int uid = UserHandle.getUid(user.id, appId); - updateRulesForUidLocked(uid); - setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, !isAllow); + updateRuleForAppIdleLocked(uid); + updateRuleForDeviceIdleLocked(uid); } } } @@ -2188,16 +2248,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE); final boolean uidForeground = isUidForegroundLocked(uid); - final boolean uidIdle = isUidIdle(uid); // derive active rules based on policy and active state int appId = UserHandle.getAppId(uid); int uidRules = RULE_ALLOW_ALL; - if (uidIdle && !mPowerSaveWhitelistAppIds.get(appId) - && !mPowerSaveTempWhitelistAppIds.get(appId)) { - uidRules = RULE_REJECT_ALL; - } else if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) { + if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) { // uid in background, and policy says to block metered data uidRules = RULE_REJECT_METERED; } else if (mRestrictBackground) { @@ -2206,7 +2262,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { uidRules = RULE_REJECT_METERED; } } else if (mRestrictPower) { - final boolean whitelisted = mPowerSaveWhitelistAppIds.get(appId) + final boolean whitelisted = mPowerSaveWhitelistExceptIdleAppIds.get(appId) || mPowerSaveTempWhitelistAppIds.get(appId); if (!whitelisted && !uidForeground && (uidPolicy & POLICY_ALLOW_BACKGROUND_BATTERY_SAVE) == 0) { @@ -2232,13 +2288,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { setUidNetworkRules(uid, rejectMetered); } - // Update firewall rules if necessary - final boolean oldFirewallReject = (oldRules & RULE_REJECT_ALL) != 0; - final boolean firewallReject = (uidRules & RULE_REJECT_ALL) != 0; - if (oldFirewallReject != firewallReject) { - setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, firewallReject); - } - // dispatch changed rule to existing listeners if (oldRules != uidRules) { mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget(); @@ -2260,7 +2309,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { try { int uid = mContext.getPackageManager().getPackageUid(packageName, userId); synchronized (mRulesLock) { - updateRulesForUidLocked(uid); + updateRuleForAppIdleLocked(uid); } } catch (NameNotFoundException nnfe) { } @@ -2422,10 +2471,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** * Add or remove a uid to the firewall blacklist for all network ifaces. */ - private void setUidFirewallRule(int chain, int uid, boolean rejectOnAll) { + private void setUidFirewallRule(int chain, int uid, int rule) { try { - mNetworkManager.setFirewallUidRule(chain, uid, - rejectOnAll ? FIREWALL_RULE_DENY : FIREWALL_RULE_ALLOW); + mNetworkManager.setFirewallUidRule(chain, uid, rule); } catch (IllegalStateException e) { Log.wtf(TAG, "problem setting firewall uid rules", e); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ce40c28..6a4ae3d 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -13037,7 +13037,8 @@ public class PackageManagerService extends IPackageManager.Stub { // they have set the special DELETE_SYSTEM_APP which requests different // semantics than normal for uninstalling system apps. if (DEBUG_REMOVE) Slog.d(TAG, "Only deleting for single user"); - ps.setUserState(user.getIdentifier(), + final int userId = user.getIdentifier(); + ps.setUserState(userId, COMPONENT_ENABLED_STATE_DEFAULT, false, //installed true, //stopped @@ -13045,7 +13046,7 @@ public class PackageManagerService extends IPackageManager.Stub { false, //hidden null, null, null, false, // blockUninstall - INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0); + ps.readUserState(userId).domainVerificationStatus, 0); if (!isSystemApp(ps)) { if (ps.isAnyInstalled(sUserManager.getUserIds())) { // Other user still have this package installed, so all diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 82ffa47..00d0fe1 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -4150,6 +4150,9 @@ final class Settings { if ((perm.info.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) { pw.print(", COSTS_MONEY"); } + if ((perm.info.flags&PermissionInfo.FLAG_HIDDEN) != 0) { + pw.print(", COSTS_HIDDEN"); + } if ((perm.info.flags&PermissionInfo.FLAG_INSTALLED) != 0) { pw.print(", INSTALLED"); } @@ -4306,7 +4309,8 @@ final class Settings { pw.println(PermissionInfo.protectionToString(p.protectionLevel)); if (p.perm != null) { pw.print(" perm="); pw.println(p.perm); - if (p.perm.info.flags != PermissionInfo.FLAG_INSTALLED) { + if ((p.perm.info.flags & PermissionInfo.FLAG_INSTALLED) == 0 + || (p.perm.info.flags & PermissionInfo.FLAG_HIDDEN) != 0) { pw.print(" flags=0x"); pw.println(Integer.toHexString(p.perm.info.flags)); } } diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index a433ec4..85f0665 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -35,6 +35,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; @@ -65,6 +66,7 @@ import android.util.AtomicFile; import android.util.KeyValueListParser; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseIntArray; import android.util.TimeUtils; import android.view.Display; @@ -799,7 +801,10 @@ public class UsageStatsService extends SystemService implements } if (packageName.equals("android")) return false; try { - if (mDeviceIdleController.isPowerSaveWhitelistApp(packageName)) { + // We allow all whitelisted apps, including those that don't want to be whitelisted + // for idle mode, because app idle (aka app standby) is really not as big an issue + // for controlling who participates vs. doze mode. + if (mDeviceIdleController.isPowerSaveWhitelistExceptIdleApp(packageName)) { return false; } } catch (RemoteException re) { @@ -825,6 +830,72 @@ public class UsageStatsService extends SystemService implements return isAppIdleUnfiltered(packageName, userService, timeNow, screenOnTime); } + int[] getIdleUidsForUser(int userId) { + if (!mAppIdleEnabled) { + return new int[0]; + } + + final long timeNow; + final UserUsageStatsService userService; + final long screenOnTime; + synchronized (mLock) { + timeNow = checkAndGetTimeLocked(); + userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow); + screenOnTime = getScreenOnTimeLocked(timeNow); + } + + List<ApplicationInfo> apps; + try { + ParceledListSlice<ApplicationInfo> slice + = AppGlobals.getPackageManager().getInstalledApplications(0, userId); + apps = slice.getList(); + } catch (RemoteException e) { + return new int[0]; + } + + // State of each uid. Key is the uid. Value lower 16 bits is the number of apps + // associated with that uid, upper 16 bits is the number of those apps that is idle. + SparseIntArray uidStates = new SparseIntArray(); + + // Now resolve all app state. Iterating over all apps, keeping track of how many + // we find for each uid and how many of those are idle. + for (int i = apps.size()-1; i >= 0; i--) { + ApplicationInfo ai = apps.get(i); + + // Check whether this app is idle. + boolean idle = isAppIdleFiltered(ai.packageName, userId, userService, timeNow, + screenOnTime); + + int index = uidStates.indexOfKey(ai.uid); + if (index < 0) { + uidStates.put(ai.uid, 1 + (idle ? 1<<16 : 0)); + } else { + int value = uidStates.valueAt(index); + uidStates.setValueAt(index, value + 1 + (idle ? 1<<16 : 0)); + } + } + + int numIdle = 0; + for (int i = uidStates.size() - 1; i >= 0; i--) { + int value = uidStates.valueAt(i); + if ((value&0x7fff) == (value>>16)) { + numIdle++; + } + } + + int[] res = new int[numIdle]; + numIdle = 0; + for (int i = uidStates.size() - 1; i >= 0; i--) { + int value = uidStates.valueAt(i); + if ((value&0x7fff) == (value>>16)) { + res[numIdle] = uidStates.keyAt(i); + numIdle++; + } + } + + return res; + } + void setAppIdle(String packageName, boolean idle, int userId) { if (packageName == null) return; @@ -1284,6 +1355,11 @@ public class UsageStatsService extends SystemService implements } @Override + public int[] getIdleUidsForUser(int userId) { + return UsageStatsService.this.getIdleUidsForUser(userId); + } + + @Override public boolean isAppIdleParoleOn() { return mAppIdleParoled; } diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml index 73cb432..7b9c9f1 100644 --- a/tests/ActivityTests/AndroidManifest.xml +++ b/tests/ActivityTests/AndroidManifest.xml @@ -24,6 +24,7 @@ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <uses-permission android:name="android.permission.MANAGE_USERS" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> + <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> <uses-sdk android:targetSdkVersion="22" /> <application android:label="ActivityTest"> <activity android:name="ActivityTestMain"> diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java index 2f0bf39..5fbfe8a 100644 --- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java +++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java @@ -465,9 +465,12 @@ public class ActivityTestMain extends Activity { menu.add("Ignore battery optimizations").setOnMenuItemClickListener( new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { - Intent intent = new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS); + Intent intent; if (!mPower.isIgnoringBatteryOptimizations(getPackageName())) { + intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); intent.setData(Uri.fromParts("package", getPackageName(), null)); + } else { + intent = new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS); } startActivity(intent); return true; |
