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.tare;
18 
19 import static android.app.tare.EconomyManager.ENABLED_MODE_OFF;
20 import static android.app.tare.EconomyManager.ENABLED_MODE_ON;
21 import static android.app.tare.EconomyManager.ENABLED_MODE_SHADOW;
22 import static android.app.tare.EconomyManager.enabledModeToString;
23 import static android.provider.Settings.Global.TARE_ALARM_MANAGER_CONSTANTS;
24 import static android.provider.Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS;
25 import static android.text.format.DateUtils.DAY_IN_MILLIS;
26 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
27 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
28 
29 import static com.android.server.tare.TareUtils.appToString;
30 import static com.android.server.tare.TareUtils.cakeToString;
31 import static com.android.server.tare.TareUtils.getCurrentTimeMillis;
32 
33 import android.annotation.NonNull;
34 import android.annotation.Nullable;
35 import android.app.AlarmManager;
36 import android.app.AppOpsManager;
37 import android.app.tare.EconomyManager;
38 import android.app.tare.IEconomyManager;
39 import android.app.usage.UsageEvents;
40 import android.app.usage.UsageStatsManagerInternal;
41 import android.content.BroadcastReceiver;
42 import android.content.ContentResolver;
43 import android.content.Context;
44 import android.content.Intent;
45 import android.content.IntentFilter;
46 import android.content.pm.PackageInfo;
47 import android.content.pm.PackageManager;
48 import android.content.pm.PackageManagerInternal;
49 import android.database.ContentObserver;
50 import android.net.Uri;
51 import android.os.BatteryManager;
52 import android.os.BatteryManagerInternal;
53 import android.os.Binder;
54 import android.os.Handler;
55 import android.os.IDeviceIdleController;
56 import android.os.Looper;
57 import android.os.Message;
58 import android.os.ParcelFileDescriptor;
59 import android.os.PowerManager;
60 import android.os.RemoteException;
61 import android.os.ServiceManager;
62 import android.os.SystemClock;
63 import android.os.UserHandle;
64 import android.provider.DeviceConfig;
65 import android.provider.Settings;
66 import android.util.ArraySet;
67 import android.util.IndentingPrintWriter;
68 import android.util.Log;
69 import android.util.Slog;
70 import android.util.SparseArrayMap;
71 import android.util.SparseLongArray;
72 import android.util.SparseSetArray;
73 
74 import com.android.internal.annotations.GuardedBy;
75 import com.android.internal.app.IAppOpsCallback;
76 import com.android.internal.app.IAppOpsService;
77 import com.android.internal.os.SomeArgs;
78 import com.android.internal.util.ArrayUtils;
79 import com.android.internal.util.DumpUtils;
80 import com.android.server.LocalServices;
81 import com.android.server.SystemService;
82 import com.android.server.pm.UserManagerInternal;
83 import com.android.server.tare.EconomicPolicy.Cost;
84 import com.android.server.tare.EconomyManagerInternal.TareStateChangeListener;
85 
86 import java.io.FileDescriptor;
87 import java.io.PrintWriter;
88 import java.util.ArrayList;
89 import java.util.List;
90 import java.util.Objects;
91 
92 /**
93  * Responsible for handling app's ARC count based on events, ensuring ARCs are credited when
94  * appropriate, and reclaiming ARCs at the right times. The IRS deals with the high level details
95  * while the {@link Agent} deals with the nitty-gritty details.
96  *
97  * Note on locking: Any function with the suffix 'Locked' needs to lock on {@link #mLock}.
98  *
99  * @hide
100  */
101 public class InternalResourceService extends SystemService {
102     public static final String TAG = "TARE-IRS";
103     public static final boolean DEBUG = Log.isLoggable("TARE", Log.DEBUG);
104 
105     static final long UNUSED_RECLAMATION_PERIOD_MS = 24 * HOUR_IN_MILLIS;
106     /** How much of an app's unused wealth should be reclaimed periodically. */
107     private static final float DEFAULT_UNUSED_RECLAMATION_PERCENTAGE = .1f;
108     /**
109      * The minimum amount of time an app must not have been used by the user before we start
110      * periodically reclaiming ARCs from it.
111      */
112     private static final long MIN_UNUSED_TIME_MS = 3 * DAY_IN_MILLIS;
113     /** The amount of time to delay reclamation by after boot. */
114     private static final long RECLAMATION_STARTUP_DELAY_MS = 30_000L;
115     /**
116      * The amount of time after TARE has first been set up that a system installer will be allowed
117      * expanded credit privileges.
118      */
119     static final long INSTALLER_FIRST_SETUP_GRACE_PERIOD_MS = 7 * DAY_IN_MILLIS;
120     /**
121      * The amount of time to wait after TARE has first been set up before considering adjusting the
122      * stock/consumption limit.
123      */
124     private static final long STOCK_ADJUSTMENT_FIRST_SETUP_GRACE_PERIOD_MS = 5 * DAY_IN_MILLIS;
125     /**
126      * The battery level above which we may consider quantitative easing (increasing the consumption
127      * limit).
128      */
129     private static final int QUANTITATIVE_EASING_BATTERY_THRESHOLD = 50;
130     /**
131      * The battery level above which we may consider adjusting the desired stock level.
132      */
133     private static final int STOCK_RECALCULATION_BATTERY_THRESHOLD = 80;
134     /**
135      * The amount of time to wait before considering recalculating the desired stock level.
136      */
137     private static final long STOCK_RECALCULATION_DELAY_MS = 16 * HOUR_IN_MILLIS;
138     /**
139      * The minimum amount of time we must have background drain for before considering
140      * recalculating the desired stock level.
141      */
142     private static final long STOCK_RECALCULATION_MIN_DATA_DURATION_MS = 8 * HOUR_IN_MILLIS;
143     private static final int PACKAGE_QUERY_FLAGS =
144             PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
145                     | PackageManager.MATCH_APEX | PackageManager.GET_PERMISSIONS;
146 
147     /** Global lock for all resource economy state. */
148     private final Object mLock = new Object();
149 
150     private final Handler mHandler;
151     private final BatteryManagerInternal mBatteryManagerInternal;
152     private final PackageManager mPackageManager;
153     private final PackageManagerInternal mPackageManagerInternal;
154 
155     private IAppOpsService mAppOpsService;
156     private IDeviceIdleController mDeviceIdleController;
157 
158     private final Agent mAgent;
159     private final Analyst mAnalyst;
160     private final ConfigObserver mConfigObserver;
161     private final EconomyManagerStub mEconomyManagerStub;
162     private final Scribe mScribe;
163 
164     @GuardedBy("mLock")
165     private CompleteEconomicPolicy mCompleteEconomicPolicy;
166 
167     @NonNull
168     @GuardedBy("mLock")
169     private final SparseArrayMap<String, InstalledPackageInfo> mPkgCache = new SparseArrayMap<>();
170 
171     /** Cached mapping of UIDs (for all users) to a list of packages in the UID. */
172     @GuardedBy("mLock")
173     private final SparseSetArray<String> mUidToPackageCache = new SparseSetArray<>();
174 
175     /** Cached mapping of userId+package to their UIDs (for all users) */
176     @GuardedBy("mPackageToUidCache")
177     private final SparseArrayMap<String, Integer> mPackageToUidCache = new SparseArrayMap<>();
178 
179     @GuardedBy("mStateChangeListeners")
180     private final SparseSetArray<TareStateChangeListener> mStateChangeListeners =
181             new SparseSetArray<>();
182 
183     /**
184      * List of packages that are fully restricted and shouldn't be allowed to run in the background.
185      */
186     @GuardedBy("mLock")
187     private final SparseSetArray<String> mRestrictedApps = new SparseSetArray<>();
188 
189     /** List of packages that are "exempted" from battery restrictions. */
190     // TODO(144864180): include userID
191     @GuardedBy("mLock")
192     private ArraySet<String> mExemptedApps = new ArraySet<>();
193 
194     @GuardedBy("mLock")
195     private final SparseArrayMap<String, Boolean> mVipOverrides = new SparseArrayMap<>();
196 
197     /**
198      * Set of temporary Very Important Packages and when their VIP status ends, in the elapsed
199      * realtime ({@link android.annotation.ElapsedRealtimeLong}) timebase.
200      */
201     @GuardedBy("mLock")
202     private final SparseArrayMap<String, Long> mTemporaryVips = new SparseArrayMap<>();
203 
204     /** Set of apps each installer is responsible for installing. */
205     @GuardedBy("mLock")
206     private final SparseArrayMap<String, ArraySet<String>> mInstallers = new SparseArrayMap<>();
207 
208     /** The package name of the wellbeing app. */
209     @GuardedBy("mLock")
210     @Nullable
211     private String mWellbeingPackage;
212 
213     private volatile boolean mHasBattery = true;
214     @EconomyManager.EnabledMode
215     private volatile int mEnabledMode;
216     private volatile int mBootPhase;
217     private volatile boolean mExemptListLoaded;
218     // In the range [0,100] to represent 0% to 100% battery.
219     @GuardedBy("mLock")
220     private int mCurrentBatteryLevel;
221 
222     // TODO(250007395): make configurable per device (via config.xml)
223     private final int mDefaultTargetBackgroundBatteryLifeHours;
224     @GuardedBy("mLock")
225     private int mTargetBackgroundBatteryLifeHours;
226 
227     private final IAppOpsCallback mApbListener = new IAppOpsCallback.Stub() {
228         @Override
229         public void opChanged(int op, int uid, String packageName) {
230             boolean restricted = false;
231             try {
232                 restricted = mAppOpsService.checkOperation(
233                         AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName)
234                         != AppOpsManager.MODE_ALLOWED;
235             } catch (RemoteException e) {
236                 // Shouldn't happen
237             }
238             final int userId = UserHandle.getUserId(uid);
239             synchronized (mLock) {
240                 if (restricted) {
241                     if (mRestrictedApps.add(userId, packageName)) {
242                         mAgent.onAppRestrictedLocked(userId, packageName);
243                     }
244                 } else if (mRestrictedApps.remove(UserHandle.getUserId(uid), packageName)) {
245                     mAgent.onAppUnrestrictedLocked(userId, packageName);
246                 }
247             }
248         }
249     };
250 
251     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
252         @Nullable
253         private String getPackageName(Intent intent) {
254             Uri uri = intent.getData();
255             return uri != null ? uri.getSchemeSpecificPart() : null;
256         }
257 
258         @Override
259         public void onReceive(Context context, Intent intent) {
260             switch (intent.getAction()) {
261                 case Intent.ACTION_BATTERY_CHANGED: {
262                     final boolean hasBattery =
263                             intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, mHasBattery);
264                     if (mHasBattery != hasBattery) {
265                         mHasBattery = hasBattery;
266                         mConfigObserver.updateEnabledStatus();
267                     }
268                 }
269                 break;
270                 case Intent.ACTION_BATTERY_LEVEL_CHANGED:
271                     onBatteryLevelChanged();
272                     break;
273                 case Intent.ACTION_PACKAGE_FULLY_REMOVED: {
274                     final String pkgName = getPackageName(intent);
275                     final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
276                     onPackageRemoved(pkgUid, pkgName);
277                 }
278                 break;
279                 case Intent.ACTION_PACKAGE_ADDED: {
280                     if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
281                         final String pkgName = getPackageName(intent);
282                         final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
283                         onPackageAdded(pkgUid, pkgName);
284                     }
285                 }
286                 break;
287                 case Intent.ACTION_PACKAGE_RESTARTED: {
288                     final String pkgName = getPackageName(intent);
289                     final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
290                     final int userId = UserHandle.getUserId(pkgUid);
291                     onPackageForceStopped(userId, pkgName);
292                 }
293                 break;
294                 case Intent.ACTION_USER_ADDED: {
295                     final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
296                     onUserAdded(userId);
297                 }
298                 break;
299                 case Intent.ACTION_USER_REMOVED: {
300                     final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
301                     onUserRemoved(userId);
302                 }
303                 break;
304                 case PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED:
305                     onExemptionListChanged();
306                     break;
307             }
308         }
309     };
310 
311     private final UsageStatsManagerInternal.UsageEventListener mSurveillanceAgent =
312             new UsageStatsManagerInternal.UsageEventListener() {
313                 /**
314                  * Callback to inform listeners of a new event.
315                  */
316                 @Override
317                 public void onUsageEvent(int userId, @NonNull UsageEvents.Event event) {
318                     mHandler.obtainMessage(MSG_PROCESS_USAGE_EVENT, userId, 0, event)
319                             .sendToTarget();
320                 }
321             };
322 
323     private final AlarmManager.OnAlarmListener mUnusedWealthReclamationListener =
324             new AlarmManager.OnAlarmListener() {
325                 @Override
326                 public void onAlarm() {
327                     synchronized (mLock) {
328                         mAgent.reclaimUnusedAssetsLocked(
329                                 DEFAULT_UNUSED_RECLAMATION_PERCENTAGE, MIN_UNUSED_TIME_MS, false);
330                         mScribe.setLastReclamationTimeLocked(getCurrentTimeMillis());
331                         scheduleUnusedWealthReclamationLocked();
332                     }
333                 }
334             };
335 
336     private static final int MSG_NOTIFY_AFFORDABILITY_CHANGE_LISTENER = 0;
337     private static final int MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT = 1;
338     private static final int MSG_PROCESS_USAGE_EVENT = 2;
339     private static final int MSG_NOTIFY_STATE_CHANGE_LISTENERS = 3;
340     private static final int MSG_NOTIFY_STATE_CHANGE_LISTENER = 4;
341     private static final int MSG_CLEAN_UP_TEMP_VIP_LIST = 5;
342     private static final String ALARM_TAG_WEALTH_RECLAMATION = "*tare.reclamation*";
343 
344     /**
345      * Initializes the system service.
346      * <p>
347      * Subclasses must define a single argument constructor that accepts the context
348      * and passes it to super.
349      * </p>
350      *
351      * @param context The system server context.
352      */
InternalResourceService(Context context)353     public InternalResourceService(Context context) {
354         super(context);
355 
356         mHandler = new IrsHandler(TareHandlerThread.get().getLooper());
357         mBatteryManagerInternal = LocalServices.getService(BatteryManagerInternal.class);
358         mPackageManager = context.getPackageManager();
359         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
360         mEconomyManagerStub = new EconomyManagerStub();
361         mAnalyst = new Analyst();
362         mScribe = new Scribe(this, mAnalyst);
363         mCompleteEconomicPolicy = new CompleteEconomicPolicy(this);
364         mAgent = new Agent(this, mScribe, mAnalyst);
365 
366         mConfigObserver = new ConfigObserver(mHandler, context);
367 
368         mDefaultTargetBackgroundBatteryLifeHours =
369                 mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)
370                         ? 100 // ~ 1.0%/hr
371                         : 40; // ~ 2.5%/hr
372         mTargetBackgroundBatteryLifeHours = mDefaultTargetBackgroundBatteryLifeHours;
373 
374         publishLocalService(EconomyManagerInternal.class, new LocalService());
375     }
376 
377     @Override
onStart()378     public void onStart() {
379         publishBinderService(Context.RESOURCE_ECONOMY_SERVICE, mEconomyManagerStub);
380     }
381 
382     @Override
onBootPhase(int phase)383     public void onBootPhase(int phase) {
384         mBootPhase = phase;
385 
386         switch (phase) {
387             case PHASE_SYSTEM_SERVICES_READY:
388                 mAppOpsService = IAppOpsService.Stub.asInterface(
389                         ServiceManager.getService(Context.APP_OPS_SERVICE));
390                 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
391                         ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
392                 mConfigObserver.start();
393                 onBootPhaseSystemServicesReady();
394                 break;
395             case PHASE_THIRD_PARTY_APPS_CAN_START:
396                 onBootPhaseThirdPartyAppsCanStart();
397                 break;
398             case PHASE_BOOT_COMPLETED:
399                 onBootPhaseBootCompleted();
400                 break;
401         }
402     }
403 
404     @NonNull
getLock()405     Object getLock() {
406         return mLock;
407     }
408 
409     /** Returns the installed packages for all users. */
410     @NonNull
411     @GuardedBy("mLock")
getCompleteEconomicPolicyLocked()412     CompleteEconomicPolicy getCompleteEconomicPolicyLocked() {
413         return mCompleteEconomicPolicy;
414     }
415 
416     /** Returns the number of apps that this app is expected to update at some point. */
getAppUpdateResponsibilityCount(final int userId, @NonNull final String pkgName)417     int getAppUpdateResponsibilityCount(final int userId, @NonNull final String pkgName) {
418         synchronized (mLock) {
419             // TODO(248274798): return 0 if the app has lost the install permission
420             return ArrayUtils.size(mInstallers.get(userId, pkgName));
421         }
422     }
423 
424     @NonNull
getInstalledPackages()425     SparseArrayMap<String, InstalledPackageInfo> getInstalledPackages() {
426         synchronized (mLock) {
427             return mPkgCache;
428         }
429     }
430 
431     /** Returns the installed packages for the specified user. */
432     @NonNull
getInstalledPackages(final int userId)433     List<InstalledPackageInfo> getInstalledPackages(final int userId) {
434         final List<InstalledPackageInfo> userPkgs = new ArrayList<>();
435         synchronized (mLock) {
436             final int uIdx = mPkgCache.indexOfKey(userId);
437             if (uIdx < 0) {
438                 return userPkgs;
439             }
440             for (int p = mPkgCache.numElementsForKeyAt(uIdx) - 1; p >= 0; --p) {
441                 final InstalledPackageInfo packageInfo = mPkgCache.valueAt(uIdx, p);
442                 userPkgs.add(packageInfo);
443             }
444         }
445         return userPkgs;
446     }
447 
448     @Nullable
getInstalledPackageInfo(final int userId, @NonNull final String pkgName)449     InstalledPackageInfo getInstalledPackageInfo(final int userId, @NonNull final String pkgName) {
450         synchronized (mLock) {
451             return mPkgCache.get(userId, pkgName);
452         }
453     }
454 
455     @GuardedBy("mLock")
getConsumptionLimitLocked()456     long getConsumptionLimitLocked() {
457         return mCurrentBatteryLevel * mScribe.getSatiatedConsumptionLimitLocked() / 100;
458     }
459 
460     @GuardedBy("mLock")
getMinBalanceLocked(final int userId, @NonNull final String pkgName)461     long getMinBalanceLocked(final int userId, @NonNull final String pkgName) {
462         return mCurrentBatteryLevel * mCompleteEconomicPolicy.getMinSatiatedBalance(userId, pkgName)
463                 / 100;
464     }
465 
466     @GuardedBy("mLock")
getInitialSatiatedConsumptionLimitLocked()467     long getInitialSatiatedConsumptionLimitLocked() {
468         return mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit();
469     }
470 
471 
getRealtimeSinceFirstSetupMs()472     long getRealtimeSinceFirstSetupMs() {
473         return mScribe.getRealtimeSinceFirstSetupMs(SystemClock.elapsedRealtime());
474     }
475 
getUid(final int userId, @NonNull final String pkgName)476     int getUid(final int userId, @NonNull final String pkgName) {
477         synchronized (mPackageToUidCache) {
478             Integer uid = mPackageToUidCache.get(userId, pkgName);
479             if (uid == null) {
480                 uid = mPackageManagerInternal.getPackageUid(pkgName, 0, userId);
481                 mPackageToUidCache.add(userId, pkgName, uid);
482             }
483             return uid;
484         }
485     }
486 
487     @EconomyManager.EnabledMode
getEnabledMode()488     int getEnabledMode() {
489         return mEnabledMode;
490     }
491 
492     @EconomyManager.EnabledMode
getEnabledMode(int policyId)493     int getEnabledMode(int policyId) {
494         synchronized (mLock) {
495             // For now, treat enabled policies as using the same enabled mode as full TARE.
496             // TODO: have enabled mode by policy
497             if (mCompleteEconomicPolicy.isPolicyEnabled(policyId)) {
498                 return mEnabledMode;
499             }
500             return ENABLED_MODE_OFF;
501         }
502     }
503 
isHeadlessSystemApp(final int userId, @NonNull String pkgName)504     boolean isHeadlessSystemApp(final int userId, @NonNull String pkgName) {
505         if (pkgName == null) {
506             Slog.wtfStack(TAG, "isHeadlessSystemApp called with null package");
507             return false;
508         }
509         synchronized (mLock) {
510             final InstalledPackageInfo ipo = getInstalledPackageInfo(userId, pkgName);
511             if (ipo != null && ipo.isHeadlessSystemApp) {
512                 return true;
513             }
514             // The wellbeing app is pre-set on the device, not expected to be interacted with
515             // much by the user, but can be expected to do work in the background on behalf of
516             // the user. As such, it's a pseudo-headless system app, so treat it as a headless
517             // system app.
518             return pkgName.equals(mWellbeingPackage);
519         }
520     }
521 
isPackageExempted(final int userId, @NonNull String pkgName)522     boolean isPackageExempted(final int userId, @NonNull String pkgName) {
523         synchronized (mLock) {
524             return mExemptedApps.contains(pkgName);
525         }
526     }
527 
isPackageRestricted(final int userId, @NonNull String pkgName)528     boolean isPackageRestricted(final int userId, @NonNull String pkgName) {
529         synchronized (mLock) {
530             return mRestrictedApps.contains(userId, pkgName);
531         }
532     }
533 
isSystem(final int userId, @NonNull String pkgName)534     boolean isSystem(final int userId, @NonNull String pkgName) {
535         if ("android".equals(pkgName)) {
536             return true;
537         }
538         return UserHandle.isCore(getUid(userId, pkgName));
539     }
540 
isVip(final int userId, @NonNull String pkgName)541     boolean isVip(final int userId, @NonNull String pkgName) {
542         return isVip(userId, pkgName, SystemClock.elapsedRealtime());
543     }
544 
isVip(final int userId, @NonNull String pkgName, final long nowElapsed)545     boolean isVip(final int userId, @NonNull String pkgName, final long nowElapsed) {
546         synchronized (mLock) {
547             final Boolean override = mVipOverrides.get(userId, pkgName);
548             if (override != null) {
549                 return override;
550             }
551         }
552         if (isSystem(userId, pkgName)) {
553             // The government, I mean the system, can create ARCs as it needs to in order to
554             // operate.
555             return true;
556         }
557         synchronized (mLock) {
558             final Long expirationTimeElapsed = mTemporaryVips.get(userId, pkgName);
559             if (expirationTimeElapsed != null) {
560                 return nowElapsed <= expirationTimeElapsed;
561             }
562         }
563         return false;
564     }
565 
onBatteryLevelChanged()566     void onBatteryLevelChanged() {
567         synchronized (mLock) {
568             final int newBatteryLevel = getCurrentBatteryLevel();
569             mAnalyst.noteBatteryLevelChange(newBatteryLevel);
570             final boolean increased = newBatteryLevel > mCurrentBatteryLevel;
571             if (increased) {
572                 if (newBatteryLevel >= STOCK_RECALCULATION_BATTERY_THRESHOLD) {
573                     maybeAdjustDesiredStockLevelLocked();
574                 }
575                 mAgent.distributeBasicIncomeLocked(newBatteryLevel);
576             } else if (newBatteryLevel == mCurrentBatteryLevel) {
577                 // The broadcast is also sent when the plug type changes...
578                 return;
579             }
580             mCurrentBatteryLevel = newBatteryLevel;
581             adjustCreditSupplyLocked(increased);
582         }
583     }
584 
onDeviceStateChanged()585     void onDeviceStateChanged() {
586         synchronized (mLock) {
587             mAgent.onDeviceStateChangedLocked();
588         }
589     }
590 
onExemptionListChanged()591     void onExemptionListChanged() {
592         final int[] userIds = LocalServices.getService(UserManagerInternal.class).getUserIds();
593         synchronized (mLock) {
594             final ArraySet<String> removed = mExemptedApps;
595             final ArraySet<String> added = new ArraySet<>();
596             try {
597                 mExemptedApps = new ArraySet<>(mDeviceIdleController.getFullPowerWhitelist());
598                 mExemptListLoaded = true;
599             } catch (RemoteException e) {
600                 // Shouldn't happen.
601             }
602 
603             for (int i = mExemptedApps.size() - 1; i >= 0; --i) {
604                 final String pkg = mExemptedApps.valueAt(i);
605                 if (!removed.contains(pkg)) {
606                     added.add(pkg);
607                 }
608                 removed.remove(pkg);
609             }
610             for (int a = added.size() - 1; a >= 0; --a) {
611                 final String pkgName = added.valueAt(a);
612                 for (int userId : userIds) {
613                     // Since the exemption list doesn't specify user ID and we track by user ID,
614                     // we need to see if the app exists on the user before talking to the agent.
615                     // Otherwise, we may end up with invalid ledgers.
616                     final boolean appExists = getUid(userId, pkgName) >= 0;
617                     if (appExists) {
618                         mAgent.onAppExemptedLocked(userId, pkgName);
619                     }
620                 }
621             }
622             for (int r = removed.size() - 1; r >= 0; --r) {
623                 final String pkgName = removed.valueAt(r);
624                 for (int userId : userIds) {
625                     // Since the exemption list doesn't specify user ID and we track by user ID,
626                     // we need to see if the app exists on the user before talking to the agent.
627                     // Otherwise, we may end up with invalid ledgers.
628                     final boolean appExists = getUid(userId, pkgName) >= 0;
629                     if (appExists) {
630                         mAgent.onAppUnexemptedLocked(userId, pkgName);
631                     }
632                 }
633             }
634         }
635     }
636 
onPackageAdded(final int uid, @NonNull final String pkgName)637     void onPackageAdded(final int uid, @NonNull final String pkgName) {
638         final int userId = UserHandle.getUserId(uid);
639         final PackageInfo packageInfo;
640         try {
641             packageInfo =
642                     mPackageManager.getPackageInfoAsUser(pkgName, PACKAGE_QUERY_FLAGS, userId);
643         } catch (PackageManager.NameNotFoundException e) {
644             Slog.wtf(TAG, "PM couldn't find newly added package: " + pkgName, e);
645             return;
646         }
647         synchronized (mPackageToUidCache) {
648             mPackageToUidCache.add(userId, pkgName, uid);
649         }
650         synchronized (mLock) {
651             final InstalledPackageInfo ipo = new InstalledPackageInfo(getContext(), userId,
652                     packageInfo);
653             final InstalledPackageInfo oldIpo = mPkgCache.add(userId, pkgName, ipo);
654             maybeUpdateInstallerStatusLocked(oldIpo, ipo);
655             mUidToPackageCache.add(uid, pkgName);
656             // TODO: only do this when the user first launches the app (app leaves stopped state)
657             mAgent.grantBirthrightLocked(userId, pkgName);
658             if (ipo.installerPackageName != null) {
659                 mAgent.noteInstantaneousEventLocked(userId, ipo.installerPackageName,
660                         JobSchedulerEconomicPolicy.REWARD_APP_INSTALL, null);
661             }
662         }
663     }
664 
onPackageForceStopped(final int userId, @NonNull final String pkgName)665     void onPackageForceStopped(final int userId, @NonNull final String pkgName) {
666         synchronized (mLock) {
667             // Remove all credits if the user force stops the app. It will slowly regain them
668             // in response to different events.
669             mAgent.reclaimAllAssetsLocked(userId, pkgName, EconomicPolicy.REGULATION_FORCE_STOP);
670         }
671     }
672 
onPackageRemoved(final int uid, @NonNull final String pkgName)673     void onPackageRemoved(final int uid, @NonNull final String pkgName) {
674         final int userId = UserHandle.getUserId(uid);
675         synchronized (mPackageToUidCache) {
676             mPackageToUidCache.delete(userId, pkgName);
677         }
678         synchronized (mLock) {
679             mUidToPackageCache.remove(uid, pkgName);
680             mVipOverrides.delete(userId, pkgName);
681             final InstalledPackageInfo ipo = mPkgCache.delete(userId, pkgName);
682             mInstallers.delete(userId, pkgName);
683             if (ipo != null && ipo.installerPackageName != null) {
684                 final ArraySet<String> list = mInstallers.get(userId, ipo.installerPackageName);
685                 if (list != null) {
686                     list.remove(pkgName);
687                 }
688             }
689             mAgent.onPackageRemovedLocked(userId, pkgName);
690         }
691     }
692 
onUidStateChanged(final int uid)693     void onUidStateChanged(final int uid) {
694         synchronized (mLock) {
695             final ArraySet<String> pkgNames = getPackagesForUidLocked(uid);
696             if (pkgNames == null) {
697                 Slog.e(TAG, "Don't have packages for uid " + uid);
698             } else {
699                 mAgent.onAppStatesChangedLocked(UserHandle.getUserId(uid), pkgNames);
700             }
701         }
702     }
703 
onUserAdded(final int userId)704     void onUserAdded(final int userId) {
705         synchronized (mLock) {
706             final List<PackageInfo> pkgs =
707                     mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId);
708             for (int i = pkgs.size() - 1; i >= 0; --i) {
709                 final InstalledPackageInfo ipo =
710                         new InstalledPackageInfo(getContext(), userId, pkgs.get(i));
711                 final InstalledPackageInfo oldIpo = mPkgCache.add(userId, ipo.packageName, ipo);
712                 maybeUpdateInstallerStatusLocked(oldIpo, ipo);
713             }
714             mAgent.grantBirthrightsLocked(userId);
715             final long nowElapsed = SystemClock.elapsedRealtime();
716             mScribe.setUserAddedTimeLocked(userId, nowElapsed);
717             grantInstallersTemporaryVipStatusLocked(userId,
718                     nowElapsed, INSTALLER_FIRST_SETUP_GRACE_PERIOD_MS);
719         }
720     }
721 
onUserRemoved(final int userId)722     void onUserRemoved(final int userId) {
723         synchronized (mLock) {
724             mVipOverrides.delete(userId);
725             final int uIdx = mPkgCache.indexOfKey(userId);
726             if (uIdx >= 0) {
727                 for (int p = mPkgCache.numElementsForKeyAt(uIdx) - 1; p >= 0; --p) {
728                     final InstalledPackageInfo pkgInfo = mPkgCache.valueAt(uIdx, p);
729                     mUidToPackageCache.remove(pkgInfo.uid);
730                 }
731             }
732             mInstallers.delete(userId);
733             mPkgCache.delete(userId);
734             mAgent.onUserRemovedLocked(userId);
735             mScribe.onUserRemovedLocked(userId);
736         }
737     }
738 
739     /**
740      * Try to increase the consumption limit if apps are reaching the current limit too quickly.
741      */
742     @GuardedBy("mLock")
maybePerformQuantitativeEasingLocked()743     void maybePerformQuantitativeEasingLocked() {
744         if (mConfigObserver.ENABLE_TIP3) {
745             maybeAdjustDesiredStockLevelLocked();
746             return;
747         }
748         if (getRealtimeSinceFirstSetupMs() < STOCK_ADJUSTMENT_FIRST_SETUP_GRACE_PERIOD_MS) {
749             // Things can be very tumultuous soon after first setup.
750             return;
751         }
752         // We don't need to increase the limit if the device runs out of consumable credits
753         // when the battery is low.
754         final long remainingConsumableCakes = mScribe.getRemainingConsumableCakesLocked();
755         if (mCurrentBatteryLevel <= QUANTITATIVE_EASING_BATTERY_THRESHOLD
756                 || remainingConsumableCakes > 0) {
757             return;
758         }
759         final long currentConsumptionLimit = mScribe.getSatiatedConsumptionLimitLocked();
760         final long shortfall = (mCurrentBatteryLevel - QUANTITATIVE_EASING_BATTERY_THRESHOLD)
761                 * currentConsumptionLimit / 100;
762         final long newConsumptionLimit = Math.min(currentConsumptionLimit + shortfall,
763                 mCompleteEconomicPolicy.getMaxSatiatedConsumptionLimit());
764         if (newConsumptionLimit != currentConsumptionLimit) {
765             Slog.i(TAG, "Increasing consumption limit from " + cakeToString(currentConsumptionLimit)
766                     + " to " + cakeToString(newConsumptionLimit));
767             mScribe.setConsumptionLimitLocked(newConsumptionLimit);
768             adjustCreditSupplyLocked(/* allowIncrease */ true);
769         }
770     }
771 
772     /**
773      * Adjust the consumption limit based on historical data and the target battery drain.
774      */
775     @GuardedBy("mLock")
maybeAdjustDesiredStockLevelLocked()776     void maybeAdjustDesiredStockLevelLocked() {
777         if (!mConfigObserver.ENABLE_TIP3) {
778             return;
779         }
780         if (getRealtimeSinceFirstSetupMs() < STOCK_ADJUSTMENT_FIRST_SETUP_GRACE_PERIOD_MS) {
781             // Things can be very tumultuous soon after first setup.
782             return;
783         }
784         // Don't adjust the limit too often or while the battery is low.
785         final long now = getCurrentTimeMillis();
786         if ((now - mScribe.getLastStockRecalculationTimeLocked()) < STOCK_RECALCULATION_DELAY_MS
787                 || mCurrentBatteryLevel <= STOCK_RECALCULATION_BATTERY_THRESHOLD) {
788             return;
789         }
790 
791         // For now, use screen off battery drain as a proxy for background battery drain.
792         // TODO: get more accurate background battery drain numbers
793         final long totalScreenOffDurationMs = mAnalyst.getBatteryScreenOffDurationMs();
794         if (totalScreenOffDurationMs < STOCK_RECALCULATION_MIN_DATA_DURATION_MS) {
795             return;
796         }
797         final long totalDischargeMah = mAnalyst.getBatteryScreenOffDischargeMah();
798         if (totalDischargeMah == 0) {
799             Slog.i(TAG, "Total discharge was 0");
800             return;
801         }
802         final long batteryCapacityMah = mBatteryManagerInternal.getBatteryFullCharge() / 1000;
803         final long estimatedLifeHours = batteryCapacityMah * totalScreenOffDurationMs
804                 / totalDischargeMah / HOUR_IN_MILLIS;
805         final long percentageOfTarget =
806                 100 * estimatedLifeHours / mTargetBackgroundBatteryLifeHours;
807         if (DEBUG) {
808             Slog.d(TAG, "maybeAdjustDesiredStockLevelLocked:"
809                     + " screenOffMs=" + totalScreenOffDurationMs
810                     + " dischargeMah=" + totalDischargeMah
811                     + " capacityMah=" + batteryCapacityMah
812                     + " estimatedLifeHours=" + estimatedLifeHours
813                     + " %ofTarget=" + percentageOfTarget);
814         }
815         final long currentConsumptionLimit = mScribe.getSatiatedConsumptionLimitLocked();
816         final long newConsumptionLimit;
817         if (percentageOfTarget > 105) {
818             // The stock is too low. We're doing pretty well. We can increase the stock slightly
819             // to let apps do more work in the background.
820             newConsumptionLimit = Math.min((long) (currentConsumptionLimit * 1.01),
821                     mCompleteEconomicPolicy.getMaxSatiatedConsumptionLimit());
822         } else if (percentageOfTarget < 100) {
823             // The stock is too high IMO. We're below the target. Decrease the stock to reduce
824             // background work.
825             newConsumptionLimit = Math.max((long) (currentConsumptionLimit * .98),
826                     mCompleteEconomicPolicy.getMinSatiatedConsumptionLimit());
827         } else {
828             // The stock is just right.
829             return;
830         }
831         // TODO(250007191): calculate and log implied service level
832         if (newConsumptionLimit != currentConsumptionLimit) {
833             Slog.i(TAG, "Adjusting consumption limit from " + cakeToString(currentConsumptionLimit)
834                     + " to " + cakeToString(newConsumptionLimit)
835                     + " because drain was " + percentageOfTarget + "% of target");
836             mScribe.setConsumptionLimitLocked(newConsumptionLimit);
837             adjustCreditSupplyLocked(/* allowIncrease */ true);
838             mScribe.setLastStockRecalculationTimeLocked(now);
839         }
840     }
841 
postAffordabilityChanged(final int userId, @NonNull final String pkgName, @NonNull Agent.ActionAffordabilityNote affordabilityNote)842     void postAffordabilityChanged(final int userId, @NonNull final String pkgName,
843             @NonNull Agent.ActionAffordabilityNote affordabilityNote) {
844         if (DEBUG) {
845             Slog.d(TAG, userId + ":" + pkgName + " affordability changed to "
846                     + affordabilityNote.isCurrentlyAffordable());
847         }
848         final SomeArgs args = SomeArgs.obtain();
849         args.argi1 = userId;
850         args.arg1 = pkgName;
851         args.arg2 = affordabilityNote;
852         mHandler.obtainMessage(MSG_NOTIFY_AFFORDABILITY_CHANGE_LISTENER, args).sendToTarget();
853     }
854 
855     @GuardedBy("mLock")
adjustCreditSupplyLocked(boolean allowIncrease)856     private void adjustCreditSupplyLocked(boolean allowIncrease) {
857         final long newLimit = getConsumptionLimitLocked();
858         final long remainingConsumableCakes = mScribe.getRemainingConsumableCakesLocked();
859         if (remainingConsumableCakes == newLimit) {
860             return;
861         }
862         if (remainingConsumableCakes > newLimit) {
863             mScribe.adjustRemainingConsumableCakesLocked(newLimit - remainingConsumableCakes);
864         } else if (allowIncrease) {
865             final double perc = mCurrentBatteryLevel / 100d;
866             final long shortfall = newLimit - remainingConsumableCakes;
867             mScribe.adjustRemainingConsumableCakesLocked((long) (perc * shortfall));
868         }
869         mAgent.onCreditSupplyChanged();
870     }
871 
872     @GuardedBy("mLock")
grantInstallersTemporaryVipStatusLocked(int userId, long nowElapsed, long grantDurationMs)873     private void grantInstallersTemporaryVipStatusLocked(int userId, long nowElapsed,
874             long grantDurationMs) {
875         final long grantEndTimeElapsed = nowElapsed + grantDurationMs;
876         final int uIdx = mPkgCache.indexOfKey(userId);
877         if (uIdx < 0) {
878             return;
879         }
880         for (int pIdx = mPkgCache.numElementsForKey(uIdx) - 1; pIdx >= 0; --pIdx) {
881             final InstalledPackageInfo ipo = mPkgCache.valueAt(uIdx, pIdx);
882 
883             if (ipo.isSystemInstaller) {
884                 final Long currentGrantEndTimeElapsed = mTemporaryVips.get(userId, ipo.packageName);
885                 if (currentGrantEndTimeElapsed == null
886                         || currentGrantEndTimeElapsed < grantEndTimeElapsed) {
887                     mTemporaryVips.add(userId, ipo.packageName, grantEndTimeElapsed);
888                 }
889             }
890         }
891         mHandler.sendEmptyMessageDelayed(MSG_CLEAN_UP_TEMP_VIP_LIST, grantDurationMs);
892     }
893 
894     @GuardedBy("mLock")
processUsageEventLocked(final int userId, @NonNull UsageEvents.Event event)895     private void processUsageEventLocked(final int userId, @NonNull UsageEvents.Event event) {
896         if (mEnabledMode == ENABLED_MODE_OFF) {
897             return;
898         }
899         final String pkgName = event.getPackageName();
900         if (DEBUG) {
901             Slog.d(TAG, "Processing event " + event.getEventType()
902                     + " (" + event.mInstanceId + ")"
903                     + " for " + appToString(userId, pkgName));
904         }
905         final long nowElapsed = SystemClock.elapsedRealtime();
906         switch (event.getEventType()) {
907             case UsageEvents.Event.ACTIVITY_RESUMED:
908                 mAgent.noteOngoingEventLocked(userId, pkgName,
909                         EconomicPolicy.REWARD_TOP_ACTIVITY, String.valueOf(event.mInstanceId),
910                         nowElapsed);
911                 break;
912             case UsageEvents.Event.ACTIVITY_PAUSED:
913             case UsageEvents.Event.ACTIVITY_STOPPED:
914             case UsageEvents.Event.ACTIVITY_DESTROYED:
915                 final long now = getCurrentTimeMillis();
916                 mAgent.stopOngoingActionLocked(userId, pkgName,
917                         EconomicPolicy.REWARD_TOP_ACTIVITY, String.valueOf(event.mInstanceId),
918                         nowElapsed, now);
919                 break;
920             case UsageEvents.Event.USER_INTERACTION:
921             case UsageEvents.Event.CHOOSER_ACTION:
922                 mAgent.noteInstantaneousEventLocked(userId, pkgName,
923                         EconomicPolicy.REWARD_OTHER_USER_INTERACTION, null);
924                 break;
925             case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
926             case UsageEvents.Event.NOTIFICATION_SEEN:
927                 mAgent.noteInstantaneousEventLocked(userId, pkgName,
928                         EconomicPolicy.REWARD_NOTIFICATION_SEEN, null);
929                 break;
930         }
931     }
932 
933     @GuardedBy("mLock")
scheduleUnusedWealthReclamationLocked()934     private void scheduleUnusedWealthReclamationLocked() {
935         final long now = getCurrentTimeMillis();
936         final long nextReclamationTime = Math.max(now + RECLAMATION_STARTUP_DELAY_MS,
937                 mScribe.getLastReclamationTimeLocked() + UNUSED_RECLAMATION_PERIOD_MS);
938         mHandler.post(() -> {
939             // Never call out to AlarmManager with the lock held. This sits below AM.
940             AlarmManager alarmManager = getContext().getSystemService(AlarmManager.class);
941             if (alarmManager != null) {
942                 alarmManager.setWindow(AlarmManager.ELAPSED_REALTIME,
943                         SystemClock.elapsedRealtime() + (nextReclamationTime - now),
944                         30 * MINUTE_IN_MILLIS,
945                         ALARM_TAG_WEALTH_RECLAMATION, mUnusedWealthReclamationListener, mHandler);
946             } else {
947                 mHandler.sendEmptyMessageDelayed(
948                         MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT, RECLAMATION_STARTUP_DELAY_MS);
949             }
950         });
951     }
952 
getCurrentBatteryLevel()953     private int getCurrentBatteryLevel() {
954         return mBatteryManagerInternal.getBatteryLevel();
955     }
956 
957     @Nullable
958     @GuardedBy("mLock")
getPackagesForUidLocked(final int uid)959     private ArraySet<String> getPackagesForUidLocked(final int uid) {
960         ArraySet<String> packages = mUidToPackageCache.get(uid);
961         if (packages == null) {
962             final String[] pkgs = mPackageManager.getPackagesForUid(uid);
963             if (pkgs != null) {
964                 for (String pkg : pkgs) {
965                     mUidToPackageCache.add(uid, pkg);
966                 }
967                 packages = mUidToPackageCache.get(uid);
968             }
969         }
970         return packages;
971     }
972 
isTareSupported()973     private boolean isTareSupported() {
974         // TARE is presently designed for devices with batteries. Don't enable it on
975         // battery-less devices for now.
976         return mHasBattery;
977     }
978 
979     @GuardedBy("mLock")
loadInstalledPackageListLocked()980     private void loadInstalledPackageListLocked() {
981         mPkgCache.clear();
982         final UserManagerInternal userManagerInternal =
983                 LocalServices.getService(UserManagerInternal.class);
984         final int[] userIds = userManagerInternal.getUserIds();
985         for (int userId : userIds) {
986             final List<PackageInfo> pkgs =
987                     mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId);
988             for (int i = pkgs.size() - 1; i >= 0; --i) {
989                 final InstalledPackageInfo ipo =
990                         new InstalledPackageInfo(getContext(), userId, pkgs.get(i));
991                 final InstalledPackageInfo oldIpo = mPkgCache.add(userId, ipo.packageName, ipo);
992                 maybeUpdateInstallerStatusLocked(oldIpo, ipo);
993             }
994         }
995     }
996 
997     /**
998      * Used to update the set of installed apps for each installer. This only has an effect if the
999      * installer package name is different between {@code oldIpo} and {@code newIpo}.
1000      */
1001     @GuardedBy("mLock")
maybeUpdateInstallerStatusLocked(@ullable InstalledPackageInfo oldIpo, @NonNull InstalledPackageInfo newIpo)1002     private void maybeUpdateInstallerStatusLocked(@Nullable InstalledPackageInfo oldIpo,
1003             @NonNull InstalledPackageInfo newIpo) {
1004         final boolean changed;
1005         if (oldIpo == null) {
1006             changed = newIpo.installerPackageName != null;
1007         } else {
1008             changed = !Objects.equals(oldIpo.installerPackageName, newIpo.installerPackageName);
1009         }
1010         if (!changed) {
1011             return;
1012         }
1013         // InstallSourceInfo doesn't track userId, so for now, assume the installer on the package's
1014         // user profile did the installation.
1015         // TODO(246640162): use the actual installer's user ID
1016         final int userId = UserHandle.getUserId(newIpo.uid);
1017         final String pkgName = newIpo.packageName;
1018         if (oldIpo != null) {
1019             final ArraySet<String> oldList = mInstallers.get(userId, oldIpo.installerPackageName);
1020             if (oldList != null) {
1021                 oldList.remove(pkgName);
1022             }
1023         }
1024         if (newIpo.installerPackageName != null) {
1025             ArraySet<String> newList = mInstallers.get(userId, newIpo.installerPackageName);
1026             if (newList == null) {
1027                 newList = new ArraySet<>();
1028                 mInstallers.add(userId, newIpo.installerPackageName, newList);
1029             }
1030             newList.add(pkgName);
1031         }
1032     }
1033 
registerListeners()1034     private void registerListeners() {
1035         final IntentFilter filter = new IntentFilter();
1036         filter.addAction(Intent.ACTION_BATTERY_CHANGED);
1037         filter.addAction(Intent.ACTION_BATTERY_LEVEL_CHANGED);
1038         filter.addAction(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
1039         getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
1040 
1041         final IntentFilter pkgFilter = new IntentFilter();
1042         pkgFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
1043         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1044         pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1045         pkgFilter.addDataScheme("package");
1046         getContext()
1047                 .registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, pkgFilter, null, null);
1048 
1049         final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
1050         userFilter.addAction(Intent.ACTION_USER_ADDED);
1051         getContext()
1052                 .registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
1053 
1054         UsageStatsManagerInternal usmi = LocalServices.getService(UsageStatsManagerInternal.class);
1055         usmi.registerListener(mSurveillanceAgent);
1056 
1057         try {
1058             mAppOpsService
1059                     .startWatchingMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, null, mApbListener);
1060         } catch (RemoteException e) {
1061             // shouldn't happen.
1062         }
1063     }
1064 
1065     /** Perform long-running and/or heavy setup work. This should be called off the main thread. */
setupHeavyWork()1066     private void setupHeavyWork() {
1067         if (mBootPhase < PHASE_THIRD_PARTY_APPS_CAN_START || mEnabledMode == ENABLED_MODE_OFF) {
1068             return;
1069         }
1070         synchronized (mLock) {
1071             mCompleteEconomicPolicy.setup(mConfigObserver.getAllDeviceConfigProperties());
1072             loadInstalledPackageListLocked();
1073             final SparseLongArray timeSinceUsersAdded;
1074             final boolean isFirstSetup = !mScribe.recordExists();
1075             final long nowElapsed = SystemClock.elapsedRealtime();
1076             if (isFirstSetup) {
1077                 mAgent.grantBirthrightsLocked();
1078                 mScribe.setConsumptionLimitLocked(
1079                         mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit());
1080                 // Set the last reclamation time to now so we don't start reclaiming assets
1081                 // too early.
1082                 mScribe.setLastReclamationTimeLocked(getCurrentTimeMillis());
1083                 timeSinceUsersAdded = new SparseLongArray();
1084             } else {
1085                 mScribe.loadFromDiskLocked();
1086                 if (mScribe.getSatiatedConsumptionLimitLocked()
1087                         < mCompleteEconomicPolicy.getMinSatiatedConsumptionLimit()
1088                         || mScribe.getSatiatedConsumptionLimitLocked()
1089                         > mCompleteEconomicPolicy.getMaxSatiatedConsumptionLimit()) {
1090                     // Reset the consumption limit since several factors may have changed.
1091                     mScribe.setConsumptionLimitLocked(
1092                             mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit());
1093                 } else {
1094                     // Adjust the supply in case battery level changed while the device was off.
1095                     adjustCreditSupplyLocked(true);
1096                 }
1097                 timeSinceUsersAdded = mScribe.getRealtimeSinceUsersAddedLocked(nowElapsed);
1098             }
1099 
1100             final int[] userIds = LocalServices.getService(UserManagerInternal.class).getUserIds();
1101             for (int userId : userIds) {
1102                 final long timeSinceUserAddedMs = timeSinceUsersAdded.get(userId, 0);
1103                 // Temporarily mark installers as VIPs so they aren't subject to credit
1104                 // limits and policies on first boot.
1105                 if (timeSinceUserAddedMs < INSTALLER_FIRST_SETUP_GRACE_PERIOD_MS) {
1106                     final long remainingGraceDurationMs =
1107                             INSTALLER_FIRST_SETUP_GRACE_PERIOD_MS - timeSinceUserAddedMs;
1108 
1109                     grantInstallersTemporaryVipStatusLocked(userId, nowElapsed,
1110                             remainingGraceDurationMs);
1111                 }
1112             }
1113             scheduleUnusedWealthReclamationLocked();
1114         }
1115     }
1116 
onBootPhaseSystemServicesReady()1117     private void onBootPhaseSystemServicesReady() {
1118         if (mBootPhase < PHASE_SYSTEM_SERVICES_READY || mEnabledMode == ENABLED_MODE_OFF) {
1119             return;
1120         }
1121         synchronized (mLock) {
1122             registerListeners();
1123             // As of Android UDC, users can't change the wellbeing package, so load it once
1124             // as soon as possible and don't bother trying to update it afterwards.
1125             mWellbeingPackage = mPackageManager.getWellbeingPackageName();
1126             mCurrentBatteryLevel = getCurrentBatteryLevel();
1127             // Get the current battery presence, if available. This would succeed if TARE is
1128             // toggled long after boot.
1129             final Intent batteryStatus = getContext().registerReceiver(null,
1130                     new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
1131             if (batteryStatus != null) {
1132                 final boolean hasBattery =
1133                         batteryStatus.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
1134                 if (mHasBattery != hasBattery) {
1135                     mHasBattery = hasBattery;
1136                     mConfigObserver.updateEnabledStatus();
1137                 }
1138             }
1139         }
1140     }
1141 
onBootPhaseThirdPartyAppsCanStart()1142     private void onBootPhaseThirdPartyAppsCanStart() {
1143         if (mBootPhase < PHASE_THIRD_PARTY_APPS_CAN_START || mEnabledMode == ENABLED_MODE_OFF) {
1144             return;
1145         }
1146         mHandler.post(this::setupHeavyWork);
1147     }
1148 
onBootPhaseBootCompleted()1149     private void onBootPhaseBootCompleted() {
1150         if (mBootPhase < PHASE_BOOT_COMPLETED || mEnabledMode == ENABLED_MODE_OFF) {
1151             return;
1152         }
1153         synchronized (mLock) {
1154             if (!mExemptListLoaded) {
1155                 try {
1156                     mExemptedApps = new ArraySet<>(mDeviceIdleController.getFullPowerWhitelist());
1157                     mExemptListLoaded = true;
1158                 } catch (RemoteException e) {
1159                     // Shouldn't happen.
1160                 }
1161             }
1162         }
1163     }
1164 
setupEverything()1165     private void setupEverything() {
1166         if (mEnabledMode == ENABLED_MODE_OFF) {
1167             return;
1168         }
1169         if (mBootPhase >= PHASE_SYSTEM_SERVICES_READY) {
1170             onBootPhaseSystemServicesReady();
1171         }
1172         if (mBootPhase >= PHASE_THIRD_PARTY_APPS_CAN_START) {
1173             onBootPhaseThirdPartyAppsCanStart();
1174         }
1175         if (mBootPhase >= PHASE_BOOT_COMPLETED) {
1176             onBootPhaseBootCompleted();
1177         }
1178     }
1179 
tearDownEverything()1180     private void tearDownEverything() {
1181         if (mEnabledMode != ENABLED_MODE_OFF) {
1182             return;
1183         }
1184         synchronized (mLock) {
1185             mAgent.tearDownLocked();
1186             mAnalyst.tearDown();
1187             mCompleteEconomicPolicy.tearDown();
1188             mExemptedApps.clear();
1189             mExemptListLoaded = false;
1190             mHandler.post(() -> {
1191                 // Never call out to AlarmManager with the lock held. This sits below AM.
1192                 AlarmManager alarmManager = getContext().getSystemService(AlarmManager.class);
1193                 if (alarmManager != null) {
1194                     alarmManager.cancel(mUnusedWealthReclamationListener);
1195                 }
1196             });
1197             mPkgCache.clear();
1198             mScribe.tearDownLocked();
1199             mUidToPackageCache.clear();
1200             getContext().unregisterReceiver(mBroadcastReceiver);
1201             UsageStatsManagerInternal usmi =
1202                     LocalServices.getService(UsageStatsManagerInternal.class);
1203             usmi.unregisterListener(mSurveillanceAgent);
1204             try {
1205                 mAppOpsService.stopWatchingMode(mApbListener);
1206             } catch (RemoteException e) {
1207                 // shouldn't happen.
1208             }
1209         }
1210         synchronized (mPackageToUidCache) {
1211             mPackageToUidCache.clear();
1212         }
1213     }
1214 
1215     private final class IrsHandler extends Handler {
IrsHandler(Looper looper)1216         IrsHandler(Looper looper) {
1217             super(looper);
1218         }
1219 
1220         @Override
handleMessage(Message msg)1221         public void handleMessage(Message msg) {
1222             switch (msg.what) {
1223                 case MSG_CLEAN_UP_TEMP_VIP_LIST: {
1224                     removeMessages(MSG_CLEAN_UP_TEMP_VIP_LIST);
1225 
1226                     synchronized (mLock) {
1227                         final long nowElapsed = SystemClock.elapsedRealtime();
1228 
1229                         long earliestExpiration = Long.MAX_VALUE;
1230                         for (int u = 0; u < mTemporaryVips.numMaps(); ++u) {
1231                             final int userId = mTemporaryVips.keyAt(u);
1232 
1233                             for (int p = mTemporaryVips.numElementsForKeyAt(u) - 1; p >= 0; --p) {
1234                                 final String pkgName = mTemporaryVips.keyAt(u, p);
1235                                 final Long expiration = mTemporaryVips.valueAt(u, p);
1236 
1237                                 if (expiration == null || expiration < nowElapsed) {
1238                                     mTemporaryVips.delete(userId, pkgName);
1239                                 } else {
1240                                     earliestExpiration = Math.min(earliestExpiration, expiration);
1241                                 }
1242                             }
1243                         }
1244 
1245                         if (earliestExpiration < Long.MAX_VALUE) {
1246                             sendEmptyMessageDelayed(MSG_CLEAN_UP_TEMP_VIP_LIST,
1247                                     earliestExpiration - nowElapsed);
1248                         }
1249                     }
1250                 }
1251                 break;
1252 
1253                 case MSG_NOTIFY_AFFORDABILITY_CHANGE_LISTENER: {
1254                     final SomeArgs args = (SomeArgs) msg.obj;
1255                     final int userId = args.argi1;
1256                     final String pkgName = (String) args.arg1;
1257                     final Agent.ActionAffordabilityNote affordabilityNote =
1258                             (Agent.ActionAffordabilityNote) args.arg2;
1259 
1260                     final EconomyManagerInternal.AffordabilityChangeListener listener =
1261                             affordabilityNote.getListener();
1262                     listener.onAffordabilityChanged(userId, pkgName,
1263                             affordabilityNote.getActionBill(),
1264                             affordabilityNote.isCurrentlyAffordable());
1265 
1266                     args.recycle();
1267                 }
1268                 break;
1269 
1270                 case MSG_NOTIFY_STATE_CHANGE_LISTENER: {
1271                     final int policy = msg.arg1;
1272                     final TareStateChangeListener listener = (TareStateChangeListener) msg.obj;
1273                     listener.onTareEnabledModeChanged(getEnabledMode(policy));
1274                 }
1275                 break;
1276 
1277                 case MSG_NOTIFY_STATE_CHANGE_LISTENERS: {
1278                     final int changedPolicies = msg.arg1;
1279                     synchronized (mStateChangeListeners) {
1280                         final int size = mStateChangeListeners.size();
1281                         for (int l = 0; l < size; ++l) {
1282                             final int policy = mStateChangeListeners.keyAt(l);
1283                             if ((policy & changedPolicies) == 0) {
1284                                 continue;
1285                             }
1286                             final ArraySet<TareStateChangeListener> listeners =
1287                                     mStateChangeListeners.get(policy);
1288                             final int enabledMode = getEnabledMode(policy);
1289                             for (int p = listeners.size() - 1; p >= 0; --p) {
1290                                 final TareStateChangeListener listener = listeners.valueAt(p);
1291                                 listener.onTareEnabledModeChanged(enabledMode);
1292                             }
1293                         }
1294                     }
1295                 }
1296                 break;
1297 
1298                 case MSG_PROCESS_USAGE_EVENT: {
1299                     final int userId = msg.arg1;
1300                     final UsageEvents.Event event = (UsageEvents.Event) msg.obj;
1301                     synchronized (mLock) {
1302                         processUsageEventLocked(userId, event);
1303                     }
1304                 }
1305                 break;
1306 
1307                 case MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT: {
1308                     removeMessages(MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT);
1309                     synchronized (mLock) {
1310                         scheduleUnusedWealthReclamationLocked();
1311                     }
1312                 }
1313                 break;
1314             }
1315         }
1316     }
1317 
1318     /**
1319      * Binder stub trampoline implementation
1320      */
1321     final class EconomyManagerStub extends IEconomyManager.Stub {
1322         /**
1323          * "dumpsys" infrastructure
1324          */
1325         @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1326         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1327             if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
1328 
1329             boolean dumpAll = true;
1330             if (!ArrayUtils.isEmpty(args)) {
1331                 String arg = args[0];
1332                 if ("-h".equals(arg) || "--help".equals(arg)) {
1333                     dumpHelp(pw);
1334                     return;
1335                 } else if ("-a".equals(arg)) {
1336                     // -a is passed when dumping a bug report. Bug reports have a time limit for
1337                     // each service dump, so we can't dump everything.
1338                     dumpAll = false;
1339                 } else if (arg.length() > 0 && arg.charAt(0) == '-') {
1340                     pw.println("Unknown option: " + arg);
1341                     return;
1342                 }
1343             }
1344 
1345             final long identityToken = Binder.clearCallingIdentity();
1346             try {
1347                 dumpInternal(new IndentingPrintWriter(pw, "  "), dumpAll);
1348             } finally {
1349                 Binder.restoreCallingIdentity(identityToken);
1350             }
1351         }
1352 
1353         @Override
1354         @EconomyManager.EnabledMode
getEnabledMode()1355         public int getEnabledMode() {
1356             return InternalResourceService.this.getEnabledMode();
1357         }
1358 
1359         @Override
handleShellCommand(@onNull ParcelFileDescriptor in, @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args)1360         public int handleShellCommand(@NonNull ParcelFileDescriptor in,
1361                 @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
1362                 @NonNull String[] args) {
1363             return (new TareShellCommand(InternalResourceService.this)).exec(
1364                     this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(),
1365                     args);
1366         }
1367     }
1368 
1369     private final class LocalService implements EconomyManagerInternal {
1370         /**
1371          * Use an extremely large value to indicate that an app can pay for a bill indefinitely.
1372          * The value set here should be large/long enough that there's no reasonable expectation
1373          * of a device operating uninterrupted (or in the exact same state) for that period of time.
1374          * We intentionally don't use Long.MAX_VALUE to avoid potential overflow if a client
1375          * doesn't check the value and just immediately adds it to the current time.
1376          */
1377         private static final long FOREVER_MS = 27 * 365 * 24 * HOUR_IN_MILLIS;
1378 
1379         @Override
registerAffordabilityChangeListener(int userId, @NonNull String pkgName, @NonNull AffordabilityChangeListener listener, @NonNull ActionBill bill)1380         public void registerAffordabilityChangeListener(int userId, @NonNull String pkgName,
1381                 @NonNull AffordabilityChangeListener listener, @NonNull ActionBill bill) {
1382             if (!isTareSupported() || isSystem(userId, pkgName)) {
1383                 // The system's affordability never changes.
1384                 return;
1385             }
1386             synchronized (mLock) {
1387                 mAgent.registerAffordabilityChangeListenerLocked(userId, pkgName, listener, bill);
1388             }
1389         }
1390 
1391         @Override
unregisterAffordabilityChangeListener(int userId, @NonNull String pkgName, @NonNull AffordabilityChangeListener listener, @NonNull ActionBill bill)1392         public void unregisterAffordabilityChangeListener(int userId, @NonNull String pkgName,
1393                 @NonNull AffordabilityChangeListener listener, @NonNull ActionBill bill) {
1394             if (isSystem(userId, pkgName)) {
1395                 // The system's affordability never changes.
1396                 return;
1397             }
1398             synchronized (mLock) {
1399                 mAgent.unregisterAffordabilityChangeListenerLocked(userId, pkgName, listener, bill);
1400             }
1401         }
1402 
1403         @Override
registerTareStateChangeListener(@onNull TareStateChangeListener listener, int policyId)1404         public void registerTareStateChangeListener(@NonNull TareStateChangeListener listener,
1405                 int policyId) {
1406             if (!isTareSupported()) {
1407                 return;
1408             }
1409             synchronized (mStateChangeListeners) {
1410                 if (mStateChangeListeners.add(policyId, listener)) {
1411                     mHandler.obtainMessage(MSG_NOTIFY_STATE_CHANGE_LISTENER, policyId, 0, listener)
1412                             .sendToTarget();
1413                 }
1414             }
1415         }
1416 
1417         @Override
unregisterTareStateChangeListener(@onNull TareStateChangeListener listener)1418         public void unregisterTareStateChangeListener(@NonNull TareStateChangeListener listener) {
1419             synchronized (mStateChangeListeners) {
1420                 for (int i = mStateChangeListeners.size() - 1; i >= 0; --i) {
1421                     final ArraySet<TareStateChangeListener> listeners =
1422                             mStateChangeListeners.get(mStateChangeListeners.keyAt(i));
1423                     listeners.remove(listener);
1424                 }
1425             }
1426         }
1427 
1428         @Override
canPayFor(int userId, @NonNull String pkgName, @NonNull ActionBill bill)1429         public boolean canPayFor(int userId, @NonNull String pkgName, @NonNull ActionBill bill) {
1430             if (mEnabledMode == ENABLED_MODE_OFF) {
1431                 return true;
1432             }
1433             if (isVip(userId, pkgName)) {
1434                 // The government, I mean the system, can create ARCs as it needs to in order to
1435                 // allow VIPs to operate.
1436                 return true;
1437             }
1438             // TODO: take temp-allowlist into consideration
1439             long requiredBalance = 0;
1440             final List<EconomyManagerInternal.AnticipatedAction> projectedActions =
1441                     bill.getAnticipatedActions();
1442             synchronized (mLock) {
1443                 for (int i = 0; i < projectedActions.size(); ++i) {
1444                     AnticipatedAction action = projectedActions.get(i);
1445                     final Cost cost = mCompleteEconomicPolicy.getCostOfAction(
1446                             action.actionId, userId, pkgName);
1447                     requiredBalance += cost.price * action.numInstantaneousCalls
1448                             + cost.price * (action.ongoingDurationMs / 1000);
1449                 }
1450                 return mAgent.getBalanceLocked(userId, pkgName) >= requiredBalance
1451                         && mScribe.getRemainingConsumableCakesLocked() >= requiredBalance;
1452             }
1453         }
1454 
1455         @Override
getMaxDurationMs(int userId, @NonNull String pkgName, @NonNull ActionBill bill)1456         public long getMaxDurationMs(int userId, @NonNull String pkgName,
1457                 @NonNull ActionBill bill) {
1458             if (mEnabledMode == ENABLED_MODE_OFF) {
1459                 return FOREVER_MS;
1460             }
1461             if (isVip(userId, pkgName)) {
1462                 return FOREVER_MS;
1463             }
1464             long totalCostPerSecond = 0;
1465             final List<EconomyManagerInternal.AnticipatedAction> projectedActions =
1466                     bill.getAnticipatedActions();
1467             synchronized (mLock) {
1468                 for (int i = 0; i < projectedActions.size(); ++i) {
1469                     AnticipatedAction action = projectedActions.get(i);
1470                     final Cost cost = mCompleteEconomicPolicy.getCostOfAction(
1471                             action.actionId, userId, pkgName);
1472                     totalCostPerSecond += cost.price;
1473                 }
1474                 if (totalCostPerSecond == 0) {
1475                     return FOREVER_MS;
1476                 }
1477                 final long minBalance = Math.min(
1478                         mAgent.getBalanceLocked(userId, pkgName),
1479                         mScribe.getRemainingConsumableCakesLocked());
1480                 return minBalance * 1000 / totalCostPerSecond;
1481             }
1482         }
1483 
1484         @Override
getEnabledMode()1485         public int getEnabledMode() {
1486             return mEnabledMode;
1487         }
1488 
1489         @Override
getEnabledMode(int policyId)1490         public int getEnabledMode(int policyId) {
1491             return InternalResourceService.this.getEnabledMode(policyId);
1492         }
1493 
1494         @Override
noteInstantaneousEvent(int userId, @NonNull String pkgName, int eventId, @Nullable String tag)1495         public void noteInstantaneousEvent(int userId, @NonNull String pkgName, int eventId,
1496                 @Nullable String tag) {
1497             if (mEnabledMode == ENABLED_MODE_OFF) {
1498                 return;
1499             }
1500             synchronized (mLock) {
1501                 mAgent.noteInstantaneousEventLocked(userId, pkgName, eventId, tag);
1502             }
1503         }
1504 
1505         @Override
noteOngoingEventStarted(int userId, @NonNull String pkgName, int eventId, @Nullable String tag)1506         public void noteOngoingEventStarted(int userId, @NonNull String pkgName, int eventId,
1507                 @Nullable String tag) {
1508             if (mEnabledMode == ENABLED_MODE_OFF) {
1509                 return;
1510             }
1511             synchronized (mLock) {
1512                 final long nowElapsed = SystemClock.elapsedRealtime();
1513                 mAgent.noteOngoingEventLocked(userId, pkgName, eventId, tag, nowElapsed);
1514             }
1515         }
1516 
1517         @Override
noteOngoingEventStopped(int userId, @NonNull String pkgName, int eventId, @Nullable String tag)1518         public void noteOngoingEventStopped(int userId, @NonNull String pkgName, int eventId,
1519                 @Nullable String tag) {
1520             if (mEnabledMode == ENABLED_MODE_OFF) {
1521                 return;
1522             }
1523             final long nowElapsed = SystemClock.elapsedRealtime();
1524             final long now = getCurrentTimeMillis();
1525             synchronized (mLock) {
1526                 mAgent.stopOngoingActionLocked(userId, pkgName, eventId, tag, nowElapsed, now);
1527             }
1528         }
1529     }
1530 
1531     private class ConfigObserver extends ContentObserver
1532             implements DeviceConfig.OnPropertiesChangedListener {
1533         private static final String KEY_ENABLE_TIP3 = "enable_tip3";
1534         private static final String KEY_TARGET_BACKGROUND_BATTERY_LIFE_HOURS =
1535                 "target_bg_battery_life_hrs";
1536 
1537         private static final boolean DEFAULT_ENABLE_TIP3 = true;
1538 
1539         /** Use a target background battery drain rate to determine consumption limits. */
1540         public boolean ENABLE_TIP3 = DEFAULT_ENABLE_TIP3;
1541 
1542         private final ContentResolver mContentResolver;
1543 
ConfigObserver(Handler handler, Context context)1544         ConfigObserver(Handler handler, Context context) {
1545             super(handler);
1546             mContentResolver = context.getContentResolver();
1547         }
1548 
start()1549         public void start() {
1550             DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_TARE,
1551                     TareHandlerThread.getExecutor(), this);
1552             mContentResolver.registerContentObserver(
1553                     Settings.Global.getUriFor(Settings.Global.ENABLE_TARE), false, this);
1554             mContentResolver.registerContentObserver(
1555                     Settings.Global.getUriFor(TARE_ALARM_MANAGER_CONSTANTS), false, this);
1556             mContentResolver.registerContentObserver(
1557                     Settings.Global.getUriFor(TARE_JOB_SCHEDULER_CONSTANTS), false, this);
1558             onPropertiesChanged(getAllDeviceConfigProperties());
1559             updateEnabledStatus();
1560         }
1561 
1562         @NonNull
getAllDeviceConfigProperties()1563         DeviceConfig.Properties getAllDeviceConfigProperties() {
1564             // Don't want to cache the Properties object locally in case it ends up being large,
1565             // especially since it'll only be used once/infrequently (during setup or on a change).
1566             return DeviceConfig.getProperties(DeviceConfig.NAMESPACE_TARE);
1567         }
1568 
1569         @Override
onChange(boolean selfChange, Uri uri)1570         public void onChange(boolean selfChange, Uri uri) {
1571             if (uri.equals(Settings.Global.getUriFor(Settings.Global.ENABLE_TARE))) {
1572                 updateEnabledStatus();
1573             } else if (uri.equals(Settings.Global.getUriFor(TARE_ALARM_MANAGER_CONSTANTS))
1574                     || uri.equals(Settings.Global.getUriFor(TARE_JOB_SCHEDULER_CONSTANTS))) {
1575                 updateEconomicPolicy();
1576             }
1577         }
1578 
1579         @Override
onPropertiesChanged(DeviceConfig.Properties properties)1580         public void onPropertiesChanged(DeviceConfig.Properties properties) {
1581             boolean economicPolicyUpdated = false;
1582             synchronized (mLock) {
1583                 for (String name : properties.getKeyset()) {
1584                     if (name == null) {
1585                         continue;
1586                     }
1587                     switch (name) {
1588                         case EconomyManager.KEY_ENABLE_TARE_MODE:
1589                             updateEnabledStatus();
1590                             break;
1591                         case KEY_ENABLE_TIP3:
1592                             ENABLE_TIP3 = properties.getBoolean(name, DEFAULT_ENABLE_TIP3);
1593                             break;
1594                         case KEY_TARGET_BACKGROUND_BATTERY_LIFE_HOURS:
1595                             synchronized (mLock) {
1596                                 mTargetBackgroundBatteryLifeHours = properties.getInt(name,
1597                                         mDefaultTargetBackgroundBatteryLifeHours);
1598                                 maybeAdjustDesiredStockLevelLocked();
1599                             }
1600                             break;
1601                         default:
1602                             if (!economicPolicyUpdated
1603                                     && (name.startsWith("am") || name.startsWith("js")
1604                                     || name.startsWith("enable_policy"))) {
1605                                 updateEconomicPolicy();
1606                                 economicPolicyUpdated = true;
1607                             }
1608                     }
1609                 }
1610             }
1611         }
1612 
updateEnabledStatus()1613         private void updateEnabledStatus() {
1614             // User setting should override DeviceConfig setting.
1615             final int tareEnabledModeDC = DeviceConfig.getInt(DeviceConfig.NAMESPACE_TARE,
1616                     EconomyManager.KEY_ENABLE_TARE_MODE, EconomyManager.DEFAULT_ENABLE_TARE_MODE);
1617             final int tareEnabledModeConfig = isTareSupported()
1618                     ? Settings.Global.getInt(mContentResolver,
1619                             Settings.Global.ENABLE_TARE, tareEnabledModeDC)
1620                     : ENABLED_MODE_OFF;
1621             final int enabledMode;
1622             if (tareEnabledModeConfig == ENABLED_MODE_OFF
1623                     || tareEnabledModeConfig == ENABLED_MODE_ON
1624                     || tareEnabledModeConfig == ENABLED_MODE_SHADOW) {
1625                 // Config has a valid enabled mode.
1626                 enabledMode = tareEnabledModeConfig;
1627             } else {
1628                 enabledMode = EconomyManager.DEFAULT_ENABLE_TARE_MODE;
1629             }
1630             if (mEnabledMode != enabledMode) {
1631                 // A full change where we've gone from OFF to {SHADOW or ON}, or vie versa.
1632                 // With this transition, we'll have to set up or tear down.
1633                 final boolean fullEnableChange =
1634                         mEnabledMode == ENABLED_MODE_OFF || enabledMode == ENABLED_MODE_OFF;
1635                 mEnabledMode = enabledMode;
1636                 if (fullEnableChange) {
1637                     if (mEnabledMode != ENABLED_MODE_OFF) {
1638                         setupEverything();
1639                     } else {
1640                         tearDownEverything();
1641                     }
1642                 }
1643                 mHandler.obtainMessage(
1644                                 MSG_NOTIFY_STATE_CHANGE_LISTENERS, EconomicPolicy.ALL_POLICIES, 0)
1645                         .sendToTarget();
1646             }
1647         }
1648 
updateEconomicPolicy()1649         private void updateEconomicPolicy() {
1650             synchronized (mLock) {
1651                 final long minLimit = mCompleteEconomicPolicy.getMinSatiatedConsumptionLimit();
1652                 final long maxLimit = mCompleteEconomicPolicy.getMaxSatiatedConsumptionLimit();
1653                 final int oldEnabledPolicies = mCompleteEconomicPolicy.getEnabledPolicyIds();
1654                 mCompleteEconomicPolicy.tearDown();
1655                 mCompleteEconomicPolicy = new CompleteEconomicPolicy(InternalResourceService.this);
1656                 if (mEnabledMode != ENABLED_MODE_OFF
1657                         && mBootPhase >= PHASE_THIRD_PARTY_APPS_CAN_START) {
1658                     mCompleteEconomicPolicy.setup(getAllDeviceConfigProperties());
1659                     if (minLimit != mCompleteEconomicPolicy.getMinSatiatedConsumptionLimit()
1660                             || maxLimit
1661                             != mCompleteEconomicPolicy.getMaxSatiatedConsumptionLimit()) {
1662                         // Reset the consumption limit since several factors may have changed.
1663                         mScribe.setConsumptionLimitLocked(
1664                                 mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit());
1665                     }
1666                     mAgent.onPricingChangedLocked();
1667                     final int newEnabledPolicies = mCompleteEconomicPolicy.getEnabledPolicyIds();
1668                     if (oldEnabledPolicies != newEnabledPolicies) {
1669                         final int changedPolicies = oldEnabledPolicies ^ newEnabledPolicies;
1670                         mHandler.obtainMessage(
1671                                         MSG_NOTIFY_STATE_CHANGE_LISTENERS, changedPolicies, 0)
1672                                 .sendToTarget();
1673                     }
1674                 }
1675             }
1676         }
1677     }
1678 
1679     // Shell command infrastructure
executeClearVip(@onNull PrintWriter pw)1680     int executeClearVip(@NonNull PrintWriter pw) {
1681         synchronized (mLock) {
1682             final SparseSetArray<String> changedPkgs = new SparseSetArray<>();
1683             for (int u = mVipOverrides.numMaps() - 1; u >= 0; --u) {
1684                 final int userId = mVipOverrides.keyAt(u);
1685 
1686                 for (int p = mVipOverrides.numElementsForKeyAt(u) - 1; p >= 0; --p) {
1687                     changedPkgs.add(userId, mVipOverrides.keyAt(u, p));
1688                 }
1689             }
1690             mVipOverrides.clear();
1691             if (mEnabledMode != ENABLED_MODE_OFF) {
1692                 mAgent.onVipStatusChangedLocked(changedPkgs);
1693             }
1694         }
1695         pw.println("Cleared all VIP statuses");
1696         return TareShellCommand.COMMAND_SUCCESS;
1697     }
1698 
executeSetVip(@onNull PrintWriter pw, int userId, @NonNull String pkgName, @Nullable Boolean newVipState)1699     int executeSetVip(@NonNull PrintWriter pw,
1700             int userId, @NonNull String pkgName, @Nullable Boolean newVipState) {
1701         final boolean changed;
1702         synchronized (mLock) {
1703             final boolean wasVip = isVip(userId, pkgName);
1704             if (newVipState == null) {
1705                 mVipOverrides.delete(userId, pkgName);
1706             } else {
1707                 mVipOverrides.add(userId, pkgName, newVipState);
1708             }
1709             changed = isVip(userId, pkgName) != wasVip;
1710             if (mEnabledMode != ENABLED_MODE_OFF && changed) {
1711                 mAgent.onVipStatusChangedLocked(userId, pkgName);
1712             }
1713         }
1714         pw.println(appToString(userId, pkgName) + " VIP status set to " + newVipState + "."
1715                 + " Final VIP state changed? " + changed);
1716         return TareShellCommand.COMMAND_SUCCESS;
1717     }
1718 
1719     // Dump infrastructure
dumpHelp(PrintWriter pw)1720     private static void dumpHelp(PrintWriter pw) {
1721         pw.println("Resource Economy (economy) dump options:");
1722         pw.println("  [-h|--help] [package] ...");
1723         pw.println("    -h | --help: print this help");
1724         pw.println("  [package] is an optional package name to limit the output to.");
1725     }
1726 
dumpInternal(final IndentingPrintWriter pw, final boolean dumpAll)1727     private void dumpInternal(final IndentingPrintWriter pw, final boolean dumpAll) {
1728         if (!isTareSupported()) {
1729             pw.print("Unsupported by device");
1730             return;
1731         }
1732         synchronized (mLock) {
1733             pw.print("Enabled mode: ");
1734             pw.println(enabledModeToString(mEnabledMode));
1735 
1736             pw.print("Current battery level: ");
1737             pw.println(mCurrentBatteryLevel);
1738 
1739             final long consumptionLimit = getConsumptionLimitLocked();
1740             pw.print("Consumption limit (current/initial-satiated/current-satiated): ");
1741             pw.print(cakeToString(consumptionLimit));
1742             pw.print("/");
1743             pw.print(cakeToString(mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit()));
1744             pw.print("/");
1745             pw.println(cakeToString(mScribe.getSatiatedConsumptionLimitLocked()));
1746 
1747             pw.print("Target bg battery life (hours): ");
1748             pw.print(mTargetBackgroundBatteryLifeHours);
1749             pw.print(" (");
1750             pw.print(String.format("%.2f", 100f / mTargetBackgroundBatteryLifeHours));
1751             pw.println("%/hr)");
1752 
1753             final long remainingConsumable = mScribe.getRemainingConsumableCakesLocked();
1754             pw.print("Goods remaining: ");
1755             pw.print(cakeToString(remainingConsumable));
1756             pw.print(" (");
1757             pw.print(String.format("%.2f", 100f * remainingConsumable / consumptionLimit));
1758             pw.println("% of current limit)");
1759 
1760             pw.print("Device wealth: ");
1761             pw.println(cakeToString(mScribe.getCakesInCirculationForLoggingLocked()));
1762 
1763             pw.println();
1764             pw.print("Exempted apps", mExemptedApps);
1765             pw.println();
1766 
1767             pw.println();
1768             pw.print("Wellbeing app=");
1769             pw.println(mWellbeingPackage == null ? "None" : mWellbeingPackage);
1770 
1771             boolean printedVips = false;
1772             pw.println();
1773             pw.print("VIPs:");
1774             pw.increaseIndent();
1775             for (int u = 0; u < mVipOverrides.numMaps(); ++u) {
1776                 final int userId = mVipOverrides.keyAt(u);
1777 
1778                 for (int p = 0; p < mVipOverrides.numElementsForKeyAt(u); ++p) {
1779                     final String pkgName = mVipOverrides.keyAt(u, p);
1780 
1781                     printedVips = true;
1782                     pw.println();
1783                     pw.print(appToString(userId, pkgName));
1784                     pw.print("=");
1785                     pw.print(mVipOverrides.valueAt(u, p));
1786                 }
1787             }
1788             if (printedVips) {
1789                 pw.println();
1790             } else {
1791                 pw.print(" None");
1792             }
1793             pw.decreaseIndent();
1794             pw.println();
1795 
1796             boolean printedTempVips = false;
1797             pw.println();
1798             pw.print("Temp VIPs:");
1799             pw.increaseIndent();
1800             for (int u = 0; u < mTemporaryVips.numMaps(); ++u) {
1801                 final int userId = mTemporaryVips.keyAt(u);
1802 
1803                 for (int p = 0; p < mTemporaryVips.numElementsForKeyAt(u); ++p) {
1804                     final String pkgName = mTemporaryVips.keyAt(u, p);
1805 
1806                     printedTempVips = true;
1807                     pw.println();
1808                     pw.print(appToString(userId, pkgName));
1809                     pw.print("=");
1810                     pw.print(mTemporaryVips.valueAt(u, p));
1811                 }
1812             }
1813             if (printedTempVips) {
1814                 pw.println();
1815             } else {
1816                 pw.print(" None");
1817             }
1818             pw.decreaseIndent();
1819             pw.println();
1820 
1821             pw.println();
1822             pw.println("Installers:");
1823             pw.increaseIndent();
1824             for (int u = 0; u < mInstallers.numMaps(); ++u) {
1825                 final int userId = mInstallers.keyAt(u);
1826 
1827                 for (int p = 0; p < mInstallers.numElementsForKeyAt(u); ++p) {
1828                     final String pkgName = mInstallers.keyAt(u, p);
1829 
1830                     pw.print(appToString(userId, pkgName));
1831                     pw.print(": ");
1832                     pw.print(mInstallers.valueAt(u, p).size());
1833                     pw.println(" apps");
1834                 }
1835             }
1836             pw.decreaseIndent();
1837 
1838             pw.println();
1839             mCompleteEconomicPolicy.dump(pw);
1840 
1841             pw.println();
1842             mScribe.dumpLocked(pw, dumpAll);
1843 
1844             pw.println();
1845             mAgent.dumpLocked(pw);
1846 
1847             pw.println();
1848             mAnalyst.dump(pw);
1849 
1850             // Put this at the end since this may be a lot and we want to have the earlier
1851             // information easily accessible.
1852             boolean printedInterestingIpos = false;
1853             pw.println();
1854             pw.print("Interesting apps:");
1855             pw.increaseIndent();
1856             for (int u = 0; u < mPkgCache.numMaps(); ++u) {
1857                 for (int p = 0; p < mPkgCache.numElementsForKeyAt(u); ++p) {
1858                     final InstalledPackageInfo ipo = mPkgCache.valueAt(u, p);
1859 
1860                     // Printing out every single app will be too much. Only print apps that
1861                     // have some interesting characteristic.
1862                     final boolean isInteresting = ipo.hasCode
1863                             && ipo.isHeadlessSystemApp
1864                             && !UserHandle.isCore(ipo.uid);
1865                     if (!isInteresting) {
1866                         continue;
1867                     }
1868 
1869                     printedInterestingIpos = true;
1870                     pw.println();
1871                     pw.print(ipo);
1872                 }
1873             }
1874             if (printedInterestingIpos) {
1875                 pw.println();
1876             } else {
1877                 pw.print(" None");
1878             }
1879             pw.decreaseIndent();
1880         }
1881     }
1882 }
1883