• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 package com.android.settings.fuelgauge;
17 
18 import android.app.AppOpsManager;
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.IntentFilter;
22 import android.content.pm.ApplicationInfo;
23 import android.content.pm.PackageInfo;
24 import android.content.pm.PackageManager;
25 import android.content.pm.ResolveInfo;
26 import android.os.BatteryConsumer;
27 import android.os.BatteryManager;
28 import android.os.BatteryStats;
29 import android.os.BatteryStatsManager;
30 import android.os.BatteryUsageStats;
31 import android.os.BatteryUsageStatsQuery;
32 import android.os.Build;
33 import android.os.Process;
34 import android.os.SystemClock;
35 import android.os.UidBatteryConsumer;
36 import android.os.UserHandle;
37 import android.provider.Settings;
38 import android.util.Log;
39 
40 import androidx.annotation.IntDef;
41 import androidx.annotation.Nullable;
42 import androidx.annotation.VisibleForTesting;
43 import androidx.annotation.WorkerThread;
44 
45 import com.android.internal.util.ArrayUtils;
46 import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
47 import com.android.settings.fuelgauge.batterytip.AnomalyInfo;
48 import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
49 import com.android.settings.fuelgauge.batterytip.StatsManagerConfig;
50 import com.android.settings.overlay.FeatureFactory;
51 import com.android.settingslib.applications.AppUtils;
52 import com.android.settingslib.fuelgauge.Estimate;
53 import com.android.settingslib.fuelgauge.EstimateKt;
54 import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
55 import com.android.settingslib.utils.PowerUtil;
56 import com.android.settingslib.utils.ThreadUtils;
57 
58 import java.lang.annotation.Retention;
59 import java.lang.annotation.RetentionPolicy;
60 import java.time.Duration;
61 import java.time.Instant;
62 import java.util.List;
63 
64 /**
65  * Utils for battery operation
66  */
67 public class BatteryUtils {
68     public static final int UID_NULL = -1;
69     public static final int SDK_NULL = -1;
70     /** Special UID value for data usage by removed apps. */
71     public static final int UID_REMOVED_APPS = -4;
72     /** Special UID value for data usage by tethering. */
73     public static final int UID_TETHERING = -5;
74     /** Special UID for aggregated other users. */
75     public static final long UID_OTHER_USERS = Long.MIN_VALUE;
76 
77     /** Flag to check if the dock defender mode has been temporarily bypassed */
78     public static final String SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS = "dock_defender_bypass";
79 
80     public static final String BYPASS_DOCK_DEFENDER_ACTION = "battery.dock.defender.bypass";
81 
82     @Retention(RetentionPolicy.SOURCE)
83     @IntDef({StatusType.SCREEN_USAGE,
84             StatusType.FOREGROUND,
85             StatusType.BACKGROUND,
86             StatusType.ALL
87     })
88     public @interface StatusType {
89         int SCREEN_USAGE = 0;
90         int FOREGROUND = 1;
91         int BACKGROUND = 2;
92         int ALL = 3;
93     }
94 
95     @Retention(RetentionPolicy.SOURCE)
96     @IntDef({DockDefenderMode.FUTURE_BYPASS,
97             DockDefenderMode.ACTIVE,
98             DockDefenderMode.TEMPORARILY_BYPASSED,
99             DockDefenderMode.DISABLED})
100     public @interface DockDefenderMode {
101         int FUTURE_BYPASS = 0;
102         int ACTIVE = 1;
103         int TEMPORARILY_BYPASSED = 2;
104         int DISABLED = 3;
105     }
106 
107     private static final String TAG = "BatteryUtils";
108 
109     private static BatteryUtils sInstance;
110     private PackageManager mPackageManager;
111 
112     private AppOpsManager mAppOpsManager;
113     private Context mContext;
114     @VisibleForTesting
115     PowerUsageFeatureProvider mPowerUsageFeatureProvider;
116 
getInstance(Context context)117     public static BatteryUtils getInstance(Context context) {
118         if (sInstance == null || sInstance.isDataCorrupted()) {
119             sInstance = new BatteryUtils(context.getApplicationContext());
120         }
121         return sInstance;
122     }
123 
124     @VisibleForTesting
BatteryUtils(Context context)125     public BatteryUtils(Context context) {
126         mContext = context;
127         mPackageManager = context.getPackageManager();
128         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
129         mPowerUsageFeatureProvider = FeatureFactory.getFactory(context)
130                 .getPowerUsageFeatureProvider(context);
131     }
132 
getProcessTimeMs(@tatusType int type, @Nullable BatteryStats.Uid uid, int which)133     public long getProcessTimeMs(@StatusType int type, @Nullable BatteryStats.Uid uid,
134             int which) {
135         if (uid == null) {
136             return 0;
137         }
138 
139         switch (type) {
140             case StatusType.SCREEN_USAGE:
141                 return getScreenUsageTimeMs(uid, which);
142             case StatusType.FOREGROUND:
143                 return getProcessForegroundTimeMs(uid, which);
144             case StatusType.BACKGROUND:
145                 return getProcessBackgroundTimeMs(uid, which);
146             case StatusType.ALL:
147                 return getProcessForegroundTimeMs(uid, which)
148                         + getProcessBackgroundTimeMs(uid, which);
149         }
150         return 0;
151     }
152 
getScreenUsageTimeMs(BatteryStats.Uid uid, int which, long rawRealTimeUs)153     private long getScreenUsageTimeMs(BatteryStats.Uid uid, int which, long rawRealTimeUs) {
154         final int foregroundTypes[] = {BatteryStats.Uid.PROCESS_STATE_TOP};
155         Log.v(TAG, "package: " + mPackageManager.getNameForUid(uid.getUid()));
156 
157         long timeUs = 0;
158         for (int type : foregroundTypes) {
159             final long localTime = uid.getProcessStateTime(type, rawRealTimeUs, which);
160             Log.v(TAG, "type: " + type + " time(us): " + localTime);
161             timeUs += localTime;
162         }
163         Log.v(TAG, "foreground time(us): " + timeUs);
164 
165         // Return the min value of STATE_TOP time and foreground activity time, since both of these
166         // time have some errors
167         return PowerUtil.convertUsToMs(
168                 Math.min(timeUs, getForegroundActivityTotalTimeUs(uid, rawRealTimeUs)));
169     }
170 
getScreenUsageTimeMs(BatteryStats.Uid uid, int which)171     private long getScreenUsageTimeMs(BatteryStats.Uid uid, int which) {
172         final long rawRealTimeUs = PowerUtil.convertMsToUs(SystemClock.elapsedRealtime());
173         return getScreenUsageTimeMs(uid, which, rawRealTimeUs);
174     }
175 
getProcessBackgroundTimeMs(BatteryStats.Uid uid, int which)176     private long getProcessBackgroundTimeMs(BatteryStats.Uid uid, int which) {
177         final long rawRealTimeUs = PowerUtil.convertMsToUs(SystemClock.elapsedRealtime());
178         final long timeUs = uid.getProcessStateTime(
179                 BatteryStats.Uid.PROCESS_STATE_BACKGROUND, rawRealTimeUs, which);
180 
181         Log.v(TAG, "package: " + mPackageManager.getNameForUid(uid.getUid()));
182         Log.v(TAG, "background time(us): " + timeUs);
183         return PowerUtil.convertUsToMs(timeUs);
184     }
185 
getProcessForegroundTimeMs(BatteryStats.Uid uid, int which)186     private long getProcessForegroundTimeMs(BatteryStats.Uid uid, int which) {
187         final long rawRealTimeUs = PowerUtil.convertMsToUs(SystemClock.elapsedRealtime());
188         return getScreenUsageTimeMs(uid, which, rawRealTimeUs)
189                 + PowerUtil.convertUsToMs(getForegroundServiceTotalTimeUs(uid, rawRealTimeUs));
190     }
191 
192     /**
193      * Returns true if the specified battery consumer should be excluded from the summary
194      * battery consumption list.
195      */
shouldHideUidBatteryConsumer(UidBatteryConsumer consumer)196     public boolean shouldHideUidBatteryConsumer(UidBatteryConsumer consumer) {
197         return shouldHideUidBatteryConsumer(consumer,
198                 mPackageManager.getPackagesForUid(consumer.getUid()));
199     }
200 
201     /**
202      * Returns true if the specified battery consumer should be excluded from the summary
203      * battery consumption list.
204      */
shouldHideUidBatteryConsumer(UidBatteryConsumer consumer, String[] packages)205     public boolean shouldHideUidBatteryConsumer(UidBatteryConsumer consumer, String[] packages) {
206         return mPowerUsageFeatureProvider.isTypeSystem(consumer.getUid(), packages)
207                 || shouldHideUidBatteryConsumerUnconditionally(consumer, packages);
208     }
209 
210     /**
211      * Returns true if the specified battery consumer should be excluded from
212      * battery consumption lists, either short or full.
213      */
shouldHideUidBatteryConsumerUnconditionally(UidBatteryConsumer consumer, String[] packages)214     public boolean shouldHideUidBatteryConsumerUnconditionally(UidBatteryConsumer consumer,
215             String[] packages) {
216         final int uid = consumer.getUid();
217         return uid == UID_TETHERING
218                 ? false
219                 : uid < 0 || isHiddenSystemModule(packages);
220     }
221 
222     /**
223      * Returns true if the specified device power component should be excluded from the summary
224      * battery consumption list.
225      */
shouldHideDevicePowerComponent(BatteryConsumer consumer, @BatteryConsumer.PowerComponent int powerComponentId)226     public boolean shouldHideDevicePowerComponent(BatteryConsumer consumer,
227             @BatteryConsumer.PowerComponent int powerComponentId) {
228         switch (powerComponentId) {
229             case BatteryConsumer.POWER_COMPONENT_IDLE:
230             case BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO:
231             case BatteryConsumer.POWER_COMPONENT_SCREEN:
232             case BatteryConsumer.POWER_COMPONENT_BLUETOOTH:
233             case BatteryConsumer.POWER_COMPONENT_WIFI:
234                 return true;
235             default:
236                 return false;
237         }
238     }
239 
240     /**
241      * Returns true if one the specified packages belongs to a hidden system module.
242      */
isHiddenSystemModule(String[] packages)243     public boolean isHiddenSystemModule(String[] packages) {
244         if (packages != null) {
245             for (int i = 0, length = packages.length; i < length; i++) {
246                 if (AppUtils.isHiddenSystemModule(mContext, packages[i])) {
247                     return true;
248                 }
249             }
250         }
251         return false;
252     }
253 
254     /**
255      * Calculate the power usage percentage for an app
256      *
257      * @param powerUsageMah   power used by the app
258      * @param totalPowerMah   total power used in the system
259      * @param dischargeAmount The discharge amount calculated by {@link BatteryStats}
260      * @return A percentage value scaled by {@paramref dischargeAmount}
261      * @see BatteryStats#getDischargeAmount(int)
262      */
calculateBatteryPercent(double powerUsageMah, double totalPowerMah, int dischargeAmount)263     public double calculateBatteryPercent(double powerUsageMah, double totalPowerMah,
264             int dischargeAmount) {
265         if (totalPowerMah == 0) {
266             return 0;
267         }
268 
269         return (powerUsageMah / totalPowerMah) * dischargeAmount;
270     }
271 
272     /**
273      * Find the package name for a {@link android.os.BatteryStats.Uid}
274      *
275      * @param uid id to get the package name
276      * @return the package name. If there are multiple packages related to
277      * given id, return the first one. Or return null if there are no known
278      * packages with the given id
279      * @see PackageManager#getPackagesForUid(int)
280      */
getPackageName(int uid)281     public String getPackageName(int uid) {
282         final String[] packageNames = mPackageManager.getPackagesForUid(uid);
283 
284         return ArrayUtils.isEmpty(packageNames) ? null : packageNames[0];
285     }
286 
287     /**
288      * Find the targetSdkVersion for package with name {@code packageName}
289      *
290      * @return the targetSdkVersion, or {@link #SDK_NULL} if {@code packageName} doesn't exist
291      */
getTargetSdkVersion(final String packageName)292     public int getTargetSdkVersion(final String packageName) {
293         try {
294             ApplicationInfo info = mPackageManager.getApplicationInfo(packageName,
295                     PackageManager.GET_META_DATA);
296 
297             return info.targetSdkVersion;
298         } catch (PackageManager.NameNotFoundException e) {
299             Log.e(TAG, "Cannot find package: " + packageName, e);
300         }
301 
302         return SDK_NULL;
303     }
304 
305     /**
306      * Check whether background restriction is enabled
307      */
isBackgroundRestrictionEnabled(final int targetSdkVersion, final int uid, final String packageName)308     public boolean isBackgroundRestrictionEnabled(final int targetSdkVersion, final int uid,
309             final String packageName) {
310         if (targetSdkVersion >= Build.VERSION_CODES.O) {
311             return true;
312         }
313         final int mode = mAppOpsManager
314                 .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, packageName);
315         return mode == AppOpsManager.MODE_IGNORED || mode == AppOpsManager.MODE_ERRORED;
316     }
317 
318     /**
319      * Calculate the time since last full charge, including the device off time
320      *
321      * @param batteryUsageStats  class that contains the data
322      * @param currentTimeMs      current wall time
323      * @return time in millis
324      */
calculateLastFullChargeTime(BatteryUsageStats batteryUsageStats, long currentTimeMs)325     public long calculateLastFullChargeTime(BatteryUsageStats batteryUsageStats,
326             long currentTimeMs) {
327         return currentTimeMs - batteryUsageStats.getStatsStartTimestamp();
328     }
329 
logRuntime(String tag, String message, long startTime)330     public static void logRuntime(String tag, String message, long startTime) {
331         Log.d(tag, message + ": " + (System.currentTimeMillis() - startTime) + "ms");
332     }
333 
334     /**
335      * Return {@code true} if battery is overheated and charging.
336      */
isBatteryDefenderOn(BatteryInfo batteryInfo)337     public static boolean isBatteryDefenderOn(BatteryInfo batteryInfo) {
338         return batteryInfo.isOverheated && !batteryInfo.discharging;
339     }
340 
341     /**
342      * Find package uid from package name
343      *
344      * @param packageName used to find the uid
345      * @return uid for packageName, or {@link #UID_NULL} if exception happens or
346      * {@code packageName} is null
347      */
getPackageUid(String packageName)348     public int getPackageUid(String packageName) {
349         try {
350             return packageName == null ? UID_NULL : mPackageManager.getPackageUid(packageName,
351                     PackageManager.GET_META_DATA);
352         } catch (PackageManager.NameNotFoundException e) {
353             return UID_NULL;
354         }
355     }
356 
setForceAppStandby(int uid, String packageName, int mode)357     public void setForceAppStandby(int uid, String packageName,
358             int mode) {
359         final boolean isPreOApp = isPreOApp(packageName);
360         if (isPreOApp) {
361             // Control whether app could run in the background if it is pre O app
362             mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, packageName, mode);
363         }
364         // Control whether app could run jobs in the background
365         mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName, mode);
366 
367         ThreadUtils.postOnBackgroundThread(() -> {
368             final BatteryDatabaseManager batteryDatabaseManager = BatteryDatabaseManager
369                     .getInstance(mContext);
370             if (mode == AppOpsManager.MODE_IGNORED) {
371                 batteryDatabaseManager.insertAction(AnomalyDatabaseHelper.ActionType.RESTRICTION,
372                         uid, packageName, System.currentTimeMillis());
373             } else if (mode == AppOpsManager.MODE_ALLOWED) {
374                 batteryDatabaseManager.deleteAction(AnomalyDatabaseHelper.ActionType.RESTRICTION,
375                         uid, packageName);
376             }
377         });
378     }
379 
isForceAppStandbyEnabled(int uid, String packageName)380     public boolean isForceAppStandbyEnabled(int uid, String packageName) {
381         return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid,
382                 packageName) == AppOpsManager.MODE_IGNORED;
383     }
384 
clearForceAppStandby(String packageName)385     public boolean clearForceAppStandby(String packageName) {
386         final int uid = getPackageUid(packageName);
387         if (uid != UID_NULL && isForceAppStandbyEnabled(uid, packageName)) {
388             setForceAppStandby(uid, packageName, AppOpsManager.MODE_ALLOWED);
389             return true;
390         } else {
391             return false;
392         }
393     }
394 
395     @WorkerThread
getBatteryInfo(final String tag)396     public BatteryInfo getBatteryInfo(final String tag) {
397         final BatteryStatsManager systemService = mContext.getSystemService(
398                 BatteryStatsManager.class);
399         BatteryUsageStats batteryUsageStats;
400         try {
401             batteryUsageStats = systemService.getBatteryUsageStats(
402                     new BatteryUsageStatsQuery.Builder().includeBatteryHistory().build());
403         } catch (RuntimeException e) {
404             Log.e(TAG, "getBatteryInfo() error from getBatteryUsageStats()", e);
405             // Use default BatteryUsageStats.
406             batteryUsageStats = new BatteryUsageStats.Builder(new String[0]).build();
407         }
408 
409         final long startTime = System.currentTimeMillis();
410 
411         // Stuff we always need to get BatteryInfo
412         final Intent batteryBroadcast = mContext.registerReceiver(null,
413                 new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
414 
415         final long elapsedRealtimeUs = PowerUtil.convertMsToUs(
416                 SystemClock.elapsedRealtime());
417 
418         BatteryInfo batteryInfo;
419         Estimate estimate = getEnhancedEstimate();
420 
421         // couldn't get estimate from cache or provider, use fallback
422         if (estimate == null) {
423             estimate = new Estimate(
424                     batteryUsageStats.getBatteryTimeRemainingMs(),
425                     false /* isBasedOnUsage */,
426                     EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
427         }
428 
429         BatteryUtils.logRuntime(tag, "BatteryInfoLoader post query", startTime);
430         batteryInfo = BatteryInfo.getBatteryInfo(mContext, batteryBroadcast,
431                 batteryUsageStats, estimate, elapsedRealtimeUs, false /* shortString */);
432         BatteryUtils.logRuntime(tag, "BatteryInfoLoader.loadInBackground", startTime);
433 
434         try {
435             batteryUsageStats.close();
436         } catch (Exception e) {
437             Log.e(TAG, "BatteryUsageStats.close() failed", e);
438         }
439         return batteryInfo;
440     }
441 
442     @VisibleForTesting
getEnhancedEstimate()443     Estimate getEnhancedEstimate() {
444         Estimate estimate = null;
445         // Get enhanced prediction if available
446         if (Duration.between(Estimate.getLastCacheUpdateTime(mContext), Instant.now())
447                 .compareTo(Duration.ofSeconds(10)) < 0) {
448             estimate = Estimate.getCachedEstimateIfAvailable(mContext);
449         } else if (mPowerUsageFeatureProvider != null &&
450                 mPowerUsageFeatureProvider.isEnhancedBatteryPredictionEnabled(mContext)) {
451             estimate = mPowerUsageFeatureProvider.getEnhancedBatteryPrediction(mContext);
452             if (estimate != null) {
453                 Estimate.storeCachedEstimate(mContext, estimate);
454             }
455         }
456         return estimate;
457     }
458 
isDataCorrupted()459     private boolean isDataCorrupted() {
460         return mPackageManager == null || mAppOpsManager == null;
461     }
462 
463     @VisibleForTesting
getForegroundActivityTotalTimeUs(BatteryStats.Uid uid, long rawRealtimeUs)464     long getForegroundActivityTotalTimeUs(BatteryStats.Uid uid, long rawRealtimeUs) {
465         final BatteryStats.Timer timer = uid.getForegroundActivityTimer();
466         if (timer != null) {
467             return timer.getTotalTimeLocked(rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
468         }
469 
470         return 0;
471     }
472 
473     @VisibleForTesting
getForegroundServiceTotalTimeUs(BatteryStats.Uid uid, long rawRealtimeUs)474     long getForegroundServiceTotalTimeUs(BatteryStats.Uid uid, long rawRealtimeUs) {
475         final BatteryStats.Timer timer = uid.getForegroundServiceTimer();
476         if (timer != null) {
477             return timer.getTotalTimeLocked(rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
478         }
479 
480         return 0;
481     }
482 
isPreOApp(final String packageName)483     public boolean isPreOApp(final String packageName) {
484         try {
485             ApplicationInfo info = mPackageManager.getApplicationInfo(packageName,
486                     PackageManager.GET_META_DATA);
487 
488             return info.targetSdkVersion < Build.VERSION_CODES.O;
489         } catch (PackageManager.NameNotFoundException e) {
490             Log.e(TAG, "Cannot find package: " + packageName, e);
491         }
492 
493         return false;
494     }
495 
isPreOApp(final String[] packageNames)496     public boolean isPreOApp(final String[] packageNames) {
497         if (ArrayUtils.isEmpty(packageNames)) {
498             return false;
499         }
500 
501         for (String packageName : packageNames) {
502             if (isPreOApp(packageName)) {
503                 return true;
504             }
505         }
506 
507         return false;
508     }
509 
510     /**
511      * Return {@code true} if we should hide anomaly app represented by {@code uid}
512      */
shouldHideAnomaly(PowerAllowlistBackend powerAllowlistBackend, int uid, AnomalyInfo anomalyInfo)513     public boolean shouldHideAnomaly(PowerAllowlistBackend powerAllowlistBackend, int uid,
514             AnomalyInfo anomalyInfo) {
515         final String[] packageNames = mPackageManager.getPackagesForUid(uid);
516         if (ArrayUtils.isEmpty(packageNames)) {
517             // Don't show it if app has been uninstalled
518             return true;
519         }
520 
521         return isSystemUid(uid) || powerAllowlistBackend.isAllowlisted(packageNames)
522                 || (isSystemApp(mPackageManager, packageNames) && !hasLauncherEntry(packageNames))
523                 || (isExcessiveBackgroundAnomaly(anomalyInfo) && !isPreOApp(packageNames));
524     }
525 
isExcessiveBackgroundAnomaly(AnomalyInfo anomalyInfo)526     private boolean isExcessiveBackgroundAnomaly(AnomalyInfo anomalyInfo) {
527         return anomalyInfo.anomalyType
528                 == StatsManagerConfig.AnomalyType.EXCESSIVE_BACKGROUND_SERVICE;
529     }
530 
isSystemUid(int uid)531     private boolean isSystemUid(int uid) {
532         final int appUid = UserHandle.getAppId(uid);
533         return appUid >= Process.ROOT_UID && appUid < Process.FIRST_APPLICATION_UID;
534     }
535 
isSystemApp(PackageManager packageManager, String[] packageNames)536     private boolean isSystemApp(PackageManager packageManager, String[] packageNames) {
537         for (String packageName : packageNames) {
538             try {
539                 final ApplicationInfo info = packageManager.getApplicationInfo(packageName,
540                         0 /* flags */);
541                 if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
542                     return true;
543                 }
544             } catch (PackageManager.NameNotFoundException e) {
545                 Log.e(TAG, "Package not found: " + packageName, e);
546             }
547         }
548 
549         return false;
550     }
551 
hasLauncherEntry(String[] packageNames)552     private boolean hasLauncherEntry(String[] packageNames) {
553         final Intent launchIntent = new Intent(Intent.ACTION_MAIN, null);
554         launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
555 
556         // If we do not specify MATCH_DIRECT_BOOT_AWARE or
557         // MATCH_DIRECT_BOOT_UNAWARE, system will derive and update the flags
558         // according to the user's lock state. When the user is locked,
559         // components
560         // with ComponentInfo#directBootAware == false will be filtered. We should
561         // explicitly include both direct boot aware and unaware components here.
562         final List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(launchIntent,
563                 PackageManager.MATCH_DISABLED_COMPONENTS
564                         | PackageManager.MATCH_DIRECT_BOOT_AWARE
565                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
566                         | PackageManager.MATCH_SYSTEM_ONLY);
567         for (int i = 0, size = resolveInfos.size(); i < size; i++) {
568             final ResolveInfo resolveInfo = resolveInfos.get(i);
569             if (ArrayUtils.contains(packageNames, resolveInfo.activityInfo.packageName)) {
570                 return true;
571             }
572         }
573 
574         return false;
575     }
576 
577     /**
578      * Return version number of an app represented by {@code packageName}, and return -1 if not
579      * found.
580      */
getAppLongVersionCode(String packageName)581     public long getAppLongVersionCode(String packageName) {
582         try {
583             final PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
584                     0 /* flags */);
585             return packageInfo.getLongVersionCode();
586         } catch (PackageManager.NameNotFoundException e) {
587             Log.e(TAG, "Cannot find package: " + packageName, e);
588         }
589 
590         return -1L;
591     }
592 
593     /** Gets the current dock defender mode */
getCurrentDockDefenderMode(Context context, BatteryInfo batteryInfo)594     public static int getCurrentDockDefenderMode(Context context, BatteryInfo batteryInfo) {
595         if (batteryInfo.pluggedStatus == BatteryManager.BATTERY_PLUGGED_DOCK) {
596             if (Settings.Global.getInt(context.getContentResolver(),
597                     SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0) == 1) {
598                 return DockDefenderMode.TEMPORARILY_BYPASSED;
599             } else if (batteryInfo.isOverheated && FeatureFactory.getFactory(context)
600                     .getPowerUsageFeatureProvider(context)
601                     .isExtraDefend()) {
602                 return DockDefenderMode.ACTIVE;
603             } else if (!batteryInfo.isOverheated) {
604                 return DockDefenderMode.FUTURE_BYPASS;
605             }
606         }
607         return DockDefenderMode.DISABLED;
608     }
609 }
610