1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.car.watchdog; 18 19 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED; 20 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING; 21 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPED; 22 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING; 23 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING; 24 import static android.content.Intent.ACTION_PACKAGE_CHANGED; 25 import static android.content.Intent.ACTION_REBOOT; 26 import static android.content.Intent.ACTION_SHUTDOWN; 27 import static android.content.Intent.ACTION_USER_REMOVED; 28 29 import static com.android.car.CarLog.TAG_WATCHDOG; 30 import static com.android.car.CarServiceUtils.assertAnyPermission; 31 import static com.android.car.CarServiceUtils.assertPermission; 32 import static com.android.car.CarServiceUtils.isEventAnyOfTypes; 33 import static com.android.car.CarServiceUtils.runOnMain; 34 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO; 35 import static com.android.car.internal.NotificationHelperBase.CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION; 36 import static com.android.car.internal.NotificationHelperBase.CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS; 37 import static com.android.car.internal.NotificationHelperBase.CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP; 38 39 import android.annotation.NonNull; 40 import android.annotation.UserIdInt; 41 import android.automotive.watchdog.internal.GarageMode; 42 import android.automotive.watchdog.internal.ICarWatchdogServiceForSystem; 43 import android.automotive.watchdog.internal.PackageInfo; 44 import android.automotive.watchdog.internal.PackageIoOveruseStats; 45 import android.automotive.watchdog.internal.PowerCycle; 46 import android.automotive.watchdog.internal.ResourceStats; 47 import android.automotive.watchdog.internal.StateType; 48 import android.automotive.watchdog.internal.UserPackageIoUsageStats; 49 import android.automotive.watchdog.internal.UserState; 50 import android.car.Car; 51 import android.car.builtin.util.Slogf; 52 import android.car.hardware.power.CarPowerManager; 53 import android.car.hardware.power.CarPowerPolicy; 54 import android.car.hardware.power.CarPowerPolicyFilter; 55 import android.car.hardware.power.ICarPowerPolicyListener; 56 import android.car.hardware.power.ICarPowerStateListener; 57 import android.car.hardware.power.PowerComponent; 58 import android.car.user.UserLifecycleEventFilter; 59 import android.car.watchdog.CarWatchdogManager; 60 import android.car.watchdog.ICarWatchdogService; 61 import android.car.watchdog.ICarWatchdogServiceCallback; 62 import android.car.watchdog.IResourceOveruseListener; 63 import android.car.watchdog.PackageKillableState; 64 import android.car.watchdog.ResourceOveruseConfiguration; 65 import android.car.watchdog.ResourceOveruseStats; 66 import android.car.watchdoglib.CarWatchdogDaemonHelper; 67 import android.content.BroadcastReceiver; 68 import android.content.Context; 69 import android.content.Intent; 70 import android.content.IntentFilter; 71 import android.os.RemoteException; 72 import android.os.ServiceSpecificException; 73 import android.os.UserHandle; 74 import android.os.UserManager; 75 import android.util.ArraySet; 76 import android.util.Log; 77 import android.util.proto.ProtoOutputStream; 78 79 import com.android.car.CarLocalServices; 80 import com.android.car.CarLog; 81 import com.android.car.CarServiceBase; 82 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 83 import com.android.car.internal.dep.Trace; 84 import com.android.car.internal.util.ArrayUtils; 85 import com.android.car.internal.util.IndentingPrintWriter; 86 import com.android.car.power.CarPowerManagementService; 87 import com.android.car.systeminterface.SystemInterface; 88 import com.android.car.user.CarUserService; 89 import com.android.internal.annotations.GuardedBy; 90 import com.android.internal.annotations.VisibleForTesting; 91 92 import java.io.File; 93 import java.lang.ref.WeakReference; 94 import java.time.Instant; 95 import java.util.Collections; 96 import java.util.List; 97 import java.util.Objects; 98 99 /** 100 * Service to implement CarWatchdogManager API. 101 */ 102 public final class CarWatchdogService extends ICarWatchdogService.Stub implements CarServiceBase { 103 static final String TAG = CarLog.tagFor(CarWatchdogService.class); 104 static final boolean DEBUG = Slogf.isLoggable(TAG, Log.DEBUG); 105 static final String ACTION_GARAGE_MODE_ON = 106 "com.android.server.jobscheduler.GARAGE_MODE_ON"; 107 static final String ACTION_GARAGE_MODE_OFF = 108 "com.android.server.jobscheduler.GARAGE_MODE_OFF"; 109 110 @VisibleForTesting 111 static final int MISSING_ARG_VALUE = -1; 112 113 private static final String FALLBACK_DATA_SYSTEM_CAR_DIR_PATH = "/data/system/car"; 114 private static final String WATCHDOG_DIR_NAME = "watchdog"; 115 116 private static final TimeSource SYSTEM_INSTANCE = new TimeSource() { 117 @Override 118 public Instant now() { 119 return Instant.now(); 120 } 121 122 @Override 123 public String toString() { 124 return "System time instance"; 125 } 126 }; 127 128 private final Context mContext; 129 private final ICarWatchdogServiceForSystemImpl mWatchdogServiceForSystem; 130 private final PackageInfoHandler mPackageInfoHandler; 131 private final WatchdogStorage mWatchdogStorage; 132 private final WatchdogProcessHandler mWatchdogProcessHandler; 133 private final WatchdogPerfHandler mWatchdogPerfHandler; 134 private final CarWatchdogDaemonHelper.OnConnectionChangeListener mConnectionListener; 135 136 private CarWatchdogDaemonHelper mCarWatchdogDaemonHelper; 137 138 private boolean mIsPowerShutdownHandled; 139 140 /* 141 * TODO(b/192481350): Listen for GarageMode change notification rather than depending on the 142 * system_server broadcast when the CarService internal API for listening GarageMode change is 143 * implemented. 144 */ 145 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 146 @Override 147 public void onReceive(Context context, Intent intent) { 148 String action = intent.getAction(); 149 Trace.beginSection("CarWatchdogService-broadcast-" + action); 150 switch (action) { 151 case CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION: 152 case CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS: 153 case CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP: 154 mWatchdogPerfHandler.processUserNotificationIntent(intent); 155 break; 156 case ACTION_GARAGE_MODE_ON: 157 case ACTION_GARAGE_MODE_OFF: 158 int garageMode; 159 synchronized (mLock) { 160 garageMode = mCurrentGarageMode = Objects.equals(action, 161 ACTION_GARAGE_MODE_ON) 162 ? GarageMode.GARAGE_MODE_ON : GarageMode.GARAGE_MODE_OFF; 163 } 164 mWatchdogPerfHandler.onGarageModeChange(garageMode); 165 if (garageMode == GarageMode.GARAGE_MODE_ON) { 166 mWatchdogStorage.shrinkDatabase(); 167 } 168 notifyGarageModeChange(garageMode); 169 break; 170 case ACTION_REBOOT: 171 case ACTION_SHUTDOWN: 172 // FLAG_RECEIVER_FOREGROUND is checked to ignore the intent from UserController 173 // when a user is stopped. 174 if ((intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) == 0) { 175 break; 176 } 177 notifyPowerCycleChange(PowerCycle.POWER_CYCLE_SHUTDOWN_ENTER); 178 break; 179 case ACTION_USER_REMOVED: { 180 UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER); 181 int userId = userHandle.getIdentifier(); 182 try { 183 mCarWatchdogDaemonHelper.notifySystemStateChange(StateType.USER_STATE, 184 userId, UserState.USER_STATE_REMOVED); 185 if (DEBUG) { 186 Slogf.d(TAG, "Notified car watchdog daemon of removed user %d", 187 userId); 188 } 189 } catch (RemoteException e) { 190 Slogf.w(TAG, e, "Failed to notify car watchdog daemon of removed user %d", 191 userId); 192 } 193 mWatchdogPerfHandler.deleteUser(userId); 194 break; 195 } 196 case ACTION_PACKAGE_CHANGED: { 197 mWatchdogPerfHandler.processPackageChangedIntent(intent); 198 break; 199 } 200 default: 201 Slogf.i(TAG, "Ignoring unknown intent %s", intent); 202 } 203 Trace.endSection(); 204 } 205 }; 206 207 private final ICarPowerStateListener mCarPowerStateListener = 208 new ICarPowerStateListener.Stub() { 209 @Override 210 public void onStateChanged(int state, long expirationTimeMs) { 211 CarPowerManagementService powerService = 212 CarLocalServices.getService(CarPowerManagementService.class); 213 if (powerService == null 214 || state == CarPowerManager.STATE_POST_SHUTDOWN_ENTER 215 || state == CarPowerManager.STATE_POST_SUSPEND_ENTER 216 || state == CarPowerManager.STATE_POST_HIBERNATION_ENTER) { 217 return; 218 } 219 onPowerState(powerService.getPowerState()); 220 } 221 }; 222 223 private final ICarPowerPolicyListener mCarDisplayPowerPolicyListener = 224 new ICarPowerPolicyListener.Stub() { 225 @Override 226 public void onPolicyChanged(CarPowerPolicy appliedPolicy, 227 CarPowerPolicy accumulatedPolicy) { 228 Trace.beginSection("CarWatchdogService-carPowerPolicyChanged-" 229 + appliedPolicy.getPolicyId()); 230 boolean isDisplayEnabled = 231 appliedPolicy.isComponentEnabled(PowerComponent.DISPLAY); 232 boolean didStateChange = false; 233 synchronized (mLock) { 234 didStateChange = mIsDisplayEnabled != isDisplayEnabled; 235 mIsDisplayEnabled = isDisplayEnabled; 236 } 237 if (didStateChange) { 238 mWatchdogPerfHandler.onDisplayStateChanged(isDisplayEnabled); 239 } 240 Trace.endSection();; 241 } 242 }; 243 244 private final Object mLock = new Object(); 245 @GuardedBy("mLock") 246 private boolean mReadyToRespond; 247 @GuardedBy("mLock") 248 private boolean mIsConnected; 249 @GuardedBy("mLock") 250 private @GarageMode int mCurrentGarageMode; 251 @GuardedBy("mLock") 252 private boolean mIsDisplayEnabled; 253 CarWatchdogService(Context context, Context carServiceBuiltinPackageContext)254 public CarWatchdogService(Context context, Context carServiceBuiltinPackageContext) { 255 this(context, carServiceBuiltinPackageContext, 256 new WatchdogStorage(context, SYSTEM_INSTANCE), SYSTEM_INSTANCE); 257 } 258 259 @VisibleForTesting CarWatchdogService(Context context, Context carServiceBuiltinPackageContext, WatchdogStorage watchdogStorage, TimeSource timeSource)260 public CarWatchdogService(Context context, Context carServiceBuiltinPackageContext, 261 WatchdogStorage watchdogStorage, TimeSource timeSource) { 262 this(context, carServiceBuiltinPackageContext, watchdogStorage, 263 timeSource, /*watchdogProcessHandler=*/ null, /*watchdogPerfHandler=*/ null); 264 } 265 266 @VisibleForTesting CarWatchdogService(Context context, Context carServiceBuiltinPackageContext, WatchdogStorage watchdogStorage, TimeSource timeSource, WatchdogProcessHandler watchdogProcessHandler, WatchdogPerfHandler watchdogPerfHandler)267 CarWatchdogService(Context context, Context carServiceBuiltinPackageContext, 268 WatchdogStorage watchdogStorage, TimeSource timeSource, 269 WatchdogProcessHandler watchdogProcessHandler, 270 WatchdogPerfHandler watchdogPerfHandler) { 271 mContext = context; 272 mWatchdogStorage = watchdogStorage; 273 mPackageInfoHandler = new PackageInfoHandler(mContext.getPackageManager()); 274 mCarWatchdogDaemonHelper = new CarWatchdogDaemonHelper(TAG_WATCHDOG); 275 mWatchdogServiceForSystem = new ICarWatchdogServiceForSystemImpl(this); 276 mWatchdogProcessHandler = watchdogProcessHandler != null ? watchdogProcessHandler 277 : new WatchdogProcessHandler(mWatchdogServiceForSystem, mCarWatchdogDaemonHelper, 278 mPackageInfoHandler); 279 mWatchdogPerfHandler = 280 watchdogPerfHandler != null ? watchdogPerfHandler : new WatchdogPerfHandler( 281 mContext, carServiceBuiltinPackageContext, 282 mCarWatchdogDaemonHelper, mPackageInfoHandler, mWatchdogStorage, 283 timeSource); 284 mConnectionListener = (isConnected) -> { 285 mWatchdogPerfHandler.onDaemonConnectionChange(isConnected); 286 synchronized (mLock) { 287 mIsConnected = isConnected; 288 } 289 registerToDaemon(); 290 }; 291 mCurrentGarageMode = GarageMode.GARAGE_MODE_OFF; 292 mIsDisplayEnabled = true; 293 } 294 295 @VisibleForTesting setCarWatchdogDaemonHelper(CarWatchdogDaemonHelper helper)296 public void setCarWatchdogDaemonHelper(CarWatchdogDaemonHelper helper) { 297 mCarWatchdogDaemonHelper = helper; 298 } 299 300 @Override init()301 public void init() { 302 Trace.beginSection("CarWatchdogService.init"); 303 // TODO(b/266008677): The daemon reads the sendResourceUsageStatsEnabled sysprop at the 304 // moment the CarWatchdogService connects to it. Therefore, the property must be set by 305 // CarWatchdogService before connecting with the CarWatchdog daemon. Set the property to 306 // true to enable the sending of resource usage stats from the daemon. 307 mWatchdogProcessHandler.init(); 308 mWatchdogPerfHandler.init(); 309 subscribePowerManagementService(); 310 subscribeUserStateChange(); 311 subscribeBroadcastReceiver(); 312 mCarWatchdogDaemonHelper.addOnConnectionChangeListener(mConnectionListener); 313 mCarWatchdogDaemonHelper.connect(); 314 synchronized (mLock) { 315 mIsPowerShutdownHandled = false; 316 } 317 // To make sure the main handler is ready for responding to car watchdog daemon, registering 318 // to the daemon is done through the main handler. Once the registration is completed, we 319 // can assume that the main handler is not too busy handling other stuffs. 320 postRegisterToDaemonMessage(); 321 if (DEBUG) { 322 Slogf.d(TAG, "CarWatchdogService is initialized"); 323 } 324 Trace.endSection(); 325 } 326 327 @Override release()328 public void release() { 329 Trace.beginSection("CarWatchdogService.release"); 330 mContext.unregisterReceiver(mBroadcastReceiver); 331 unsubscribePowerManagementService(); 332 mWatchdogPerfHandler.release(); 333 mWatchdogStorage.release(); 334 unregisterFromDaemon(); 335 mCarWatchdogDaemonHelper.disconnect(); 336 Trace.endSection(); 337 } 338 339 @Override 340 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dump(IndentingPrintWriter writer)341 public void dump(IndentingPrintWriter writer) { 342 writer.println("*" + getClass().getSimpleName() + "*"); 343 writer.increaseIndent(); 344 synchronized (mLock) { 345 writer.println("Current garage mode: " + toGarageModeString(mCurrentGarageMode)); 346 writer.println("Is power shutdown handled: " + mIsPowerShutdownHandled); 347 } 348 mWatchdogProcessHandler.dump(writer); 349 mWatchdogPerfHandler.dump(writer); 350 writer.decreaseIndent(); 351 } 352 353 @Override 354 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dumpProto(ProtoOutputStream proto)355 public void dumpProto(ProtoOutputStream proto) { 356 synchronized (mLock) { 357 proto.write(CarWatchdogDumpProto.CURRENT_GARAGE_MODE, mCurrentGarageMode); 358 } 359 mWatchdogProcessHandler.dumpProto(proto); 360 mWatchdogPerfHandler.dumpProto(proto); 361 } 362 363 /** 364 * Registers {@link android.car.watchdog.ICarWatchdogServiceCallback} to 365 * {@link CarWatchdogService}. 366 */ 367 @Override registerClient(ICarWatchdogServiceCallback client, int timeout)368 public void registerClient(ICarWatchdogServiceCallback client, int timeout) { 369 assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG); 370 mWatchdogProcessHandler.registerClient(client, timeout); 371 } 372 373 /** 374 * Unregisters {@link android.car.watchdog.ICarWatchdogServiceCallback} from 375 * {@link CarWatchdogService}. 376 */ 377 @Override unregisterClient(ICarWatchdogServiceCallback client)378 public void unregisterClient(ICarWatchdogServiceCallback client) { 379 assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG); 380 mWatchdogProcessHandler.unregisterClient(client); 381 } 382 383 /** 384 * Tells {@link CarWatchdogService} that the client is alive. 385 */ 386 @Override tellClientAlive(ICarWatchdogServiceCallback client, int sessionId)387 public void tellClientAlive(ICarWatchdogServiceCallback client, int sessionId) { 388 assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG); 389 mWatchdogProcessHandler.tellClientAlive(client, sessionId); 390 } 391 392 /** Returns {@link android.car.watchdog.ResourceOveruseStats} for the calling package. */ 393 @Override 394 @NonNull getResourceOveruseStats( @arWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, @CarWatchdogManager.StatsPeriod int maxStatsPeriod)395 public ResourceOveruseStats getResourceOveruseStats( 396 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, 397 @CarWatchdogManager.StatsPeriod int maxStatsPeriod) { 398 return mWatchdogPerfHandler.getResourceOveruseStats(resourceOveruseFlag, maxStatsPeriod); 399 } 400 401 /** 402 * Returns {@link android.car.watchdog.ResourceOveruseStats} for all packages for the maximum 403 * specified period, and the specified resource types with stats greater than or equal to the 404 * minimum specified stats. 405 */ 406 @Override 407 @NonNull getAllResourceOveruseStats( @arWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, @CarWatchdogManager.MinimumStatsFlag int minimumStatsFlag, @CarWatchdogManager.StatsPeriod int maxStatsPeriod)408 public List<ResourceOveruseStats> getAllResourceOveruseStats( 409 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, 410 @CarWatchdogManager.MinimumStatsFlag int minimumStatsFlag, 411 @CarWatchdogManager.StatsPeriod int maxStatsPeriod) { 412 assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS); 413 return mWatchdogPerfHandler.getAllResourceOveruseStats(resourceOveruseFlag, 414 minimumStatsFlag, maxStatsPeriod); 415 } 416 417 /** Returns {@link android.car.watchdog.ResourceOveruseStats} for the specified user package. */ 418 @Override 419 @NonNull getResourceOveruseStatsForUserPackage( @onNull String packageName, @NonNull UserHandle userHandle, @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, @CarWatchdogManager.StatsPeriod int maxStatsPeriod)420 public ResourceOveruseStats getResourceOveruseStatsForUserPackage( 421 @NonNull String packageName, @NonNull UserHandle userHandle, 422 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, 423 @CarWatchdogManager.StatsPeriod int maxStatsPeriod) { 424 assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS); 425 return mWatchdogPerfHandler.getResourceOveruseStatsForUserPackage(packageName, userHandle, 426 resourceOveruseFlag, maxStatsPeriod); 427 } 428 429 /** 430 * Adds {@link android.car.watchdog.IResourceOveruseListener} for the calling package's resource 431 * overuse notifications. 432 */ 433 @Override addResourceOveruseListener( @arWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, @NonNull IResourceOveruseListener listener)434 public void addResourceOveruseListener( 435 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, 436 @NonNull IResourceOveruseListener listener) { 437 mWatchdogPerfHandler.addResourceOveruseListener(resourceOveruseFlag, listener); 438 } 439 440 /** 441 * Removes the previously added {@link android.car.watchdog.IResourceOveruseListener} for the 442 * calling package's resource overuse notifications. 443 */ 444 @Override removeResourceOveruseListener(@onNull IResourceOveruseListener listener)445 public void removeResourceOveruseListener(@NonNull IResourceOveruseListener listener) { 446 mWatchdogPerfHandler.removeResourceOveruseListener(listener); 447 } 448 449 /** 450 * Adds {@link android.car.watchdog.IResourceOveruseListener} for all packages' resource overuse 451 * notifications. 452 */ 453 @Override addResourceOveruseListenerForSystem( @arWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, @NonNull IResourceOveruseListener listener)454 public void addResourceOveruseListenerForSystem( 455 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, 456 @NonNull IResourceOveruseListener listener) { 457 assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS); 458 mWatchdogPerfHandler.addResourceOveruseListenerForSystem(resourceOveruseFlag, listener); 459 } 460 461 /** 462 * Removes the previously added {@link android.car.watchdog.IResourceOveruseListener} for all 463 * packages' resource overuse notifications. 464 */ 465 @Override removeResourceOveruseListenerForSystem(@onNull IResourceOveruseListener listener)466 public void removeResourceOveruseListenerForSystem(@NonNull IResourceOveruseListener listener) { 467 assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS); 468 mWatchdogPerfHandler.removeResourceOveruseListenerForSystem(listener); 469 } 470 471 /** Sets whether or not a user package is killable on resource overuse. */ 472 @Override setKillablePackageAsUser(String packageName, UserHandle userHandle, boolean isKillable)473 public void setKillablePackageAsUser(String packageName, UserHandle userHandle, 474 boolean isKillable) { 475 assertPermission(mContext, Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG); 476 mWatchdogPerfHandler.setKillablePackageAsUser(packageName, userHandle, isKillable); 477 } 478 479 /** 480 * Returns all {@link android.car.watchdog.PackageKillableState} on resource overuse for 481 * the specified user. 482 */ 483 @Override 484 @NonNull getPackageKillableStatesAsUser(UserHandle userHandle)485 public List<PackageKillableState> getPackageKillableStatesAsUser(UserHandle userHandle) { 486 assertPermission(mContext, Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG); 487 return mWatchdogPerfHandler.getPackageKillableStatesAsUser(userHandle); 488 } 489 490 /** 491 * Sets {@link android.car.watchdog.ResourceOveruseConfiguration} for the specified resources. 492 */ 493 @Override 494 @CarWatchdogManager.ReturnCode setResourceOveruseConfigurations( List<ResourceOveruseConfiguration> configurations, @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag)495 public int setResourceOveruseConfigurations( 496 List<ResourceOveruseConfiguration> configurations, 497 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) 498 throws RemoteException { 499 assertPermission(mContext, Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG); 500 return mWatchdogPerfHandler.setResourceOveruseConfigurations(configurations, 501 resourceOveruseFlag); 502 } 503 504 /** Returns the available {@link android.car.watchdog.ResourceOveruseConfiguration}. */ 505 @Override 506 @NonNull getResourceOveruseConfigurations( @arWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag)507 public List<ResourceOveruseConfiguration> getResourceOveruseConfigurations( 508 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) { 509 assertAnyPermission(mContext, Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG, 510 Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS); 511 return mWatchdogPerfHandler.getResourceOveruseConfigurations(resourceOveruseFlag); 512 } 513 514 /** 515 * Enables/disables the watchdog daemon client health check process. 516 */ controlProcessHealthCheck(boolean enable)517 public void controlProcessHealthCheck(boolean enable) { 518 assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG); 519 mWatchdogProcessHandler.controlProcessHealthCheck(enable); 520 } 521 522 /** 523 * Injects power state signals. 524 * 525 * <p>Called by car shell command. 526 * 527 * @param powerState Power state to inject. 528 */ injectPowerState(int powerState)529 public void injectPowerState(int powerState) { 530 assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG); 531 onPowerState(powerState); 532 } 533 534 /** 535 * Handles power state signals. 536 */ onPowerState(int powerState)537 private void onPowerState(int powerState) { 538 int powerCycle = carPowerStateToPowerCycle(powerState); 539 if (powerCycle < 0) { 540 return; 541 } 542 Trace.beginSection("CarWatchdogService-powerStateChanged-" 543 + CarPowerManagementService.powerStateToString(powerState)); 544 switch (powerCycle) { 545 case PowerCycle.POWER_CYCLE_SHUTDOWN_PREPARE: 546 // Perform time consuming disk I/O operation during shutdown prepare to avoid 547 // incomplete I/O. 548 mWatchdogPerfHandler.writeMetadataFile(); 549 break; 550 case PowerCycle.POWER_CYCLE_SHUTDOWN_ENTER: 551 // Watchdog service and daemon performs garage mode monitoring so delay writing 552 // to database until after shutdown enter. 553 mWatchdogPerfHandler.writeToDatabase(); 554 break; 555 case PowerCycle.POWER_CYCLE_SUSPEND_EXIT: 556 break; 557 // ON covers resume. 558 case PowerCycle.POWER_CYCLE_RESUME: 559 // There might be outdated & incorrect info. We should reset them before 560 // starting to do health check. 561 mWatchdogProcessHandler.prepareHealthCheck(); 562 break; 563 default: 564 return; 565 } 566 notifyPowerCycleChange(powerCycle); 567 Trace.endSection(); 568 } 569 570 /** 571 * Kills a specific package for a user due to resource overuse. 572 573 * <p>Called only by the car shell "watchdog-resource-overuse-kill" 574 * command, which is only used by tests. 575 * 576 * @return whether package was killed 577 */ performResourceOveruseKill(String packageName, @UserIdInt int userId)578 public boolean performResourceOveruseKill(String packageName, @UserIdInt int userId) { 579 assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG); 580 581 UserHandle userHandle = UserHandle.of(userId); 582 List<PackageKillableState> packageKillableStates = 583 getPackageKillableStatesAsUser(userHandle); 584 585 for (int i = 0; i < packageKillableStates.size(); i++) { 586 PackageKillableState state = packageKillableStates.get(i); 587 if (packageName.equals(state.getPackageName())) { 588 int killableState = state.getKillableState(); 589 if (killableState != PackageKillableState.KILLABLE_STATE_YES) { 590 String stateName = PackageKillableState.killableStateToString(killableState); 591 Slogf.d(TAG, "Failed to kill package '%s' for user %d because the " 592 + "package has state '%s'\n", packageName, userId, stateName); 593 return false; 594 } 595 break; 596 } 597 } 598 599 return mWatchdogPerfHandler.disablePackageForUser(packageName, userId); 600 } 601 602 /** 603 * Sets the thread priority for a specific thread. 604 * 605 * The thread must belong to the calling process. 606 * 607 * @throws IllegalArgumentException If the policy/priority is not valid. 608 * @throws IllegalStateException If the provided tid does not belong to the calling process. 609 * @throws RemoteException If binder error happens. 610 * @throws ServiceSpecificException If car watchdog daemon failed to set the thread priority. 611 * @throws UnsupportedOperationException If the current android release doesn't support the API. 612 */ setThreadPriority(int pid, int tid, int uid, int policy, int priority)613 public void setThreadPriority(int pid, int tid, int uid, int policy, int priority) 614 throws RemoteException { 615 mCarWatchdogDaemonHelper.setThreadPriority(pid, tid, uid, policy, priority); 616 } 617 618 /** 619 * Gets the thread scheduling policy and priority for the specified thread. 620 * 621 * The thread must belong to the calling process. 622 * 623 * @throws IllegalStateException If the provided tid does not belong to the calling process or 624 * car watchdog daemon failed to get the priority. 625 * @throws RemoteException If binder error happens. 626 * @throws UnsupportedOperationException If the current android release doesn't support the API. 627 */ getThreadPriority(int pid, int tid, int uid)628 public int[] getThreadPriority(int pid, int tid, int uid) throws RemoteException { 629 try { 630 return mCarWatchdogDaemonHelper.getThreadPriority(pid, tid, uid); 631 } catch (ServiceSpecificException e) { 632 // Car watchdog daemon failed to get the priority. 633 throw new IllegalStateException(e); 634 } 635 } 636 637 @VisibleForTesting getClientCount(int timeout)638 int getClientCount(int timeout) { 639 return mWatchdogProcessHandler.getClientCount(timeout); 640 } 641 642 @VisibleForTesting setOveruseHandlingDelay(long millis)643 void setOveruseHandlingDelay(long millis) { 644 mWatchdogPerfHandler.setOveruseHandlingDelay(millis); 645 } 646 getWatchdogDirFile()647 static File getWatchdogDirFile() { 648 SystemInterface systemInterface = CarLocalServices.getService(SystemInterface.class); 649 String systemCarDirPath = systemInterface == null ? FALLBACK_DATA_SYSTEM_CAR_DIR_PATH 650 : systemInterface.getSystemCarDir().getAbsolutePath(); 651 return new File(systemCarDirPath, WATCHDOG_DIR_NAME); 652 } 653 notifyAllUserStates()654 private void notifyAllUserStates() { 655 Trace.beginSection("CarWatchdogService.notifyAllUserStates"); 656 UserManager userManager = mContext.getSystemService(UserManager.class); 657 List<UserHandle> users = userManager.getUserHandles(/* excludeDying= */ false); 658 try { 659 // TODO(b/152780162): reduce the number of RPC calls(isUserRunning). 660 for (int i = 0; i < users.size(); ++i) { 661 UserHandle user = users.get(i); 662 int userState = userManager.isUserRunning(user) 663 ? UserState.USER_STATE_STARTED 664 : UserState.USER_STATE_STOPPED; 665 mCarWatchdogDaemonHelper.notifySystemStateChange(StateType.USER_STATE, 666 user.getIdentifier(), userState); 667 mWatchdogProcessHandler.updateUserState(user.getIdentifier(), 668 userState == UserState.USER_STATE_STOPPED); 669 } 670 if (DEBUG) { 671 Slogf.d(TAG, "Notified car watchdog daemon of user states"); 672 } 673 } catch (RemoteException | RuntimeException e) { 674 // When car watchdog daemon is not connected, the {@link mCarWatchdogDaemonHelper} 675 // throws IllegalStateException. Catch the exception to avoid crashing the process. 676 Slogf.w(TAG, e, "Notifying latest user states failed"); 677 } 678 Trace.endSection(); 679 } 680 notifyPowerCycleChange(@owerCycle int powerCycle)681 private void notifyPowerCycleChange(@PowerCycle int powerCycle) { 682 try { 683 // There are two signals sent during power off, ACTION_SHUTDOWN (from the broadcast 684 // receiver) and SHUTDOWN_ENTER (from the ICarPowerStateListener). This checks 685 // if one signal has already been sent and avoids doing shutdown twice. 686 synchronized (mLock) { 687 if (powerCycle == PowerCycle.POWER_CYCLE_SHUTDOWN_ENTER) { 688 if (mIsPowerShutdownHandled) { 689 return; 690 } 691 mIsPowerShutdownHandled = true; 692 } 693 } 694 mCarWatchdogDaemonHelper.notifySystemStateChange( 695 StateType.POWER_CYCLE, powerCycle, MISSING_ARG_VALUE); 696 if (DEBUG) { 697 Slogf.d(TAG, "Notified car watchdog daemon of power cycle(%d)", powerCycle); 698 } 699 } catch (RemoteException | RuntimeException e) { 700 // When car watchdog daemon is not connected, the {@link mCarWatchdogDaemonHelper} 701 // throws IllegalStateException. Catch the exception to avoid crashing the process. 702 Slogf.w(TAG, e, "Notifying power cycle change to %d failed", powerCycle); 703 } 704 } 705 notifyGarageModeChange(@arageMode int garageMode)706 private void notifyGarageModeChange(@GarageMode int garageMode) { 707 try { 708 mCarWatchdogDaemonHelper.notifySystemStateChange( 709 StateType.GARAGE_MODE, garageMode, MISSING_ARG_VALUE); 710 if (DEBUG) { 711 Slogf.d(TAG, "Notified car watchdog daemon of garage mode(%d)", garageMode); 712 } 713 } catch (RemoteException | RuntimeException e) { 714 // When car watchdog daemon is not connected, the {@link mCarWatchdogDaemonHelper} 715 // throws IllegalStateException. Catch the exception to avoid crashing the process. 716 Slogf.w(TAG, e, "Notifying garage mode change to %d failed", garageMode); 717 } 718 } 719 postRegisterToDaemonMessage()720 private void postRegisterToDaemonMessage() { 721 runOnMain(() -> { 722 synchronized (mLock) { 723 mReadyToRespond = true; 724 } 725 registerToDaemon(); 726 }); 727 } 728 registerToDaemon()729 private void registerToDaemon() { 730 synchronized (mLock) { 731 if (!mIsConnected || !mReadyToRespond) { 732 return; 733 } 734 } 735 Trace.beginSection("CarWatchdogService.registerToDaemon"); 736 try { 737 mCarWatchdogDaemonHelper.registerCarWatchdogService(mWatchdogServiceForSystem); 738 if (DEBUG) { 739 Slogf.d(TAG, "CarWatchdogService registers to car watchdog daemon"); 740 } 741 } catch (RemoteException | RuntimeException e) { 742 // When car watchdog daemon is not connected, the {@link mCarWatchdogDaemonHelper} 743 // throws IllegalStateException. Catch the exception to avoid crashing the process. 744 Slogf.w(TAG, e, "Cannot register to car watchdog daemon"); 745 } 746 notifyAllUserStates(); 747 CarPowerManagementService powerService = 748 CarLocalServices.getService(CarPowerManagementService.class); 749 if (powerService != null) { 750 int powerState = powerService.getPowerState(); 751 int powerCycle = carPowerStateToPowerCycle(powerState); 752 if (powerCycle >= 0) { 753 notifyPowerCycleChange(powerCycle); 754 } else { 755 Slogf.i(TAG, "Skipping notifying %d power state", powerState); 756 } 757 } 758 int garageMode; 759 synchronized (mLock) { 760 // To avoid race condition, fetch {@link mCurrentGarageMode} just before 761 // the {@link notifyGarageModeChange} call. For instance, if {@code mCurrentGarageMode} 762 // changes before the above {@link notifyPowerCycleChange} call returns, 763 // the {@link garageMode}'s value will be out of date. 764 garageMode = mCurrentGarageMode; 765 } 766 notifyGarageModeChange(garageMode); 767 Trace.endSection(); 768 } 769 unregisterFromDaemon()770 private void unregisterFromDaemon() { 771 Trace.beginSection("CarWatchdogService.unregisterFromDaemon"); 772 try { 773 mCarWatchdogDaemonHelper.unregisterCarWatchdogService(mWatchdogServiceForSystem); 774 if (DEBUG) { 775 Slogf.d(TAG, "CarWatchdogService unregisters from car watchdog daemon"); 776 } 777 } catch (RemoteException | RuntimeException e) { 778 // When car watchdog daemon is not connected, the {@link mCarWatchdogDaemonHelper} 779 // throws IllegalStateException. Catch the exception to avoid crashing the process. 780 Slogf.w(TAG, e, "Cannot unregister from car watchdog daemon"); 781 } 782 Trace.endSection(); 783 } 784 subscribePowerManagementService()785 private void subscribePowerManagementService() { 786 CarPowerManagementService powerService = 787 CarLocalServices.getService(CarPowerManagementService.class); 788 if (powerService == null) { 789 Slogf.w(TAG, "Cannot get CarPowerManagementService"); 790 return; 791 } 792 powerService.registerListener(mCarPowerStateListener); 793 powerService.addPowerPolicyListener( 794 new CarPowerPolicyFilter.Builder().setComponents(PowerComponent.DISPLAY).build(), 795 mCarDisplayPowerPolicyListener); 796 } 797 unsubscribePowerManagementService()798 private void unsubscribePowerManagementService() { 799 CarPowerManagementService powerService = 800 CarLocalServices.getService(CarPowerManagementService.class); 801 if (powerService == null) { 802 Slogf.w(TAG, "Cannot get CarPowerManagementService"); 803 return; 804 } 805 powerService.unregisterListener(mCarPowerStateListener); 806 powerService.removePowerPolicyListener(mCarDisplayPowerPolicyListener); 807 } 808 subscribeUserStateChange()809 private void subscribeUserStateChange() { 810 CarUserService userService = CarLocalServices.getService(CarUserService.class); 811 if (userService == null) { 812 Slogf.w(TAG, "Cannot get CarUserService"); 813 return; 814 } 815 UserLifecycleEventFilter userEventFilter = 816 new UserLifecycleEventFilter.Builder() 817 .addEventType(USER_LIFECYCLE_EVENT_TYPE_STARTING) 818 .addEventType(USER_LIFECYCLE_EVENT_TYPE_SWITCHING) 819 .addEventType(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING) 820 .addEventType(USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED) 821 .addEventType(USER_LIFECYCLE_EVENT_TYPE_STOPPED).build(); 822 userService.addUserLifecycleListener(userEventFilter, (event) -> { 823 if (!isEventAnyOfTypes(TAG, event, USER_LIFECYCLE_EVENT_TYPE_STARTING, 824 USER_LIFECYCLE_EVENT_TYPE_SWITCHING, USER_LIFECYCLE_EVENT_TYPE_UNLOCKING, 825 USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED, USER_LIFECYCLE_EVENT_TYPE_STOPPED)) { 826 return; 827 } 828 829 int userId = event.getUserHandle().getIdentifier(); 830 int userState; 831 String userStateDesc; 832 switch (event.getEventType()) { 833 case USER_LIFECYCLE_EVENT_TYPE_STARTING: 834 mWatchdogProcessHandler.updateUserState(userId, /*isStopped=*/ false); 835 userState = UserState.USER_STATE_STARTED; 836 userStateDesc = "STARTING"; 837 break; 838 case USER_LIFECYCLE_EVENT_TYPE_SWITCHING: 839 userState = UserState.USER_STATE_SWITCHING; 840 userStateDesc = "SWITCHING"; 841 break; 842 case USER_LIFECYCLE_EVENT_TYPE_UNLOCKING: 843 userState = UserState.USER_STATE_UNLOCKING; 844 userStateDesc = "UNLOCKING"; 845 break; 846 case USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED: 847 userState = UserState.USER_STATE_POST_UNLOCKED; 848 userStateDesc = "POST_UNLOCKED"; 849 break; 850 case USER_LIFECYCLE_EVENT_TYPE_STOPPED: 851 mWatchdogProcessHandler.updateUserState(userId, /*isStopped=*/ true); 852 userState = UserState.USER_STATE_STOPPED; 853 userStateDesc = "STOPPING"; 854 break; 855 default: 856 return; 857 } 858 try { 859 mCarWatchdogDaemonHelper.notifySystemStateChange(StateType.USER_STATE, userId, 860 userState); 861 if (DEBUG) { 862 Slogf.d(TAG, "Notified car watchdog daemon user %d's user state, %s", 863 userId, userStateDesc); 864 } 865 } catch (RemoteException | RuntimeException e) { 866 // When car watchdog daemon is not connected, the {@link mCarWatchdogDaemonHelper} 867 // throws IllegalStateException. Catch the exception to avoid crashing the process. 868 Slogf.w(TAG, e, "Notifying user state change failed"); 869 } 870 }); 871 } 872 subscribeBroadcastReceiver()873 private void subscribeBroadcastReceiver() { 874 IntentFilter filter = new IntentFilter(); 875 filter.addAction(CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION); 876 filter.addAction(ACTION_GARAGE_MODE_ON); 877 filter.addAction(ACTION_GARAGE_MODE_OFF); 878 filter.addAction(CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS); 879 filter.addAction(CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP); 880 filter.addAction(ACTION_USER_REMOVED); 881 filter.addAction(ACTION_REBOOT); 882 filter.addAction(ACTION_SHUTDOWN); 883 884 mContext.registerReceiverForAllUsers(mBroadcastReceiver, filter, 885 Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG, /* scheduler= */ null, 886 Context.RECEIVER_NOT_EXPORTED); 887 888 // The package data scheme applies only for the ACTION_PACKAGE_CHANGED action. So, add a 889 // filter for this action separately. Otherwise, the broadcast receiver won't receive 890 // notifications for other actions. 891 IntentFilter packageChangedFilter = new IntentFilter(); 892 packageChangedFilter.addAction(ACTION_PACKAGE_CHANGED); 893 packageChangedFilter.addDataScheme("package"); 894 895 mContext.registerReceiverForAllUsers(mBroadcastReceiver, packageChangedFilter, 896 /* broadcastPermission= */ null, /* scheduler= */ null, 897 Context.RECEIVER_NOT_EXPORTED); 898 } 899 carPowerStateToPowerCycle(int powerState)900 private static int carPowerStateToPowerCycle(int powerState) { 901 switch (powerState) { 902 // SHUTDOWN_PREPARE covers suspend and shutdown. 903 case CarPowerManager.STATE_SHUTDOWN_PREPARE: 904 return PowerCycle.POWER_CYCLE_SHUTDOWN_PREPARE; 905 case CarPowerManager.STATE_SHUTDOWN_ENTER: 906 case CarPowerManager.STATE_SUSPEND_ENTER: 907 case CarPowerManager.STATE_HIBERNATION_ENTER: 908 return PowerCycle.POWER_CYCLE_SHUTDOWN_ENTER; 909 case CarPowerManager.STATE_SUSPEND_EXIT: 910 case CarPowerManager.STATE_HIBERNATION_EXIT: 911 return PowerCycle.POWER_CYCLE_SUSPEND_EXIT; 912 // ON covers resume. 913 case CarPowerManager.STATE_ON: 914 return PowerCycle.POWER_CYCLE_RESUME; 915 default: 916 Slogf.e(TAG, "Invalid power state: %d", powerState); 917 } 918 return -1; 919 } 920 toGarageModeString(@arageMode int garageMode)921 private static String toGarageModeString(@GarageMode int garageMode) { 922 switch (garageMode) { 923 case GarageMode.GARAGE_MODE_OFF: 924 return "GARAGE_MODE_OFF"; 925 case GarageMode.GARAGE_MODE_ON: 926 return "GARAGE_MODE_ON"; 927 default: 928 Slogf.e(TAG, "Invalid garage mode: %d", garageMode); 929 } 930 return "INVALID"; 931 } 932 933 private static final class ICarWatchdogServiceForSystemImpl 934 extends ICarWatchdogServiceForSystem.Stub { 935 private final WeakReference<CarWatchdogService> mService; 936 ICarWatchdogServiceForSystemImpl(CarWatchdogService service)937 ICarWatchdogServiceForSystemImpl(CarWatchdogService service) { 938 mService = new WeakReference<>(service); 939 } 940 941 @Override checkIfAlive(int sessionId, int timeout)942 public void checkIfAlive(int sessionId, int timeout) { 943 CarWatchdogService service = mService.get(); 944 if (service == null) { 945 Slogf.w(TAG, "CarWatchdogService is not available"); 946 return; 947 } 948 service.mWatchdogProcessHandler.postHealthCheckMessage(sessionId); 949 } 950 951 @Override prepareProcessTermination()952 public void prepareProcessTermination() { 953 Slogf.w(TAG, "CarWatchdogService is about to be killed by car watchdog daemon"); 954 } 955 956 @Override getPackageInfosForUids( int[] uids, List<String> vendorPackagePrefixes)957 public List<PackageInfo> getPackageInfosForUids( 958 int[] uids, List<String> vendorPackagePrefixes) { 959 if (ArrayUtils.isEmpty(uids)) { 960 Slogf.w(TAG, "UID list is empty"); 961 return Collections.emptyList(); 962 } 963 CarWatchdogService service = mService.get(); 964 if (service == null) { 965 Slogf.w(TAG, "CarWatchdogService is not available"); 966 return Collections.emptyList(); 967 } 968 return service.mPackageInfoHandler.getPackageInfosForUids(uids, vendorPackagePrefixes); 969 } 970 971 // TODO(b/269191275): This method was replaced by onLatestResourceStats in Android U. 972 // Make method no-op in Android W (N+2 releases). 973 @Override latestIoOveruseStats(List<PackageIoOveruseStats> packageIoOveruseStats)974 public void latestIoOveruseStats(List<PackageIoOveruseStats> packageIoOveruseStats) { 975 if (packageIoOveruseStats.isEmpty()) { 976 Slogf.w(TAG, "Latest I/O overuse stats is empty"); 977 return; 978 } 979 CarWatchdogService service = mService.get(); 980 if (service == null) { 981 Slogf.w(TAG, "CarWatchdogService is not available"); 982 return; 983 } 984 service.mWatchdogPerfHandler.latestIoOveruseStats(packageIoOveruseStats); 985 } 986 987 @Override onLatestResourceStats(List<ResourceStats> resourceStats)988 public void onLatestResourceStats(List<ResourceStats> resourceStats) { 989 // TODO(b/266008146): Handle the resourceUsageStats. 990 if (resourceStats.isEmpty()) { 991 Slogf.w(TAG, "Latest resource stats is empty"); 992 return; 993 } 994 CarWatchdogService service = mService.get(); 995 if (service == null) { 996 Slogf.w(TAG, "CarWatchdogService is not available"); 997 return; 998 } 999 for (int i = 0; i < resourceStats.size(); i++) { 1000 ResourceStats stats = resourceStats.get(i); 1001 if (stats.resourceOveruseStats == null 1002 || stats.resourceOveruseStats.packageIoOveruseStats.isEmpty()) { 1003 Slogf.w(TAG, "Received latest I/O overuse stats is empty"); 1004 continue; 1005 } 1006 service.mWatchdogPerfHandler.latestIoOveruseStats( 1007 stats.resourceOveruseStats.packageIoOveruseStats); 1008 } 1009 } 1010 1011 @Override resetResourceOveruseStats(List<String> packageNames)1012 public void resetResourceOveruseStats(List<String> packageNames) { 1013 if (packageNames.isEmpty()) { 1014 Slogf.w(TAG, "Provided an empty package name to reset resource overuse stats"); 1015 return; 1016 } 1017 CarWatchdogService service = mService.get(); 1018 if (service == null) { 1019 Slogf.w(TAG, "CarWatchdogService is not available"); 1020 return; 1021 } 1022 service.mWatchdogPerfHandler.resetResourceOveruseStats(new ArraySet<>(packageNames)); 1023 } 1024 1025 // TODO(b/273354756): This method was replaced by an async request/response pattern 1026 // Android U. Requests for the I/O stats are received through the requestTodayIoUsageStats 1027 // method. And responses are sent through the carwatchdog daemon via 1028 // ICarWatchdog#onTodayIoUsageStats. Make method no-op in Android W (N+2 releases). 1029 @Override getTodayIoUsageStats()1030 public List<UserPackageIoUsageStats> getTodayIoUsageStats() { 1031 CarWatchdogService service = mService.get(); 1032 if (service == null) { 1033 Slogf.w(TAG, "CarWatchdogService is not available"); 1034 return Collections.emptyList(); 1035 } 1036 return service.mWatchdogPerfHandler.getTodayIoUsageStats(); 1037 } 1038 1039 @Override requestAidlVhalPid()1040 public void requestAidlVhalPid() { 1041 CarWatchdogService service = mService.get(); 1042 if (service == null) { 1043 Slogf.w(TAG, "CarWatchdogService is not available"); 1044 return; 1045 } 1046 service.mWatchdogProcessHandler.asyncFetchAidlVhalPid(); 1047 } 1048 1049 @Override requestTodayIoUsageStats()1050 public void requestTodayIoUsageStats() { 1051 CarWatchdogService service = mService.get(); 1052 if (service == null) { 1053 Slogf.w(TAG, "CarWatchdogService is not available"); 1054 return; 1055 } 1056 service.mWatchdogPerfHandler.asyncFetchTodayIoUsageStats(); 1057 } 1058 } 1059 } 1060