Loading core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -33451,6 +33451,7 @@ package android.os { field public static final int LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF = 1; // 0x1 field public static final int LOCATION_MODE_NO_CHANGE = 0; // 0x0 field public static final int LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF = 4; // 0x4 field public static final int LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL = 4; // 0x4 field public static final int LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST = 2; // 0x2 field public static final int LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION = 1; // 0x1 field public static final String LOW_POWER_STANDBY_FEATURE_WAKE_ON_LAN = "com.android.lowpowerstandby.WAKE_ON_LAN"; core/java/android/os/PowerManager.java +14 −0 Original line number Diff line number Diff line Loading @@ -3057,6 +3057,7 @@ public final class PowerManager { @IntDef(prefix = { "LOW_POWER_STANDBY_ALLOWED_REASON_" }, flag = true, value = { LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION, LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST, LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL, }) @Retention(RetentionPolicy.SOURCE) public @interface LowPowerStandbyAllowedReason { Loading @@ -3076,6 +3077,15 @@ public final class PowerManager { */ public static final int LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST = 1 << 1; /** * Exempts apps with ongoing calls. * * <p>This includes apps with foreground services of type "phoneCall". * * @see #isAllowedInLowPowerStandby(int) */ public static final int LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL = 1 << 2; /** @hide */ public static String lowPowerStandbyAllowedReasonsToString( @LowPowerStandbyAllowedReason int allowedReasons) { Loading @@ -3088,6 +3098,10 @@ public final class PowerManager { allowedStrings.add("ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST"); allowedReasons &= ~LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST; } if ((allowedReasons & LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL) != 0) { allowedStrings.add("ALLOWED_REASON_ONGOING_CALL"); allowedReasons &= ~LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL; } if (allowedReasons != 0) { allowedStrings.add(String.valueOf(allowedReasons)); } Loading services/core/java/com/android/server/power/LowPowerStandbyController.java +101 −3 Original line number Diff line number Diff line Loading @@ -16,19 +16,25 @@ package com.android.server.power; import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL; import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST; import static android.os.PowerManager.lowPowerStandbyAllowedReasonsToString; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AlarmManager; import android.app.IActivityManager; import android.app.IForegroundServiceObserver; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.database.ContentObserver; import android.net.Uri; Loading @@ -53,6 +59,7 @@ import android.util.ArraySet; import android.util.AtomicFile; import android.util.IndentingPrintWriter; import android.util.Slog; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.Xml; import android.util.proto.ProtoOutputStream; Loading Loading @@ -82,6 +89,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.Supplier; /** * Controls Low Power Standby state. Loading Loading @@ -115,7 +123,8 @@ public class LowPowerStandbyController { private static final int MSG_NOTIFY_ACTIVE_CHANGED = 1; private static final int MSG_NOTIFY_ALLOWLIST_CHANGED = 2; private static final int MSG_NOTIFY_POLICY_CHANGED = 3; private static final int MSG_NOTIFY_STANDBY_PORTS_CHANGED = 4; private static final int MSG_FOREGROUND_SERVICE_STATE_CHANGED = 4; private static final int MSG_NOTIFY_STANDBY_PORTS_CHANGED = 5; private static final String TAG_ROOT = "low-power-standby-policy"; private static final String TAG_IDENTIFIER = "identifier"; Loading @@ -127,6 +136,7 @@ public class LowPowerStandbyController { private final Handler mHandler; private final SettingsObserver mSettingsObserver; private final DeviceConfigWrapper mDeviceConfig; private final Supplier<IActivityManager> mActivityManager; private final File mPolicyFile; private final Object mLock = new Object(); Loading Loading @@ -160,6 +170,7 @@ public class LowPowerStandbyController { }; private final TempAllowlistChangeListener mTempAllowlistChangeListener = new TempAllowlistChangeListener(); private final PhoneCallServiceTracker mPhoneCallServiceTracker = new PhoneCallServiceTracker(); private final BroadcastReceiver mPackageBroadcastReceiver = new BroadcastReceiver() { @Override Loading Loading @@ -243,6 +254,7 @@ public class LowPowerStandbyController { private AlarmManager mAlarmManager; @GuardedBy("mLock") private PowerManager mPowerManager; private ActivityManagerInternal mActivityManagerInternal; @GuardedBy("mLock") private boolean mSupportedConfig; @GuardedBy("mLock") Loading Loading @@ -314,18 +326,20 @@ public class LowPowerStandbyController { public LowPowerStandbyController(Context context, Looper looper) { this(context, looper, SystemClock::elapsedRealtime, new DeviceConfigWrapper(), new DeviceConfigWrapper(), () -> ActivityManager.getService(), new File(Environment.getDataSystemDirectory(), "low_power_standby_policy.xml")); } @VisibleForTesting LowPowerStandbyController(Context context, Looper looper, Clock clock, DeviceConfigWrapper deviceConfig, File policyFile) { DeviceConfigWrapper deviceConfig, Supplier<IActivityManager> activityManager, File policyFile) { mContext = context; mHandler = new LowPowerStandbyHandler(looper); mClock = clock; mSettingsObserver = new SettingsObserver(mHandler); mDeviceConfig = deviceConfig; mActivityManager = activityManager; mPolicyFile = policyFile; } Loading @@ -343,6 +357,7 @@ public class LowPowerStandbyController { mAlarmManager = mContext.getSystemService(AlarmManager.class); mPowerManager = mContext.getSystemService(PowerManager.class); mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mStandbyTimeoutConfig = resources.getInteger( R.integer.config_lowPowerStandbyNonInteractiveTimeout); Loading Loading @@ -707,6 +722,8 @@ public class LowPowerStandbyController { PowerAllowlistInternal pai = LocalServices.getService(PowerAllowlistInternal.class); pai.registerTempAllowlistChangeListener(mTempAllowlistChangeListener); mPhoneCallServiceTracker.register(); } private void unregisterListeners() { Loading Loading @@ -1142,6 +1159,10 @@ public class LowPowerStandbyController { case MSG_NOTIFY_POLICY_CHANGED: notifyPolicyChanged((LowPowerStandbyPolicy) msg.obj); break; case MSG_FOREGROUND_SERVICE_STATE_CHANGED: final int uid = msg.arg1; mPhoneCallServiceTracker.foregroundServiceStateChanged(uid); break; case MSG_NOTIFY_STANDBY_PORTS_CHANGED: notifyStandbyPortsChanged(); break; Loading Loading @@ -1406,4 +1427,81 @@ public class LowPowerStandbyController { LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST); } } final class PhoneCallServiceTracker extends IForegroundServiceObserver.Stub { private boolean mRegistered = false; private final SparseBooleanArray mUidsWithPhoneCallService = new SparseBooleanArray(); public void register() { if (mRegistered) { return; } try { mActivityManager.get().registerForegroundServiceObserver(this); mRegistered = true; } catch (RemoteException e) { // call within system server } } @Override public void onForegroundStateChanged(IBinder serviceToken, String packageName, int userId, boolean isForeground) { try { final long now = mClock.elapsedRealtime(); final int uid = mContext.getPackageManager() .getPackageUidAsUser(packageName, userId); final Message message = mHandler.obtainMessage(MSG_FOREGROUND_SERVICE_STATE_CHANGED, uid, 0); mHandler.sendMessageAtTime(message, now); } catch (PackageManager.NameNotFoundException e) { if (DEBUG) { Slog.d(TAG, "onForegroundStateChanged: Unknown package: " + packageName + ", userId=" + userId); } } } public void foregroundServiceStateChanged(int uid) { if (DEBUG) { Slog.d(TAG, "foregroundServiceStateChanged: uid=" + uid); } final boolean hadPhoneCallService = mUidsWithPhoneCallService.get(uid); final boolean hasPhoneCallService = mActivityManagerInternal.hasRunningForegroundService(uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL); if (DEBUG) { Slog.d(TAG, "uid=" + uid + ", hasPhoneCallService=" + hasPhoneCallService + ", hadPhoneCallService=" + hadPhoneCallService); } if (hasPhoneCallService == hadPhoneCallService) { return; } if (hasPhoneCallService) { mUidsWithPhoneCallService.append(uid, true); uidStartedPhoneCallService(uid); } else { mUidsWithPhoneCallService.delete(uid); uidStoppedPhoneCallService(uid); } } private void uidStartedPhoneCallService(int uid) { if (DEBUG) { Slog.d(TAG, "FGS of type phoneCall started: uid=" + uid); } addToAllowlistInternal(uid, LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL); } private void uidStoppedPhoneCallService(int uid) { if (DEBUG) { Slog.d(TAG, "FGSs of type phoneCall stopped: uid=" + uid); } removeFromAllowlistInternal(uid, LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL); } } } services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java +55 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.power; import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL; import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST; import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION; import static android.os.PowerManager.LOW_POWER_STANDBY_FEATURE_WAKE_ON_LAN; Loading Loading @@ -44,10 +45,14 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.app.ActivityManagerInternal; import android.app.AlarmManager; import android.app.IActivityManager; import android.app.IForegroundServiceObserver; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.net.Uri; import android.os.Binder; Loading Loading @@ -118,6 +123,8 @@ public class LowPowerStandbyControllerTest { @Mock private DeviceConfigWrapper mDeviceConfigWrapperMock; @Mock private IActivityManager mIActivityManagerMock; @Mock private AlarmManager mAlarmManagerMock; @Mock private PackageManager mPackageManagerMock; Loading @@ -131,6 +138,8 @@ public class LowPowerStandbyControllerTest { private NetworkPolicyManagerInternal mNetworkPolicyManagerInternalMock; @Mock private PowerAllowlistInternal mPowerAllowlistInternalMock; @Mock private ActivityManagerInternal mActivityManagerInternalMock; @Before public void setUp() throws Exception { Loading @@ -145,6 +154,7 @@ public class LowPowerStandbyControllerTest { addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock); addLocalServiceMock(NetworkPolicyManagerInternal.class, mNetworkPolicyManagerInternalMock); addLocalServiceMock(PowerAllowlistInternal.class, mPowerAllowlistInternalMock); addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock); when(mIPowerManagerMock.isInteractive()).thenReturn(true); Loading @@ -171,13 +181,18 @@ public class LowPowerStandbyControllerTest { UserHandle.of(USER_ID_1), UserHandle.of(USER_ID_2))); when(mPackageManagerMock.getPackageUid(eq(TEST_PKG1), any())).thenReturn(TEST_PKG1_APP_ID); when(mPackageManagerMock.getPackageUid(eq(TEST_PKG2), any())).thenReturn(TEST_PKG2_APP_ID); when(mPackageManagerMock.getPackageUidAsUser(eq(TEST_PKG1), eq(USER_ID_1))) .thenReturn(TEST_PKG1_APP_ID); when(mPackageManagerMock.getPackageUidAsUser(eq(TEST_PKG2), eq(USER_ID_1))) .thenReturn(TEST_PKG2_APP_ID); mClock = new OffsettableClock.Stopped(); mTestLooper = new TestLooper(mClock::now); mTestPolicyFile = new File(mContextSpy.getCacheDir(), "lps_policy.xml"); mController = new LowPowerStandbyController(mContextSpy, mTestLooper.getLooper(), () -> mClock.now(), mDeviceConfigWrapperMock, mTestPolicyFile); () -> mClock.now(), mDeviceConfigWrapperMock, () -> mIActivityManagerMock, mTestPolicyFile); } @After Loading @@ -186,6 +201,8 @@ public class LowPowerStandbyControllerTest { LocalServices.removeServiceForTest(LowPowerStandbyControllerInternal.class); LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class); LocalServices.removeServiceForTest(PowerAllowlistInternal.class); LocalServices.removeServiceForTest(ActivityManagerInternal.class); mTestPolicyFile.delete(); } Loading Loading @@ -713,6 +730,43 @@ public class LowPowerStandbyControllerTest { verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[0]); } @Test public void testAllowReason_ongoingPhoneCallService() throws Exception { mController.systemReady(); mController.setEnabled(true); mController.setPolicy(policyWithAllowedReasons( LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL)); mTestLooper.dispatchAll(); ArgumentCaptor<IForegroundServiceObserver> fgsObserverCapt = ArgumentCaptor.forClass(IForegroundServiceObserver.class); verify(mIActivityManagerMock).registerForegroundServiceObserver(fgsObserverCapt.capture()); IForegroundServiceObserver fgsObserver = fgsObserverCapt.getValue(); when(mActivityManagerInternalMock.hasRunningForegroundService(eq(TEST_PKG1_APP_ID), eq(ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL))).thenReturn(true); fgsObserver.onForegroundStateChanged(null, TEST_PKG1, USER_ID_1, true); mTestLooper.dispatchAll(); verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{TEST_PKG1_APP_ID}); when(mActivityManagerInternalMock.hasRunningForegroundService(eq(TEST_PKG2_APP_ID), eq(ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL))).thenReturn(true); fgsObserver.onForegroundStateChanged(null, TEST_PKG2, USER_ID_1, true); mTestLooper.dispatchAll(); verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist( new int[]{TEST_PKG1_APP_ID, TEST_PKG2_APP_ID}); when(mActivityManagerInternalMock.hasRunningForegroundService(eq(TEST_PKG1_APP_ID), eq(ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL))).thenReturn(false); fgsObserver.onForegroundStateChanged(null, TEST_PKG1, USER_ID_1, false); mTestLooper.dispatchAll(); verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{TEST_PKG2_APP_ID}); mController.setPolicy(EMPTY_POLICY); mTestLooper.dispatchAll(); verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[0]); } @Test public void testStandbyPorts_broadcastChangedIfPackageIsExempt() throws Exception { mController.systemReady(); Loading Loading
core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -33451,6 +33451,7 @@ package android.os { field public static final int LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF = 1; // 0x1 field public static final int LOCATION_MODE_NO_CHANGE = 0; // 0x0 field public static final int LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF = 4; // 0x4 field public static final int LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL = 4; // 0x4 field public static final int LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST = 2; // 0x2 field public static final int LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION = 1; // 0x1 field public static final String LOW_POWER_STANDBY_FEATURE_WAKE_ON_LAN = "com.android.lowpowerstandby.WAKE_ON_LAN";
core/java/android/os/PowerManager.java +14 −0 Original line number Diff line number Diff line Loading @@ -3057,6 +3057,7 @@ public final class PowerManager { @IntDef(prefix = { "LOW_POWER_STANDBY_ALLOWED_REASON_" }, flag = true, value = { LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION, LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST, LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL, }) @Retention(RetentionPolicy.SOURCE) public @interface LowPowerStandbyAllowedReason { Loading @@ -3076,6 +3077,15 @@ public final class PowerManager { */ public static final int LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST = 1 << 1; /** * Exempts apps with ongoing calls. * * <p>This includes apps with foreground services of type "phoneCall". * * @see #isAllowedInLowPowerStandby(int) */ public static final int LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL = 1 << 2; /** @hide */ public static String lowPowerStandbyAllowedReasonsToString( @LowPowerStandbyAllowedReason int allowedReasons) { Loading @@ -3088,6 +3098,10 @@ public final class PowerManager { allowedStrings.add("ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST"); allowedReasons &= ~LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST; } if ((allowedReasons & LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL) != 0) { allowedStrings.add("ALLOWED_REASON_ONGOING_CALL"); allowedReasons &= ~LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL; } if (allowedReasons != 0) { allowedStrings.add(String.valueOf(allowedReasons)); } Loading
services/core/java/com/android/server/power/LowPowerStandbyController.java +101 −3 Original line number Diff line number Diff line Loading @@ -16,19 +16,25 @@ package com.android.server.power; import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL; import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST; import static android.os.PowerManager.lowPowerStandbyAllowedReasonsToString; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AlarmManager; import android.app.IActivityManager; import android.app.IForegroundServiceObserver; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.database.ContentObserver; import android.net.Uri; Loading @@ -53,6 +59,7 @@ import android.util.ArraySet; import android.util.AtomicFile; import android.util.IndentingPrintWriter; import android.util.Slog; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.Xml; import android.util.proto.ProtoOutputStream; Loading Loading @@ -82,6 +89,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.Supplier; /** * Controls Low Power Standby state. Loading Loading @@ -115,7 +123,8 @@ public class LowPowerStandbyController { private static final int MSG_NOTIFY_ACTIVE_CHANGED = 1; private static final int MSG_NOTIFY_ALLOWLIST_CHANGED = 2; private static final int MSG_NOTIFY_POLICY_CHANGED = 3; private static final int MSG_NOTIFY_STANDBY_PORTS_CHANGED = 4; private static final int MSG_FOREGROUND_SERVICE_STATE_CHANGED = 4; private static final int MSG_NOTIFY_STANDBY_PORTS_CHANGED = 5; private static final String TAG_ROOT = "low-power-standby-policy"; private static final String TAG_IDENTIFIER = "identifier"; Loading @@ -127,6 +136,7 @@ public class LowPowerStandbyController { private final Handler mHandler; private final SettingsObserver mSettingsObserver; private final DeviceConfigWrapper mDeviceConfig; private final Supplier<IActivityManager> mActivityManager; private final File mPolicyFile; private final Object mLock = new Object(); Loading Loading @@ -160,6 +170,7 @@ public class LowPowerStandbyController { }; private final TempAllowlistChangeListener mTempAllowlistChangeListener = new TempAllowlistChangeListener(); private final PhoneCallServiceTracker mPhoneCallServiceTracker = new PhoneCallServiceTracker(); private final BroadcastReceiver mPackageBroadcastReceiver = new BroadcastReceiver() { @Override Loading Loading @@ -243,6 +254,7 @@ public class LowPowerStandbyController { private AlarmManager mAlarmManager; @GuardedBy("mLock") private PowerManager mPowerManager; private ActivityManagerInternal mActivityManagerInternal; @GuardedBy("mLock") private boolean mSupportedConfig; @GuardedBy("mLock") Loading Loading @@ -314,18 +326,20 @@ public class LowPowerStandbyController { public LowPowerStandbyController(Context context, Looper looper) { this(context, looper, SystemClock::elapsedRealtime, new DeviceConfigWrapper(), new DeviceConfigWrapper(), () -> ActivityManager.getService(), new File(Environment.getDataSystemDirectory(), "low_power_standby_policy.xml")); } @VisibleForTesting LowPowerStandbyController(Context context, Looper looper, Clock clock, DeviceConfigWrapper deviceConfig, File policyFile) { DeviceConfigWrapper deviceConfig, Supplier<IActivityManager> activityManager, File policyFile) { mContext = context; mHandler = new LowPowerStandbyHandler(looper); mClock = clock; mSettingsObserver = new SettingsObserver(mHandler); mDeviceConfig = deviceConfig; mActivityManager = activityManager; mPolicyFile = policyFile; } Loading @@ -343,6 +357,7 @@ public class LowPowerStandbyController { mAlarmManager = mContext.getSystemService(AlarmManager.class); mPowerManager = mContext.getSystemService(PowerManager.class); mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mStandbyTimeoutConfig = resources.getInteger( R.integer.config_lowPowerStandbyNonInteractiveTimeout); Loading Loading @@ -707,6 +722,8 @@ public class LowPowerStandbyController { PowerAllowlistInternal pai = LocalServices.getService(PowerAllowlistInternal.class); pai.registerTempAllowlistChangeListener(mTempAllowlistChangeListener); mPhoneCallServiceTracker.register(); } private void unregisterListeners() { Loading Loading @@ -1142,6 +1159,10 @@ public class LowPowerStandbyController { case MSG_NOTIFY_POLICY_CHANGED: notifyPolicyChanged((LowPowerStandbyPolicy) msg.obj); break; case MSG_FOREGROUND_SERVICE_STATE_CHANGED: final int uid = msg.arg1; mPhoneCallServiceTracker.foregroundServiceStateChanged(uid); break; case MSG_NOTIFY_STANDBY_PORTS_CHANGED: notifyStandbyPortsChanged(); break; Loading Loading @@ -1406,4 +1427,81 @@ public class LowPowerStandbyController { LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST); } } final class PhoneCallServiceTracker extends IForegroundServiceObserver.Stub { private boolean mRegistered = false; private final SparseBooleanArray mUidsWithPhoneCallService = new SparseBooleanArray(); public void register() { if (mRegistered) { return; } try { mActivityManager.get().registerForegroundServiceObserver(this); mRegistered = true; } catch (RemoteException e) { // call within system server } } @Override public void onForegroundStateChanged(IBinder serviceToken, String packageName, int userId, boolean isForeground) { try { final long now = mClock.elapsedRealtime(); final int uid = mContext.getPackageManager() .getPackageUidAsUser(packageName, userId); final Message message = mHandler.obtainMessage(MSG_FOREGROUND_SERVICE_STATE_CHANGED, uid, 0); mHandler.sendMessageAtTime(message, now); } catch (PackageManager.NameNotFoundException e) { if (DEBUG) { Slog.d(TAG, "onForegroundStateChanged: Unknown package: " + packageName + ", userId=" + userId); } } } public void foregroundServiceStateChanged(int uid) { if (DEBUG) { Slog.d(TAG, "foregroundServiceStateChanged: uid=" + uid); } final boolean hadPhoneCallService = mUidsWithPhoneCallService.get(uid); final boolean hasPhoneCallService = mActivityManagerInternal.hasRunningForegroundService(uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL); if (DEBUG) { Slog.d(TAG, "uid=" + uid + ", hasPhoneCallService=" + hasPhoneCallService + ", hadPhoneCallService=" + hadPhoneCallService); } if (hasPhoneCallService == hadPhoneCallService) { return; } if (hasPhoneCallService) { mUidsWithPhoneCallService.append(uid, true); uidStartedPhoneCallService(uid); } else { mUidsWithPhoneCallService.delete(uid); uidStoppedPhoneCallService(uid); } } private void uidStartedPhoneCallService(int uid) { if (DEBUG) { Slog.d(TAG, "FGS of type phoneCall started: uid=" + uid); } addToAllowlistInternal(uid, LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL); } private void uidStoppedPhoneCallService(int uid) { if (DEBUG) { Slog.d(TAG, "FGSs of type phoneCall stopped: uid=" + uid); } removeFromAllowlistInternal(uid, LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL); } } }
services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java +55 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.power; import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL; import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST; import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION; import static android.os.PowerManager.LOW_POWER_STANDBY_FEATURE_WAKE_ON_LAN; Loading Loading @@ -44,10 +45,14 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.app.ActivityManagerInternal; import android.app.AlarmManager; import android.app.IActivityManager; import android.app.IForegroundServiceObserver; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.net.Uri; import android.os.Binder; Loading Loading @@ -118,6 +123,8 @@ public class LowPowerStandbyControllerTest { @Mock private DeviceConfigWrapper mDeviceConfigWrapperMock; @Mock private IActivityManager mIActivityManagerMock; @Mock private AlarmManager mAlarmManagerMock; @Mock private PackageManager mPackageManagerMock; Loading @@ -131,6 +138,8 @@ public class LowPowerStandbyControllerTest { private NetworkPolicyManagerInternal mNetworkPolicyManagerInternalMock; @Mock private PowerAllowlistInternal mPowerAllowlistInternalMock; @Mock private ActivityManagerInternal mActivityManagerInternalMock; @Before public void setUp() throws Exception { Loading @@ -145,6 +154,7 @@ public class LowPowerStandbyControllerTest { addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock); addLocalServiceMock(NetworkPolicyManagerInternal.class, mNetworkPolicyManagerInternalMock); addLocalServiceMock(PowerAllowlistInternal.class, mPowerAllowlistInternalMock); addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock); when(mIPowerManagerMock.isInteractive()).thenReturn(true); Loading @@ -171,13 +181,18 @@ public class LowPowerStandbyControllerTest { UserHandle.of(USER_ID_1), UserHandle.of(USER_ID_2))); when(mPackageManagerMock.getPackageUid(eq(TEST_PKG1), any())).thenReturn(TEST_PKG1_APP_ID); when(mPackageManagerMock.getPackageUid(eq(TEST_PKG2), any())).thenReturn(TEST_PKG2_APP_ID); when(mPackageManagerMock.getPackageUidAsUser(eq(TEST_PKG1), eq(USER_ID_1))) .thenReturn(TEST_PKG1_APP_ID); when(mPackageManagerMock.getPackageUidAsUser(eq(TEST_PKG2), eq(USER_ID_1))) .thenReturn(TEST_PKG2_APP_ID); mClock = new OffsettableClock.Stopped(); mTestLooper = new TestLooper(mClock::now); mTestPolicyFile = new File(mContextSpy.getCacheDir(), "lps_policy.xml"); mController = new LowPowerStandbyController(mContextSpy, mTestLooper.getLooper(), () -> mClock.now(), mDeviceConfigWrapperMock, mTestPolicyFile); () -> mClock.now(), mDeviceConfigWrapperMock, () -> mIActivityManagerMock, mTestPolicyFile); } @After Loading @@ -186,6 +201,8 @@ public class LowPowerStandbyControllerTest { LocalServices.removeServiceForTest(LowPowerStandbyControllerInternal.class); LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class); LocalServices.removeServiceForTest(PowerAllowlistInternal.class); LocalServices.removeServiceForTest(ActivityManagerInternal.class); mTestPolicyFile.delete(); } Loading Loading @@ -713,6 +730,43 @@ public class LowPowerStandbyControllerTest { verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[0]); } @Test public void testAllowReason_ongoingPhoneCallService() throws Exception { mController.systemReady(); mController.setEnabled(true); mController.setPolicy(policyWithAllowedReasons( LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL)); mTestLooper.dispatchAll(); ArgumentCaptor<IForegroundServiceObserver> fgsObserverCapt = ArgumentCaptor.forClass(IForegroundServiceObserver.class); verify(mIActivityManagerMock).registerForegroundServiceObserver(fgsObserverCapt.capture()); IForegroundServiceObserver fgsObserver = fgsObserverCapt.getValue(); when(mActivityManagerInternalMock.hasRunningForegroundService(eq(TEST_PKG1_APP_ID), eq(ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL))).thenReturn(true); fgsObserver.onForegroundStateChanged(null, TEST_PKG1, USER_ID_1, true); mTestLooper.dispatchAll(); verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{TEST_PKG1_APP_ID}); when(mActivityManagerInternalMock.hasRunningForegroundService(eq(TEST_PKG2_APP_ID), eq(ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL))).thenReturn(true); fgsObserver.onForegroundStateChanged(null, TEST_PKG2, USER_ID_1, true); mTestLooper.dispatchAll(); verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist( new int[]{TEST_PKG1_APP_ID, TEST_PKG2_APP_ID}); when(mActivityManagerInternalMock.hasRunningForegroundService(eq(TEST_PKG1_APP_ID), eq(ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL))).thenReturn(false); fgsObserver.onForegroundStateChanged(null, TEST_PKG1, USER_ID_1, false); mTestLooper.dispatchAll(); verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{TEST_PKG2_APP_ID}); mController.setPolicy(EMPTY_POLICY); mTestLooper.dispatchAll(); verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[0]); } @Test public void testStandbyPorts_broadcastChangedIfPackageIsExempt() throws Exception { mController.systemReady(); Loading