1 /* 2 * Copyright (C) 2022 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.car.settings.applications.performance; 18 19 import static android.car.settings.CarSettings.Secure.KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE; 20 21 import android.car.watchdog.CarWatchdogManager; 22 import android.car.watchdog.PackageKillableState; 23 import android.content.ContentResolver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.pm.ApplicationInfo; 27 import android.content.pm.PackageManager; 28 import android.content.pm.ResolveInfo; 29 import android.os.Process; 30 import android.os.UserHandle; 31 import android.provider.Settings; 32 import android.text.TextUtils; 33 import android.util.ArraySet; 34 35 import com.android.car.settings.R; 36 import com.android.car.settings.common.ConfirmationDialogFragment; 37 import com.android.car.settings.common.FragmentController; 38 39 import java.util.ArrayList; 40 import java.util.Arrays; 41 import java.util.List; 42 import java.util.Objects; 43 import java.util.Set; 44 45 /** 46 * Utility functions for use in Performance-impacting apps settings and Prioritize app settings. 47 */ 48 public final class PerfImpactingAppsUtils { 49 50 private static final String PACKAGES_DISABLED_ON_RESOURCE_OVERUSE_SEPARATOR = ";"; 51 PerfImpactingAppsUtils()52 private PerfImpactingAppsUtils() {} 53 54 /** 55 * Returns the {@link android.car.watchdog.PackageKillableState.KillableState} for the package 56 * and user provided. 57 */ getKillableState(String packageName, UserHandle userHandle, CarWatchdogManager manager)58 public static int getKillableState(String packageName, UserHandle userHandle, 59 CarWatchdogManager manager) { 60 return Objects.requireNonNull(manager) 61 .getPackageKillableStatesAsUser(userHandle).stream() 62 .filter(pks -> pks.getPackageName().equals(packageName)) 63 .findFirst().map(PackageKillableState::getKillableState).orElse(-1); 64 } 65 66 /** 67 * Shows confirmation dialog when user chooses to prioritize an app disabled because of resource 68 * overuse. 69 */ showPrioritizeAppConfirmationDialog(Context context, FragmentController fragmentController, ConfirmationDialogFragment.ConfirmListener listener, String dialogTag)70 public static void showPrioritizeAppConfirmationDialog(Context context, 71 FragmentController fragmentController, 72 ConfirmationDialogFragment.ConfirmListener listener, String dialogTag) { 73 ConfirmationDialogFragment dialogFragment = 74 new ConfirmationDialogFragment.Builder(context) 75 .setTitle(R.string.prioritize_app_performance_dialog_title) 76 .setMessage(R.string.prioritize_app_performance_dialog_text) 77 .setPositiveButton(R.string.prioritize_app_performance_dialog_action_on, 78 listener) 79 .setNegativeButton(R.string.prioritize_app_performance_dialog_action_off, 80 /* rejectListener= */ null) 81 .build(); 82 fragmentController.showDialog(dialogFragment, dialogTag); 83 } 84 85 /** 86 * Returns the set of package names disabled due to resource overuse. 87 */ getDisabledPackages(Context context)88 public static Set<String> getDisabledPackages(Context context) { 89 ContentResolver contentResolverForUser = context.createContextAsUser( 90 UserHandle.getUserHandleForUid(Process.myUid()), /* flags= */ 0) 91 .getContentResolver(); 92 return extractPackages(Settings.Secure.getString(contentResolverForUser, 93 KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE)); 94 } 95 96 /** 97 * Returns a list of application infos disabled due to resource overuse. 98 */ getDisabledAppInfos(Context context)99 public static List<ApplicationInfo> getDisabledAppInfos(Context context) { 100 Set<String> disabledPackageNames = getDisabledPackages(context); 101 if (disabledPackageNames.isEmpty()) { 102 return new ArrayList<>(0); 103 } 104 PackageManager packageManager = context.getPackageManager(); 105 List<ResolveInfo> allPackages = packageManager.queryIntentActivities( 106 new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER), 107 PackageManager.ResolveInfoFlags.of(PackageManager.GET_RESOLVED_FILTER 108 | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS)); 109 List<ApplicationInfo> disabledAppInfos = new ArrayList<>(allPackages.size()); 110 for (int idx = 0; idx < allPackages.size(); idx++) { 111 ApplicationInfo applicationInfo = allPackages.get(idx).activityInfo.applicationInfo; 112 if (disabledPackageNames.contains(applicationInfo.packageName)) { 113 disabledAppInfos.add(applicationInfo); 114 // Match only the first occurrence of a package. 115 // |PackageManager#queryIntentActivities| can return duplicate packages. 116 disabledPackageNames.remove(applicationInfo.packageName); 117 } 118 } 119 return disabledAppInfos; 120 } 121 extractPackages(String settingsString)122 private static ArraySet<String> extractPackages(String settingsString) { 123 return TextUtils.isEmpty(settingsString) ? new ArraySet<>() 124 : new ArraySet<>(Arrays.asList(settingsString.split( 125 PACKAGES_DISABLED_ON_RESOURCE_OVERUSE_SEPARATOR))); 126 } 127 } 128