1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.power;
18 
19 import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL;
20 import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST;
21 import static android.os.PowerManager.lowPowerStandbyAllowedReasonsToString;
22 
23 import android.Manifest;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.app.ActivityManager;
27 import android.app.ActivityManagerInternal;
28 import android.app.AlarmManager;
29 import android.app.IActivityManager;
30 import android.app.IForegroundServiceObserver;
31 import android.content.BroadcastReceiver;
32 import android.content.ContentResolver;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.content.IntentFilter;
36 import android.content.pm.PackageManager;
37 import android.content.pm.ServiceInfo;
38 import android.content.res.Resources;
39 import android.database.ContentObserver;
40 import android.net.Uri;
41 import android.os.Environment;
42 import android.os.Handler;
43 import android.os.IBinder;
44 import android.os.Looper;
45 import android.os.Message;
46 import android.os.PowerManager;
47 import android.os.PowerManager.LowPowerStandbyAllowedReason;
48 import android.os.PowerManager.LowPowerStandbyPolicy;
49 import android.os.PowerManager.LowPowerStandbyPortDescription;
50 import android.os.PowerManagerInternal;
51 import android.os.RemoteException;
52 import android.os.SystemClock;
53 import android.os.UserHandle;
54 import android.os.UserManager;
55 import android.provider.DeviceConfig;
56 import android.provider.Settings;
57 import android.text.TextUtils;
58 import android.util.ArraySet;
59 import android.util.AtomicFile;
60 import android.util.IndentingPrintWriter;
61 import android.util.Slog;
62 import android.util.SparseBooleanArray;
63 import android.util.SparseIntArray;
64 import android.util.Xml;
65 import android.util.proto.ProtoOutputStream;
66 
67 import com.android.internal.R;
68 import com.android.internal.annotations.GuardedBy;
69 import com.android.internal.annotations.VisibleForTesting;
70 import com.android.modules.utils.TypedXmlPullParser;
71 import com.android.modules.utils.TypedXmlSerializer;
72 import com.android.server.LocalServices;
73 import com.android.server.PowerAllowlistInternal;
74 import com.android.server.net.NetworkPolicyManagerInternal;
75 
76 import org.xmlpull.v1.XmlPullParser;
77 import org.xmlpull.v1.XmlPullParserException;
78 
79 import java.io.File;
80 import java.io.FileInputStream;
81 import java.io.FileNotFoundException;
82 import java.io.FileOutputStream;
83 import java.io.IOException;
84 import java.io.PrintWriter;
85 import java.util.ArrayList;
86 import java.util.Arrays;
87 import java.util.Collections;
88 import java.util.List;
89 import java.util.Objects;
90 import java.util.Set;
91 import java.util.concurrent.Executor;
92 import java.util.function.Supplier;
93 
94 /**
95  * Controls Low Power Standby state.
96  *
97  * Instantiated by {@link PowerManagerService} only if Low Power Standby is supported.
98  *
99  * <p>Low Power Standby is active when all of the following conditions are met:
100  * <ul>
101  *   <li>Low Power Standby is enabled
102  *   <li>The device is not interactive, and has been non-interactive for a given timeout
103  *   <li>The device is not in a doze maintenance window (devices may be configured to also
104  *   apply restrictions during doze maintenance windows, see {@link #setActiveDuringMaintenance})
105  * </ul>
106  *
107  * <p>When Low Power Standby is active, the following restrictions are applied to applications
108  * with procstate less important than {@link android.app.ActivityManager#PROCESS_STATE_BOUND_TOP}
109  * unless they are exempted (see {@link LowPowerStandbyPolicy}):
110  * <ul>
111  *   <li>Network access is blocked
112  *   <li>Wakelocks are disabled
113  * </ul>
114  *
115  * @hide
116  */
117 public class LowPowerStandbyController {
118     private static final String TAG = "LowPowerStandbyController";
119     private static final boolean DEBUG = false;
120     private static final boolean DEFAULT_ACTIVE_DURING_MAINTENANCE = false;
121 
122     private static final int MSG_STANDBY_TIMEOUT = 0;
123     private static final int MSG_NOTIFY_ACTIVE_CHANGED = 1;
124     private static final int MSG_NOTIFY_ALLOWLIST_CHANGED = 2;
125     private static final int MSG_NOTIFY_POLICY_CHANGED = 3;
126     private static final int MSG_FOREGROUND_SERVICE_STATE_CHANGED = 4;
127     private static final int MSG_NOTIFY_STANDBY_PORTS_CHANGED = 5;
128 
129     private static final String TAG_ROOT = "low-power-standby-policy";
130     private static final String TAG_IDENTIFIER = "identifier";
131     private static final String TAG_EXEMPT_PACKAGE = "exempt-package";
132     private static final String TAG_ALLOWED_REASONS = "allowed-reasons";
133     private static final String TAG_ALLOWED_FEATURES = "allowed-features";
134     private static final String ATTR_VALUE = "value";
135 
136     private final Handler mHandler;
137     private final SettingsObserver mSettingsObserver;
138     private final DeviceConfigWrapper mDeviceConfig;
139     private final Supplier<IActivityManager> mActivityManager;
140     private final File mPolicyFile;
141     private final Object mLock = new Object();
142 
143     private final Context mContext;
144     private final Clock mClock;
145     private final AlarmManager.OnAlarmListener mOnStandbyTimeoutExpired =
146             this::onStandbyTimeoutExpired;
147     private final LowPowerStandbyControllerInternal mLocalService = new LocalService();
148     private final SparseIntArray mUidAllowedReasons = new SparseIntArray();
149     private final List<StandbyPortsLock> mStandbyPortLocks = new ArrayList<>();
150 
151     @GuardedBy("mLock")
152     private boolean mEnableCustomPolicy;
153     private boolean mEnableStandbyPorts;
154 
155     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
156         @Override
157         public void onReceive(Context context, Intent intent) {
158             switch (intent.getAction()) {
159                 case Intent.ACTION_SCREEN_OFF:
160                     onNonInteractive();
161                     break;
162                 case Intent.ACTION_SCREEN_ON:
163                     onInteractive();
164                     break;
165                 case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
166                     onDeviceIdleModeChanged();
167                     break;
168             }
169         }
170     };
171     private final TempAllowlistChangeListener mTempAllowlistChangeListener =
172             new TempAllowlistChangeListener();
173     private final PhoneCallServiceTracker mPhoneCallServiceTracker = new PhoneCallServiceTracker();
174 
175     private final BroadcastReceiver mPackageBroadcastReceiver = new BroadcastReceiver() {
176         @Override
177         public void onReceive(Context context, Intent intent) {
178             if (DEBUG) {
179                 Slog.d(TAG, "Received package intent: action=" + intent.getAction() + ", data="
180                         + intent.getData());
181             }
182             final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
183             if (replacing) {
184                 return;
185             }
186             final Uri intentUri = intent.getData();
187             final String packageName = (intentUri != null) ? intentUri.getSchemeSpecificPart()
188                     : null;
189             synchronized (mLock) {
190                 final LowPowerStandbyPolicy policy = getPolicy();
191                 if (policy.getExemptPackages().contains(packageName)) {
192                     enqueueNotifyAllowlistChangedLocked();
193                 }
194             }
195         }
196     };
197 
198     private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
199         @Override
200         public void onReceive(Context context, Intent intent) {
201             if (DEBUG) {
202                 Slog.d(TAG, "Received user intent: action=" + intent.getAction());
203             }
204             synchronized (mLock) {
205                 enqueueNotifyAllowlistChangedLocked();
206             }
207         }
208     };
209 
210     private final class StandbyPortsLock implements IBinder.DeathRecipient {
211         private final IBinder mToken;
212         private final int mUid;
213         private final List<LowPowerStandbyPortDescription> mPorts;
214 
StandbyPortsLock(IBinder token, int uid, List<LowPowerStandbyPortDescription> ports)215         StandbyPortsLock(IBinder token, int uid, List<LowPowerStandbyPortDescription> ports) {
216             mToken = token;
217             mUid = uid;
218             mPorts = ports;
219         }
220 
linkToDeath()221         public boolean linkToDeath() {
222             try {
223                 mToken.linkToDeath(this, 0);
224                 return true;
225             } catch (RemoteException e) {
226                 Slog.i(TAG, "StandbyPorts token already died");
227                 return false;
228             }
229         }
230 
unlinkToDeath()231         public void unlinkToDeath() {
232             mToken.unlinkToDeath(this, 0);
233         }
234 
getToken()235         public IBinder getToken() {
236             return mToken;
237         }
238 
getUid()239         public int getUid() {
240             return mUid;
241         }
242 
getPorts()243         public List<LowPowerStandbyPortDescription> getPorts() {
244             return mPorts;
245         }
246 
247         @Override
binderDied()248         public void binderDied() {
249             releaseStandbyPorts(mToken);
250         }
251     }
252 
253     @GuardedBy("mLock")
254     private AlarmManager mAlarmManager;
255     @GuardedBy("mLock")
256     private PowerManager mPowerManager;
257     private ActivityManagerInternal mActivityManagerInternal;
258     @GuardedBy("mLock")
259     private boolean mSupportedConfig;
260     @GuardedBy("mLock")
261     private boolean mEnabledByDefaultConfig;
262     @GuardedBy("mLock")
263     private int mStandbyTimeoutConfig;
264 
265     /** Whether Low Power Standby is enabled in Settings */
266     @GuardedBy("mLock")
267     private boolean mIsEnabled;
268 
269     /**
270      * Whether Low Power Standby is currently active (enforcing restrictions).
271      */
272     @GuardedBy("mLock")
273     private boolean mIsActive;
274 
275     /** Whether the device is currently interactive */
276     @GuardedBy("mLock")
277     private boolean mIsInteractive;
278 
279     /** The time the device was last interactive, in {@link SystemClock#elapsedRealtime()}. */
280     @GuardedBy("mLock")
281     private long mLastInteractiveTimeElapsed;
282 
283     /**
284      * Whether we are in device idle mode.
285      * During maintenance windows Low Power Standby is deactivated to allow
286      * apps to run maintenance tasks.
287      */
288     @GuardedBy("mLock")
289     private boolean mIsDeviceIdle;
290 
291     /**
292      * Whether the device has entered idle mode since becoming non-interactive.
293      * In the initial non-idle period after turning the screen off, Low Power Standby is already
294      * allowed to become active. Later non-idle periods are treated as maintenance windows, during
295      * which Low Power Standby is deactivated to allow apps to run maintenance tasks.
296      */
297     @GuardedBy("mLock")
298     private boolean mIdleSinceNonInteractive;
299 
300     /** Whether Low Power Standby restrictions should be active during doze maintenance mode. */
301     @GuardedBy("mLock")
302     private boolean mActiveDuringMaintenance;
303 
304     /** Force Low Power Standby to be active. */
305     @GuardedBy("mLock")
306     private boolean mForceActive;
307 
308     /** Current Low Power Standby policy. */
309     @GuardedBy("mLock")
310     @Nullable
311     private LowPowerStandbyPolicy mPolicy;
312 
313     @VisibleForTesting
314     static final LowPowerStandbyPolicy DEFAULT_POLICY = new LowPowerStandbyPolicy(
315             "DEFAULT_POLICY",
316             Collections.emptySet(),
317             PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION,
318             Collections.emptySet());
319 
320     /** Functional interface for providing time. */
321     @VisibleForTesting
322     interface Clock {
323         /** Returns milliseconds since boot, including time spent in sleep. */
elapsedRealtime()324         long elapsedRealtime();
325     }
326 
LowPowerStandbyController(Context context, Looper looper)327     public LowPowerStandbyController(Context context, Looper looper) {
328         this(context, looper, SystemClock::elapsedRealtime,
329                 new DeviceConfigWrapper(), () -> ActivityManager.getService(),
330                 new File(Environment.getDataSystemDirectory(), "low_power_standby_policy.xml"));
331     }
332 
333     @VisibleForTesting
LowPowerStandbyController(Context context, Looper looper, Clock clock, DeviceConfigWrapper deviceConfig, Supplier<IActivityManager> activityManager, File policyFile)334     LowPowerStandbyController(Context context, Looper looper, Clock clock,
335             DeviceConfigWrapper deviceConfig, Supplier<IActivityManager> activityManager,
336             File policyFile) {
337         mContext = context;
338         mHandler = new LowPowerStandbyHandler(looper);
339         mClock = clock;
340         mSettingsObserver = new SettingsObserver(mHandler);
341         mDeviceConfig = deviceConfig;
342         mActivityManager = activityManager;
343         mPolicyFile = policyFile;
344     }
345 
346     /** Call when system services are ready */
347     @VisibleForTesting
systemReady()348     public void systemReady() {
349         final Resources resources = mContext.getResources();
350         synchronized (mLock) {
351             mSupportedConfig = resources.getBoolean(
352                     com.android.internal.R.bool.config_lowPowerStandbySupported);
353 
354             if (!mSupportedConfig) {
355                 return;
356             }
357 
358             mAlarmManager = mContext.getSystemService(AlarmManager.class);
359             mPowerManager = mContext.getSystemService(PowerManager.class);
360             mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
361 
362             mStandbyTimeoutConfig = resources.getInteger(
363                     R.integer.config_lowPowerStandbyNonInteractiveTimeout);
364             mEnabledByDefaultConfig = resources.getBoolean(
365                     R.bool.config_lowPowerStandbyEnabledByDefault);
366 
367             mIsInteractive = mPowerManager.isInteractive();
368 
369             mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
370                     Settings.Global.LOW_POWER_STANDBY_ENABLED),
371                     false, mSettingsObserver, UserHandle.USER_ALL);
372             mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
373                     Settings.Global.LOW_POWER_STANDBY_ACTIVE_DURING_MAINTENANCE),
374                     false, mSettingsObserver, UserHandle.USER_ALL);
375 
376             mDeviceConfig.registerPropertyUpdateListener(mContext.getMainExecutor(),
377                     properties -> onDeviceConfigFlagsChanged());
378             mEnableCustomPolicy = mDeviceConfig.enableCustomPolicy();
379             mEnableStandbyPorts = mDeviceConfig.enableStandbyPorts();
380 
381             if (mEnableCustomPolicy) {
382                 mPolicy = loadPolicy();
383             } else {
384                 mPolicy = DEFAULT_POLICY;
385             }
386             initSettingsLocked();
387             updateSettingsLocked();
388 
389             if (mIsEnabled) {
390                 registerListeners();
391             }
392         }
393 
394         LocalServices.addService(LowPowerStandbyControllerInternal.class, mLocalService);
395     }
396 
onDeviceConfigFlagsChanged()397     private void onDeviceConfigFlagsChanged() {
398         synchronized (mLock) {
399             boolean enableCustomPolicy = mDeviceConfig.enableCustomPolicy();
400             if (mEnableCustomPolicy != enableCustomPolicy) {
401                 enqueueNotifyPolicyChangedLocked();
402                 enqueueNotifyAllowlistChangedLocked();
403                 mEnableCustomPolicy = enableCustomPolicy;
404             }
405 
406             mEnableStandbyPorts = mDeviceConfig.enableStandbyPorts();
407         }
408     }
409 
410     @GuardedBy("mLock")
initSettingsLocked()411     private void initSettingsLocked() {
412         final ContentResolver resolver = mContext.getContentResolver();
413         if (mSupportedConfig) {
414             final int enabledSetting = Settings.Global.getInt(resolver,
415                     Settings.Global.LOW_POWER_STANDBY_ENABLED, /* def= */ -1);
416 
417             // If the ENABLED setting hasn't been assigned yet, set it to its default value.
418             // This ensures reading the setting reflects the enabled state, without having to know
419             // the default value for this device.
420             if (enabledSetting == -1) {
421                 Settings.Global.putInt(resolver, Settings.Global.LOW_POWER_STANDBY_ENABLED,
422                         /* value= */ mEnabledByDefaultConfig ? 1 : 0);
423             }
424         }
425     }
426 
427     @GuardedBy("mLock")
updateSettingsLocked()428     private void updateSettingsLocked() {
429         final ContentResolver resolver = mContext.getContentResolver();
430         mIsEnabled = mSupportedConfig && Settings.Global.getInt(resolver,
431                 Settings.Global.LOW_POWER_STANDBY_ENABLED,
432                 mEnabledByDefaultConfig ? 1 : 0) != 0;
433         mActiveDuringMaintenance = Settings.Global.getInt(resolver,
434                 Settings.Global.LOW_POWER_STANDBY_ACTIVE_DURING_MAINTENANCE,
435                 DEFAULT_ACTIVE_DURING_MAINTENANCE ? 1 : 0) != 0;
436 
437         updateActiveLocked();
438     }
439 
440     @Nullable
loadPolicy()441     private LowPowerStandbyPolicy loadPolicy() {
442         final AtomicFile file = getPolicyFile();
443         if (!file.exists()) {
444             return null;
445         }
446         if (DEBUG) {
447             Slog.d(TAG, "Loading policy from " + file.getBaseFile());
448         }
449 
450         try (FileInputStream in = file.openRead()) {
451             String identifier = null;
452             Set<String> exemptPackages = new ArraySet<>();
453             int allowedReasons = 0;
454             Set<String> allowedFeatures = new ArraySet<>();
455 
456             TypedXmlPullParser parser = Xml.resolvePullParser(in);
457 
458             int type;
459             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
460                 if (type != XmlPullParser.START_TAG) {
461                     continue;
462                 }
463                 final int depth = parser.getDepth();
464                 // Check the root tag
465                 final String tag = parser.getName();
466                 if (depth == 1) {
467                     if (!TAG_ROOT.equals(tag)) {
468                         Slog.e(TAG, "Invalid root tag: " + tag);
469                         return null;
470                     }
471                     continue;
472                 }
473                 // Assume depth == 2
474                 switch (tag) {
475                     case TAG_IDENTIFIER:
476                         identifier = parser.getAttributeValue(null, ATTR_VALUE);
477                         break;
478                     case TAG_EXEMPT_PACKAGE:
479                         exemptPackages.add(parser.getAttributeValue(null, ATTR_VALUE));
480                         break;
481                     case TAG_ALLOWED_REASONS:
482                         allowedReasons = parser.getAttributeInt(null, ATTR_VALUE);
483                         break;
484                     case TAG_ALLOWED_FEATURES:
485                         allowedFeatures.add(parser.getAttributeValue(null, ATTR_VALUE));
486                         break;
487                     default:
488                         Slog.e(TAG, "Invalid tag: " + tag);
489                         break;
490                 }
491             }
492 
493             final LowPowerStandbyPolicy policy = new LowPowerStandbyPolicy(identifier,
494                     exemptPackages, allowedReasons, allowedFeatures);
495             if (DEBUG) {
496                 Slog.d(TAG, "Loaded policy: " + policy);
497             }
498             return policy;
499         } catch (FileNotFoundException e) {
500             // Use the default
501             return null;
502         } catch (IOException | NullPointerException | IllegalArgumentException
503                 | XmlPullParserException e) {
504             Slog.e(TAG, "Failed to read policy file " + file.getBaseFile(), e);
505             return null;
506         }
507     }
508 
writeTagValue(TypedXmlSerializer out, String tag, String value)509     static void writeTagValue(TypedXmlSerializer out, String tag, String value) throws IOException {
510         if (TextUtils.isEmpty(value)) return;
511 
512         out.startTag(null, tag);
513         out.attribute(null, ATTR_VALUE, value);
514         out.endTag(null, tag);
515     }
516 
writeTagValue(TypedXmlSerializer out, String tag, int value)517     static void writeTagValue(TypedXmlSerializer out, String tag, int value) throws IOException {
518         out.startTag(null, tag);
519         out.attributeInt(null, ATTR_VALUE, value);
520         out.endTag(null, tag);
521     }
522 
savePolicy(@ullable LowPowerStandbyPolicy policy)523     private void savePolicy(@Nullable LowPowerStandbyPolicy policy) {
524         final AtomicFile file = getPolicyFile();
525         if (DEBUG) {
526             Slog.d(TAG, "Saving policy to " + file.getBaseFile());
527         }
528         if (policy == null) {
529             file.delete();
530             return;
531         }
532 
533         FileOutputStream outs = null;
534         try {
535             file.getBaseFile().mkdirs();
536             outs = file.startWrite();
537 
538             // Write to XML
539             TypedXmlSerializer out = Xml.resolveSerializer(outs);
540             out.startDocument(null, true);
541             out.startTag(null, TAG_ROOT);
542 
543             // Body.
544             writeTagValue(out, TAG_IDENTIFIER, policy.getIdentifier());
545             for (String exemptPackage : policy.getExemptPackages()) {
546                 writeTagValue(out, TAG_EXEMPT_PACKAGE, exemptPackage);
547             }
548             writeTagValue(out, TAG_ALLOWED_REASONS, policy.getAllowedReasons());
549             for (String allowedFeature : policy.getAllowedFeatures()) {
550                 writeTagValue(out, TAG_ALLOWED_FEATURES, allowedFeature);
551             }
552 
553             // Epilogue.
554             out.endTag(null, TAG_ROOT);
555             out.endDocument();
556 
557             // Close.
558             file.finishWrite(outs);
559         } catch (IOException e) {
560             Slog.e(TAG, "Failed to write policy to file " + file.getBaseFile(), e);
561             file.failWrite(outs);
562         }
563     }
564 
enqueueSavePolicy(@ullable LowPowerStandbyPolicy policy)565     private void enqueueSavePolicy(@Nullable LowPowerStandbyPolicy policy) {
566         mHandler.post(() -> savePolicy(policy));
567     }
568 
getPolicyFile()569     private AtomicFile getPolicyFile() {
570         return new AtomicFile(mPolicyFile);
571     }
572 
573     @GuardedBy("mLock")
updateActiveLocked()574     private void updateActiveLocked() {
575         final long now = mClock.elapsedRealtime();
576         final boolean standbyTimeoutExpired =
577                 (now - mLastInteractiveTimeElapsed) >= mStandbyTimeoutConfig;
578         final boolean maintenanceMode = mIdleSinceNonInteractive && !mIsDeviceIdle;
579         final boolean newActive =
580                 mForceActive || (mIsEnabled && !mIsInteractive && standbyTimeoutExpired
581                         && (!maintenanceMode || mActiveDuringMaintenance));
582         if (DEBUG) {
583             Slog.d(TAG, "updateActiveLocked: mIsEnabled=" + mIsEnabled + ", mIsInteractive="
584                     + mIsInteractive + ", standbyTimeoutExpired=" + standbyTimeoutExpired
585                     + ", mIdleSinceNonInteractive=" + mIdleSinceNonInteractive + ", mIsDeviceIdle="
586                     + mIsDeviceIdle + ", mActiveDuringMaintenance=" + mActiveDuringMaintenance
587                     + ", mForceActive=" + mForceActive + ", mIsActive=" + mIsActive + ", newActive="
588                     + newActive);
589         }
590         if (mIsActive != newActive) {
591             mIsActive = newActive;
592             if (DEBUG) {
593                 Slog.d(TAG, "mIsActive changed, mIsActive=" + mIsActive);
594             }
595             enqueueNotifyActiveChangedLocked();
596         }
597     }
598 
onNonInteractive()599     private void onNonInteractive() {
600         if (DEBUG) {
601             Slog.d(TAG, "onNonInteractive");
602         }
603         final long now = mClock.elapsedRealtime();
604         synchronized (mLock) {
605             mIsInteractive = false;
606             mIsDeviceIdle = false;
607             mLastInteractiveTimeElapsed = now;
608 
609             if (mStandbyTimeoutConfig > 0) {
610                 scheduleStandbyTimeoutAlarmLocked();
611             }
612 
613             updateActiveLocked();
614         }
615     }
616 
onInteractive()617     private void onInteractive() {
618         if (DEBUG) {
619             Slog.d(TAG, "onInteractive");
620         }
621 
622         synchronized (mLock) {
623             cancelStandbyTimeoutAlarmLocked();
624             mIsInteractive = true;
625             mIsDeviceIdle = false;
626             mIdleSinceNonInteractive = false;
627             updateActiveLocked();
628         }
629     }
630 
631     @GuardedBy("mLock")
scheduleStandbyTimeoutAlarmLocked()632     private void scheduleStandbyTimeoutAlarmLocked() {
633         final long nextAlarmTime = SystemClock.elapsedRealtime() + mStandbyTimeoutConfig;
634         mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
635                 nextAlarmTime, "LowPowerStandbyController.StandbyTimeout",
636                 mOnStandbyTimeoutExpired, mHandler);
637     }
638 
639     @GuardedBy("mLock")
cancelStandbyTimeoutAlarmLocked()640     private void cancelStandbyTimeoutAlarmLocked() {
641         mAlarmManager.cancel(mOnStandbyTimeoutExpired);
642     }
643 
onDeviceIdleModeChanged()644     private void onDeviceIdleModeChanged() {
645         synchronized (mLock) {
646             mIsDeviceIdle = mPowerManager.isDeviceIdleMode();
647             if (DEBUG) {
648                 Slog.d(TAG, "onDeviceIdleModeChanged, mIsDeviceIdle=" + mIsDeviceIdle);
649             }
650 
651             mIdleSinceNonInteractive = mIdleSinceNonInteractive || mIsDeviceIdle;
652             updateActiveLocked();
653         }
654     }
655 
656     @GuardedBy("mLock")
onEnabledLocked()657     private void onEnabledLocked() {
658         if (DEBUG) {
659             Slog.d(TAG, "onEnabledLocked");
660         }
661 
662         if (mPowerManager.isInteractive()) {
663             onInteractive();
664         } else {
665             onNonInteractive();
666         }
667 
668         registerListeners();
669     }
670 
671     @GuardedBy("mLock")
onDisabledLocked()672     private void onDisabledLocked() {
673         if (DEBUG) {
674             Slog.d(TAG, "onDisabledLocked");
675         }
676 
677         cancelStandbyTimeoutAlarmLocked();
678         unregisterListeners();
679         updateActiveLocked();
680     }
681 
682     @VisibleForTesting
onSettingsChanged()683     void onSettingsChanged() {
684         if (DEBUG) {
685             Slog.d(TAG, "onSettingsChanged");
686         }
687         synchronized (mLock) {
688             final boolean oldEnabled = mIsEnabled;
689             updateSettingsLocked();
690 
691             if (mIsEnabled != oldEnabled) {
692                 if (mIsEnabled) {
693                     onEnabledLocked();
694                 } else {
695                     onDisabledLocked();
696                 }
697 
698                 notifyEnabledChangedLocked();
699             }
700         }
701     }
702 
registerListeners()703     private void registerListeners() {
704         IntentFilter intentFilter = new IntentFilter();
705         intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
706         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
707         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
708 
709         mContext.registerReceiver(mBroadcastReceiver, intentFilter);
710 
711         IntentFilter packageFilter = new IntentFilter();
712         packageFilter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
713         packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
714         packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
715         packageFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
716         mContext.registerReceiver(mPackageBroadcastReceiver, packageFilter);
717 
718         final IntentFilter userFilter = new IntentFilter();
719         userFilter.addAction(Intent.ACTION_USER_ADDED);
720         userFilter.addAction(Intent.ACTION_USER_REMOVED);
721         mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
722 
723         PowerAllowlistInternal pai = LocalServices.getService(PowerAllowlistInternal.class);
724         pai.registerTempAllowlistChangeListener(mTempAllowlistChangeListener);
725 
726         mPhoneCallServiceTracker.register();
727     }
728 
unregisterListeners()729     private void unregisterListeners() {
730         mContext.unregisterReceiver(mBroadcastReceiver);
731         mContext.unregisterReceiver(mPackageBroadcastReceiver);
732         mContext.unregisterReceiver(mUserReceiver);
733 
734         PowerAllowlistInternal pai = LocalServices.getService(PowerAllowlistInternal.class);
735         pai.unregisterTempAllowlistChangeListener(mTempAllowlistChangeListener);
736     }
737 
738     @GuardedBy("mLock")
notifyEnabledChangedLocked()739     private void notifyEnabledChangedLocked() {
740         if (DEBUG) {
741             Slog.d(TAG, "notifyEnabledChangedLocked, mIsEnabled=" + mIsEnabled);
742         }
743 
744         final Intent intent = new Intent(PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED);
745         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
746         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
747     }
748 
749     @GuardedBy("mLock")
enqueueNotifyPolicyChangedLocked()750     private void enqueueNotifyPolicyChangedLocked() {
751         final long now = mClock.elapsedRealtime();
752         final Message msg = mHandler.obtainMessage(MSG_NOTIFY_POLICY_CHANGED, getPolicy());
753         mHandler.sendMessageAtTime(msg, now);
754     }
755 
notifyPolicyChanged(LowPowerStandbyPolicy policy)756     private void notifyPolicyChanged(LowPowerStandbyPolicy policy) {
757         if (DEBUG) {
758             Slog.d(TAG, "notifyPolicyChanged, policy=" + policy);
759         }
760 
761         final Intent intent = new Intent(
762                 PowerManager.ACTION_LOW_POWER_STANDBY_POLICY_CHANGED);
763         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
764         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
765     }
766 
onStandbyTimeoutExpired()767     private void onStandbyTimeoutExpired() {
768         if (DEBUG) {
769             Slog.d(TAG, "onStandbyTimeoutExpired");
770         }
771         synchronized (mLock) {
772             updateActiveLocked();
773         }
774     }
775 
776     @GuardedBy("mLock")
enqueueNotifyActiveChangedLocked()777     private void enqueueNotifyActiveChangedLocked() {
778         final long now = mClock.elapsedRealtime();
779         final Message msg = mHandler.obtainMessage(MSG_NOTIFY_ACTIVE_CHANGED, mIsActive);
780         mHandler.sendMessageAtTime(msg, now);
781     }
782 
783     /** Notify other system components about the updated Low Power Standby active state */
notifyActiveChanged(boolean active)784     private void notifyActiveChanged(boolean active) {
785         if (DEBUG) {
786             Slog.d(TAG, "notifyActiveChanged, active=" + active);
787         }
788         final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
789         final NetworkPolicyManagerInternal npmi = LocalServices.getService(
790                 NetworkPolicyManagerInternal.class);
791 
792         pmi.setLowPowerStandbyActive(active);
793         npmi.setLowPowerStandbyActive(active);
794     }
795 
796     @VisibleForTesting
isActive()797     boolean isActive() {
798         synchronized (mLock) {
799             return mIsActive;
800         }
801     }
802 
isSupported()803     boolean isSupported() {
804         synchronized (mLock) {
805             return mSupportedConfig;
806         }
807     }
808 
isEnabled()809     boolean isEnabled() {
810         synchronized (mLock) {
811             return mSupportedConfig && mIsEnabled;
812         }
813     }
814 
setEnabled(boolean enabled)815     void setEnabled(boolean enabled) {
816         synchronized (mLock) {
817             if (!mSupportedConfig) {
818                 Slog.w(TAG, "Low Power Standby cannot be enabled "
819                         + "because it is not supported on this device");
820                 return;
821             }
822 
823             Settings.Global.putInt(mContext.getContentResolver(),
824                     Settings.Global.LOW_POWER_STANDBY_ENABLED, enabled ? 1 : 0);
825             onSettingsChanged();
826         }
827     }
828 
829     /** Set whether Low Power Standby should be active during doze maintenance mode. */
830     @VisibleForTesting
setActiveDuringMaintenance(boolean activeDuringMaintenance)831     public void setActiveDuringMaintenance(boolean activeDuringMaintenance) {
832         synchronized (mLock) {
833             if (!mSupportedConfig) {
834                 Slog.w(TAG, "Low Power Standby settings cannot be changed "
835                         + "because it is not supported on this device");
836                 return;
837             }
838 
839             Settings.Global.putInt(mContext.getContentResolver(),
840                     Settings.Global.LOW_POWER_STANDBY_ACTIVE_DURING_MAINTENANCE,
841                     activeDuringMaintenance ? 1 : 0);
842             onSettingsChanged();
843         }
844     }
845 
forceActive(boolean active)846     void forceActive(boolean active) {
847         synchronized (mLock) {
848             mForceActive = active;
849             updateActiveLocked();
850         }
851     }
852 
setPolicy(@ullable LowPowerStandbyPolicy policy)853     void setPolicy(@Nullable LowPowerStandbyPolicy policy) {
854         synchronized (mLock) {
855             if (!mSupportedConfig) {
856                 Slog.w(TAG, "Low Power Standby policy cannot be changed "
857                         + "because it is not supported on this device");
858                 return;
859             }
860 
861             if (!mEnableCustomPolicy) {
862                 Slog.d(TAG, "Custom policies are not enabled.");
863                 return;
864             }
865 
866             if (DEBUG) {
867                 Slog.d(TAG, "setPolicy: policy=" + policy);
868             }
869             if (Objects.equals(mPolicy, policy)) {
870                 return;
871             }
872 
873             boolean allowlistChanged = policyChangeAffectsAllowlistLocked(mPolicy, policy);
874             mPolicy = policy;
875             enqueueSavePolicy(mPolicy);
876             if (allowlistChanged) {
877                 enqueueNotifyAllowlistChangedLocked();
878             }
879             enqueueNotifyPolicyChangedLocked();
880         }
881     }
882 
883     @Nullable
getPolicy()884     LowPowerStandbyPolicy getPolicy() {
885         synchronized (mLock) {
886             if (!mSupportedConfig) {
887                 return null;
888             } else if (mEnableCustomPolicy) {
889                 return policyOrDefault(mPolicy);
890             } else {
891                 return DEFAULT_POLICY;
892             }
893         }
894     }
895 
896     @NonNull
policyOrDefault(@ullable LowPowerStandbyPolicy policy)897     private LowPowerStandbyPolicy policyOrDefault(@Nullable LowPowerStandbyPolicy policy) {
898         if (policy == null) {
899             return DEFAULT_POLICY;
900         }
901         return policy;
902     }
903 
isPackageExempt(int uid)904     boolean isPackageExempt(int uid) {
905         synchronized (mLock) {
906             if (!isEnabled()) {
907                 return true;
908             }
909 
910             return getExemptPackageAppIdsLocked().contains(UserHandle.getAppId(uid));
911         }
912     }
913 
isAllowed(@owPowerStandbyAllowedReason int reason)914     boolean isAllowed(@LowPowerStandbyAllowedReason int reason) {
915         synchronized (mLock) {
916             if (!isEnabled()) {
917                 return true;
918             }
919 
920             return (getPolicy().getAllowedReasons() & reason) != 0;
921         }
922     }
923 
isAllowed(String feature)924     boolean isAllowed(String feature) {
925         synchronized (mLock) {
926             if (!mSupportedConfig) {
927                 return true;
928             }
929 
930             return !isEnabled() || getPolicy().getAllowedFeatures().contains(feature);
931         }
932     }
933 
findIndexOfStandbyPorts(@onNull IBinder token)934     private int findIndexOfStandbyPorts(@NonNull IBinder token) {
935         for (int i = 0; i < mStandbyPortLocks.size(); i++) {
936             if (mStandbyPortLocks.get(i).getToken() == token) {
937                 return i;
938             }
939         }
940         return -1;
941     }
942 
acquireStandbyPorts(@onNull IBinder token, int uid, @NonNull List<LowPowerStandbyPortDescription> ports)943     void acquireStandbyPorts(@NonNull IBinder token, int uid,
944             @NonNull List<LowPowerStandbyPortDescription> ports) {
945         validatePorts(ports);
946 
947         StandbyPortsLock standbyPortsLock = new StandbyPortsLock(token, uid, ports);
948         synchronized (mLock) {
949             if (findIndexOfStandbyPorts(token) != -1) {
950                 return;
951             }
952 
953             if (standbyPortsLock.linkToDeath()) {
954                 mStandbyPortLocks.add(standbyPortsLock);
955                 if (mEnableStandbyPorts && isEnabled() && isPackageExempt(uid)) {
956                     enqueueNotifyStandbyPortsChangedLocked();
957                 }
958             }
959         }
960     }
961 
validatePorts(@onNull List<LowPowerStandbyPortDescription> ports)962     void validatePorts(@NonNull List<LowPowerStandbyPortDescription> ports) {
963         for (LowPowerStandbyPortDescription portDescription : ports) {
964             int port = portDescription.getPortNumber();
965             if (port < 0 || port > 0xFFFF) {
966                 throw new IllegalArgumentException("port out of range:" + port);
967             }
968         }
969     }
970 
releaseStandbyPorts(@onNull IBinder token)971     void releaseStandbyPorts(@NonNull IBinder token) {
972         synchronized (mLock) {
973             int index = findIndexOfStandbyPorts(token);
974             if (index == -1) {
975                 return;
976             }
977 
978             StandbyPortsLock standbyPortsLock = mStandbyPortLocks.remove(index);
979             standbyPortsLock.unlinkToDeath();
980             if (mEnableStandbyPorts && isEnabled() && isPackageExempt(standbyPortsLock.getUid())) {
981                 enqueueNotifyStandbyPortsChangedLocked();
982             }
983         }
984     }
985 
986     @NonNull
getActiveStandbyPorts()987     List<LowPowerStandbyPortDescription> getActiveStandbyPorts() {
988         List<LowPowerStandbyPortDescription> activeStandbyPorts = new ArrayList<>();
989         synchronized (mLock) {
990             if (!isEnabled() || !mEnableStandbyPorts) {
991                 return activeStandbyPorts;
992             }
993 
994             List<Integer> exemptPackageAppIds = getExemptPackageAppIdsLocked();
995             for (StandbyPortsLock standbyPortsLock : mStandbyPortLocks) {
996                 int standbyPortsAppid = UserHandle.getAppId(standbyPortsLock.getUid());
997                 if (exemptPackageAppIds.contains(standbyPortsAppid)) {
998                     activeStandbyPorts.addAll(standbyPortsLock.getPorts());
999                 }
1000             }
1001 
1002             return activeStandbyPorts;
1003         }
1004     }
1005 
policyChangeAffectsAllowlistLocked( @ullable LowPowerStandbyPolicy oldPolicy, @Nullable LowPowerStandbyPolicy newPolicy)1006     private boolean policyChangeAffectsAllowlistLocked(
1007             @Nullable LowPowerStandbyPolicy oldPolicy, @Nullable LowPowerStandbyPolicy newPolicy) {
1008         final LowPowerStandbyPolicy policyA = policyOrDefault(oldPolicy);
1009         final LowPowerStandbyPolicy policyB = policyOrDefault(newPolicy);
1010         int allowedReasonsInUse = 0;
1011         for (int i = 0; i < mUidAllowedReasons.size(); i++) {
1012             allowedReasonsInUse |= mUidAllowedReasons.valueAt(i);
1013         }
1014 
1015         int policyAllowedReasonsChanged = policyA.getAllowedReasons() ^ policyB.getAllowedReasons();
1016 
1017         boolean exemptPackagesChanged = !policyA.getExemptPackages().equals(
1018                 policyB.getExemptPackages());
1019 
1020         return (policyAllowedReasonsChanged & allowedReasonsInUse) != 0 || exemptPackagesChanged;
1021     }
1022 
dump(PrintWriter pw)1023     void dump(PrintWriter pw) {
1024         final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
1025 
1026         ipw.println();
1027         ipw.println("Low Power Standby Controller:");
1028         ipw.increaseIndent();
1029         synchronized (mLock) {
1030             ipw.print("mIsActive=");
1031             ipw.println(mIsActive);
1032             ipw.print("mIsEnabled=");
1033             ipw.println(mIsEnabled);
1034             ipw.print("mSupportedConfig=");
1035             ipw.println(mSupportedConfig);
1036             ipw.print("mEnabledByDefaultConfig=");
1037             ipw.println(mEnabledByDefaultConfig);
1038             ipw.print("mStandbyTimeoutConfig=");
1039             ipw.println(mStandbyTimeoutConfig);
1040             ipw.print("mEnableCustomPolicy=");
1041             ipw.println(mEnableCustomPolicy);
1042 
1043             if (mIsActive || mIsEnabled) {
1044                 ipw.print("mIsInteractive=");
1045                 ipw.println(mIsInteractive);
1046                 ipw.print("mLastInteractiveTime=");
1047                 ipw.println(mLastInteractiveTimeElapsed);
1048                 ipw.print("mIdleSinceNonInteractive=");
1049                 ipw.println(mIdleSinceNonInteractive);
1050                 ipw.print("mIsDeviceIdle=");
1051                 ipw.println(mIsDeviceIdle);
1052             }
1053 
1054             final int[] allowlistUids = getAllowlistUidsLocked();
1055             ipw.print("Allowed UIDs=");
1056             ipw.println(Arrays.toString(allowlistUids));
1057 
1058             final LowPowerStandbyPolicy policy = getPolicy();
1059             if (policy != null) {
1060                 ipw.println();
1061                 ipw.println("mPolicy:");
1062                 ipw.increaseIndent();
1063                 ipw.print("mIdentifier=");
1064                 ipw.println(policy.getIdentifier());
1065                 ipw.print("mExemptPackages=");
1066                 ipw.println(String.join(",", policy.getExemptPackages()));
1067                 ipw.print("mAllowedReasons=");
1068                 ipw.println(lowPowerStandbyAllowedReasonsToString(policy.getAllowedReasons()));
1069                 ipw.print("mAllowedFeatures=");
1070                 ipw.println(String.join(",", policy.getAllowedFeatures()));
1071                 ipw.decreaseIndent();
1072             }
1073 
1074             ipw.println();
1075             ipw.println("UID allowed reasons:");
1076             ipw.increaseIndent();
1077             for (int i = 0; i < mUidAllowedReasons.size(); i++) {
1078                 if (mUidAllowedReasons.valueAt(i) > 0) {
1079                     ipw.print(mUidAllowedReasons.keyAt(i));
1080                     ipw.print(": ");
1081                     ipw.println(
1082                             lowPowerStandbyAllowedReasonsToString(mUidAllowedReasons.valueAt(i)));
1083                 }
1084             }
1085             ipw.decreaseIndent();
1086 
1087             final List<LowPowerStandbyPortDescription> activeStandbyPorts = getActiveStandbyPorts();
1088             if (!activeStandbyPorts.isEmpty()) {
1089                 ipw.println();
1090                 ipw.println("Active standby ports locks:");
1091                 ipw.increaseIndent();
1092                 for (LowPowerStandbyPortDescription portDescription : activeStandbyPorts) {
1093                     ipw.print(portDescription.toString());
1094                 }
1095                 ipw.decreaseIndent();
1096             }
1097         }
1098         ipw.decreaseIndent();
1099     }
1100 
dumpProto(ProtoOutputStream proto, long tag)1101     void dumpProto(ProtoOutputStream proto, long tag) {
1102         synchronized (mLock) {
1103             final long token = proto.start(tag);
1104             proto.write(LowPowerStandbyControllerDumpProto.IS_ACTIVE, mIsActive);
1105             proto.write(LowPowerStandbyControllerDumpProto.IS_ENABLED, mIsEnabled);
1106             proto.write(LowPowerStandbyControllerDumpProto.IS_SUPPORTED_CONFIG, mSupportedConfig);
1107             proto.write(LowPowerStandbyControllerDumpProto.IS_ENABLED_BY_DEFAULT_CONFIG,
1108                     mEnabledByDefaultConfig);
1109             proto.write(LowPowerStandbyControllerDumpProto.IS_INTERACTIVE, mIsInteractive);
1110             proto.write(LowPowerStandbyControllerDumpProto.LAST_INTERACTIVE_TIME,
1111                     mLastInteractiveTimeElapsed);
1112             proto.write(LowPowerStandbyControllerDumpProto.STANDBY_TIMEOUT_CONFIG,
1113                     mStandbyTimeoutConfig);
1114             proto.write(LowPowerStandbyControllerDumpProto.IDLE_SINCE_NON_INTERACTIVE,
1115                     mIdleSinceNonInteractive);
1116             proto.write(LowPowerStandbyControllerDumpProto.IS_DEVICE_IDLE, mIsDeviceIdle);
1117 
1118             final int[] allowlistUids = getAllowlistUidsLocked();
1119             for (int appId : allowlistUids) {
1120                 proto.write(LowPowerStandbyControllerDumpProto.ALLOWLIST, appId);
1121             }
1122 
1123             final LowPowerStandbyPolicy policy = getPolicy();
1124             if (policy != null) {
1125                 long policyToken = proto.start(LowPowerStandbyControllerDumpProto.POLICY);
1126                 proto.write(LowPowerStandbyPolicyProto.IDENTIFIER, policy.getIdentifier());
1127                 for (String exemptPackage : policy.getExemptPackages()) {
1128                     proto.write(LowPowerStandbyPolicyProto.EXEMPT_PACKAGES, exemptPackage);
1129                 }
1130                 proto.write(LowPowerStandbyPolicyProto.ALLOWED_REASONS, policy.getAllowedReasons());
1131                 for (String feature : policy.getAllowedFeatures()) {
1132                     proto.write(LowPowerStandbyPolicyProto.ALLOWED_FEATURES, feature);
1133                 }
1134                 proto.end(policyToken);
1135             }
1136             proto.end(token);
1137         }
1138     }
1139 
1140     private class LowPowerStandbyHandler extends Handler {
LowPowerStandbyHandler(Looper looper)1141         LowPowerStandbyHandler(Looper looper) {
1142             super(looper);
1143         }
1144 
1145         @Override
handleMessage(Message msg)1146         public void handleMessage(Message msg) {
1147             switch (msg.what) {
1148                 case MSG_STANDBY_TIMEOUT:
1149                     onStandbyTimeoutExpired();
1150                     break;
1151                 case MSG_NOTIFY_ACTIVE_CHANGED:
1152                     boolean active = (boolean) msg.obj;
1153                     notifyActiveChanged(active);
1154                     break;
1155                 case MSG_NOTIFY_ALLOWLIST_CHANGED:
1156                     final int[] allowlistUids = (int[]) msg.obj;
1157                     notifyAllowlistChanged(allowlistUids);
1158                     break;
1159                 case MSG_NOTIFY_POLICY_CHANGED:
1160                     notifyPolicyChanged((LowPowerStandbyPolicy) msg.obj);
1161                     break;
1162                 case MSG_FOREGROUND_SERVICE_STATE_CHANGED:
1163                     final int uid = msg.arg1;
1164                     mPhoneCallServiceTracker.foregroundServiceStateChanged(uid);
1165                     break;
1166                 case MSG_NOTIFY_STANDBY_PORTS_CHANGED:
1167                     notifyStandbyPortsChanged();
1168                     break;
1169             }
1170         }
1171     }
1172 
1173     @GuardedBy("mLock")
hasAllowedReasonLocked(int uid, @LowPowerStandbyAllowedReason int allowedReason)1174     private boolean hasAllowedReasonLocked(int uid,
1175             @LowPowerStandbyAllowedReason int allowedReason) {
1176         int allowedReasons = mUidAllowedReasons.get(uid);
1177         return (allowedReasons & allowedReason) != 0;
1178     }
1179 
1180     @GuardedBy("mLock")
addAllowedReasonLocked(int uid, @LowPowerStandbyAllowedReason int allowedReason)1181     private boolean addAllowedReasonLocked(int uid,
1182             @LowPowerStandbyAllowedReason int allowedReason) {
1183         int allowedReasons = mUidAllowedReasons.get(uid);
1184         final int newAllowReasons = allowedReasons | allowedReason;
1185         mUidAllowedReasons.put(uid, newAllowReasons);
1186         return allowedReasons != newAllowReasons;
1187     }
1188 
1189     @GuardedBy("mLock")
removeAllowedReasonLocked(int uid, @LowPowerStandbyAllowedReason int allowedReason)1190     private boolean removeAllowedReasonLocked(int uid,
1191             @LowPowerStandbyAllowedReason int allowedReason) {
1192         int allowedReasons = mUidAllowedReasons.get(uid);
1193         if (allowedReasons == 0) {
1194             return false;
1195         }
1196 
1197         final int newAllowedReasons = allowedReasons & ~allowedReason;
1198         if (newAllowedReasons == 0) {
1199             mUidAllowedReasons.removeAt(mUidAllowedReasons.indexOfKey(uid));
1200         } else {
1201             mUidAllowedReasons.put(uid, newAllowedReasons);
1202         }
1203         return allowedReasons != newAllowedReasons;
1204     }
1205 
addToAllowlistInternal(int uid, @LowPowerStandbyAllowedReason int allowedReason)1206     private void addToAllowlistInternal(int uid, @LowPowerStandbyAllowedReason int allowedReason) {
1207         if (DEBUG) {
1208             Slog.i(TAG,
1209                     "Adding to allowlist: uid=" + uid + ", allowedReason=" + allowedReason);
1210         }
1211         synchronized (mLock) {
1212             if (!mSupportedConfig) {
1213                 return;
1214             }
1215             if (allowedReason != 0 && !hasAllowedReasonLocked(uid, allowedReason)) {
1216                 addAllowedReasonLocked(uid, allowedReason);
1217                 if ((getPolicy().getAllowedReasons() & allowedReason) != 0) {
1218                     enqueueNotifyAllowlistChangedLocked();
1219                 }
1220             }
1221         }
1222     }
1223 
removeFromAllowlistInternal(int uid, @LowPowerStandbyAllowedReason int allowedReason)1224     private void removeFromAllowlistInternal(int uid,
1225             @LowPowerStandbyAllowedReason int allowedReason) {
1226         if (DEBUG) {
1227             Slog.i(TAG, "Removing from allowlist: uid=" + uid + ", allowedReason=" + allowedReason);
1228         }
1229         synchronized (mLock) {
1230             if (!mSupportedConfig) {
1231                 return;
1232             }
1233             if (allowedReason != 0 && hasAllowedReasonLocked(uid, allowedReason)) {
1234                 removeAllowedReasonLocked(uid, allowedReason);
1235                 if ((getPolicy().getAllowedReasons() & allowedReason) != 0) {
1236                     enqueueNotifyAllowlistChangedLocked();
1237                 }
1238             }
1239         }
1240     }
1241 
1242     @GuardedBy("mLock")
1243     @NonNull
getExemptPackageAppIdsLocked()1244     private List<Integer> getExemptPackageAppIdsLocked() {
1245         final PackageManager packageManager = mContext.getPackageManager();
1246         final LowPowerStandbyPolicy policy = getPolicy();
1247         final List<Integer> appIds = new ArrayList<>();
1248         if (policy == null) {
1249             return appIds;
1250         }
1251 
1252         for (String packageName : policy.getExemptPackages()) {
1253             try {
1254                 int packageUid = packageManager.getPackageUid(packageName,
1255                         PackageManager.PackageInfoFlags.of(0));
1256                 int appId = UserHandle.getAppId(packageUid);
1257                 appIds.add(appId);
1258             } catch (PackageManager.NameNotFoundException e) {
1259                 if (DEBUG) {
1260                     Slog.d(TAG, "Package UID cannot be resolved: packageName=" + packageName);
1261                 }
1262             }
1263         }
1264 
1265         return appIds;
1266     }
1267 
1268     @GuardedBy("mLock")
getAllowlistUidsLocked()1269     private int[] getAllowlistUidsLocked() {
1270         final UserManager userManager = mContext.getSystemService(UserManager.class);
1271         final List<UserHandle> userHandles = userManager.getUserHandles(true);
1272         final ArraySet<Integer> uids = new ArraySet<>(mUidAllowedReasons.size());
1273         final LowPowerStandbyPolicy policy = getPolicy();
1274         if (policy == null) {
1275             return new int[0];
1276         }
1277 
1278         final int policyAllowedReasons = policy.getAllowedReasons();
1279         for (int i = 0; i < mUidAllowedReasons.size(); i++) {
1280             Integer uid = mUidAllowedReasons.keyAt(i);
1281             if ((mUidAllowedReasons.valueAt(i) & policyAllowedReasons) != 0) {
1282                 uids.add(uid);
1283             }
1284         }
1285 
1286         for (int appId : getExemptPackageAppIdsLocked()) {
1287             for (int uid : uidsForAppId(appId, userHandles)) {
1288                 uids.add(uid);
1289             }
1290         }
1291 
1292         int[] allowlistUids = new int[uids.size()];
1293         for (int i = 0; i < uids.size(); i++) {
1294             allowlistUids[i] = uids.valueAt(i);
1295         }
1296         Arrays.sort(allowlistUids);
1297         return allowlistUids;
1298     }
1299 
uidsForAppId(int appUid, List<UserHandle> userHandles)1300     private int[] uidsForAppId(int appUid, List<UserHandle> userHandles) {
1301         final int appId = UserHandle.getAppId(appUid);
1302         final int[] uids = new int[userHandles.size()];
1303         for (int i = 0; i < userHandles.size(); i++) {
1304             uids[i] = userHandles.get(i).getUid(appId);
1305         }
1306         return uids;
1307     }
1308 
1309     @GuardedBy("mLock")
enqueueNotifyAllowlistChangedLocked()1310     private void enqueueNotifyAllowlistChangedLocked() {
1311         final long now = mClock.elapsedRealtime();
1312         final int[] allowlistUids = getAllowlistUidsLocked();
1313 
1314         if (DEBUG) {
1315             Slog.d(TAG, "enqueueNotifyAllowlistChangedLocked: allowlistUids=" + Arrays.toString(
1316                     allowlistUids));
1317         }
1318 
1319         final Message msg = mHandler.obtainMessage(MSG_NOTIFY_ALLOWLIST_CHANGED, allowlistUids);
1320         mHandler.sendMessageAtTime(msg, now);
1321     }
1322 
notifyAllowlistChanged(int[] allowlistUids)1323     private void notifyAllowlistChanged(int[] allowlistUids) {
1324         if (DEBUG) {
1325             Slog.d(TAG, "notifyAllowlistChanged: " + Arrays.toString(allowlistUids));
1326         }
1327 
1328         final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
1329         final NetworkPolicyManagerInternal npmi = LocalServices.getService(
1330                 NetworkPolicyManagerInternal.class);
1331         pmi.setLowPowerStandbyAllowlist(allowlistUids);
1332         npmi.setLowPowerStandbyAllowlist(allowlistUids);
1333     }
1334 
1335     @GuardedBy("mLock")
enqueueNotifyStandbyPortsChangedLocked()1336     private void enqueueNotifyStandbyPortsChangedLocked() {
1337         final long now = mClock.elapsedRealtime();
1338 
1339         if (DEBUG) {
1340             Slog.d(TAG, "enqueueNotifyStandbyPortsChangedLocked");
1341         }
1342 
1343         final Message msg = mHandler.obtainMessage(MSG_NOTIFY_STANDBY_PORTS_CHANGED);
1344         mHandler.sendMessageAtTime(msg, now);
1345     }
1346 
notifyStandbyPortsChanged()1347     private void notifyStandbyPortsChanged() {
1348         if (DEBUG) {
1349             Slog.d(TAG, "notifyStandbyPortsChanged");
1350         }
1351 
1352         final Intent intent = new Intent(PowerManager.ACTION_LOW_POWER_STANDBY_PORTS_CHANGED);
1353         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
1354         mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
1355                 Manifest.permission.MANAGE_LOW_POWER_STANDBY);
1356     }
1357 
1358     /**
1359      * Class that is used to read device config for low power standby configuration.
1360      */
1361     @VisibleForTesting
1362     public static class DeviceConfigWrapper {
1363         public static final String NAMESPACE = "low_power_standby";
1364         public static final String FEATURE_FLAG_ENABLE_POLICY = "enable_policy";
1365         public static final String FEATURE_FLAG_ENABLE_STANDBY_PORTS = "enable_standby_ports";
1366 
1367         /**
1368          * Returns true if custom policies are enabled.
1369          * Otherwise, returns false, and the default policy will be used.
1370          */
enableCustomPolicy()1371         public boolean enableCustomPolicy() {
1372             return DeviceConfig.getBoolean(NAMESPACE, FEATURE_FLAG_ENABLE_POLICY, false);
1373         }
1374 
1375         /**
1376          * Returns true if standby ports are enabled.
1377          * Otherwise, returns false, and {@link #getActiveStandbyPorts()} will always be empty.
1378          */
enableStandbyPorts()1379         public boolean enableStandbyPorts() {
1380             return DeviceConfig.getBoolean(NAMESPACE, FEATURE_FLAG_ENABLE_STANDBY_PORTS, false);
1381         }
1382 
1383         /**
1384          * Registers a DeviceConfig update listener.
1385          */
registerPropertyUpdateListener( @onNull Executor executor, @NonNull DeviceConfig.OnPropertiesChangedListener onPropertiesChangedListener)1386         public void registerPropertyUpdateListener(
1387                 @NonNull Executor executor,
1388                 @NonNull DeviceConfig.OnPropertiesChangedListener onPropertiesChangedListener) {
1389             DeviceConfig.addOnPropertiesChangedListener(NAMESPACE, executor,
1390                     onPropertiesChangedListener);
1391         }
1392     }
1393 
1394     private final class LocalService extends LowPowerStandbyControllerInternal {
1395         @Override
addToAllowlist(int uid, @LowPowerStandbyAllowedReason int allowedReason)1396         public void addToAllowlist(int uid, @LowPowerStandbyAllowedReason int allowedReason) {
1397             addToAllowlistInternal(uid, allowedReason);
1398         }
1399 
1400         @Override
removeFromAllowlist(int uid, @LowPowerStandbyAllowedReason int allowedReason)1401         public void removeFromAllowlist(int uid, @LowPowerStandbyAllowedReason int allowedReason) {
1402             removeFromAllowlistInternal(uid, allowedReason);
1403         }
1404     }
1405 
1406     private final class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler)1407         SettingsObserver(Handler handler) {
1408             super(handler);
1409         }
1410 
1411         @Override
onChange(boolean selfChange, Uri uri)1412         public void onChange(boolean selfChange, Uri uri) {
1413             onSettingsChanged();
1414         }
1415     }
1416 
1417     final class TempAllowlistChangeListener implements
1418             PowerAllowlistInternal.TempAllowlistChangeListener {
1419         @Override
onAppAdded(int uid)1420         public void onAppAdded(int uid) {
1421             addToAllowlistInternal(uid, LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST);
1422         }
1423 
1424         @Override
onAppRemoved(int uid)1425         public void onAppRemoved(int uid) {
1426             removeFromAllowlistInternal(uid,
1427                     LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST);
1428         }
1429     }
1430 
1431     final class PhoneCallServiceTracker extends IForegroundServiceObserver.Stub {
1432         private boolean mRegistered = false;
1433         private final SparseBooleanArray mUidsWithPhoneCallService = new SparseBooleanArray();
1434 
register()1435         public void register() {
1436             if (mRegistered) {
1437                 return;
1438             }
1439             try {
1440                 mActivityManager.get().registerForegroundServiceObserver(this);
1441                 mRegistered = true;
1442             } catch (RemoteException e) {
1443                 // call within system server
1444             }
1445         }
1446 
1447         @Override
onForegroundStateChanged(IBinder serviceToken, String packageName, int userId, boolean isForeground)1448         public void onForegroundStateChanged(IBinder serviceToken, String packageName,
1449                 int userId, boolean isForeground) {
1450             try {
1451                 final long now = mClock.elapsedRealtime();
1452                 final int uid = mContext.getPackageManager()
1453                         .getPackageUidAsUser(packageName, userId);
1454                 final Message message =
1455                         mHandler.obtainMessage(MSG_FOREGROUND_SERVICE_STATE_CHANGED, uid, 0);
1456                 mHandler.sendMessageAtTime(message, now);
1457             } catch (PackageManager.NameNotFoundException e) {
1458                 if (DEBUG) {
1459                     Slog.d(TAG, "onForegroundStateChanged: Unknown package: " + packageName
1460                             + ", userId=" + userId);
1461                 }
1462             }
1463         }
1464 
foregroundServiceStateChanged(int uid)1465         public void foregroundServiceStateChanged(int uid) {
1466             if (DEBUG) {
1467                 Slog.d(TAG, "foregroundServiceStateChanged: uid=" + uid);
1468             }
1469 
1470             final boolean hadPhoneCallService = mUidsWithPhoneCallService.get(uid);
1471             final boolean hasPhoneCallService =
1472                     mActivityManagerInternal.hasRunningForegroundService(uid,
1473                             ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL);
1474 
1475             if (DEBUG) {
1476                 Slog.d(TAG, "uid=" + uid + ", hasPhoneCallService=" + hasPhoneCallService
1477                         + ", hadPhoneCallService=" + hadPhoneCallService);
1478             }
1479 
1480             if (hasPhoneCallService == hadPhoneCallService) {
1481                 return;
1482             }
1483 
1484             if (hasPhoneCallService) {
1485                 mUidsWithPhoneCallService.append(uid, true);
1486                 uidStartedPhoneCallService(uid);
1487             } else {
1488                 mUidsWithPhoneCallService.delete(uid);
1489                 uidStoppedPhoneCallService(uid);
1490             }
1491         }
1492 
uidStartedPhoneCallService(int uid)1493         private void uidStartedPhoneCallService(int uid) {
1494             if (DEBUG) {
1495                 Slog.d(TAG, "FGS of type phoneCall started: uid=" + uid);
1496             }
1497             addToAllowlistInternal(uid, LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL);
1498         }
1499 
uidStoppedPhoneCallService(int uid)1500         private void uidStoppedPhoneCallService(int uid) {
1501             if (DEBUG) {
1502                 Slog.d(TAG, "FGSs of type phoneCall stopped: uid=" + uid);
1503             }
1504             removeFromAllowlistInternal(uid, LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL);
1505         }
1506     }
1507 }
1508