blob: 3c13dc907022336868f0a0d5092d929be2df1e8f [file] [log] [blame]
Lakshman Annadorai016127e2021-03-18 09:11:43 -07001/*
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
17package com.android.car.watchdog;
18
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070019import static android.automotive.watchdog.internal.ResourceOveruseActionType.KILLED;
20import static android.automotive.watchdog.internal.ResourceOveruseActionType.KILLED_RECURRING_OVERUSE;
21import static android.automotive.watchdog.internal.ResourceOveruseActionType.NOT_KILLED;
22import static android.automotive.watchdog.internal.ResourceOveruseActionType.NOT_KILLED_USER_OPTED;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070023import static android.car.watchdog.CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070024import static android.car.watchdog.PackageKillableState.KILLABLE_STATE_NEVER;
25import static android.car.watchdog.PackageKillableState.KILLABLE_STATE_NO;
26import static android.car.watchdog.PackageKillableState.KILLABLE_STATE_YES;
27import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
28import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
29import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
30
Lakshman Annadorai94323ff2021-04-29 12:14:34 -070031import static com.android.car.watchdog.CarWatchdogService.DEBUG;
32import static com.android.car.watchdog.CarWatchdogService.TAG;
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070033import static com.android.car.watchdog.PackageInfoHandler.SHARED_PACKAGE_PREFIX;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070034import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070035
36import android.annotation.NonNull;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070037import android.annotation.UserIdInt;
38import android.app.ActivityThread;
39import android.automotive.watchdog.ResourceType;
Lakshman Annadoraie1720472021-04-13 15:22:57 -070040import android.automotive.watchdog.internal.ApplicationCategoryType;
41import android.automotive.watchdog.internal.ComponentType;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070042import android.automotive.watchdog.internal.PackageIdentifier;
43import android.automotive.watchdog.internal.PackageIoOveruseStats;
Lakshman Annadoraie1720472021-04-13 15:22:57 -070044import android.automotive.watchdog.internal.PackageMetadata;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070045import android.automotive.watchdog.internal.PackageResourceOveruseAction;
Lakshman Annadoraie1720472021-04-13 15:22:57 -070046import android.automotive.watchdog.internal.PerStateIoOveruseThreshold;
47import android.automotive.watchdog.internal.ResourceSpecificConfiguration;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070048import android.car.watchdog.CarWatchdogManager;
49import android.car.watchdog.IResourceOveruseListener;
Lakshman Annadoraie1720472021-04-13 15:22:57 -070050import android.car.watchdog.IoOveruseAlertThreshold;
51import android.car.watchdog.IoOveruseConfiguration;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070052import android.car.watchdog.IoOveruseStats;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070053import android.car.watchdog.PackageKillableState;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070054import android.car.watchdog.PackageKillableState.KillableState;
55import android.car.watchdog.PerStateBytes;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070056import android.car.watchdog.ResourceOveruseConfiguration;
57import android.car.watchdog.ResourceOveruseStats;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070058import android.car.watchdoglib.CarWatchdogDaemonHelper;
59import android.content.Context;
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070060import android.content.pm.ApplicationInfo;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070061import android.content.pm.IPackageManager;
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -070062import android.content.pm.PackageInfo;
63import android.content.pm.PackageManager;
64import android.content.pm.UserInfo;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070065import android.os.Binder;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070066import android.os.Handler;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070067import android.os.IBinder;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070068import android.os.Looper;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070069import android.os.RemoteException;
Lakshman Annadorai94323ff2021-04-29 12:14:34 -070070import android.os.SystemClock;
71import android.os.TransactionTooLargeException;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070072import android.os.UserHandle;
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -070073import android.os.UserManager;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070074import android.util.ArrayMap;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070075import android.util.ArraySet;
76import android.util.IndentingPrintWriter;
77import android.util.SparseArray;
Jahdiel Alvarez8bf64ce2021-07-21 01:03:42 +000078import android.util.SparseBooleanArray;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070079
Lakshman Annadorai016127e2021-03-18 09:11:43 -070080import com.android.internal.annotations.GuardedBy;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070081import com.android.internal.annotations.VisibleForTesting;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070082import com.android.internal.util.Preconditions;
83import com.android.server.utils.Slogf;
84
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070085import java.time.ZoneOffset;
86import java.time.ZonedDateTime;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070087import java.util.ArrayList;
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070088import java.util.Collections;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070089import java.util.List;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070090import java.util.Map;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070091import java.util.Objects;
92import java.util.Set;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070093import java.util.function.BiFunction;
Lakshman Annadorai16999d22021-05-25 08:33:30 -070094import java.util.function.Consumer;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070095
96/**
97 * Handles system resource performance monitoring module.
98 */
99public final class WatchdogPerfHandler {
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700100 public static final String INTERNAL_APPLICATION_CATEGORY_TYPE_MAPS = "MAPS";
101 public static final String INTERNAL_APPLICATION_CATEGORY_TYPE_MEDIA = "MEDIA";
102 public static final String INTERNAL_APPLICATION_CATEGORY_TYPE_UNKNOWN = "UNKNOWN";
103
Jahdiel Alvarez8bf64ce2021-07-21 01:03:42 +0000104 static final long RESOURCE_OVERUSE_KILLING_DELAY_MILLS = 10_000;
105
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700106 private static final long MAX_WAIT_TIME_MILLS = 3_000;
107
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700108 private final Context mContext;
109 private final CarWatchdogDaemonHelper mCarWatchdogDaemonHelper;
110 private final PackageInfoHandler mPackageInfoHandler;
111 private final Handler mMainHandler;
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700112 private final Object mLock = new Object();
113 /*
114 * Cache of added resource overuse listeners by uid.
115 */
116 @GuardedBy("mLock")
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700117 private final ArrayMap<String, PackageResourceUsage> mUsageByUserPackage = new ArrayMap<>();
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700118 @GuardedBy("mLock")
119 private final List<PackageResourceOveruseAction> mOveruseActionsByUserPackage =
120 new ArrayList<>();
121 @GuardedBy("mLock")
Lakshman Annadorai16999d22021-05-25 08:33:30 -0700122 private final SparseArray<ArrayList<ResourceOveruseListenerInfo>> mOveruseListenerInfosByUid =
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700123 new SparseArray<>();
124 @GuardedBy("mLock")
Lakshman Annadorai16999d22021-05-25 08:33:30 -0700125 private final SparseArray<ArrayList<ResourceOveruseListenerInfo>>
126 mOveruseSystemListenerInfosByUid = new SparseArray<>();
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700127 /* Set of safe-to-kill system and vendor packages. */
128 @GuardedBy("mLock")
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700129 public final ArraySet<String> mSafeToKillPackages = new ArraySet<>();
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700130 /* Default killable state for packages when not updated by the user. */
131 @GuardedBy("mLock")
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700132 public final ArraySet<String> mDefaultNotKillableGenericPackages = new ArraySet<>();
Lakshman Annadorai8ee56ec2021-04-27 11:51:08 -0700133 @GuardedBy("mLock")
134 private ZonedDateTime mLastStatsReportUTC;
135 @GuardedBy("mLock")
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700136 private List<android.automotive.watchdog.internal.ResourceOveruseConfiguration>
137 mPendingSetResourceOveruseConfigurationsRequest = null;
138 @GuardedBy("mLock")
Lakshman Annadorai8ee56ec2021-04-27 11:51:08 -0700139 boolean mIsConnectedToDaemon;
Jahdiel Alvarez8bf64ce2021-07-21 01:03:42 +0000140 @GuardedBy("mLock")
141 long mResourceOveruseKillingDelayMills;
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700142
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700143 public WatchdogPerfHandler(Context context, CarWatchdogDaemonHelper daemonHelper,
Lakshman Annadoraid7b8a032021-04-20 12:31:05 -0700144 PackageInfoHandler packageInfoHandler) {
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700145 mContext = context;
146 mCarWatchdogDaemonHelper = daemonHelper;
147 mPackageInfoHandler = packageInfoHandler;
148 mMainHandler = new Handler(Looper.getMainLooper());
149 mLastStatsReportUTC = ZonedDateTime.now(ZoneOffset.UTC);
Jahdiel Alvarez8bf64ce2021-07-21 01:03:42 +0000150 mResourceOveruseKillingDelayMills = RESOURCE_OVERUSE_KILLING_DELAY_MILLS;
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700151 }
152
153 /** Initializes the handler. */
154 public void init() {
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700155 /*
156 * TODO(b/183947162): Opt-in to receive package change broadcast and handle package enabled
157 * state changes.
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700158 * TODO(b/192294393): Persist in-memory data: Read the current day's I/O overuse stats from
159 * database.
160 * TODO(b/192665269): Fetch the safe-to-kill from daemon on initialization and update
161 * mSafeToKillPackages.
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700162 */
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700163 synchronized (mLock) {
164 checkAndHandleDateChangeLocked();
165 }
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700166 if (DEBUG) {
167 Slogf.d(TAG, "WatchdogPerfHandler is initialized");
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700168 }
169 }
170
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700171 /** Releases the handler */
172 public void release() {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700173 /* TODO(b/192294393): Write daily usage to SQLite DB storage. */
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700174 if (DEBUG) {
175 Slogf.d(TAG, "WatchdogPerfHandler is released");
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700176 }
177 }
178
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700179 /** Dumps its state. */
180 public void dump(IndentingPrintWriter writer) {
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700181 /*
182 * TODO(b/183436216): Implement this method.
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700183 */
184 }
185
Lakshman Annadorai8ee56ec2021-04-27 11:51:08 -0700186 /** Retries any pending requests on re-connecting to the daemon */
187 public void onDaemonConnectionChange(boolean isConnected) {
188 synchronized (mLock) {
189 mIsConnectedToDaemon = isConnected;
190 }
191 if (isConnected) {
192 /*
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700193 * Retry pending set resource overuse configuration request before processing any new
194 * set/get requests. Thus notify the waiting requests only after the retry completes.
Lakshman Annadorai8ee56ec2021-04-27 11:51:08 -0700195 */
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700196 retryPendingSetResourceOveruseConfigurations();
197 }
198 synchronized (mLock) {
199 mLock.notifyAll();
Lakshman Annadorai8ee56ec2021-04-27 11:51:08 -0700200 }
201 }
202
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700203 /** Returns resource overuse stats for the calling package. */
204 @NonNull
205 public ResourceOveruseStats getResourceOveruseStats(
206 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
207 @CarWatchdogManager.StatsPeriod int maxStatsPeriod) {
208 Preconditions.checkArgument((resourceOveruseFlag > 0),
209 "Must provide valid resource overuse flag");
210 Preconditions.checkArgument((maxStatsPeriod > 0),
211 "Must provide valid maximum stats period");
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700212 // When more resource stats are added, make this as optional.
213 Preconditions.checkArgument((resourceOveruseFlag & FLAG_RESOURCE_OVERUSE_IO) != 0,
214 "Must provide resource I/O overuse flag");
215 int callingUid = Binder.getCallingUid();
216 int callingUserId = UserHandle.getUserId(callingUid);
217 UserHandle callingUserHandle = UserHandle.of(callingUserId);
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700218 String genericPackageName =
219 mPackageInfoHandler.getNamesForUids(new int[]{callingUid})
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700220 .get(callingUid, null);
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700221 if (genericPackageName == null) {
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700222 Slogf.w(TAG, "Failed to fetch package info for uid %d", callingUid);
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700223 return new ResourceOveruseStats.Builder("", callingUserHandle).build();
224 }
225 ResourceOveruseStats.Builder statsBuilder =
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700226 new ResourceOveruseStats.Builder(genericPackageName, callingUserHandle);
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700227 statsBuilder.setIoOveruseStats(
228 getIoOveruseStatsForPeriod(callingUserId, genericPackageName, maxStatsPeriod));
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700229 if (DEBUG) {
230 Slogf.d(TAG, "Returning all resource overuse stats for calling uid %d [user %d and "
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700231 + "package '%s']", callingUid, callingUserId, genericPackageName);
Lakshman Annadoraid7b8a032021-04-20 12:31:05 -0700232 }
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700233 return statsBuilder.build();
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700234 }
235
236 /** Returns resource overuse stats for all packages. */
237 @NonNull
238 public List<ResourceOveruseStats> getAllResourceOveruseStats(
239 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
240 @CarWatchdogManager.MinimumStatsFlag int minimumStatsFlag,
241 @CarWatchdogManager.StatsPeriod int maxStatsPeriod) {
242 Preconditions.checkArgument((resourceOveruseFlag > 0),
243 "Must provide valid resource overuse flag");
244 Preconditions.checkArgument((maxStatsPeriod > 0),
245 "Must provide valid maximum stats period");
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700246 // When more resource types are added, make this as optional.
247 Preconditions.checkArgument((resourceOveruseFlag & FLAG_RESOURCE_OVERUSE_IO) != 0,
248 "Must provide resource I/O overuse flag");
249 long minimumBytesWritten = getMinimumBytesWritten(minimumStatsFlag);
250 List<ResourceOveruseStats> allStats = new ArrayList<>();
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700251 synchronized (mLock) {
252 for (int i = 0; i < mUsageByUserPackage.size(); ++i) {
253 PackageResourceUsage usage = mUsageByUserPackage.valueAt(i);
254 ResourceOveruseStats.Builder statsBuilder = usage.getResourceOveruseStatsBuilder();
255 IoOveruseStats ioOveruseStats =
256 getIoOveruseStatsLocked(usage, minimumBytesWritten, maxStatsPeriod);
257 if (ioOveruseStats == null) {
258 continue;
259 }
260 allStats.add(statsBuilder.setIoOveruseStats(ioOveruseStats).build());
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700261 }
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700262 }
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700263 if (DEBUG) {
264 Slogf.d(TAG, "Returning all resource overuse stats");
Lakshman Annadoraid7b8a032021-04-20 12:31:05 -0700265 }
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700266 return allStats;
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700267 }
268
269 /** Returns resource overuse stats for the specified user package. */
270 @NonNull
271 public ResourceOveruseStats getResourceOveruseStatsForUserPackage(
272 @NonNull String packageName, @NonNull UserHandle userHandle,
273 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
274 @CarWatchdogManager.StatsPeriod int maxStatsPeriod) {
275 Objects.requireNonNull(packageName, "Package name must be non-null");
276 Objects.requireNonNull(userHandle, "User handle must be non-null");
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700277 Preconditions.checkArgument(!userHandle.equals(UserHandle.ALL),
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700278 "Must provide the user handle for a specific user");
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700279 Preconditions.checkArgument((resourceOveruseFlag > 0),
280 "Must provide valid resource overuse flag");
281 Preconditions.checkArgument((maxStatsPeriod > 0),
282 "Must provide valid maximum stats period");
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700283 // When more resource types are added, make this as optional.
284 Preconditions.checkArgument((resourceOveruseFlag & FLAG_RESOURCE_OVERUSE_IO) != 0,
285 "Must provide resource I/O overuse flag");
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700286 String genericPackageName =
287 mPackageInfoHandler.getNameForUserPackage(packageName, userHandle.getIdentifier());
288 if (genericPackageName == null) {
289 throw new IllegalArgumentException("Package '" + packageName + "' not found");
290 }
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700291 ResourceOveruseStats.Builder statsBuilder =
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700292 new ResourceOveruseStats.Builder(genericPackageName, userHandle);
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700293 statsBuilder.setIoOveruseStats(getIoOveruseStatsForPeriod(userHandle.getIdentifier(),
294 genericPackageName, maxStatsPeriod));
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700295 if (DEBUG) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700296 Slogf.d(TAG, "Returning resource overuse stats for user %d, package '%s', "
297 + "generic package '%s'", userHandle.getIdentifier(), packageName,
298 genericPackageName);
Lakshman Annadoraid7b8a032021-04-20 12:31:05 -0700299 }
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700300 return statsBuilder.build();
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700301 }
302
303 /** Adds the resource overuse listener. */
304 public void addResourceOveruseListener(
305 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
306 @NonNull IResourceOveruseListener listener) {
307 Objects.requireNonNull(listener, "Listener must be non-null");
308 Preconditions.checkArgument((resourceOveruseFlag > 0),
309 "Must provide valid resource overuse flag");
310 synchronized (mLock) {
311 addResourceOveruseListenerLocked(resourceOveruseFlag, listener,
312 mOveruseListenerInfosByUid);
313 }
314 }
315
316 /** Removes the previously added resource overuse listener. */
317 public void removeResourceOveruseListener(@NonNull IResourceOveruseListener listener) {
318 Objects.requireNonNull(listener, "Listener must be non-null");
319 synchronized (mLock) {
320 removeResourceOveruseListenerLocked(listener, mOveruseListenerInfosByUid);
321 }
322 }
323
324 /** Adds the resource overuse system listener. */
325 public void addResourceOveruseListenerForSystem(
326 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
327 @NonNull IResourceOveruseListener listener) {
328 Objects.requireNonNull(listener, "Listener must be non-null");
329 Preconditions.checkArgument((resourceOveruseFlag > 0),
330 "Must provide valid resource overuse flag");
331 synchronized (mLock) {
332 addResourceOveruseListenerLocked(resourceOveruseFlag, listener,
333 mOveruseSystemListenerInfosByUid);
334 }
335 }
336
337 /** Removes the previously added resource overuse system listener. */
338 public void removeResourceOveruseListenerForSystem(@NonNull IResourceOveruseListener listener) {
339 Objects.requireNonNull(listener, "Listener must be non-null");
340 synchronized (mLock) {
341 removeResourceOveruseListenerLocked(listener, mOveruseSystemListenerInfosByUid);
342 }
343 }
344
345 /** Sets whether or not a package is killable on resource overuse. */
346 public void setKillablePackageAsUser(String packageName, UserHandle userHandle,
347 boolean isKillable) {
348 Objects.requireNonNull(packageName, "Package name must be non-null");
349 Objects.requireNonNull(userHandle, "User handle must be non-null");
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700350
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700351 if (userHandle.equals(UserHandle.ALL)) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700352 setPackageKillableStateForAllUsers(packageName, isKillable);
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700353 return;
354 }
355 int userId = userHandle.getIdentifier();
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700356 String genericPackageName = mPackageInfoHandler.getNameForUserPackage(packageName, userId);
357 if (genericPackageName == null) {
358 throw new IllegalArgumentException("Package '" + packageName + "' not found");
359 }
360 String key = getUserPackageUniqueId(userId, genericPackageName);
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700361 synchronized (mLock) {
362 /*
363 * When the queried package is not cached in {@link mUsageByUserPackage}, the set API
364 * will update the killable state even when the package should never be killed.
365 * But the get API will return the correct killable state. This behavior is tolerable
366 * because in production the set API should be called only after the get API.
367 * For instance, when this case happens by mistake and the package overuses resource
368 * between the set and the get API calls, the daemon will provide correct killable
369 * state when pushing the latest stats. Ergo, the invalid killable state doesn't have
370 * any effect.
371 */
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700372 PackageResourceUsage usage = mUsageByUserPackage.get(key);
373 if (usage == null) {
374 usage = new PackageResourceUsage(userId, genericPackageName);
375 }
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700376 if (!usage.setKillableStateLocked(isKillable)) {
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700377 Slogf.e(TAG, "User %d cannot set killable state for package '%s'",
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700378 userHandle.getIdentifier(), genericPackageName);
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700379 throw new IllegalArgumentException("Package killable state is not updatable");
380 }
381 mUsageByUserPackage.put(key, usage);
382 }
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700383 if (DEBUG) {
384 Slogf.d(TAG, "Successfully set killable package state for user %d", userId);
Lakshman Annadoraid7b8a032021-04-20 12:31:05 -0700385 }
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700386 }
387
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700388 private void setPackageKillableStateForAllUsers(String packageName, boolean isKillable) {
389 UserManager userManager = UserManager.get(mContext);
390 List<UserInfo> userInfos = userManager.getAliveUsers();
391 String genericPackageName = null;
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700392 synchronized (mLock) {
393 for (int i = 0; i < userInfos.size(); ++i) {
394 int userId = userInfos.get(i).id;
395 String name = mPackageInfoHandler.getNameForUserPackage(packageName, userId);
396 if (name == null) {
397 continue;
398 }
399 genericPackageName = name;
400 String key = getUserPackageUniqueId(userId, genericPackageName);
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700401 PackageResourceUsage usage = mUsageByUserPackage.get(key);
402 if (usage == null) {
403 continue;
404 }
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700405 if (!usage.setKillableStateLocked(isKillable)) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700406 Slogf.e(TAG, "Cannot set killable state for package '%s'", packageName);
407 throw new IllegalArgumentException(
408 "Package killable state is not updatable");
409 }
410 }
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700411 if (genericPackageName != null) {
412 if (!isKillable) {
413 mDefaultNotKillableGenericPackages.add(genericPackageName);
414 } else {
415 mDefaultNotKillableGenericPackages.remove(genericPackageName);
416 }
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700417 }
418 }
419 if (DEBUG) {
420 Slogf.d(TAG, "Successfully set killable package state for all users");
421 }
422 }
423
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700424 /** Returns the list of package killable states on resource overuse for the user. */
425 @NonNull
426 public List<PackageKillableState> getPackageKillableStatesAsUser(UserHandle userHandle) {
427 Objects.requireNonNull(userHandle, "User handle must be non-null");
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700428 PackageManager pm = mContext.getPackageManager();
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700429 if (!userHandle.equals(UserHandle.ALL)) {
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700430 if (DEBUG) {
431 Slogf.d(TAG, "Returning all package killable states for user %d",
Lakshman Annadoraid7b8a032021-04-20 12:31:05 -0700432 userHandle.getIdentifier());
433 }
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700434 return getPackageKillableStatesForUserId(userHandle.getIdentifier(), pm);
435 }
436 List<PackageKillableState> packageKillableStates = new ArrayList<>();
437 UserManager userManager = UserManager.get(mContext);
438 List<UserInfo> userInfos = userManager.getAliveUsers();
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700439 for (int i = 0; i < userInfos.size(); ++i) {
440 packageKillableStates.addAll(
441 getPackageKillableStatesForUserId(userInfos.get(i).id, pm));
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700442 }
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700443 if (DEBUG) {
444 Slogf.d(TAG, "Returning all package killable states for all users");
Lakshman Annadoraid7b8a032021-04-20 12:31:05 -0700445 }
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700446 return packageKillableStates;
447 }
448
449 private List<PackageKillableState> getPackageKillableStatesForUserId(int userId,
450 PackageManager pm) {
451 List<PackageInfo> packageInfos = pm.getInstalledPackagesAsUser(/* flags= */0, userId);
452 List<PackageKillableState> states = new ArrayList<>();
453 synchronized (mLock) {
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700454 ArrayMap<String, List<ApplicationInfo>> applicationInfosBySharedPackage =
455 new ArrayMap<>();
456 for (int i = 0; i < packageInfos.size(); ++i) {
457 PackageInfo packageInfo = packageInfos.get(i);
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700458 String genericPackageName = mPackageInfoHandler.getNameForPackage(packageInfo);
459 if (packageInfo.sharedUserId == null) {
460 int killableState = getPackageKillableStateForUserPackageLocked(
461 userId, genericPackageName,
462 mPackageInfoHandler.getComponentType(packageInfo.applicationInfo),
463 mSafeToKillPackages.contains(genericPackageName));
464 states.add(new PackageKillableState(packageInfo.packageName, userId,
465 killableState));
466 continue;
467 }
468 List<ApplicationInfo> applicationInfos =
469 applicationInfosBySharedPackage.get(genericPackageName);
470 if (applicationInfos == null) {
471 applicationInfos = new ArrayList<>();
472 }
473 applicationInfos.add(packageInfo.applicationInfo);
474 applicationInfosBySharedPackage.put(genericPackageName, applicationInfos);
475 }
476 for (Map.Entry<String, List<ApplicationInfo>> entry :
477 applicationInfosBySharedPackage.entrySet()) {
478 String genericPackageName = entry.getKey();
479 List<ApplicationInfo> applicationInfos = entry.getValue();
480 int componentType = mPackageInfoHandler.getSharedComponentType(
481 applicationInfos, genericPackageName);
482 boolean isSafeToKill = mSafeToKillPackages.contains(genericPackageName);
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700483 for (int i = 0; i < applicationInfos.size(); ++i) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700484 isSafeToKill = isSafeToKill
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700485 || mSafeToKillPackages.contains(applicationInfos.get(i).packageName);
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700486 }
487 int killableState = getPackageKillableStateForUserPackageLocked(
488 userId, genericPackageName, componentType, isSafeToKill);
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700489 for (int i = 0; i < applicationInfos.size(); ++i) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700490 states.add(new PackageKillableState(
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700491 applicationInfos.get(i).packageName, userId, killableState));
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700492 }
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700493 }
494 }
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700495 if (DEBUG) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700496 Slogf.d(TAG, "Returning the package killable states for user packages");
Lakshman Annadoraid7b8a032021-04-20 12:31:05 -0700497 }
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700498 return states;
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700499 }
500
501 /** Sets the given resource overuse configurations. */
Lakshman Annadorai8ee56ec2021-04-27 11:51:08 -0700502 @CarWatchdogManager.ReturnCode
503 public int setResourceOveruseConfigurations(
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700504 List<ResourceOveruseConfiguration> configurations,
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700505 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag)
506 throws RemoteException {
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700507 Objects.requireNonNull(configurations, "Configurations must be non-null");
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700508 Preconditions.checkArgument((configurations.size() > 0),
509 "Must provide at least one configuration");
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700510 Preconditions.checkArgument((resourceOveruseFlag > 0),
511 "Must provide valid resource overuse flag");
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700512 ArraySet<Integer> seenComponentTypes = new ArraySet<>();
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700513 List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> internalConfigs =
514 new ArrayList<>();
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700515 for (int i = 0; i < configurations.size(); ++i) {
516 ResourceOveruseConfiguration config = configurations.get(i);
Lakshman Annadorai8ee56ec2021-04-27 11:51:08 -0700517 /*
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700518 * TODO(b/186119640): Make sure the validation done here matches the validation done in
Lakshman Annadorai8ee56ec2021-04-27 11:51:08 -0700519 * the daemon so set requests retried at a later time will complete successfully.
520 */
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700521 int componentType = config.getComponentType();
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700522 if (toComponentTypeStr(componentType).equals("UNKNOWN")) {
523 throw new IllegalArgumentException("Invalid component type in the configuration");
524 }
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700525 if (seenComponentTypes.contains(componentType)) {
526 throw new IllegalArgumentException(
527 "Cannot provide duplicate configurations for the same component type");
528 }
529 if ((resourceOveruseFlag & FLAG_RESOURCE_OVERUSE_IO) != 0
530 && config.getIoOveruseConfiguration() == null) {
531 throw new IllegalArgumentException("Must provide I/O overuse configuration");
532 }
533 seenComponentTypes.add(config.getComponentType());
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700534 internalConfigs.add(toInternalResourceOveruseConfiguration(config,
535 resourceOveruseFlag));
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700536 }
Lakshman Annadorai8ee56ec2021-04-27 11:51:08 -0700537 synchronized (mLock) {
538 if (!mIsConnectedToDaemon) {
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700539 setPendingSetResourceOveruseConfigurationsRequestLocked(internalConfigs);
Lakshman Annadorai8ee56ec2021-04-27 11:51:08 -0700540 return CarWatchdogManager.RETURN_CODE_SUCCESS;
541 }
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700542 /* Verify no pending request in progress. */
543 setPendingSetResourceOveruseConfigurationsRequestLocked(null);
Lakshman Annadorai8ee56ec2021-04-27 11:51:08 -0700544 }
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700545 return setResourceOveruseConfigurationsInternal(internalConfigs,
546 /* isPendingRequest= */ false);
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700547 }
548
549 /** Returns the available resource overuse configurations. */
550 @NonNull
551 public List<ResourceOveruseConfiguration> getResourceOveruseConfigurations(
552 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) {
553 Preconditions.checkArgument((resourceOveruseFlag > 0),
554 "Must provide valid resource overuse flag");
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700555 if (!isConnectedToDaemon()) {
Lakshman Annadorai8ee56ec2021-04-27 11:51:08 -0700556 throw new IllegalStateException("Car watchdog daemon is not connected");
557 }
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700558 synchronized (mLock) {
559 /* Verify no pending request in progress. */
560 setPendingSetResourceOveruseConfigurationsRequestLocked(null);
561 }
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700562 List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> internalConfigs =
563 new ArrayList<>();
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700564 try {
565 internalConfigs = mCarWatchdogDaemonHelper.getResourceOveruseConfigurations();
566 } catch (RemoteException | RuntimeException e) {
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700567 Slogf.w(TAG, e, "Failed to fetch resource overuse configurations");
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700568 throw new IllegalStateException(e);
569 }
570 List<ResourceOveruseConfiguration> configs = new ArrayList<>();
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700571 for (int i = 0; i < internalConfigs.size(); ++i) {
572 configs.add(
573 toResourceOveruseConfiguration(internalConfigs.get(i), resourceOveruseFlag));
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700574 }
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700575 if (DEBUG) {
576 Slogf.d(TAG, "Returning the resource overuse configuration");
Lakshman Annadoraid7b8a032021-04-20 12:31:05 -0700577 }
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700578 return configs;
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700579 }
580
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700581 /** Processes the latest I/O overuse stats */
582 public void latestIoOveruseStats(List<PackageIoOveruseStats> packageIoOveruseStats) {
Jahdiel Alvarez8bf64ce2021-07-21 01:03:42 +0000583 SparseBooleanArray recurringIoOverusesByUid = new SparseBooleanArray();
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700584 int[] uids = new int[packageIoOveruseStats.size()];
585 for (int i = 0; i < packageIoOveruseStats.size(); ++i) {
586 uids[i] = packageIoOveruseStats.get(i).uid;
587 }
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700588 SparseArray<String> genericPackageNamesByUid = mPackageInfoHandler.getNamesForUids(uids);
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700589 synchronized (mLock) {
590 checkAndHandleDateChangeLocked();
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700591 for (int i = 0; i < packageIoOveruseStats.size(); ++i) {
592 PackageIoOveruseStats stats = packageIoOveruseStats.get(i);
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700593 String genericPackageName = genericPackageNamesByUid.get(stats.uid);
594 if (genericPackageName == null) {
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700595 continue;
596 }
597 int userId = UserHandle.getUserId(stats.uid);
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700598 PackageResourceUsage usage = cacheAndFetchUsageLocked(userId, genericPackageName,
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700599 stats.ioOveruseStats);
600 if (stats.shouldNotify) {
601 /*
602 * Packages that exceed the warn threshold percentage should be notified as well
603 * and only the daemon is aware of such packages. Thus the flag is used to
604 * indicate which packages should be notified.
605 */
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700606 ResourceOveruseStats resourceOveruseStats =
607 usage.getResourceOveruseStatsBuilder().setIoOveruseStats(
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700608 usage.getIoOveruseStatsLocked()).build();
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700609 notifyResourceOveruseStatsLocked(stats.uid, resourceOveruseStats);
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700610 }
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700611
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700612 if (!usage.ioUsage.exceedsThreshold()) {
613 continue;
614 }
615 PackageResourceOveruseAction overuseAction = new PackageResourceOveruseAction();
616 overuseAction.packageIdentifier = new PackageIdentifier();
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700617 overuseAction.packageIdentifier.name = genericPackageName;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700618 overuseAction.packageIdentifier.uid = stats.uid;
619 overuseAction.resourceTypes = new int[]{ ResourceType.IO };
620 overuseAction.resourceOveruseActionType = NOT_KILLED;
621 /*
622 * No action required on I/O overuse on one of the following cases:
623 * #1 The package is not safe to kill as it is critical for system stability.
624 * #2 The package has no recurring overuse behavior and the user opted to not
625 * kill the package so honor the user's decision.
626 */
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700627 int killableState = usage.getKillableStateLocked();
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700628 if (killableState == KILLABLE_STATE_NEVER) {
629 mOveruseActionsByUserPackage.add(overuseAction);
630 continue;
631 }
632 boolean hasRecurringOveruse = isRecurringOveruseLocked(usage);
633 if (!hasRecurringOveruse && killableState == KILLABLE_STATE_NO) {
634 overuseAction.resourceOveruseActionType = NOT_KILLED_USER_OPTED;
635 mOveruseActionsByUserPackage.add(overuseAction);
636 continue;
637 }
Jahdiel Alvarez8bf64ce2021-07-21 01:03:42 +0000638
639 recurringIoOverusesByUid.put(stats.uid, hasRecurringOveruse);
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700640 }
641 if (!mOveruseActionsByUserPackage.isEmpty()) {
642 mMainHandler.sendMessage(obtainMessage(
643 WatchdogPerfHandler::notifyActionsTakenOnOveruse, this));
644 }
Jahdiel Alvarez8bf64ce2021-07-21 01:03:42 +0000645 if (recurringIoOverusesByUid.size() > 0) {
646 mMainHandler.sendMessageDelayed(
647 obtainMessage(WatchdogPerfHandler::handleIoOveruseKilling,
648 this, recurringIoOverusesByUid, genericPackageNamesByUid),
649 mResourceOveruseKillingDelayMills);
650 }
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700651 }
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700652 if (DEBUG) {
653 Slogf.d(TAG, "Processed latest I/O overuse stats");
Lakshman Annadoraid7b8a032021-04-20 12:31:05 -0700654 }
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700655 }
656
657 /** Notify daemon about the actions take on resource overuse */
658 public void notifyActionsTakenOnOveruse() {
659 List<PackageResourceOveruseAction> actions;
660 synchronized (mLock) {
661 if (mOveruseActionsByUserPackage.isEmpty()) {
662 return;
663 }
664 actions = new ArrayList<>(mOveruseActionsByUserPackage);
665 mOveruseActionsByUserPackage.clear();
666 }
667 try {
668 mCarWatchdogDaemonHelper.actionTakenOnResourceOveruse(actions);
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700669 } catch (RemoteException | RuntimeException e) {
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700670 Slogf.w(TAG, e, "Failed to notify car watchdog daemon of actions taken on resource "
671 + "overuse");
Lakshman Annadoraid7b8a032021-04-20 12:31:05 -0700672 }
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700673 if (DEBUG) {
674 Slogf.d(TAG, "Notified car watchdog daemon of actions taken on resource overuse");
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700675 }
676 }
677
Jahdiel Alvarez8bf64ce2021-07-21 01:03:42 +0000678 /** Handle packages that exceed resource overuse thresholds */
679 private void handleIoOveruseKilling(SparseBooleanArray recurringIoOverusesByUid,
680 SparseArray<String> genericPackageNamesByUid) {
681 IPackageManager packageManager = ActivityThread.getPackageManager();
682 synchronized (mLock) {
683 for (int i = 0; i < recurringIoOverusesByUid.size(); i++) {
684 int uid = recurringIoOverusesByUid.keyAt(i);
685 boolean hasRecurringOveruse = recurringIoOverusesByUid.valueAt(i);
686 String genericPackageName = genericPackageNamesByUid.get(uid);
687 int userId = UserHandle.getUserId(uid);
688 String key = getUserPackageUniqueId(userId, genericPackageName);
689 PackageResourceUsage usage = mUsageByUserPackage.get(key);
690
691 PackageResourceOveruseAction overuseAction = new PackageResourceOveruseAction();
692 overuseAction.packageIdentifier = new PackageIdentifier();
693 overuseAction.packageIdentifier.name = genericPackageName;
694 overuseAction.packageIdentifier.uid = uid;
695 overuseAction.resourceTypes = new int[]{ ResourceType.IO };
696 overuseAction.resourceOveruseActionType = NOT_KILLED;
697
698 List<String> packages = Collections.singletonList(genericPackageName);
699 if (usage.isSharedPackage()) {
700 packages = mPackageInfoHandler.getPackagesForUid(uid, genericPackageName);
701 }
702 for (int pkgIdx = 0; pkgIdx < packages.size(); pkgIdx++) {
703 String packageName = packages.get(pkgIdx);
704 try {
705 int oldEnabledState = -1;
706 if (!hasRecurringOveruse) {
707 oldEnabledState = packageManager.getApplicationEnabledSetting(
708 packageName, userId);
709 if (oldEnabledState == COMPONENT_ENABLED_STATE_DISABLED
710 || oldEnabledState == COMPONENT_ENABLED_STATE_DISABLED_USER
711 || oldEnabledState
712 == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
713 continue;
714 }
715 }
716 packageManager.setApplicationEnabledSetting(packageName,
717 COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, /* flags= */ 0, userId,
718 mContext.getPackageName());
719 overuseAction.resourceOveruseActionType = hasRecurringOveruse
720 ? KILLED_RECURRING_OVERUSE : KILLED;
721 if (oldEnabledState != -1) {
722 usage.oldEnabledStateByPackage.put(packageName, oldEnabledState);
723 }
724 } catch (RemoteException e) {
725 Slogf.e(TAG, "Failed to disable application for user %d, package '%s'",
726 userId, packageName);
727 }
728 }
729 mOveruseActionsByUserPackage.add(overuseAction);
730 }
731 if (!mOveruseActionsByUserPackage.isEmpty()) {
732 notifyActionsTakenOnOveruse();
733 }
734 }
735 }
736
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700737 /** Resets the resource overuse stats for the given generic package names. */
738 public void resetResourceOveruseStats(Set<String> genericPackageNames) {
Lakshman Annadoraiec4d08a2021-04-30 08:29:10 -0700739 synchronized (mLock) {
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700740 for (int i = 0; i < mUsageByUserPackage.size(); ++i) {
741 PackageResourceUsage usage = mUsageByUserPackage.valueAt(i);
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700742 if (genericPackageNames.contains(usage.genericPackageName)) {
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700743 usage.resetStatsLocked();
Lakshman Annadoraiec4d08a2021-04-30 08:29:10 -0700744 /*
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700745 * TODO(b/192294393): When the stats are persisted in local DB, reset the stats
Lakshman Annadoraiec4d08a2021-04-30 08:29:10 -0700746 * for this package from local DB.
747 */
748 }
749 }
750 }
751 }
752
Jahdiel Alvarez8bf64ce2021-07-21 01:03:42 +0000753 /** Set the delay to kill a package after the package is notified of resource overuse. */
754 public void setResourceOveruseKillingDelay(long millis) {
755 synchronized (mLock) {
756 mResourceOveruseKillingDelayMills = millis;
757 }
758 }
759
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700760 @GuardedBy("mLock")
761 private int getPackageKillableStateForUserPackageLocked(
762 int userId, String genericPackageName, int componentType, boolean isSafeToKill) {
763 String key = getUserPackageUniqueId(userId, genericPackageName);
764 PackageResourceUsage usage = mUsageByUserPackage.get(key);
765 if (usage == null) {
766 usage = new PackageResourceUsage(userId, genericPackageName);
767 }
768 int killableState = usage.syncAndFetchKillableStateLocked(componentType, isSafeToKill);
769 mUsageByUserPackage.put(key, usage);
770 return killableState;
771 }
772
773 @GuardedBy("mLock")
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700774 private void notifyResourceOveruseStatsLocked(int uid,
775 ResourceOveruseStats resourceOveruseStats) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700776 String genericPackageName = resourceOveruseStats.getPackageName();
Lakshman Annadorai16999d22021-05-25 08:33:30 -0700777 ArrayList<ResourceOveruseListenerInfo> listenerInfos = mOveruseListenerInfosByUid.get(uid);
778 if (listenerInfos != null) {
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700779 for (int i = 0; i < listenerInfos.size(); ++i) {
780 listenerInfos.get(i).notifyListener(
781 FLAG_RESOURCE_OVERUSE_IO, uid, genericPackageName, resourceOveruseStats);
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700782 }
783 }
784 for (int i = 0; i < mOveruseSystemListenerInfosByUid.size(); ++i) {
Lakshman Annadorai16999d22021-05-25 08:33:30 -0700785 ArrayList<ResourceOveruseListenerInfo> systemListenerInfos =
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700786 mOveruseSystemListenerInfosByUid.valueAt(i);
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700787 for (int j = 0; j < systemListenerInfos.size(); ++j) {
788 systemListenerInfos.get(j).notifyListener(
789 FLAG_RESOURCE_OVERUSE_IO, uid, genericPackageName, resourceOveruseStats);
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700790 }
791 }
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700792 if (DEBUG) {
793 Slogf.d(TAG, "Notified resource overuse stats to listening applications");
Lakshman Annadoraid7b8a032021-04-20 12:31:05 -0700794 }
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700795 }
796
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700797 @GuardedBy("mLock")
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700798 private void checkAndHandleDateChangeLocked() {
799 ZonedDateTime previousUTC = mLastStatsReportUTC;
800 mLastStatsReportUTC = ZonedDateTime.now(ZoneOffset.UTC);
801 if (mLastStatsReportUTC.getDayOfYear() == previousUTC.getDayOfYear()
802 && mLastStatsReportUTC.getYear() == previousUTC.getYear()) {
803 return;
804 }
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700805 for (int i = 0; i < mUsageByUserPackage.size(); ++i) {
806 PackageResourceUsage usage = mUsageByUserPackage.valueAt(i);
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700807 // Forgive the daily disabled package on date change.
808 for (Map.Entry<String, Integer> entry : usage.oldEnabledStateByPackage.entrySet()) {
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700809 try {
810 IPackageManager packageManager = ActivityThread.getPackageManager();
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700811 if (packageManager.getApplicationEnabledSetting(entry.getKey(),
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700812 usage.userId)
813 != COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
814 continue;
815 }
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700816 packageManager.setApplicationEnabledSetting(entry.getKey(),
817 entry.getValue(),
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700818 /* flags= */ 0, usage.userId, mContext.getPackageName());
819 } catch (RemoteException e) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700820 Slogf.e(TAG,
821 "Failed to reset enabled setting for disabled package '%s', user '%d'",
822 usage.genericPackageName, usage.userId);
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700823 }
824 }
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700825 /* TODO(b/192294393): Stash the old usage into SQLite DB storage. */
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700826 usage.resetStatsLocked();
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700827 }
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700828 if (DEBUG) {
829 Slogf.d(TAG, "Handled date change successfully");
Lakshman Annadoraid7b8a032021-04-20 12:31:05 -0700830 }
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700831 }
832
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700833 @GuardedBy("mLock")
834 private PackageResourceUsage cacheAndFetchUsageLocked(
835 @UserIdInt int userId, String genericPackageName,
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700836 android.automotive.watchdog.IoOveruseStats internalStats) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700837 String key = getUserPackageUniqueId(userId, genericPackageName);
838 PackageResourceUsage usage = mUsageByUserPackage.get(key);
839 if (usage == null) {
840 usage = new PackageResourceUsage(userId, genericPackageName);
841 }
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700842 usage.updateLocked(internalStats);
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700843 mUsageByUserPackage.put(key, usage);
844 return usage;
845 }
846
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700847 @GuardedBy("mLock")
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700848 private boolean isRecurringOveruseLocked(PackageResourceUsage ioUsage) {
849 /*
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700850 * TODO(b/192294393): Look up I/O overuse history and determine whether or not the package
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700851 * has recurring I/O overuse behavior.
852 */
853 return false;
854 }
855
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700856 private IoOveruseStats getIoOveruseStatsForPeriod(int userId, String genericPackageName,
857 @CarWatchdogManager.StatsPeriod int maxStatsPeriod) {
858 synchronized (mLock) {
859 String key = getUserPackageUniqueId(userId, genericPackageName);
860 PackageResourceUsage usage = mUsageByUserPackage.get(key);
861 if (usage == null) {
862 return null;
863 }
864 return getIoOveruseStatsLocked(usage, /* minimumBytesWritten= */ 0, maxStatsPeriod);
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700865 }
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700866 }
867
868 @GuardedBy("mLock")
869 private IoOveruseStats getIoOveruseStatsLocked(PackageResourceUsage usage,
870 long minimumBytesWritten, @CarWatchdogManager.StatsPeriod int maxStatsPeriod) {
871 IoOveruseStats stats = usage.getIoOveruseStatsLocked();
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -0700872 long totalBytesWritten = stats != null ? stats.getTotalBytesWritten() : 0;
873 /*
874 * TODO(b/185431129): When maxStatsPeriod > current day, populate the historical stats
875 * from the local database. Also handle the case where the package doesn't have current
876 * day stats but has historical stats.
877 */
878 if (totalBytesWritten < minimumBytesWritten) {
879 return null;
880 }
881 return stats;
882 }
883
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700884 @GuardedBy("mLock")
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700885 private void addResourceOveruseListenerLocked(
886 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
887 @NonNull IResourceOveruseListener listener,
Lakshman Annadorai16999d22021-05-25 08:33:30 -0700888 SparseArray<ArrayList<ResourceOveruseListenerInfo>> listenerInfosByUid) {
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700889 int callingPid = Binder.getCallingPid();
890 int callingUid = Binder.getCallingUid();
891 boolean isListenerForSystem = listenerInfosByUid == mOveruseSystemListenerInfosByUid;
892 String listenerType = isListenerForSystem ? "resource overuse listener for system" :
893 "resource overuse listener";
894
Lakshman Annadorai16999d22021-05-25 08:33:30 -0700895 IBinder binder = listener.asBinder();
896 ArrayList<ResourceOveruseListenerInfo> listenerInfos = listenerInfosByUid.get(callingUid);
897 if (listenerInfos == null) {
898 listenerInfos = new ArrayList<>();
899 listenerInfosByUid.put(callingUid, listenerInfos);
900 }
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700901 for (int i = 0; i < listenerInfos.size(); ++i) {
902 if (listenerInfos.get(i).listener.asBinder() == binder) {
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700903 throw new IllegalStateException(
904 "Cannot add " + listenerType + " as it is already added");
905 }
906 }
907
908 ResourceOveruseListenerInfo listenerInfo = new ResourceOveruseListenerInfo(listener,
909 resourceOveruseFlag, callingPid, callingUid, isListenerForSystem);
910 try {
911 listenerInfo.linkToDeath();
912 } catch (RemoteException e) {
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700913 Slogf.w(TAG, "Cannot add %s: linkToDeath to listener failed", listenerType);
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700914 return;
915 }
Lakshman Annadorai16999d22021-05-25 08:33:30 -0700916 listenerInfos.add(listenerInfo);
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700917 if (DEBUG) {
Lakshman Annadorai16999d22021-05-25 08:33:30 -0700918 Slogf.d(TAG, "The %s (pid: %d, uid: %d) is added", listenerType,
919 callingPid, callingUid);
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700920 }
921 }
922
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700923 @GuardedBy("mLock")
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700924 private void removeResourceOveruseListenerLocked(@NonNull IResourceOveruseListener listener,
Lakshman Annadorai16999d22021-05-25 08:33:30 -0700925 SparseArray<ArrayList<ResourceOveruseListenerInfo>> listenerInfosByUid) {
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700926 int callingUid = Binder.getCallingUid();
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700927 String listenerType = listenerInfosByUid == mOveruseSystemListenerInfosByUid
928 ? "resource overuse system listener" : "resource overuse listener";
Lakshman Annadorai16999d22021-05-25 08:33:30 -0700929 ArrayList<ResourceOveruseListenerInfo> listenerInfos = listenerInfosByUid.get(callingUid);
930 if (listenerInfos == null) {
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700931 Slogf.w(TAG, "Cannot remove the %s: it has not been registered before", listenerType);
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700932 return;
933 }
Lakshman Annadorai16999d22021-05-25 08:33:30 -0700934 IBinder binder = listener.asBinder();
935 ResourceOveruseListenerInfo cachedListenerInfo = null;
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700936 for (int i = 0; i < listenerInfos.size(); ++i) {
937 if (listenerInfos.get(i).listener.asBinder() == binder) {
938 cachedListenerInfo = listenerInfos.get(i);
Lakshman Annadorai16999d22021-05-25 08:33:30 -0700939 break;
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700940 }
941 }
Lakshman Annadorai16999d22021-05-25 08:33:30 -0700942 if (cachedListenerInfo == null) {
943 Slogf.w(TAG, "Cannot remove the %s: it has not been registered before", listenerType);
944 return;
945 }
946 cachedListenerInfo.unlinkToDeath();
947 listenerInfos.remove(cachedListenerInfo);
948 if (listenerInfos.isEmpty()) {
949 listenerInfosByUid.remove(callingUid);
950 }
951 if (DEBUG) {
952 Slogf.d(TAG, "The %s (pid: %d, uid: %d) is removed", listenerType,
953 cachedListenerInfo.pid, cachedListenerInfo.uid);
954 }
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700955 }
956
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700957 @GuardedBy("mLock")
958 private void setPendingSetResourceOveruseConfigurationsRequestLocked(
959 List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> configs) {
960 if (mPendingSetResourceOveruseConfigurationsRequest != null) {
961 if (mPendingSetResourceOveruseConfigurationsRequest == configs) {
962 return;
963 }
964 throw new IllegalStateException(
965 "Pending setResourceOveruseConfigurations request in progress");
966 }
967 mPendingSetResourceOveruseConfigurationsRequest = configs;
968 }
969
970 private void retryPendingSetResourceOveruseConfigurations() {
971 List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> configs;
Lakshman Annadorai8ee56ec2021-04-27 11:51:08 -0700972 synchronized (mLock) {
Lakshman Annadorai94323ff2021-04-29 12:14:34 -0700973 if (mPendingSetResourceOveruseConfigurationsRequest == null) {
974 return;
975 }
976 configs = mPendingSetResourceOveruseConfigurationsRequest;
977 }
978 try {
979 int result = setResourceOveruseConfigurationsInternal(configs,
980 /* isPendingRequest= */ true);
981 if (result != CarWatchdogManager.RETURN_CODE_SUCCESS) {
982 Slogf.e(TAG, "Failed to set pending resource overuse configurations. Return code "
983 + "%d", result);
984 }
985 } catch (Exception e) {
986 Slogf.e(TAG, e, "Exception on set pending resource overuse configurations");
987 }
988 }
989
990 private int setResourceOveruseConfigurationsInternal(
991 List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> configs,
992 boolean isPendingRequest) throws RemoteException {
993 boolean doClearPendingRequest = isPendingRequest;
994 try {
995 mCarWatchdogDaemonHelper.updateResourceOveruseConfigurations(configs);
996 } catch (RemoteException e) {
997 if (e instanceof TransactionTooLargeException) {
998 throw e;
999 }
1000 Slogf.e(TAG, e, "Remote exception on set resource overuse configuration");
1001 synchronized (mLock) {
1002 setPendingSetResourceOveruseConfigurationsRequestLocked(configs);
1003 }
1004 doClearPendingRequest = false;
1005 return CarWatchdogManager.RETURN_CODE_SUCCESS;
1006 } finally {
1007 if (doClearPendingRequest) {
1008 synchronized (mLock) {
1009 mPendingSetResourceOveruseConfigurationsRequest = null;
1010 }
Lakshman Annadorai8ee56ec2021-04-27 11:51:08 -07001011 }
1012 }
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -07001013 /* TODO(b/192665269): Fetch safe-to-kill list from daemon and update mSafeToKillPackages. */
Lakshman Annadorai94323ff2021-04-29 12:14:34 -07001014 if (DEBUG) {
1015 Slogf.d(TAG, "Set the resource overuse configuration successfully");
1016 }
1017 return CarWatchdogManager.RETURN_CODE_SUCCESS;
1018 }
1019
1020 private boolean isConnectedToDaemon() {
1021 synchronized (mLock) {
1022 long startTimeMillis = SystemClock.uptimeMillis();
1023 long sleptDurationMillis = SystemClock.uptimeMillis() - startTimeMillis;
1024 while (!mIsConnectedToDaemon && sleptDurationMillis < MAX_WAIT_TIME_MILLS) {
1025 try {
1026 mLock.wait(MAX_WAIT_TIME_MILLS - sleptDurationMillis);
1027 } catch (InterruptedException e) {
1028 Thread.currentThread().interrupt();
1029 continue;
1030 } finally {
1031 sleptDurationMillis = SystemClock.uptimeMillis() - startTimeMillis;
1032 }
1033 break;
1034 }
1035 return mIsConnectedToDaemon;
1036 }
Lakshman Annadorai8ee56ec2021-04-27 11:51:08 -07001037 }
1038
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -07001039 private static String getUserPackageUniqueId(int userId, String genericPackageName) {
1040 return String.valueOf(userId) + ":" + genericPackageName;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -07001041 }
1042
1043 @VisibleForTesting
1044 static IoOveruseStats.Builder toIoOveruseStatsBuilder(
1045 android.automotive.watchdog.IoOveruseStats internalStats) {
1046 IoOveruseStats.Builder statsBuilder = new IoOveruseStats.Builder(
1047 internalStats.startTime, internalStats.durationInSeconds);
1048 statsBuilder.setRemainingWriteBytes(
1049 toPerStateBytes(internalStats.remainingWriteBytes));
1050 statsBuilder.setTotalBytesWritten(totalPerStateBytes(internalStats.writtenBytes));
1051 statsBuilder.setTotalOveruses(internalStats.totalOveruses);
1052 return statsBuilder;
1053 }
1054
1055 private static PerStateBytes toPerStateBytes(
1056 android.automotive.watchdog.PerStateBytes internalPerStateBytes) {
Lakshman Annadoraie1720472021-04-13 15:22:57 -07001057 return new PerStateBytes(internalPerStateBytes.foregroundBytes,
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -07001058 internalPerStateBytes.backgroundBytes, internalPerStateBytes.garageModeBytes);
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -07001059 }
1060
1061 private static long totalPerStateBytes(
1062 android.automotive.watchdog.PerStateBytes internalPerStateBytes) {
1063 BiFunction<Long, Long, Long> sum = (l, r) -> {
1064 return (Long.MAX_VALUE - l > r) ? l + r : Long.MAX_VALUE;
1065 };
1066 return sum.apply(sum.apply(internalPerStateBytes.foregroundBytes,
1067 internalPerStateBytes.backgroundBytes), internalPerStateBytes.garageModeBytes);
1068 }
1069
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -07001070 private static long getMinimumBytesWritten(
1071 @CarWatchdogManager.MinimumStatsFlag int minimumStatsIoFlag) {
1072 switch (minimumStatsIoFlag) {
1073 case 0:
1074 return 0;
1075 case CarWatchdogManager.FLAG_MINIMUM_STATS_IO_1_MB:
1076 return 1024 * 1024;
1077 case CarWatchdogManager.FLAG_MINIMUM_STATS_IO_100_MB:
1078 return 100 * 1024 * 1024;
1079 case CarWatchdogManager.FLAG_MINIMUM_STATS_IO_1_GB:
1080 return 1024 * 1024 * 1024;
1081 default:
1082 throw new IllegalArgumentException(
1083 "Must provide valid minimum stats flag for I/O resource");
1084 }
1085 }
1086
Lakshman Annadoraie1720472021-04-13 15:22:57 -07001087 private static android.automotive.watchdog.internal.ResourceOveruseConfiguration
1088 toInternalResourceOveruseConfiguration(ResourceOveruseConfiguration config,
1089 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) {
1090 android.automotive.watchdog.internal.ResourceOveruseConfiguration internalConfig =
1091 new android.automotive.watchdog.internal.ResourceOveruseConfiguration();
1092 internalConfig.componentType = config.getComponentType();
1093 internalConfig.safeToKillPackages = config.getSafeToKillPackages();
1094 internalConfig.vendorPackagePrefixes = config.getVendorPackagePrefixes();
1095 internalConfig.packageMetadata = new ArrayList<>();
1096 for (Map.Entry<String, String> entry : config.getPackagesToAppCategoryTypes().entrySet()) {
1097 if (entry.getKey().isEmpty()) {
1098 continue;
1099 }
1100 PackageMetadata metadata = new PackageMetadata();
1101 metadata.packageName = entry.getKey();
1102 switch(entry.getValue()) {
1103 case ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS:
1104 metadata.appCategoryType = ApplicationCategoryType.MAPS;
1105 break;
1106 case ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MEDIA:
1107 metadata.appCategoryType = ApplicationCategoryType.MEDIA;
1108 break;
1109 default:
1110 continue;
1111 }
1112 internalConfig.packageMetadata.add(metadata);
1113 }
1114 internalConfig.resourceSpecificConfigurations = new ArrayList<>();
1115 if ((resourceOveruseFlag & FLAG_RESOURCE_OVERUSE_IO) != 0
1116 && config.getIoOveruseConfiguration() != null) {
1117 internalConfig.resourceSpecificConfigurations.add(
1118 toResourceSpecificConfiguration(config.getComponentType(),
1119 config.getIoOveruseConfiguration()));
1120 }
1121 return internalConfig;
1122 }
1123
1124 private static ResourceSpecificConfiguration
1125 toResourceSpecificConfiguration(int componentType, IoOveruseConfiguration config) {
1126 android.automotive.watchdog.internal.IoOveruseConfiguration internalConfig =
1127 new android.automotive.watchdog.internal.IoOveruseConfiguration();
1128 internalConfig.componentLevelThresholds = toPerStateIoOveruseThreshold(
1129 toComponentTypeStr(componentType), config.getComponentLevelThresholds());
1130 internalConfig.packageSpecificThresholds = toPerStateIoOveruseThresholds(
1131 config.getPackageSpecificThresholds());
1132 internalConfig.categorySpecificThresholds = toPerStateIoOveruseThresholds(
1133 config.getAppCategorySpecificThresholds());
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001134 for (int i = 0; i < internalConfig.categorySpecificThresholds.size(); ++i) {
1135 PerStateIoOveruseThreshold threshold = internalConfig.categorySpecificThresholds.get(i);
Lakshman Annadoraie1720472021-04-13 15:22:57 -07001136 switch(threshold.name) {
1137 case ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS:
1138 threshold.name = INTERNAL_APPLICATION_CATEGORY_TYPE_MAPS;
1139 break;
1140 case ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MEDIA:
1141 threshold.name = INTERNAL_APPLICATION_CATEGORY_TYPE_MEDIA;
1142 break;
1143 default:
1144 threshold.name = INTERNAL_APPLICATION_CATEGORY_TYPE_UNKNOWN;
1145 }
1146 }
1147 internalConfig.systemWideThresholds = toInternalIoOveruseAlertThresholds(
1148 config.getSystemWideThresholds());
1149
1150 ResourceSpecificConfiguration resourceSpecificConfig = new ResourceSpecificConfiguration();
1151 resourceSpecificConfig.setIoOveruseConfiguration(internalConfig);
1152 return resourceSpecificConfig;
1153 }
1154
1155 @VisibleForTesting
1156 static String toComponentTypeStr(int componentType) {
1157 switch(componentType) {
1158 case ComponentType.SYSTEM:
1159 return "SYSTEM";
1160 case ComponentType.VENDOR:
1161 return "VENDOR";
1162 case ComponentType.THIRD_PARTY:
1163 return "THIRD_PARTY";
1164 default:
1165 return "UNKNOWN";
1166 }
1167 }
1168
1169 private static List<PerStateIoOveruseThreshold> toPerStateIoOveruseThresholds(
1170 Map<String, PerStateBytes> thresholds) {
1171 List<PerStateIoOveruseThreshold> internalThresholds = new ArrayList<>();
1172 for (Map.Entry<String, PerStateBytes> entry : thresholds.entrySet()) {
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001173 if (!thresholds.isEmpty()) {
Lakshman Annadoraie1720472021-04-13 15:22:57 -07001174 internalThresholds.add(toPerStateIoOveruseThreshold(entry.getKey(),
1175 entry.getValue()));
1176 }
1177 }
1178 return internalThresholds;
1179 }
1180
1181 private static PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(String name,
1182 PerStateBytes perStateBytes) {
1183 PerStateIoOveruseThreshold threshold = new PerStateIoOveruseThreshold();
1184 threshold.name = name;
1185 threshold.perStateWriteBytes = new android.automotive.watchdog.PerStateBytes();
1186 threshold.perStateWriteBytes.foregroundBytes = perStateBytes.getForegroundModeBytes();
1187 threshold.perStateWriteBytes.backgroundBytes = perStateBytes.getBackgroundModeBytes();
1188 threshold.perStateWriteBytes.garageModeBytes = perStateBytes.getGarageModeBytes();
1189 return threshold;
1190 }
1191
1192 private static List<android.automotive.watchdog.internal.IoOveruseAlertThreshold>
1193 toInternalIoOveruseAlertThresholds(List<IoOveruseAlertThreshold> thresholds) {
1194 List<android.automotive.watchdog.internal.IoOveruseAlertThreshold> internalThresholds =
1195 new ArrayList<>();
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001196 for (int i = 0; i < thresholds.size(); ++i) {
1197 if (thresholds.get(i).getDurationInSeconds() == 0
1198 || thresholds.get(i).getWrittenBytesPerSecond() == 0) {
Lakshman Annadoraie1720472021-04-13 15:22:57 -07001199 continue;
1200 }
1201 android.automotive.watchdog.internal.IoOveruseAlertThreshold internalThreshold =
1202 new android.automotive.watchdog.internal.IoOveruseAlertThreshold();
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001203 internalThreshold.durationInSeconds = thresholds.get(i).getDurationInSeconds();
1204 internalThreshold.writtenBytesPerSecond = thresholds.get(i).getWrittenBytesPerSecond();
Lakshman Annadoraie1720472021-04-13 15:22:57 -07001205 internalThresholds.add(internalThreshold);
1206 }
1207 return internalThresholds;
1208 }
1209
1210 private static ResourceOveruseConfiguration toResourceOveruseConfiguration(
1211 android.automotive.watchdog.internal.ResourceOveruseConfiguration internalConfig,
1212 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) {
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001213 ArrayMap<String, String> packagesToAppCategoryTypes = new ArrayMap<>();
1214 for (int i = 0; i < internalConfig.packageMetadata.size(); ++i) {
Lakshman Annadoraie1720472021-04-13 15:22:57 -07001215 String categoryTypeStr;
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001216 switch (internalConfig.packageMetadata.get(i).appCategoryType) {
Lakshman Annadoraie1720472021-04-13 15:22:57 -07001217 case ApplicationCategoryType.MAPS:
1218 categoryTypeStr = ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS;
1219 break;
1220 case ApplicationCategoryType.MEDIA:
1221 categoryTypeStr = ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MEDIA;
1222 break;
1223 default:
1224 continue;
1225 }
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001226 packagesToAppCategoryTypes.put(
1227 internalConfig.packageMetadata.get(i).packageName, categoryTypeStr);
Lakshman Annadoraie1720472021-04-13 15:22:57 -07001228 }
1229 ResourceOveruseConfiguration.Builder configBuilder =
1230 new ResourceOveruseConfiguration.Builder(
1231 internalConfig.componentType,
1232 internalConfig.safeToKillPackages,
1233 internalConfig.vendorPackagePrefixes,
1234 packagesToAppCategoryTypes);
1235 for (ResourceSpecificConfiguration resourceSpecificConfig :
1236 internalConfig.resourceSpecificConfigurations) {
1237 if (resourceSpecificConfig.getTag()
1238 == ResourceSpecificConfiguration.ioOveruseConfiguration
1239 && (resourceOveruseFlag & FLAG_RESOURCE_OVERUSE_IO) != 0) {
1240 configBuilder.setIoOveruseConfiguration(toIoOveruseConfiguration(
1241 resourceSpecificConfig.getIoOveruseConfiguration()));
1242 }
1243 }
1244 return configBuilder.build();
1245 }
1246
1247 private static IoOveruseConfiguration toIoOveruseConfiguration(
1248 android.automotive.watchdog.internal.IoOveruseConfiguration internalConfig) {
1249 PerStateBytes componentLevelThresholds =
1250 toPerStateBytes(internalConfig.componentLevelThresholds.perStateWriteBytes);
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001251 ArrayMap<String, PerStateBytes> packageSpecificThresholds =
Lakshman Annadoraie1720472021-04-13 15:22:57 -07001252 toPerStateBytesMap(internalConfig.packageSpecificThresholds);
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001253 ArrayMap<String, PerStateBytes> appCategorySpecificThresholds =
Lakshman Annadoraie1720472021-04-13 15:22:57 -07001254 toPerStateBytesMap(internalConfig.categorySpecificThresholds);
1255 replaceKey(appCategorySpecificThresholds, INTERNAL_APPLICATION_CATEGORY_TYPE_MAPS,
1256 ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS);
1257 replaceKey(appCategorySpecificThresholds, INTERNAL_APPLICATION_CATEGORY_TYPE_MEDIA,
1258 ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MEDIA);
1259 List<IoOveruseAlertThreshold> systemWideThresholds =
1260 toIoOveruseAlertThresholds(internalConfig.systemWideThresholds);
1261
1262 IoOveruseConfiguration.Builder configBuilder = new IoOveruseConfiguration.Builder(
1263 componentLevelThresholds, packageSpecificThresholds, appCategorySpecificThresholds,
1264 systemWideThresholds);
1265 return configBuilder.build();
1266 }
1267
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001268 private static ArrayMap<String, PerStateBytes> toPerStateBytesMap(
Lakshman Annadoraie1720472021-04-13 15:22:57 -07001269 List<PerStateIoOveruseThreshold> thresholds) {
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001270 ArrayMap<String, PerStateBytes> thresholdsMap = new ArrayMap<>();
1271 for (int i = 0; i < thresholds.size(); ++i) {
1272 thresholdsMap.put(
1273 thresholds.get(i).name, toPerStateBytes(thresholds.get(i).perStateWriteBytes));
Lakshman Annadoraie1720472021-04-13 15:22:57 -07001274 }
1275 return thresholdsMap;
1276 }
1277
1278 private static List<IoOveruseAlertThreshold> toIoOveruseAlertThresholds(
1279 List<android.automotive.watchdog.internal.IoOveruseAlertThreshold> internalThresholds) {
1280 List<IoOveruseAlertThreshold> thresholds = new ArrayList<>();
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001281 for (int i = 0; i < internalThresholds.size(); ++i) {
1282 thresholds.add(new IoOveruseAlertThreshold(internalThresholds.get(i).durationInSeconds,
1283 internalThresholds.get(i).writtenBytesPerSecond));
Lakshman Annadoraie1720472021-04-13 15:22:57 -07001284 }
1285 return thresholds;
1286 }
1287
1288 private static void replaceKey(Map<String, PerStateBytes> map, String oldKey, String newKey) {
1289 PerStateBytes perStateBytes = map.get(oldKey);
1290 if (perStateBytes != null) {
1291 map.put(newKey, perStateBytes);
1292 map.remove(oldKey);
1293 }
1294 }
1295
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -07001296 private final class PackageResourceUsage {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -07001297 public final String genericPackageName;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -07001298 public @UserIdInt final int userId;
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001299 @GuardedBy("mLock")
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -07001300 public final PackageIoUsage ioUsage = new PackageIoUsage();
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001301 @GuardedBy("mLock")
1302 public final ArrayMap<String, Integer> oldEnabledStateByPackage = new ArrayMap<>();
1303 @GuardedBy("mLock")
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -07001304 private @KillableState int mKillableState;
1305
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -07001306 /** Must be called only after acquiring {@link mLock} */
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -07001307 PackageResourceUsage(@UserIdInt int userId, String genericPackageName) {
1308 this.genericPackageName = genericPackageName;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -07001309 this.userId = userId;
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -07001310 this.mKillableState = mDefaultNotKillableGenericPackages.contains(genericPackageName)
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -07001311 ? KILLABLE_STATE_NO : KILLABLE_STATE_YES;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -07001312 }
1313
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -07001314 public boolean isSharedPackage() {
1315 return this.genericPackageName.startsWith(SHARED_PACKAGE_PREFIX);
1316 }
1317
1318 @GuardedBy("mLock")
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -07001319 public void updateLocked(android.automotive.watchdog.IoOveruseStats internalStats) {
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -07001320 if (!internalStats.killableOnOveruse) {
1321 /*
1322 * Killable value specified in the internal stats is provided by the native daemon.
1323 * This value reflects whether or not an application is safe-to-kill on overuse.
1324 * This setting is from the I/O overuse configuration specified by the system and
1325 * vendor services and doesn't reflect the user choices. Thus if the internal stats
1326 * specify the application is not killable, the application is not safe-to-kill.
1327 */
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -07001328 mKillableState = KILLABLE_STATE_NEVER;
1329 } else if (mKillableState == KILLABLE_STATE_NEVER) {
1330 /*
1331 * This case happens when a previously unsafe to kill system/vendor package was
1332 * recently marked as safe-to-kill so update the old state to the default value.
1333 */
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -07001334 mKillableState = mDefaultNotKillableGenericPackages.contains(genericPackageName)
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -07001335 ? KILLABLE_STATE_NO : KILLABLE_STATE_YES;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -07001336 }
1337 ioUsage.update(internalStats);
1338 }
1339
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -07001340 public ResourceOveruseStats.Builder getResourceOveruseStatsBuilder() {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -07001341 return new ResourceOveruseStats.Builder(genericPackageName, UserHandle.of(userId));
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -07001342 }
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -07001343
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001344 @GuardedBy("mLock")
1345 public IoOveruseStats getIoOveruseStatsLocked() {
Lakshman Annadoraif5c1d142021-04-15 12:51:46 -07001346 if (!ioUsage.hasUsage()) {
1347 return null;
1348 }
1349 return ioUsage.getStatsBuilder().setKillableOnOveruse(
1350 mKillableState != KILLABLE_STATE_NEVER).build();
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -07001351 }
1352
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001353 @GuardedBy("mLock")
1354 public @KillableState int getKillableStateLocked() {
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -07001355 return mKillableState;
1356 }
1357
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001358 @GuardedBy("mLock")
1359 public boolean setKillableStateLocked(boolean isKillable) {
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -07001360 if (mKillableState == KILLABLE_STATE_NEVER) {
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -07001361 return false;
1362 }
1363 mKillableState = isKillable ? KILLABLE_STATE_YES : KILLABLE_STATE_NO;
1364 return true;
1365 }
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -07001366
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -07001367 @GuardedBy("mLock")
1368 public int syncAndFetchKillableStateLocked(int myComponentType, boolean isSafeToKill) {
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -07001369 /*
1370 * The killable state goes out-of-sync:
1371 * 1. When the on-device safe-to-kill list is recently updated and the user package
1372 * didn't have any resource usage so the native daemon didn't update the killable state.
1373 * 2. When a package has no resource usage and is initialized outside of processing the
1374 * latest resource usage stats.
1375 */
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -07001376 if (myComponentType != ComponentType.THIRD_PARTY && !isSafeToKill) {
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -07001377 mKillableState = KILLABLE_STATE_NEVER;
1378 } else if (mKillableState == KILLABLE_STATE_NEVER) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -07001379 mKillableState = mDefaultNotKillableGenericPackages.contains(genericPackageName)
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -07001380 ? KILLABLE_STATE_NO : KILLABLE_STATE_YES;
1381 }
1382 return mKillableState;
1383 }
Lakshman Annadoraiec4d08a2021-04-30 08:29:10 -07001384
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -07001385 @GuardedBy("mLock")
1386 public void resetStatsLocked() {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -07001387 oldEnabledStateByPackage.clear();
Lakshman Annadoraiec4d08a2021-04-30 08:29:10 -07001388 ioUsage.resetStats();
1389 }
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -07001390 }
1391
1392 private static final class PackageIoUsage {
1393 private android.automotive.watchdog.IoOveruseStats mIoOveruseStats;
1394 private android.automotive.watchdog.PerStateBytes mForgivenWriteBytes;
1395 private long mTotalTimesKilled;
1396
1397 PackageIoUsage() {
1398 mTotalTimesKilled = 0;
1399 }
1400
1401 public boolean hasUsage() {
1402 return mIoOveruseStats != null;
1403 }
1404
1405 public void update(android.automotive.watchdog.IoOveruseStats internalStats) {
1406 mIoOveruseStats = internalStats;
1407 if (exceedsThreshold()) {
1408 /*
1409 * Forgive written bytes on overuse as the package is either forgiven or killed on
1410 * overuse. When the package is killed, the user may opt to open the corresponding
1411 * app and the package should be forgiven anyways.
1412 * NOTE: If this logic is updated, update the daemon side logic as well.
1413 */
1414 mForgivenWriteBytes = internalStats.writtenBytes;
1415 }
1416 }
1417
1418 public IoOveruseStats.Builder getStatsBuilder() {
1419 IoOveruseStats.Builder statsBuilder = toIoOveruseStatsBuilder(mIoOveruseStats);
1420 statsBuilder.setTotalTimesKilled(mTotalTimesKilled);
1421 return statsBuilder;
1422 }
1423
1424 public boolean exceedsThreshold() {
1425 if (!hasUsage()) {
1426 return false;
1427 }
1428 android.automotive.watchdog.PerStateBytes remaining =
1429 mIoOveruseStats.remainingWriteBytes;
1430 return remaining.foregroundBytes == 0 || remaining.backgroundBytes == 0
1431 || remaining.garageModeBytes == 0;
1432 }
1433
Lakshman Annadoraiec4d08a2021-04-30 08:29:10 -07001434 public void resetStats() {
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -07001435 mIoOveruseStats = null;
1436 mForgivenWriteBytes = null;
1437 mTotalTimesKilled = 0;
1438 }
1439 }
1440
Lakshman Annadorai016127e2021-03-18 09:11:43 -07001441 private final class ResourceOveruseListenerInfo implements IBinder.DeathRecipient {
1442 public final IResourceOveruseListener listener;
1443 public final @CarWatchdogManager.ResourceOveruseFlag int flag;
1444 public final int pid;
1445 public final int uid;
1446 public final boolean isListenerForSystem;
1447
1448 ResourceOveruseListenerInfo(IResourceOveruseListener listener,
1449 @CarWatchdogManager.ResourceOveruseFlag int flag, int pid, int uid,
1450 boolean isListenerForSystem) {
1451 this.listener = listener;
1452 this.flag = flag;
1453 this.pid = pid;
1454 this.uid = uid;
1455 this.isListenerForSystem = isListenerForSystem;
1456 }
1457
1458 @Override
1459 public void binderDied() {
Lakshman Annadorai94323ff2021-04-29 12:14:34 -07001460 Slogf.w(TAG, "Resource overuse listener%s (pid: %d) died",
Lakshman Annadorai016127e2021-03-18 09:11:43 -07001461 isListenerForSystem ? " for system" : "", pid);
Lakshman Annadorai16999d22021-05-25 08:33:30 -07001462 Consumer<SparseArray<ArrayList<ResourceOveruseListenerInfo>>> removeListenerInfo =
1463 listenerInfosByUid -> {
1464 ArrayList<ResourceOveruseListenerInfo> listenerInfos =
1465 listenerInfosByUid.get(uid);
1466 if (listenerInfos == null) {
1467 return;
1468 }
1469 listenerInfos.remove(this);
1470 if (listenerInfos.isEmpty()) {
1471 listenerInfosByUid.remove(uid);
1472 }
1473 };
1474 if (isListenerForSystem) {
1475 removeListenerInfo.accept(mOveruseSystemListenerInfosByUid);
1476 } else {
1477 removeListenerInfo.accept(mOveruseListenerInfosByUid);
1478 }
Lakshman Annadorai016127e2021-03-18 09:11:43 -07001479 unlinkToDeath();
1480 }
1481
Lakshman Annadorai16999d22021-05-25 08:33:30 -07001482 public void notifyListener(@CarWatchdogManager.ResourceOveruseFlag int resourceType,
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -07001483 int overusingUid, String overusingGenericPackageName,
Lakshman Annadorai16999d22021-05-25 08:33:30 -07001484 ResourceOveruseStats resourceOveruseStats) {
1485 if ((flag & resourceType) == 0) {
1486 return;
1487 }
1488 try {
1489 listener.onOveruse(resourceOveruseStats);
1490 } catch (RemoteException e) {
1491 Slogf.e(TAG, "Failed to notify %s (uid %d, pid: %d) of resource overuse by "
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -07001492 + "package(uid %d, generic package name '%s'): %s",
Lakshman Annadorai16999d22021-05-25 08:33:30 -07001493 (isListenerForSystem ? "system listener" : "listener"), uid, pid,
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -07001494 overusingUid, overusingGenericPackageName, e);
Lakshman Annadorai16999d22021-05-25 08:33:30 -07001495 }
1496 }
1497
Lakshman Annadorai016127e2021-03-18 09:11:43 -07001498 private void linkToDeath() throws RemoteException {
1499 listener.asBinder().linkToDeath(this, 0);
1500 }
1501
1502 private void unlinkToDeath() {
1503 listener.asBinder().unlinkToDeath(this, 0);
1504 }
1505 }
1506}