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