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.car.settings.applications; 18 19 import android.car.Car; 20 import android.car.drivingstate.CarUxRestrictions; 21 import android.car.watchdog.CarWatchdogManager; 22 import android.car.watchdog.PackageKillableState; 23 import android.content.Context; 24 import android.content.pm.PackageInfo; 25 import android.os.UserHandle; 26 27 import androidx.annotation.VisibleForTesting; 28 import androidx.preference.TwoStatePreference; 29 30 import com.android.car.settings.R; 31 import com.android.car.settings.common.ConfirmationDialogFragment; 32 import com.android.car.settings.common.FragmentController; 33 import com.android.car.settings.common.Logger; 34 import com.android.car.settings.common.PreferenceController; 35 import com.android.internal.annotations.GuardedBy; 36 37 import java.util.Objects; 38 39 /** 40 * Controller for preference which enables / disables I/O overuse killing for an application. 41 */ 42 public class PeakPerformancePreferenceController extends PreferenceController<TwoStatePreference> { 43 private static final Logger LOG = new Logger(PeakPerformancePreferenceController.class); 44 45 @VisibleForTesting 46 static final String TURN_OFF_PEAK_PERFORMANCE_DIALOG_TAG = 47 "com.android.car.settings.applications.TurnOffPeakPerformanceDialog"; 48 49 private final Object mLock = new Object(); 50 @GuardedBy("mLock") 51 private CarWatchdogManager mCarWatchdogManager; 52 53 private Car mCar; 54 private String mPackageName; 55 private UserHandle mUserHandle; 56 private int mKillableState; 57 PeakPerformancePreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)58 public PeakPerformancePreferenceController(Context context, String preferenceKey, 59 FragmentController fragmentController, 60 CarUxRestrictions uxRestrictions) { 61 super(context, preferenceKey, fragmentController, uxRestrictions); 62 } 63 64 @Override onCreateInternal()65 protected void onCreateInternal() { 66 if (mCar != null && mCar.isConnected()) { 67 mCar.disconnect(); 68 mCar = null; 69 } 70 mCar = Car.createCar(getContext(), null, Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, 71 (Car car, boolean ready) -> { 72 synchronized (mLock) { 73 if (ready) { 74 mCarWatchdogManager = (CarWatchdogManager) car.getCarManager( 75 Car.CAR_WATCHDOG_SERVICE); 76 } else { 77 mCarWatchdogManager = null; 78 } 79 } 80 }); 81 } 82 83 @Override onDestroyInternal()84 protected void onDestroyInternal() { 85 if (mCar != null) { 86 mCar.disconnect(); 87 mCar = null; 88 } 89 } 90 91 /** 92 * Set the package info of the application. 93 */ setPackageInfo(PackageInfo packageInfo)94 public void setPackageInfo(PackageInfo packageInfo) { 95 mPackageName = packageInfo.packageName; 96 mUserHandle = UserHandle.getUserHandleForUid(packageInfo.applicationInfo.uid); 97 } 98 99 @Override getPreferenceType()100 protected Class<TwoStatePreference> getPreferenceType() { 101 return TwoStatePreference.class; 102 } 103 104 @Override updateState(TwoStatePreference preference)105 protected void updateState(TwoStatePreference preference) { 106 mKillableState = getKillableState(); 107 preference.setSummary(getContext().getString(R.string.peak_performance_summary)); 108 preference.setChecked(mKillableState == PackageKillableState.KILLABLE_STATE_YES); 109 preference.setEnabled(mKillableState != PackageKillableState.KILLABLE_STATE_NEVER); 110 } 111 112 @Override handlePreferenceChanged(TwoStatePreference preference, Object newValue)113 protected boolean handlePreferenceChanged(TwoStatePreference preference, Object newValue) { 114 if (mKillableState == PackageKillableState.KILLABLE_STATE_NEVER) { 115 return false; 116 } 117 118 boolean shouldKill = (boolean) newValue; 119 120 // If shouldKill is true, switch toggle going from OFF to ON. 121 if (shouldKill) { 122 setKillableState(true); 123 preference.setChecked(true); 124 mKillableState = PackageKillableState.KILLABLE_STATE_YES; 125 } else { 126 ConfirmationDialogFragment dialogFragment = 127 new ConfirmationDialogFragment.Builder(getContext()) 128 .setTitle(R.string.peak_performance_dialog_title) 129 .setMessage(R.string.peak_performance_dialog_text) 130 .setPositiveButton(R.string.peak_performance_dialog_action_off, 131 arguments -> { 132 setKillableState(false); 133 preference.setChecked(false); 134 mKillableState = PackageKillableState.KILLABLE_STATE_NO; 135 }) 136 .setNegativeButton( 137 R.string.peak_performance_dialog_action_on, 138 /* rejectListener= */null) 139 .build(); 140 getFragmentController().showDialog(dialogFragment, 141 TURN_OFF_PEAK_PERFORMANCE_DIALOG_TAG); 142 } 143 return shouldKill; 144 } 145 getKillableState()146 private int getKillableState() { 147 synchronized (mLock) { 148 return Objects.requireNonNull(mCarWatchdogManager).getPackageKillableStatesAsUser( 149 mUserHandle).stream() 150 .filter(pks -> pks.getPackageName().equals(mPackageName)) 151 .findFirst().map(PackageKillableState::getKillableState).orElse(-1); 152 } 153 } 154 setKillableState(boolean isKillable)155 private void setKillableState(boolean isKillable) { 156 synchronized (mLock) { 157 mCarWatchdogManager.setKillablePackageAsUser(mPackageName, mUserHandle, isKillable); 158 } 159 } 160 } 161