blob: e609bbe5736c5566eb9b4813f56e0d1663a1e919 [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
31import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070032
33import android.annotation.NonNull;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070034import android.annotation.UserIdInt;
35import android.app.ActivityThread;
36import android.automotive.watchdog.ResourceType;
Lakshman Annadoraie1720472021-04-13 15:22:57 -070037import android.automotive.watchdog.internal.ApplicationCategoryType;
38import android.automotive.watchdog.internal.ComponentType;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070039import android.automotive.watchdog.internal.PackageIdentifier;
40import android.automotive.watchdog.internal.PackageIoOveruseStats;
Lakshman Annadoraie1720472021-04-13 15:22:57 -070041import android.automotive.watchdog.internal.PackageMetadata;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070042import android.automotive.watchdog.internal.PackageResourceOveruseAction;
Lakshman Annadoraie1720472021-04-13 15:22:57 -070043import android.automotive.watchdog.internal.PerStateIoOveruseThreshold;
44import android.automotive.watchdog.internal.ResourceSpecificConfiguration;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070045import android.car.watchdog.CarWatchdogManager;
46import android.car.watchdog.IResourceOveruseListener;
Lakshman Annadoraie1720472021-04-13 15:22:57 -070047import android.car.watchdog.IoOveruseAlertThreshold;
48import android.car.watchdog.IoOveruseConfiguration;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070049import android.car.watchdog.IoOveruseStats;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070050import android.car.watchdog.PackageKillableState;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070051import android.car.watchdog.PackageKillableState.KillableState;
52import android.car.watchdog.PerStateBytes;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070053import android.car.watchdog.ResourceOveruseConfiguration;
54import android.car.watchdog.ResourceOveruseStats;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070055import android.car.watchdoglib.CarWatchdogDaemonHelper;
56import android.content.Context;
57import android.content.pm.IPackageManager;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070058import android.os.Binder;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070059import android.os.Handler;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070060import android.os.IBinder;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070061import android.os.Looper;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070062import android.os.RemoteException;
63import android.os.UserHandle;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070064import android.util.ArrayMap;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070065import android.util.ArraySet;
66import android.util.IndentingPrintWriter;
67import android.util.SparseArray;
68
69import com.android.car.CarLog;
70import com.android.internal.annotations.GuardedBy;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070071import com.android.internal.annotations.VisibleForTesting;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070072import com.android.internal.util.Preconditions;
73import com.android.server.utils.Slogf;
74
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070075import java.time.ZoneOffset;
76import java.time.ZonedDateTime;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070077import java.util.ArrayList;
78import java.util.List;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070079import java.util.Map;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070080import java.util.Objects;
81import java.util.Set;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070082import java.util.function.BiFunction;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070083
84/**
85 * Handles system resource performance monitoring module.
86 */
87public final class WatchdogPerfHandler {
Lakshman Annadoraie1720472021-04-13 15:22:57 -070088 public static final String INTERNAL_APPLICATION_CATEGORY_TYPE_MAPS = "MAPS";
89 public static final String INTERNAL_APPLICATION_CATEGORY_TYPE_MEDIA = "MEDIA";
90 public static final String INTERNAL_APPLICATION_CATEGORY_TYPE_UNKNOWN = "UNKNOWN";
91
Lakshman Annadorai016127e2021-03-18 09:11:43 -070092 private static final String TAG = CarLog.tagFor(CarWatchdogService.class);
93
94 private final boolean mIsDebugEnabled;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -070095 private final Context mContext;
96 private final CarWatchdogDaemonHelper mCarWatchdogDaemonHelper;
97 private final PackageInfoHandler mPackageInfoHandler;
98 private final Handler mMainHandler;
Lakshman Annadorai016127e2021-03-18 09:11:43 -070099 private final Object mLock = new Object();
100 /*
101 * Cache of added resource overuse listeners by uid.
102 */
103 @GuardedBy("mLock")
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700104 private final Map<String, PackageResourceUsage> mUsageByUserPackage = new ArrayMap<>();
105 @GuardedBy("mLock")
106 private final List<PackageResourceOveruseAction> mOveruseActionsByUserPackage =
107 new ArrayList<>();
108 @GuardedBy("mLock")
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700109 private final SparseArray<ResourceOveruseListenerInfo> mOveruseListenerInfosByUid =
110 new SparseArray<>();
111 @GuardedBy("mLock")
112 private final SparseArray<ResourceOveruseListenerInfo> mOveruseSystemListenerInfosByUid =
113 new SparseArray<>();
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700114 @GuardedBy("mLock")
115 private ZonedDateTime mLastStatsReportUTC;
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700116
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700117 public WatchdogPerfHandler(Context context, CarWatchdogDaemonHelper daemonHelper,
118 PackageInfoHandler packageInfoHandler, boolean isDebugEnabled) {
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700119 mIsDebugEnabled = isDebugEnabled;
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700120 mContext = context;
121 mCarWatchdogDaemonHelper = daemonHelper;
122 mPackageInfoHandler = packageInfoHandler;
123 mMainHandler = new Handler(Looper.getMainLooper());
124 mLastStatsReportUTC = ZonedDateTime.now(ZoneOffset.UTC);
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700125 }
126
127 /** Initializes the handler. */
128 public void init() {
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700129 /*
130 * TODO(b/183947162): Opt-in to receive package change broadcast and handle package enabled
131 * state changes.
132 *
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700133 * TODO(b/170741935): Read the current day's I/O overuse stats from database and push them
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700134 * to the daemon.
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700135 */
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700136 synchronized (mLock) {
137 checkAndHandleDateChangeLocked();
138 }
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700139 if (mIsDebugEnabled) {
140 Slogf.d(TAG, "WatchdogPerfHandler is initialized");
141 }
142 }
143
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700144 /** Releases the handler */
145 public void release() {
146 /*
147 * TODO(b/170741935): Write daily usage to SQLite DB storage.
148 */
149 if (mIsDebugEnabled) {
150 Slogf.d(TAG, "WatchdogPerfHandler is released");
151 }
152 }
153
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700154 /** Dumps its state. */
155 public void dump(IndentingPrintWriter writer) {
156 /**
157 * TODO(b/170741935): Implement this method.
158 */
159 }
160
161 /** Returns resource overuse stats for the calling package. */
162 @NonNull
163 public ResourceOveruseStats getResourceOveruseStats(
164 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
165 @CarWatchdogManager.StatsPeriod int maxStatsPeriod) {
166 Preconditions.checkArgument((resourceOveruseFlag > 0),
167 "Must provide valid resource overuse flag");
168 Preconditions.checkArgument((maxStatsPeriod > 0),
169 "Must provide valid maximum stats period");
170 // TODO(b/170741935): Implement this method.
171 return new ResourceOveruseStats.Builder("",
172 UserHandle.getUserHandleForUid(Binder.getCallingUid())).build();
173 }
174
175 /** Returns resource overuse stats for all packages. */
176 @NonNull
177 public List<ResourceOveruseStats> getAllResourceOveruseStats(
178 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
179 @CarWatchdogManager.MinimumStatsFlag int minimumStatsFlag,
180 @CarWatchdogManager.StatsPeriod int maxStatsPeriod) {
181 Preconditions.checkArgument((resourceOveruseFlag > 0),
182 "Must provide valid resource overuse flag");
183 Preconditions.checkArgument((maxStatsPeriod > 0),
184 "Must provide valid maximum stats period");
185 // TODO(b/170741935): Implement this method.
186 return new ArrayList<>();
187 }
188
189 /** Returns resource overuse stats for the specified user package. */
190 @NonNull
191 public ResourceOveruseStats getResourceOveruseStatsForUserPackage(
192 @NonNull String packageName, @NonNull UserHandle userHandle,
193 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
194 @CarWatchdogManager.StatsPeriod int maxStatsPeriod) {
195 Objects.requireNonNull(packageName, "Package name must be non-null");
196 Objects.requireNonNull(userHandle, "User handle must be non-null");
197 Preconditions.checkArgument((resourceOveruseFlag > 0),
198 "Must provide valid resource overuse flag");
199 Preconditions.checkArgument((maxStatsPeriod > 0),
200 "Must provide valid maximum stats period");
201 // TODO(b/170741935): Implement this method.
202 return new ResourceOveruseStats.Builder("", userHandle).build();
203 }
204
205 /** Adds the resource overuse listener. */
206 public void addResourceOveruseListener(
207 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
208 @NonNull IResourceOveruseListener listener) {
209 Objects.requireNonNull(listener, "Listener must be non-null");
210 Preconditions.checkArgument((resourceOveruseFlag > 0),
211 "Must provide valid resource overuse flag");
212 synchronized (mLock) {
213 addResourceOveruseListenerLocked(resourceOveruseFlag, listener,
214 mOveruseListenerInfosByUid);
215 }
216 }
217
218 /** Removes the previously added resource overuse listener. */
219 public void removeResourceOveruseListener(@NonNull IResourceOveruseListener listener) {
220 Objects.requireNonNull(listener, "Listener must be non-null");
221 synchronized (mLock) {
222 removeResourceOveruseListenerLocked(listener, mOveruseListenerInfosByUid);
223 }
224 }
225
226 /** Adds the resource overuse system listener. */
227 public void addResourceOveruseListenerForSystem(
228 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
229 @NonNull IResourceOveruseListener listener) {
230 Objects.requireNonNull(listener, "Listener must be non-null");
231 Preconditions.checkArgument((resourceOveruseFlag > 0),
232 "Must provide valid resource overuse flag");
233 synchronized (mLock) {
234 addResourceOveruseListenerLocked(resourceOveruseFlag, listener,
235 mOveruseSystemListenerInfosByUid);
236 }
237 }
238
239 /** Removes the previously added resource overuse system listener. */
240 public void removeResourceOveruseListenerForSystem(@NonNull IResourceOveruseListener listener) {
241 Objects.requireNonNull(listener, "Listener must be non-null");
242 synchronized (mLock) {
243 removeResourceOveruseListenerLocked(listener, mOveruseSystemListenerInfosByUid);
244 }
245 }
246
247 /** Sets whether or not a package is killable on resource overuse. */
248 public void setKillablePackageAsUser(String packageName, UserHandle userHandle,
249 boolean isKillable) {
250 Objects.requireNonNull(packageName, "Package name must be non-null");
251 Objects.requireNonNull(userHandle, "User handle must be non-null");
252 /*
253 * TODO(b/170741935): Add/remove the package from the user do-no-kill list.
254 * If the {@code userHandle == UserHandle.ALL}, update the settings for all users.
255 */
256 }
257
258 /** Returns the list of package killable states on resource overuse for the user. */
259 @NonNull
260 public List<PackageKillableState> getPackageKillableStatesAsUser(UserHandle userHandle) {
261 Objects.requireNonNull(userHandle, "User handle must be non-null");
262 // TODO(b/170741935): Implement this method.
263 return new ArrayList<>();
264 }
265
266 /** Sets the given resource overuse configurations. */
267 public void setResourceOveruseConfigurations(
268 List<ResourceOveruseConfiguration> configurations,
269 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) {
270 Objects.requireNonNull(configurations, "Configurations must be non-null");
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700271 Preconditions.checkArgument((configurations.size() > 0),
272 "Must provide at least one configuration");
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700273 Preconditions.checkArgument((resourceOveruseFlag > 0),
274 "Must provide valid resource overuse flag");
275 Set<Integer> seenComponentTypes = new ArraySet<>();
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700276 List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> internalConfigs =
277 new ArrayList<>();
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700278 for (ResourceOveruseConfiguration config : configurations) {
279 int componentType = config.getComponentType();
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700280 if (toComponentTypeStr(componentType).equals("UNKNOWN")) {
281 throw new IllegalArgumentException("Invalid component type in the configuration");
282 }
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700283 if (seenComponentTypes.contains(componentType)) {
284 throw new IllegalArgumentException(
285 "Cannot provide duplicate configurations for the same component type");
286 }
287 if ((resourceOveruseFlag & FLAG_RESOURCE_OVERUSE_IO) != 0
288 && config.getIoOveruseConfiguration() == null) {
289 throw new IllegalArgumentException("Must provide I/O overuse configuration");
290 }
291 seenComponentTypes.add(config.getComponentType());
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700292 internalConfigs.add(toInternalResourceOveruseConfiguration(config,
293 resourceOveruseFlag));
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700294 }
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700295
296 // TODO(b/186119640): Add retry logic when daemon is not available.
297 try {
298 mCarWatchdogDaemonHelper.updateResourceOveruseConfigurations(internalConfigs);
299 } catch (IllegalArgumentException e) {
300 Slogf.w(TAG, "Failed to set resource overuse configurations: %s", e);
301 throw e;
302 } catch (RemoteException | RuntimeException e) {
303 Slogf.w(TAG, "Failed to set resource overuse configurations: %s", e);
304 throw new IllegalStateException(e);
305 }
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700306 }
307
308 /** Returns the available resource overuse configurations. */
309 @NonNull
310 public List<ResourceOveruseConfiguration> getResourceOveruseConfigurations(
311 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) {
312 Preconditions.checkArgument((resourceOveruseFlag > 0),
313 "Must provide valid resource overuse flag");
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700314 List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> internalConfigs =
315 new ArrayList<>();
316 // TODO(b/186119640): Add retry logic when daemon is not available.
317 try {
318 internalConfigs = mCarWatchdogDaemonHelper.getResourceOveruseConfigurations();
319 } catch (RemoteException | RuntimeException e) {
320 Slogf.w(TAG, "Failed to fetch resource overuse configurations: %s", e);
321 throw new IllegalStateException(e);
322 }
323 List<ResourceOveruseConfiguration> configs = new ArrayList<>();
324 for (android.automotive.watchdog.internal.ResourceOveruseConfiguration internalConfig
325 : internalConfigs) {
326 configs.add(toResourceOveruseConfiguration(internalConfig, resourceOveruseFlag));
327 }
328 return configs;
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700329 }
330
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700331 /** Processes the latest I/O overuse stats */
332 public void latestIoOveruseStats(List<PackageIoOveruseStats> packageIoOveruseStats) {
333 int[] uids = new int[packageIoOveruseStats.size()];
334 for (int i = 0; i < packageIoOveruseStats.size(); ++i) {
335 uids[i] = packageIoOveruseStats.get(i).uid;
336 }
337 SparseArray<String> packageNamesByUid = mPackageInfoHandler.getPackageNamesForUids(uids);
338 synchronized (mLock) {
339 checkAndHandleDateChangeLocked();
340 for (PackageIoOveruseStats stats : packageIoOveruseStats) {
341 String packageName = packageNamesByUid.get(stats.uid, null);
342 if (packageName == null) {
343 continue;
344 }
345 int userId = UserHandle.getUserId(stats.uid);
346 PackageResourceUsage usage = cacheAndFetchUsageLocked(userId, packageName,
347 stats.ioOveruseStats);
348 if (stats.shouldNotify) {
349 /*
350 * Packages that exceed the warn threshold percentage should be notified as well
351 * and only the daemon is aware of such packages. Thus the flag is used to
352 * indicate which packages should be notified.
353 */
354 notifyResourceOveruseStatsLocked(stats.uid,
355 usage.getResourceOveruseStatsWithIo());
356 }
357 if (!usage.ioUsage.exceedsThreshold()) {
358 continue;
359 }
360 PackageResourceOveruseAction overuseAction = new PackageResourceOveruseAction();
361 overuseAction.packageIdentifier = new PackageIdentifier();
362 overuseAction.packageIdentifier.name = packageName;
363 overuseAction.packageIdentifier.uid = stats.uid;
364 overuseAction.resourceTypes = new int[]{ ResourceType.IO };
365 overuseAction.resourceOveruseActionType = NOT_KILLED;
366 /*
367 * No action required on I/O overuse on one of the following cases:
368 * #1 The package is not safe to kill as it is critical for system stability.
369 * #2 The package has no recurring overuse behavior and the user opted to not
370 * kill the package so honor the user's decision.
371 */
372 String userPackageId = getUserPackageUniqueId(userId, packageName);
373 int killableState = usage.getKillableState();
374 if (killableState == KILLABLE_STATE_NEVER) {
375 mOveruseActionsByUserPackage.add(overuseAction);
376 continue;
377 }
378 boolean hasRecurringOveruse = isRecurringOveruseLocked(usage);
379 if (!hasRecurringOveruse && killableState == KILLABLE_STATE_NO) {
380 overuseAction.resourceOveruseActionType = NOT_KILLED_USER_OPTED;
381 mOveruseActionsByUserPackage.add(overuseAction);
382 continue;
383 }
384 try {
385 int oldEnabledState = -1;
386 IPackageManager packageManager = ActivityThread.getPackageManager();
387 if (!hasRecurringOveruse) {
388 oldEnabledState = packageManager.getApplicationEnabledSetting(packageName,
389 userId);
390
391 if (oldEnabledState == COMPONENT_ENABLED_STATE_DISABLED
392 || oldEnabledState == COMPONENT_ENABLED_STATE_DISABLED_USER
393 || oldEnabledState == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
394 mOveruseActionsByUserPackage.add(overuseAction);
395 continue;
396 }
397 }
398
399 packageManager.setApplicationEnabledSetting(packageName,
400 COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, /* flags= */ 0, userId,
401 mContext.getPackageName());
402
403 overuseAction.resourceOveruseActionType = hasRecurringOveruse
404 ? KILLED_RECURRING_OVERUSE : KILLED;
405 if (!hasRecurringOveruse) {
406 usage.oldEnabledState = oldEnabledState;
407 }
408 } catch (RemoteException e) {
409 Slogf.e(TAG, "Failed to disable application enabled setting for user %d, "
410 + "package '%s'", userId, packageName);
411 }
412 mOveruseActionsByUserPackage.add(overuseAction);
413 }
414 if (!mOveruseActionsByUserPackage.isEmpty()) {
415 mMainHandler.sendMessage(obtainMessage(
416 WatchdogPerfHandler::notifyActionsTakenOnOveruse, this));
417 }
418 }
419 }
420
421 /** Notify daemon about the actions take on resource overuse */
422 public void notifyActionsTakenOnOveruse() {
423 List<PackageResourceOveruseAction> actions;
424 synchronized (mLock) {
425 if (mOveruseActionsByUserPackage.isEmpty()) {
426 return;
427 }
428 actions = new ArrayList<>(mOveruseActionsByUserPackage);
429 mOveruseActionsByUserPackage.clear();
430 }
431 try {
432 mCarWatchdogDaemonHelper.actionTakenOnResourceOveruse(actions);
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700433 } catch (RemoteException | RuntimeException e) {
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700434 Slogf.w(TAG, "Failed to notify car watchdog daemon of actions taken on "
435 + "resource overuse: %s", e);
436 }
437 }
438
439 private void notifyResourceOveruseStatsLocked(int uid,
440 ResourceOveruseStats resourceOveruseStats) {
441 String packageName = resourceOveruseStats.getPackageName();
442 ResourceOveruseListenerInfo listenerInfo = mOveruseListenerInfosByUid.get(uid, null);
443 if (listenerInfo != null && (listenerInfo.flag & FLAG_RESOURCE_OVERUSE_IO) != 0) {
444 try {
445 listenerInfo.listener.onOveruse(resourceOveruseStats);
446 } catch (RemoteException e) {
447 Slogf.e(TAG,
448 "Failed to notify listener(uid %d, package '%s') on resource overuse: %s",
449 uid, resourceOveruseStats, e);
450 }
451 }
452 for (int i = 0; i < mOveruseSystemListenerInfosByUid.size(); ++i) {
453 ResourceOveruseListenerInfo systemListenerInfo =
454 mOveruseSystemListenerInfosByUid.valueAt(i);
455 if ((systemListenerInfo.flag & FLAG_RESOURCE_OVERUSE_IO) == 0) {
456 continue;
457 }
458 try {
459 systemListenerInfo.listener.onOveruse(resourceOveruseStats);
460 } catch (RemoteException e) {
461 Slogf.e(TAG, "Failed to notify system listener(uid %d, pid: %d) of resource "
462 + "overuse by package(uid %d, package '%s'): %s",
463 systemListenerInfo.uid, systemListenerInfo.pid, uid, packageName, e);
464 }
465 }
466 }
467
468 private void checkAndHandleDateChangeLocked() {
469 ZonedDateTime previousUTC = mLastStatsReportUTC;
470 mLastStatsReportUTC = ZonedDateTime.now(ZoneOffset.UTC);
471 if (mLastStatsReportUTC.getDayOfYear() == previousUTC.getDayOfYear()
472 && mLastStatsReportUTC.getYear() == previousUTC.getYear()) {
473 return;
474 }
475 for (PackageResourceUsage usage : mUsageByUserPackage.values()) {
476 if (usage.oldEnabledState > 0) {
477 // Forgive the daily disabled package on date change.
478 try {
479 IPackageManager packageManager = ActivityThread.getPackageManager();
480 if (packageManager.getApplicationEnabledSetting(usage.packageName,
481 usage.userId)
482 != COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
483 continue;
484 }
485 packageManager.setApplicationEnabledSetting(usage.packageName,
486 usage.oldEnabledState,
487 /* flags= */ 0, usage.userId, mContext.getPackageName());
488 } catch (RemoteException e) {
489 Slogf.e(TAG,
490 "Failed to reset enabled setting for disabled package '%s', user %d",
491 usage.packageName, usage.userId);
492 }
493 }
494 /* TODO(b/170741935): Stash the old usage into SQLite DB storage. */
495 usage.ioUsage.clear();
496 }
497 }
498
499 private PackageResourceUsage cacheAndFetchUsageLocked(@UserIdInt int userId, String packageName,
500 android.automotive.watchdog.IoOveruseStats internalStats) {
501 String key = getUserPackageUniqueId(userId, packageName);
502 PackageResourceUsage usage = mUsageByUserPackage.getOrDefault(key,
503 new PackageResourceUsage(userId, packageName));
504 usage.update(internalStats);
505 mUsageByUserPackage.put(key, usage);
506 return usage;
507 }
508
509 private boolean isRecurringOveruseLocked(PackageResourceUsage ioUsage) {
510 /*
511 * TODO(b/170741935): Look up I/O overuse history and determine whether or not the package
512 * has recurring I/O overuse behavior.
513 */
514 return false;
515 }
516
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700517 private void addResourceOveruseListenerLocked(
518 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
519 @NonNull IResourceOveruseListener listener,
520 SparseArray<ResourceOveruseListenerInfo> listenerInfosByUid) {
521 int callingPid = Binder.getCallingPid();
522 int callingUid = Binder.getCallingUid();
523 boolean isListenerForSystem = listenerInfosByUid == mOveruseSystemListenerInfosByUid;
524 String listenerType = isListenerForSystem ? "resource overuse listener for system" :
525 "resource overuse listener";
526
527 ResourceOveruseListenerInfo existingListenerInfo = listenerInfosByUid.get(callingUid, null);
528 if (existingListenerInfo != null) {
529 IBinder binder = listener.asBinder();
530 if (existingListenerInfo.listener.asBinder() == binder) {
531 throw new IllegalStateException(
532 "Cannot add " + listenerType + " as it is already added");
533 }
534 }
535
536 ResourceOveruseListenerInfo listenerInfo = new ResourceOveruseListenerInfo(listener,
537 resourceOveruseFlag, callingPid, callingUid, isListenerForSystem);
538 try {
539 listenerInfo.linkToDeath();
540 } catch (RemoteException e) {
541 Slogf.w(TAG, "Cannot add %s: linkToDeath to listener failed", listenerType);
542 return;
543 }
544
545 if (existingListenerInfo != null) {
546 Slogf.w(TAG, "Overwriting existing %s: pid %d, uid: %d", listenerType,
547 existingListenerInfo.pid, existingListenerInfo.uid);
548 existingListenerInfo.unlinkToDeath();
549 }
550
551
552 listenerInfosByUid.put(callingUid, listenerInfo);
553 if (mIsDebugEnabled) {
554 Slogf.d(TAG, "The %s (pid: %d, uid: %d) is added", listenerType,
555 callingPid, callingUid);
556 }
557 }
558
559 private void removeResourceOveruseListenerLocked(@NonNull IResourceOveruseListener listener,
560 SparseArray<ResourceOveruseListenerInfo> listenerInfosByUid) {
561 int callingUid = Binder.getCallingUid();
562
563 String listenerType = listenerInfosByUid == mOveruseSystemListenerInfosByUid
564 ? "resource overuse system listener" : "resource overuse listener";
565
566 ResourceOveruseListenerInfo listenerInfo = listenerInfosByUid.get(callingUid, null);
567 if (listenerInfo == null || listenerInfo.listener != listener) {
568 Slogf.w(TAG, "Cannot remove the %s: it has not been registered before", listenerType);
569 return;
570 }
571 listenerInfo.unlinkToDeath();
572 listenerInfosByUid.remove(callingUid);
573 if (mIsDebugEnabled) {
574 Slogf.d(TAG, "The %s (pid: %d, uid: %d) is removed", listenerType, listenerInfo.pid,
575 listenerInfo.uid);
576 }
577 }
578
579 private void onResourceOveruseListenerDeath(int uid, boolean isListenerForSystem) {
580 synchronized (mLock) {
581 if (isListenerForSystem) {
582 mOveruseSystemListenerInfosByUid.remove(uid);
583 } else {
584 mOveruseListenerInfosByUid.remove(uid);
585 }
586 }
587 }
588
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700589 private static String getUserPackageUniqueId(int userId, String packageName) {
590 return String.valueOf(userId) + ":" + packageName;
591 }
592
593 @VisibleForTesting
594 static IoOveruseStats.Builder toIoOveruseStatsBuilder(
595 android.automotive.watchdog.IoOveruseStats internalStats) {
596 IoOveruseStats.Builder statsBuilder = new IoOveruseStats.Builder(
597 internalStats.startTime, internalStats.durationInSeconds);
598 statsBuilder.setRemainingWriteBytes(
599 toPerStateBytes(internalStats.remainingWriteBytes));
600 statsBuilder.setTotalBytesWritten(totalPerStateBytes(internalStats.writtenBytes));
601 statsBuilder.setTotalOveruses(internalStats.totalOveruses);
602 return statsBuilder;
603 }
604
605 private static PerStateBytes toPerStateBytes(
606 android.automotive.watchdog.PerStateBytes internalPerStateBytes) {
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700607 return new PerStateBytes(internalPerStateBytes.foregroundBytes,
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700608 internalPerStateBytes.backgroundBytes, internalPerStateBytes.garageModeBytes);
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700609 }
610
611 private static long totalPerStateBytes(
612 android.automotive.watchdog.PerStateBytes internalPerStateBytes) {
613 BiFunction<Long, Long, Long> sum = (l, r) -> {
614 return (Long.MAX_VALUE - l > r) ? l + r : Long.MAX_VALUE;
615 };
616 return sum.apply(sum.apply(internalPerStateBytes.foregroundBytes,
617 internalPerStateBytes.backgroundBytes), internalPerStateBytes.garageModeBytes);
618 }
619
Lakshman Annadoraie1720472021-04-13 15:22:57 -0700620 private static android.automotive.watchdog.internal.ResourceOveruseConfiguration
621 toInternalResourceOveruseConfiguration(ResourceOveruseConfiguration config,
622 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) {
623 android.automotive.watchdog.internal.ResourceOveruseConfiguration internalConfig =
624 new android.automotive.watchdog.internal.ResourceOveruseConfiguration();
625 internalConfig.componentType = config.getComponentType();
626 internalConfig.safeToKillPackages = config.getSafeToKillPackages();
627 internalConfig.vendorPackagePrefixes = config.getVendorPackagePrefixes();
628 internalConfig.packageMetadata = new ArrayList<>();
629 for (Map.Entry<String, String> entry : config.getPackagesToAppCategoryTypes().entrySet()) {
630 if (entry.getKey().isEmpty()) {
631 continue;
632 }
633 PackageMetadata metadata = new PackageMetadata();
634 metadata.packageName = entry.getKey();
635 switch(entry.getValue()) {
636 case ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS:
637 metadata.appCategoryType = ApplicationCategoryType.MAPS;
638 break;
639 case ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MEDIA:
640 metadata.appCategoryType = ApplicationCategoryType.MEDIA;
641 break;
642 default:
643 continue;
644 }
645 internalConfig.packageMetadata.add(metadata);
646 }
647 internalConfig.resourceSpecificConfigurations = new ArrayList<>();
648 if ((resourceOveruseFlag & FLAG_RESOURCE_OVERUSE_IO) != 0
649 && config.getIoOveruseConfiguration() != null) {
650 internalConfig.resourceSpecificConfigurations.add(
651 toResourceSpecificConfiguration(config.getComponentType(),
652 config.getIoOveruseConfiguration()));
653 }
654 return internalConfig;
655 }
656
657 private static ResourceSpecificConfiguration
658 toResourceSpecificConfiguration(int componentType, IoOveruseConfiguration config) {
659 android.automotive.watchdog.internal.IoOveruseConfiguration internalConfig =
660 new android.automotive.watchdog.internal.IoOveruseConfiguration();
661 internalConfig.componentLevelThresholds = toPerStateIoOveruseThreshold(
662 toComponentTypeStr(componentType), config.getComponentLevelThresholds());
663 internalConfig.packageSpecificThresholds = toPerStateIoOveruseThresholds(
664 config.getPackageSpecificThresholds());
665 internalConfig.categorySpecificThresholds = toPerStateIoOveruseThresholds(
666 config.getAppCategorySpecificThresholds());
667 for (PerStateIoOveruseThreshold threshold : internalConfig.categorySpecificThresholds) {
668 switch(threshold.name) {
669 case ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS:
670 threshold.name = INTERNAL_APPLICATION_CATEGORY_TYPE_MAPS;
671 break;
672 case ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MEDIA:
673 threshold.name = INTERNAL_APPLICATION_CATEGORY_TYPE_MEDIA;
674 break;
675 default:
676 threshold.name = INTERNAL_APPLICATION_CATEGORY_TYPE_UNKNOWN;
677 }
678 }
679 internalConfig.systemWideThresholds = toInternalIoOveruseAlertThresholds(
680 config.getSystemWideThresholds());
681
682 ResourceSpecificConfiguration resourceSpecificConfig = new ResourceSpecificConfiguration();
683 resourceSpecificConfig.setIoOveruseConfiguration(internalConfig);
684 return resourceSpecificConfig;
685 }
686
687 @VisibleForTesting
688 static String toComponentTypeStr(int componentType) {
689 switch(componentType) {
690 case ComponentType.SYSTEM:
691 return "SYSTEM";
692 case ComponentType.VENDOR:
693 return "VENDOR";
694 case ComponentType.THIRD_PARTY:
695 return "THIRD_PARTY";
696 default:
697 return "UNKNOWN";
698 }
699 }
700
701 private static List<PerStateIoOveruseThreshold> toPerStateIoOveruseThresholds(
702 Map<String, PerStateBytes> thresholds) {
703 List<PerStateIoOveruseThreshold> internalThresholds = new ArrayList<>();
704 for (Map.Entry<String, PerStateBytes> entry : thresholds.entrySet()) {
705 if (!entry.getKey().isEmpty()) {
706 internalThresholds.add(toPerStateIoOveruseThreshold(entry.getKey(),
707 entry.getValue()));
708 }
709 }
710 return internalThresholds;
711 }
712
713 private static PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(String name,
714 PerStateBytes perStateBytes) {
715 PerStateIoOveruseThreshold threshold = new PerStateIoOveruseThreshold();
716 threshold.name = name;
717 threshold.perStateWriteBytes = new android.automotive.watchdog.PerStateBytes();
718 threshold.perStateWriteBytes.foregroundBytes = perStateBytes.getForegroundModeBytes();
719 threshold.perStateWriteBytes.backgroundBytes = perStateBytes.getBackgroundModeBytes();
720 threshold.perStateWriteBytes.garageModeBytes = perStateBytes.getGarageModeBytes();
721 return threshold;
722 }
723
724 private static List<android.automotive.watchdog.internal.IoOveruseAlertThreshold>
725 toInternalIoOveruseAlertThresholds(List<IoOveruseAlertThreshold> thresholds) {
726 List<android.automotive.watchdog.internal.IoOveruseAlertThreshold> internalThresholds =
727 new ArrayList<>();
728 for (IoOveruseAlertThreshold threshold : thresholds) {
729 if (threshold.getDurationInSeconds() == 0
730 || threshold.getWrittenBytesPerSecond() == 0) {
731 continue;
732 }
733 android.automotive.watchdog.internal.IoOveruseAlertThreshold internalThreshold =
734 new android.automotive.watchdog.internal.IoOveruseAlertThreshold();
735 internalThreshold.durationInSeconds = threshold.getDurationInSeconds();
736 internalThreshold.writtenBytesPerSecond = threshold.getWrittenBytesPerSecond();
737 internalThresholds.add(internalThreshold);
738 }
739 return internalThresholds;
740 }
741
742 private static ResourceOveruseConfiguration toResourceOveruseConfiguration(
743 android.automotive.watchdog.internal.ResourceOveruseConfiguration internalConfig,
744 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) {
745 Map<String, String> packagesToAppCategoryTypes = new ArrayMap<>();
746 for (PackageMetadata metadata : internalConfig.packageMetadata) {
747 String categoryTypeStr;
748 switch (metadata.appCategoryType) {
749 case ApplicationCategoryType.MAPS:
750 categoryTypeStr = ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS;
751 break;
752 case ApplicationCategoryType.MEDIA:
753 categoryTypeStr = ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MEDIA;
754 break;
755 default:
756 continue;
757 }
758 packagesToAppCategoryTypes.put(metadata.packageName, categoryTypeStr);
759 }
760 ResourceOveruseConfiguration.Builder configBuilder =
761 new ResourceOveruseConfiguration.Builder(
762 internalConfig.componentType,
763 internalConfig.safeToKillPackages,
764 internalConfig.vendorPackagePrefixes,
765 packagesToAppCategoryTypes);
766 for (ResourceSpecificConfiguration resourceSpecificConfig :
767 internalConfig.resourceSpecificConfigurations) {
768 if (resourceSpecificConfig.getTag()
769 == ResourceSpecificConfiguration.ioOveruseConfiguration
770 && (resourceOveruseFlag & FLAG_RESOURCE_OVERUSE_IO) != 0) {
771 configBuilder.setIoOveruseConfiguration(toIoOveruseConfiguration(
772 resourceSpecificConfig.getIoOveruseConfiguration()));
773 }
774 }
775 return configBuilder.build();
776 }
777
778 private static IoOveruseConfiguration toIoOveruseConfiguration(
779 android.automotive.watchdog.internal.IoOveruseConfiguration internalConfig) {
780 PerStateBytes componentLevelThresholds =
781 toPerStateBytes(internalConfig.componentLevelThresholds.perStateWriteBytes);
782 Map<String, PerStateBytes> packageSpecificThresholds =
783 toPerStateBytesMap(internalConfig.packageSpecificThresholds);
784 Map<String, PerStateBytes> appCategorySpecificThresholds =
785 toPerStateBytesMap(internalConfig.categorySpecificThresholds);
786 replaceKey(appCategorySpecificThresholds, INTERNAL_APPLICATION_CATEGORY_TYPE_MAPS,
787 ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS);
788 replaceKey(appCategorySpecificThresholds, INTERNAL_APPLICATION_CATEGORY_TYPE_MEDIA,
789 ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MEDIA);
790 List<IoOveruseAlertThreshold> systemWideThresholds =
791 toIoOveruseAlertThresholds(internalConfig.systemWideThresholds);
792
793 IoOveruseConfiguration.Builder configBuilder = new IoOveruseConfiguration.Builder(
794 componentLevelThresholds, packageSpecificThresholds, appCategorySpecificThresholds,
795 systemWideThresholds);
796 return configBuilder.build();
797 }
798
799 private static Map<String, PerStateBytes> toPerStateBytesMap(
800 List<PerStateIoOveruseThreshold> thresholds) {
801 Map<String, PerStateBytes> thresholdsMap = new ArrayMap<>();
802 for (PerStateIoOveruseThreshold threshold : thresholds) {
803 thresholdsMap.put(threshold.name, toPerStateBytes(threshold.perStateWriteBytes));
804 }
805 return thresholdsMap;
806 }
807
808 private static List<IoOveruseAlertThreshold> toIoOveruseAlertThresholds(
809 List<android.automotive.watchdog.internal.IoOveruseAlertThreshold> internalThresholds) {
810 List<IoOveruseAlertThreshold> thresholds = new ArrayList<>();
811 for (android.automotive.watchdog.internal.IoOveruseAlertThreshold internalThreshold
812 : internalThresholds) {
813 thresholds.add(new IoOveruseAlertThreshold(internalThreshold.durationInSeconds,
814 internalThreshold.writtenBytesPerSecond));
815 }
816 return thresholds;
817 }
818
819 private static void replaceKey(Map<String, PerStateBytes> map, String oldKey, String newKey) {
820 PerStateBytes perStateBytes = map.get(oldKey);
821 if (perStateBytes != null) {
822 map.put(newKey, perStateBytes);
823 map.remove(oldKey);
824 }
825 }
826
Lakshman Annadoraicf5f3a92021-04-02 15:26:16 -0700827 private static final class PackageResourceUsage {
828 public final String packageName;
829 public @UserIdInt final int userId;
830 public final PackageIoUsage ioUsage;
831 public int oldEnabledState;
832
833 private @KillableState int mKillableState;
834
835 PackageResourceUsage(@UserIdInt int userId, String packageName) {
836 this.packageName = packageName;
837 this.userId = userId;
838 this.ioUsage = new PackageIoUsage();
839 this.oldEnabledState = -1;
840 this.mKillableState = KILLABLE_STATE_YES;
841 }
842
843 public void update(android.automotive.watchdog.IoOveruseStats internalStats) {
844 if (!internalStats.killableOnOveruse) {
845 /*
846 * Killable value specified in the internal stats is provided by the native daemon.
847 * This value reflects whether or not an application is safe-to-kill on overuse.
848 * This setting is from the I/O overuse configuration specified by the system and
849 * vendor services and doesn't reflect the user choices. Thus if the internal stats
850 * specify the application is not killable, the application is not safe-to-kill.
851 */
852 this.mKillableState = KILLABLE_STATE_NEVER;
853 }
854 ioUsage.update(internalStats);
855 }
856
857 public ResourceOveruseStats getResourceOveruseStatsWithIo() {
858 IoOveruseStats ioOveruseStats = null;
859 if (ioUsage.hasUsage()) {
860 ioOveruseStats = ioUsage.getStatsBuilder().setKillableOnOveruse(
861 mKillableState != PackageKillableState.KILLABLE_STATE_NEVER).build();
862 }
863
864 return new ResourceOveruseStats.Builder(packageName, UserHandle.of(userId))
865 .setIoOveruseStats(ioOveruseStats).build();
866 }
867
868 public @KillableState int getKillableState() {
869 return mKillableState;
870 }
871
872 public boolean setKillableState(boolean isKillable) {
873 if (mKillableState == PackageKillableState.KILLABLE_STATE_NEVER) {
874 return false;
875 }
876 mKillableState = isKillable ? KILLABLE_STATE_YES : KILLABLE_STATE_NO;
877 return true;
878 }
879 }
880
881 private static final class PackageIoUsage {
882 private android.automotive.watchdog.IoOveruseStats mIoOveruseStats;
883 private android.automotive.watchdog.PerStateBytes mForgivenWriteBytes;
884 private long mTotalTimesKilled;
885
886 PackageIoUsage() {
887 mTotalTimesKilled = 0;
888 }
889
890 public boolean hasUsage() {
891 return mIoOveruseStats != null;
892 }
893
894 public void update(android.automotive.watchdog.IoOveruseStats internalStats) {
895 mIoOveruseStats = internalStats;
896 if (exceedsThreshold()) {
897 /*
898 * Forgive written bytes on overuse as the package is either forgiven or killed on
899 * overuse. When the package is killed, the user may opt to open the corresponding
900 * app and the package should be forgiven anyways.
901 * NOTE: If this logic is updated, update the daemon side logic as well.
902 */
903 mForgivenWriteBytes = internalStats.writtenBytes;
904 }
905 }
906
907 public IoOveruseStats.Builder getStatsBuilder() {
908 IoOveruseStats.Builder statsBuilder = toIoOveruseStatsBuilder(mIoOveruseStats);
909 statsBuilder.setTotalTimesKilled(mTotalTimesKilled);
910 return statsBuilder;
911 }
912
913 public boolean exceedsThreshold() {
914 if (!hasUsage()) {
915 return false;
916 }
917 android.automotive.watchdog.PerStateBytes remaining =
918 mIoOveruseStats.remainingWriteBytes;
919 return remaining.foregroundBytes == 0 || remaining.backgroundBytes == 0
920 || remaining.garageModeBytes == 0;
921 }
922
923 public void clear() {
924 mIoOveruseStats = null;
925 mForgivenWriteBytes = null;
926 mTotalTimesKilled = 0;
927 }
928 }
929
Lakshman Annadorai016127e2021-03-18 09:11:43 -0700930 private final class ResourceOveruseListenerInfo implements IBinder.DeathRecipient {
931 public final IResourceOveruseListener listener;
932 public final @CarWatchdogManager.ResourceOveruseFlag int flag;
933 public final int pid;
934 public final int uid;
935 public final boolean isListenerForSystem;
936
937 ResourceOveruseListenerInfo(IResourceOveruseListener listener,
938 @CarWatchdogManager.ResourceOveruseFlag int flag, int pid, int uid,
939 boolean isListenerForSystem) {
940 this.listener = listener;
941 this.flag = flag;
942 this.pid = pid;
943 this.uid = uid;
944 this.isListenerForSystem = isListenerForSystem;
945 }
946
947 @Override
948 public void binderDied() {
949 Slogf.w(TAG, "Resource overuse listener%s (pid: %d) died",
950 isListenerForSystem ? " for system" : "", pid);
951 onResourceOveruseListenerDeath(uid, isListenerForSystem);
952 unlinkToDeath();
953 }
954
955 private void linkToDeath() throws RemoteException {
956 listener.asBinder().linkToDeath(this, 0);
957 }
958
959 private void unlinkToDeath() {
960 listener.asBinder().unlinkToDeath(this, 0);
961 }
962 }
963}