• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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