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