From 3b16cf4f47142a845bf0ede54ef8ef956506c6c3 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 1 Jul 2015 15:05:04 -0700 Subject: [PATCH] Device idle fixes: issue #22209630 and issue #22225665 Issue #22209630: Only allow whitelisted apps to put apps on the temp whitelist We now check whether the calling app is a system uid or in the whitelist and, if not, throw an exception. Issue #22225665: Alarm still goes off in idle mode (doze) Fix a bug where we were not clearing the calling identity when coming through the dump command to the service, and as a result when we would eventually call out to the alarm manager it wouldn't do what we want. This was only broken when being controlled by the shell. Also adjust the network policy manager service's handling of device idle transitions to only toggle the device idle state, which gets rid of the long delay we have coming out of idle mode. And add in a bit of logging around going in/out of idle mode to try to understand where things may be slow in the future. Change-Id: I4a41f790e9b0bb31330314b94111557d479f2ba5 --- core/java/android/os/UserHandle.java | 11 ++ .../android/server/DeviceIdleController.java | 172 +++++++++++------- .../com/android/server/EventLogTags.logtags | 10 +- .../net/NetworkPolicyManagerService.java | 8 +- .../server/power/PowerManagerService.java | 5 + 5 files changed, 141 insertions(+), 65 deletions(-) diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java index 511bd5f4f6c72..20bcf62a42e64 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -216,6 +216,17 @@ public final class UserHandle implements Parcelable { } } + /** + * Generate a text representation of the uid, breaking out its individual + * components -- user, app, isolated, etc. + * @hide + */ + public static String formatUid(int uid) { + StringBuilder sb = new StringBuilder(); + formatUid(sb, uid); + return sb.toString(); + } + /** * Generate a text representation of the uid, breaking out its individual * components -- user, app, isolated, etc. diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index dc203ffaee33c..c8dc565d51284 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -157,16 +157,21 @@ public class DeviceIdleController extends SystemService */ private final ArrayMap mPowerSaveWhitelistUserApps = new ArrayMap<>(); + /** + * 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. */ - private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray(); + private final SparseBooleanArray mPowerSaveWhitelistAllAppIds = new SparseBooleanArray(); /** * Current app IDs that are in the complete power save white list. This array can * be shared with others because it will not be modified once set. */ - private int[] mPowerSaveWhitelistAppIdArray = new int[0]; + private int[] mPowerSaveWhitelistAllAppIdArray = new int[0]; /** * List of end times for UIDs that are temporarily marked as being allowed to access @@ -478,6 +483,7 @@ public class DeviceIdleController extends SystemService handleWriteConfigFile(); } break; case MSG_REPORT_IDLE_ON: { + EventLogTags.writeDeviceIdleOnStart(); mLocalPowerManager.setDeviceIdleMode(true); try { mNetworkPolicyManager.setDeviceIdleMode(true); @@ -485,8 +491,10 @@ public class DeviceIdleController extends SystemService } catch (RemoteException e) { } getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL); + EventLogTags.writeDeviceIdleOnComplete(); } break; case MSG_REPORT_IDLE_OFF: { + EventLogTags.writeDeviceIdleOffStart("unknown"); mLocalPowerManager.setDeviceIdleMode(false); try { mNetworkPolicyManager.setDeviceIdleMode(false); @@ -494,11 +502,14 @@ public class DeviceIdleController extends SystemService } catch (RemoteException e) { } getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL); + EventLogTags.writeDeviceIdleOffComplete(); } break; case MSG_REPORT_ACTIVE: { String activeReason = (String)msg.obj; int activeUid = msg.arg1; boolean needBroadcast = msg.arg2 != 0; + EventLogTags.writeDeviceIdleOffStart( + activeReason != null ? activeReason : "unknown"); mLocalPowerManager.setDeviceIdleMode(false); try { mNetworkPolicyManager.setDeviceIdleMode(false); @@ -508,6 +519,7 @@ public class DeviceIdleController extends SystemService if (needBroadcast) { getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL); } + EventLogTags.writeDeviceIdleOffComplete(); } break; case MSG_TEMP_APP_WHITELIST_TIMEOUT: { int uid = msg.arg1; @@ -557,17 +569,18 @@ public class DeviceIdleController extends SystemService getContext().enforceCallingPermission( Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, "No permission to change device idle whitelist"); + final int callingUid = Binder.getCallingUid(); userId = ActivityManagerNative.getDefault().handleIncomingUser( Binder.getCallingPid(), - Binder.getCallingUid(), + callingUid, userId, /*allowAll=*/ false, /*requireFull=*/ false, "addPowerSaveTempWhitelistApp", null); final long token = Binder.clearCallingIdentity(); try { - DeviceIdleController.this.addPowerSaveTempWhitelistAppInternal(packageName, - duration, userId); + DeviceIdleController.this.addPowerSaveTempWhitelistAppInternal(callingUid, + packageName, duration, userId); } finally { Binder.restoreCallingIdentity(token); } @@ -586,7 +599,7 @@ public class DeviceIdleController extends SystemService public final class LocalService { public void addPowerSaveTempWhitelistAppDirect(int appId, long duration) { - DeviceIdleController.this.addPowerSaveTempWhitelistAppDirectInternal(appId, duration); + addPowerSaveTempWhitelistAppDirectInternal(0, appId, duration); } } @@ -614,8 +627,9 @@ public class DeviceIdleController extends SystemService try { ApplicationInfo ai = pm.getApplicationInfo(pkg, 0); if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { - mPowerSaveWhitelistApps.put(ai.packageName, - UserHandle.getAppId(ai.uid)); + int appid = UserHandle.getAppId(ai.uid); + mPowerSaveWhitelistApps.put(ai.packageName, appid); + mPowerSaveWhitelistSystemAppIds.put(appid, true); } } catch (PackageManager.NameNotFoundException e) { } @@ -667,14 +681,15 @@ public class DeviceIdleController extends SystemService mSensingAlarmIntent = PendingIntent.getBroadcast(getContext(), 0, intentSensing, 0); mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); - mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY + | Intent.FLAG_RECEIVER_FOREGROUND); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.addAction(ACTION_STEP_IDLE_STATE); getContext().registerReceiver(mReceiver, filter); - mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAppIdArray); + mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray); mDisplayManager.registerDisplayListener(mDisplayListener, null); updateDisplayLocked(); @@ -747,7 +762,7 @@ public class DeviceIdleController extends SystemService public int[] getAppIdWhitelistInternal() { synchronized (this) { - return mPowerSaveWhitelistAppIdArray; + return mPowerSaveWhitelistAllAppIdArray; } } @@ -761,12 +776,12 @@ public class DeviceIdleController extends SystemService * Adds an app to the temporary whitelist and resets the endTime for granting the * app an exemption to access network and acquire wakelocks. */ - public void addPowerSaveTempWhitelistAppInternal(String packageName, long duration, - int userId) { + public void addPowerSaveTempWhitelistAppInternal(int callingUid, String packageName, + long duration, int userId) { try { int uid = getContext().getPackageManager().getPackageUid(packageName, userId); int appId = UserHandle.getAppId(uid); - addPowerSaveTempWhitelistAppDirectInternal(appId, duration); + addPowerSaveTempWhitelistAppDirectInternal(callingUid, appId, duration); } catch (NameNotFoundException e) { } } @@ -775,9 +790,17 @@ public class DeviceIdleController extends SystemService * Adds an app to the temporary whitelist and resets the endTime for granting the * app an exemption to access network and acquire wakelocks. */ - public void addPowerSaveTempWhitelistAppDirectInternal(int appId, long duration) { + public void addPowerSaveTempWhitelistAppDirectInternal(int callingUid, int appId, + long duration) { final long timeNow = SystemClock.elapsedRealtime(); synchronized (this) { + int callingAppId = UserHandle.getAppId(callingUid); + if (callingAppId >= Process.FIRST_APPLICATION_UID) { + if (!mPowerSaveWhitelistSystemAppIds.get(callingAppId)) { + throw new SecurityException("Calling app " + UserHandle.formatUid(callingUid) + + " is not on whitelist"); + } + } duration = Math.min(duration, mConstants.MAX_TEMP_APP_WHITELIST_DURATION); long currentEndTime = mTempWhitelistAppIdEndTimes.get(appId); // Set the new end time @@ -1026,25 +1049,25 @@ public class DeviceIdleController extends SystemService } private void updateWhitelistAppIdsLocked() { - mPowerSaveWhitelistAppIds.clear(); + mPowerSaveWhitelistAllAppIds.clear(); for (int i=0; i= args.length) { - pw.println("At least one package name must be specified"); - return; - } - while (i < args.length) { - arg = args[i]; + long token = Binder.clearCallingIdentity(); + try { i++; - addPowerSaveTempWhitelistAppInternal(arg, 10000L, userId); + if (i >= args.length) { + pw.println("At least one package name must be specified"); + return; + } + while (i < args.length) { + arg = args[i]; + i++; + addPowerSaveTempWhitelistAppInternal(0, arg, 10000L, userId); + } + } finally { + Binder.restoreCallingIdentity(token); } } else if (arg.length() > 0 && arg.charAt(0) == '-'){ pw.println("Unknown option: " + arg); @@ -1337,12 +1385,12 @@ public class DeviceIdleController extends SystemService pw.println(mPowerSaveWhitelistUserApps.keyAt(i)); } } - size = mPowerSaveWhitelistAppIds.size(); + size = mPowerSaveWhitelistAllAppIds.size(); if (size > 0) { - pw.println(" Whitelist app ids:"); + pw.println(" Whitelist all app ids:"); for (int i = 0; i < size; i++) { pw.print(" "); - pw.print(mPowerSaveWhitelistAppIds.keyAt(i)); + pw.print(mPowerSaveWhitelistAllAppIds.keyAt(i)); pw.println(); } } diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags index 43b640b434ce5..2842f858012d5 100644 --- a/services/core/java/com/android/server/EventLogTags.logtags +++ b/services/core/java/com/android/server/EventLogTags.logtags @@ -183,6 +183,12 @@ option java_package com.android.server 34000 device_idle (state|1|5), (reason|3) 34001 device_idle_step 34002 device_idle_wake_from_idle (is_idle|1|5), (reason|3) +34003 device_idle_on_start +34004 device_idle_on_phase (what|3) +34005 device_idle_on_complete +34006 device_idle_off_start (reason|3) +34007 device_idle_off_phase (what|3) +34008 device_idle_off_complete # --------------------------- # DisplayManagerService.java @@ -224,8 +230,8 @@ option java_package com.android.server # --------------------------- # IdleMaintenanceService.java # --------------------------- -2753 idle_maintenance_window_start (time|2|3), (lastUserActivity|2|3), (batteryLevel|1|6), (batteryCharging|1|5) -2754 idle_maintenance_window_finish (time|2|3), (lastUserActivity|2|3), (batteryLevel|1|6), (batteryCharging|1|5) +51500 idle_maintenance_window_start (time|2|3), (lastUserActivity|2|3), (batteryLevel|1|6), (batteryCharging|1|5) +51501 idle_maintenance_window_finish (time|2|3), (lastUserActivity|2|3), (batteryLevel|1|6), (batteryCharging|1|5) # --------------------------- # MountService.java diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index d4b725656e082..f618c3eb7cf86 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -146,6 +146,7 @@ import android.util.SparseIntArray; import android.util.TrustedTime; import android.util.Xml; +import com.android.server.EventLogTags; import libcore.io.IoUtils; import com.android.internal.R; @@ -1764,7 +1765,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (mDeviceIdleMode != enabled) { mDeviceIdleMode = enabled; if (mSystemReady) { - updateRulesForGlobalChangeLocked(true); + updateRulesForDeviceIdleLocked(); + } + if (enabled) { + EventLogTags.writeDeviceIdleOnPhase("net"); + } else { + EventLogTags.writeDeviceIdleOffPhase("net"); } } } diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 5a0bee90fad6f..3f59755616400 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -2311,6 +2311,11 @@ public final class PowerManagerService extends SystemService if (mDeviceIdleMode != enabled) { mDeviceIdleMode = enabled; updateWakeLockDisabledStatesLocked(); + if (enabled) { + EventLogTags.writeDeviceIdleOnPhase("power"); + } else { + EventLogTags.writeDeviceIdleOffPhase("power"); + } } } }