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.PlatformVersion.VERSION_CODES; 20 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED; 21 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING; 22 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPED; 23 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING; 24 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING; 25 import static android.content.Intent.ACTION_PACKAGE_CHANGED; 26 import static android.content.Intent.ACTION_REBOOT; 27 import static android.content.Intent.ACTION_SHUTDOWN; 28 import static android.content.Intent.ACTION_USER_REMOVED; 29 30 import static com.android.car.CarLog.TAG_WATCHDOG; 31 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO; 32 import static com.android.car.util.Utils.isEventAnyOfTypes; 33 34 import android.annotation.NonNull; 35 import android.annotation.UserIdInt; 36 import android.automotive.watchdog.internal.GarageMode; 37 import android.automotive.watchdog.internal.ICarWatchdogServiceForSystem; 38 import android.automotive.watchdog.internal.PackageInfo; 39 import android.automotive.watchdog.internal.PackageIoOveruseStats; 40 import android.automotive.watchdog.internal.PowerCycle; 41 import android.automotive.watchdog.internal.StateType; 42 import android.automotive.watchdog.internal.UserPackageIoUsageStats; 43 import android.automotive.watchdog.internal.UserState; 44 import android.car.Car; 45 import android.car.builtin.util.Slogf; 46 import android.car.hardware.power.CarPowerManager; 47 import android.car.hardware.power.CarPowerPolicy; 48 import android.car.hardware.power.CarPowerPolicyFilter; 49 import android.car.hardware.power.ICarPowerPolicyListener; 50 import android.car.hardware.power.ICarPowerStateListener; 51 import android.car.hardware.power.PowerComponent; 52 import android.car.user.UserLifecycleEventFilter; 53 import android.car.watchdog.CarWatchdogManager; 54 import android.car.watchdog.ICarWatchdogService; 55 import android.car.watchdog.ICarWatchdogServiceCallback; 56 import android.car.watchdog.IResourceOveruseListener; 57 import android.car.watchdog.PackageKillableState; 58 import android.car.watchdog.ResourceOveruseConfiguration; 59 import android.car.watchdog.ResourceOveruseStats; 60 import android.car.watchdoglib.CarWatchdogDaemonHelper; 61 import android.content.BroadcastReceiver; 62 import android.content.Context; 63 import android.content.Intent; 64 import android.content.IntentFilter; 65 import android.os.RemoteException; 66 import android.os.ServiceSpecificException; 67 import android.os.UserHandle; 68 import android.os.UserManager; 69 import android.util.ArraySet; 70 import android.util.Log; 71 72 import com.android.car.CarLocalServices; 73 import com.android.car.CarLog; 74 import com.android.car.CarServiceBase; 75 import com.android.car.CarServiceUtils; 76 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 77 import com.android.car.internal.util.ArrayUtils; 78 import com.android.car.internal.util.IndentingPrintWriter; 79 import com.android.car.power.CarPowerManagementService; 80 import com.android.car.systeminterface.SystemInterface; 81 import com.android.car.user.CarUserService; 82 import com.android.internal.annotations.GuardedBy; 83 import com.android.internal.annotations.VisibleForTesting; 84 85 import java.io.File; 86 import java.lang.ref.WeakReference; 87 import java.time.Instant; 88 import java.util.List; 89 90 /** 91 * Service to implement CarWatchdogManager API. 92 */ 93 public final class CarWatchdogService extends ICarWatchdogService.Stub implements CarServiceBase { 94 static final String TAG = CarLog.tagFor(CarWatchdogService.class); 95 static final boolean DEBUG = Slogf.isLoggable(TAG, Log.DEBUG); 96 static final String ACTION_GARAGE_MODE_ON = 97 "com.android.server.jobscheduler.GARAGE_MODE_ON"; 98 static final String ACTION_GARAGE_MODE_OFF = 99 "com.android.server.jobscheduler.GARAGE_MODE_OFF"; 100 static final String ACTION_LAUNCH_APP_SETTINGS = 101 "com.android.car.watchdog.ACTION_LAUNCH_APP_SETTINGS"; 102 static final String ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION = 103 "com.android.car.watchdog.ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION"; 104 // TODO(b/244474850): Delete the intent in W release. After TM-QPR2, it is not used anymore by 105 // the notification helper. 106 /** 107 * @deprecated - Prefer dismissing resource over notifications using the 108 * {@code ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION} intent action. 109 */ 110 @Deprecated 111 static final String ACTION_RESOURCE_OVERUSE_DISABLE_APP = 112 "com.android.car.watchdog.ACTION_RESOURCE_OVERUSE_DISABLE_APP"; 113 114 @VisibleForTesting 115 static final int MISSING_ARG_VALUE = -1; 116 117 private static final String FALLBACK_DATA_SYSTEM_CAR_DIR_PATH = "/data/system/car"; 118 private static final String WATCHDOG_DIR_NAME = "watchdog"; 119 120 private static final TimeSource SYSTEM_INSTANCE = new TimeSource() { 121 @Override 122 public Instant now() { 123 return Instant.now(); 124 } 125 126 @Override 127 public String toString() { 128 return "System time instance"; 129 } 130 }; 131 132 private final Context mContext; 133 private final ICarWatchdogServiceForSystemImpl mWatchdogServiceForSystem; 134 private final PackageInfoHandler mPackageInfoHandler; 135 private final WatchdogStorage mWatchdogStorage; 136 private final WatchdogProcessHandler mWatchdogProcessHandler; 137 private final WatchdogPerfHandler mWatchdogPerfHandler; 138 private final CarWatchdogDaemonHelper.OnConnectionChangeListener mConnectionListener; 139 140 private CarWatchdogDaemonHelper mCarWatchdogDaemonHelper; 141 142 /* 143 * TODO(b/192481350): Listen for GarageMode change notification rather than depending on the 144 * system_server broadcast when the CarService internal API for listening GarageMode change is 145 * implemented. 146 */ 147 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 148 @Override 149 public void onReceive(Context context, Intent intent) { 150 String action = intent.getAction(); 151 switch (action) { 152 case ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION: 153 case ACTION_LAUNCH_APP_SETTINGS: 154 case ACTION_RESOURCE_OVERUSE_DISABLE_APP: 155 mWatchdogPerfHandler.processUserNotificationIntent(intent); 156 break; 157 case ACTION_GARAGE_MODE_ON: 158 case ACTION_GARAGE_MODE_OFF: 159 int garageMode; 160 synchronized (mLock) { 161 garageMode = mCurrentGarageMode = action.equals(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 int powerCycle = PowerCycle.POWER_CYCLE_SHUTDOWN_ENTER; 178 try { 179 mCarWatchdogDaemonHelper.notifySystemStateChange(StateType.POWER_CYCLE, 180 powerCycle, /* arg2= */ 0); 181 if (DEBUG) { 182 Slogf.d(TAG, "Notified car watchdog daemon of power cycle(%d)", 183 powerCycle); 184 } 185 } catch (Exception e) { 186 Slogf.w(TAG, e, "Notifying power cycle state change failed"); 187 } 188 break; 189 case ACTION_USER_REMOVED: { 190 UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER); 191 int userId = userHandle.getIdentifier(); 192 try { 193 mCarWatchdogDaemonHelper.notifySystemStateChange(StateType.USER_STATE, 194 userId, UserState.USER_STATE_REMOVED); 195 if (DEBUG) { 196 Slogf.d(TAG, "Notified car watchdog daemon of removed user %d", 197 userId); 198 } 199 } catch (RemoteException e) { 200 Slogf.w(TAG, e, "Failed to notify car watchdog daemon of removed user %d", 201 userId); 202 } 203 mWatchdogPerfHandler.deleteUser(userId); 204 break; 205 } 206 case ACTION_PACKAGE_CHANGED: { 207 mWatchdogPerfHandler.processPackageChangedIntent(intent); 208 break; 209 } 210 } 211 } 212 }; 213 214 private final ICarPowerStateListener mCarPowerStateListener = 215 new ICarPowerStateListener.Stub() { 216 @Override 217 public void onStateChanged(int state, long expirationTimeMs) { 218 CarPowerManagementService powerService = 219 CarLocalServices.getService(CarPowerManagementService.class); 220 if (powerService == null) { 221 return; 222 } 223 int powerCycle = carPowerStateToPowerCycle(powerService.getPowerState()); 224 switch (powerCycle) { 225 case PowerCycle.POWER_CYCLE_SHUTDOWN_PREPARE: 226 // Perform time consuming disk I/O operation during shutdown prepare to avoid 227 // incomplete I/O. 228 mWatchdogPerfHandler.writeMetadataFile(); 229 break; 230 case PowerCycle.POWER_CYCLE_SHUTDOWN_ENTER: 231 // Watchdog service and daemon performs garage mode monitoring so delay writing 232 // to database until after shutdown enter. 233 mWatchdogPerfHandler.writeToDatabase(); 234 break; 235 case PowerCycle.POWER_CYCLE_SUSPEND_EXIT: 236 break; 237 // ON covers resume. 238 case PowerCycle.POWER_CYCLE_RESUME: 239 // There might be outdated & incorrect info. We should reset them before 240 // starting to do health check. 241 mWatchdogProcessHandler.prepareHealthCheck(); 242 break; 243 default: 244 return; 245 } 246 notifyPowerCycleChange(powerCycle); 247 } 248 }; 249 250 private final ICarPowerPolicyListener mCarDisplayPowerPolicyListener = 251 new ICarPowerPolicyListener.Stub() { 252 @Override 253 public void onPolicyChanged(CarPowerPolicy appliedPolicy, 254 CarPowerPolicy accumulatedPolicy) { 255 boolean isDisplayEnabled = 256 appliedPolicy.isComponentEnabled(PowerComponent.DISPLAY); 257 boolean didStateChange = false; 258 synchronized (mLock) { 259 didStateChange = mIsDisplayEnabled != isDisplayEnabled; 260 mIsDisplayEnabled = isDisplayEnabled; 261 } 262 if (didStateChange) { 263 mWatchdogPerfHandler.onDisplayStateChanged(isDisplayEnabled); 264 } 265 } 266 }; 267 268 private final Object mLock = new Object(); 269 @GuardedBy("mLock") 270 private boolean mReadyToRespond; 271 @GuardedBy("mLock") 272 private boolean mIsConnected; 273 @GuardedBy("mLock") 274 private @GarageMode int mCurrentGarageMode; 275 @GuardedBy("mLock") 276 private boolean mIsDisplayEnabled; 277 CarWatchdogService(Context context, Context carServiceBuiltinPackageContext)278 public CarWatchdogService(Context context, Context carServiceBuiltinPackageContext) { 279 this(context, carServiceBuiltinPackageContext, 280 new WatchdogStorage(context, SYSTEM_INSTANCE), SYSTEM_INSTANCE); 281 } 282 283 @VisibleForTesting CarWatchdogService(Context context, Context carServiceBuiltinPackageContext, WatchdogStorage watchdogStorage, TimeSource timeSource)284 public CarWatchdogService(Context context, Context carServiceBuiltinPackageContext, 285 WatchdogStorage watchdogStorage, TimeSource timeSource) { 286 mContext = context; 287 mWatchdogStorage = watchdogStorage; 288 mPackageInfoHandler = new PackageInfoHandler(mContext.getPackageManager()); 289 mCarWatchdogDaemonHelper = new CarWatchdogDaemonHelper(TAG_WATCHDOG); 290 mWatchdogServiceForSystem = new ICarWatchdogServiceForSystemImpl(this); 291 mWatchdogProcessHandler = new WatchdogProcessHandler(mWatchdogServiceForSystem, 292 mCarWatchdogDaemonHelper); 293 mWatchdogPerfHandler = new WatchdogPerfHandler(mContext, carServiceBuiltinPackageContext, 294 mCarWatchdogDaemonHelper, mPackageInfoHandler, mWatchdogStorage, timeSource); 295 mConnectionListener = (isConnected) -> { 296 mWatchdogPerfHandler.onDaemonConnectionChange(isConnected); 297 synchronized (mLock) { 298 mIsConnected = isConnected; 299 } 300 registerToDaemon(); 301 }; 302 mCurrentGarageMode = GarageMode.GARAGE_MODE_OFF; 303 mIsDisplayEnabled = true; 304 } 305 306 @VisibleForTesting setCarWatchdogDaemonHelper(CarWatchdogDaemonHelper helper)307 public void setCarWatchdogDaemonHelper(CarWatchdogDaemonHelper helper) { 308 mCarWatchdogDaemonHelper = helper; 309 } 310 311 @Override init()312 public void init() { 313 mWatchdogProcessHandler.init(); 314 mWatchdogPerfHandler.init(); 315 subscribePowerManagementService(); 316 subscribeUserStateChange(); 317 subscribeBroadcastReceiver(); 318 mCarWatchdogDaemonHelper.addOnConnectionChangeListener(mConnectionListener); 319 mCarWatchdogDaemonHelper.connect(); 320 // To make sure the main handler is ready for responding to car watchdog daemon, registering 321 // to the daemon is done through the main handler. Once the registration is completed, we 322 // can assume that the main handler is not too busy handling other stuffs. 323 postRegisterToDaemonMessage(); 324 if (DEBUG) { 325 Slogf.d(TAG, "CarWatchdogService is initialized"); 326 } 327 } 328 329 @Override release()330 public void release() { 331 mContext.unregisterReceiver(mBroadcastReceiver); 332 unsubscribePowerManagementService(); 333 mWatchdogPerfHandler.release(); 334 mWatchdogStorage.release(); 335 unregisterFromDaemon(); 336 mCarWatchdogDaemonHelper.disconnect(); 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 } 347 mWatchdogProcessHandler.dump(writer); 348 mWatchdogPerfHandler.dump(writer); 349 writer.decreaseIndent(); 350 } 351 352 /** 353 * Registers {@link android.car.watchdog.ICarWatchdogServiceCallback} to 354 * {@link CarWatchdogService}. 355 */ 356 @Override registerClient(ICarWatchdogServiceCallback client, int timeout)357 public void registerClient(ICarWatchdogServiceCallback client, int timeout) { 358 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG); 359 mWatchdogProcessHandler.registerClient(client, timeout); 360 } 361 362 /** 363 * Unregisters {@link android.car.watchdog.ICarWatchdogServiceCallback} from 364 * {@link CarWatchdogService}. 365 */ 366 @Override unregisterClient(ICarWatchdogServiceCallback client)367 public void unregisterClient(ICarWatchdogServiceCallback client) { 368 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG); 369 mWatchdogProcessHandler.unregisterClient(client); 370 } 371 372 /** 373 * Tells {@link CarWatchdogService} that the client is alive. 374 */ 375 @Override tellClientAlive(ICarWatchdogServiceCallback client, int sessionId)376 public void tellClientAlive(ICarWatchdogServiceCallback client, int sessionId) { 377 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG); 378 mWatchdogProcessHandler.tellClientAlive(client, sessionId); 379 } 380 381 /** Returns {@link android.car.watchdog.ResourceOveruseStats} for the calling package. */ 382 @Override 383 @NonNull getResourceOveruseStats( @arWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, @CarWatchdogManager.StatsPeriod int maxStatsPeriod)384 public ResourceOveruseStats getResourceOveruseStats( 385 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, 386 @CarWatchdogManager.StatsPeriod int maxStatsPeriod) { 387 return mWatchdogPerfHandler.getResourceOveruseStats(resourceOveruseFlag, maxStatsPeriod); 388 } 389 390 /** 391 * Returns {@link android.car.watchdog.ResourceOveruseStats} for all packages for the maximum 392 * specified period, and the specified resource types with stats greater than or equal to the 393 * minimum specified stats. 394 */ 395 @Override 396 @NonNull getAllResourceOveruseStats( @arWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, @CarWatchdogManager.MinimumStatsFlag int minimumStatsFlag, @CarWatchdogManager.StatsPeriod int maxStatsPeriod)397 public List<ResourceOveruseStats> getAllResourceOveruseStats( 398 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, 399 @CarWatchdogManager.MinimumStatsFlag int minimumStatsFlag, 400 @CarWatchdogManager.StatsPeriod int maxStatsPeriod) { 401 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS); 402 return mWatchdogPerfHandler.getAllResourceOveruseStats(resourceOveruseFlag, 403 minimumStatsFlag, maxStatsPeriod); 404 } 405 406 /** Returns {@link android.car.watchdog.ResourceOveruseStats} for the specified user package. */ 407 @Override 408 @NonNull getResourceOveruseStatsForUserPackage( @onNull String packageName, @NonNull UserHandle userHandle, @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, @CarWatchdogManager.StatsPeriod int maxStatsPeriod)409 public ResourceOveruseStats getResourceOveruseStatsForUserPackage( 410 @NonNull String packageName, @NonNull UserHandle userHandle, 411 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, 412 @CarWatchdogManager.StatsPeriod int maxStatsPeriod) { 413 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS); 414 return mWatchdogPerfHandler.getResourceOveruseStatsForUserPackage(packageName, userHandle, 415 resourceOveruseFlag, maxStatsPeriod); 416 } 417 418 /** 419 * Adds {@link android.car.watchdog.IResourceOveruseListener} for the calling package's resource 420 * overuse notifications. 421 */ 422 @Override addResourceOveruseListener( @arWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, @NonNull IResourceOveruseListener listener)423 public void addResourceOveruseListener( 424 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, 425 @NonNull IResourceOveruseListener listener) { 426 mWatchdogPerfHandler.addResourceOveruseListener(resourceOveruseFlag, listener); 427 } 428 429 /** 430 * Removes the previously added {@link android.car.watchdog.IResourceOveruseListener} for the 431 * calling package's resource overuse notifications. 432 */ 433 @Override removeResourceOveruseListener(@onNull IResourceOveruseListener listener)434 public void removeResourceOveruseListener(@NonNull IResourceOveruseListener listener) { 435 mWatchdogPerfHandler.removeResourceOveruseListener(listener); 436 } 437 438 /** 439 * Adds {@link android.car.watchdog.IResourceOveruseListener} for all packages' resource overuse 440 * notifications. 441 */ 442 @Override addResourceOveruseListenerForSystem( @arWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, @NonNull IResourceOveruseListener listener)443 public void addResourceOveruseListenerForSystem( 444 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag, 445 @NonNull IResourceOveruseListener listener) { 446 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS); 447 mWatchdogPerfHandler.addResourceOveruseListenerForSystem(resourceOveruseFlag, listener); 448 } 449 450 /** 451 * Removes the previously added {@link android.car.watchdog.IResourceOveruseListener} for all 452 * packages' resource overuse notifications. 453 */ 454 @Override removeResourceOveruseListenerForSystem(@onNull IResourceOveruseListener listener)455 public void removeResourceOveruseListenerForSystem(@NonNull IResourceOveruseListener listener) { 456 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS); 457 mWatchdogPerfHandler.removeResourceOveruseListenerForSystem(listener); 458 } 459 460 /** Sets whether or not a user package is killable on resource overuse. */ 461 @Override setKillablePackageAsUser(String packageName, UserHandle userHandle, boolean isKillable)462 public void setKillablePackageAsUser(String packageName, UserHandle userHandle, 463 boolean isKillable) { 464 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG); 465 mWatchdogPerfHandler.setKillablePackageAsUser(packageName, userHandle, isKillable); 466 } 467 468 /** 469 * Returns all {@link android.car.watchdog.PackageKillableState} on resource overuse for 470 * the specified user. 471 */ 472 @Override 473 @NonNull getPackageKillableStatesAsUser(UserHandle userHandle)474 public List<PackageKillableState> getPackageKillableStatesAsUser(UserHandle userHandle) { 475 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG); 476 return mWatchdogPerfHandler.getPackageKillableStatesAsUser(userHandle); 477 } 478 479 /** 480 * Sets {@link android.car.watchdog.ResourceOveruseConfiguration} for the specified resources. 481 */ 482 @Override 483 @CarWatchdogManager.ReturnCode setResourceOveruseConfigurations( List<ResourceOveruseConfiguration> configurations, @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag)484 public int setResourceOveruseConfigurations( 485 List<ResourceOveruseConfiguration> configurations, 486 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) 487 throws RemoteException { 488 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG); 489 return mWatchdogPerfHandler.setResourceOveruseConfigurations(configurations, 490 resourceOveruseFlag); 491 } 492 493 /** Returns the available {@link android.car.watchdog.ResourceOveruseConfiguration}. */ 494 @Override 495 @NonNull getResourceOveruseConfigurations( @arWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag)496 public List<ResourceOveruseConfiguration> getResourceOveruseConfigurations( 497 @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) { 498 CarServiceUtils.assertAnyPermission(mContext, Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG, 499 Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS); 500 return mWatchdogPerfHandler.getResourceOveruseConfigurations(resourceOveruseFlag); 501 } 502 503 /** 504 * Enables/disables the watchdog daemon client health check process. 505 */ controlProcessHealthCheck(boolean enable)506 public void controlProcessHealthCheck(boolean enable) { 507 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG); 508 mWatchdogProcessHandler.controlProcessHealthCheck(enable); 509 } 510 511 /** 512 * Kills a specific package for a user due to resource overuse. 513 * 514 * @return whether package was killed 515 */ performResourceOveruseKill(String packageName, @UserIdInt int userId)516 public boolean performResourceOveruseKill(String packageName, @UserIdInt int userId) { 517 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG); 518 return mWatchdogPerfHandler.disablePackageForUser(packageName, userId); 519 } 520 521 /** 522 * Sets the thread priority for a specific thread. 523 * 524 * The thread must belong to the calling process. 525 * 526 * @throws IllegalArgumentException If the policy/priority is not valid. 527 * @throws IllegalStateException If the provided tid does not belong to the calling process. 528 * @throws RemoteException If binder error happens. 529 * @throws ServiceSpecificException If car watchdog daemon failed to set the thread priority. 530 * @throws UnsupportedOperationException If the current android release doesn't support the API. 531 */ setThreadPriority(int pid, int tid, int uid, int policy, int priority)532 public void setThreadPriority(int pid, int tid, int uid, int policy, int priority) 533 throws RemoteException { 534 mCarWatchdogDaemonHelper.setThreadPriority(pid, tid, uid, policy, priority); 535 } 536 537 /** 538 * Gets the thread scheduling policy and priority for the specified thread. 539 * 540 * The thread must belong to the calling process. 541 * 542 * @throws IllegalStateException If the provided tid does not belong to the calling process or 543 * car watchdog daemon failed to get the priority. 544 * @throws RemoteException If binder error happens. 545 * @throws UnsupportedOperationException If the current android release doesn't support the API. 546 */ getThreadPriority(int pid, int tid, int uid)547 public int[] getThreadPriority(int pid, int tid, int uid) throws RemoteException { 548 try { 549 return mCarWatchdogDaemonHelper.getThreadPriority(pid, tid, uid); 550 } catch (ServiceSpecificException e) { 551 // Car watchdog daemon failed to get the priority. 552 throw new IllegalStateException(e); 553 } 554 } 555 556 @VisibleForTesting getClientCount(int timeout)557 int getClientCount(int timeout) { 558 return mWatchdogProcessHandler.getClientCount(timeout); 559 } 560 561 @VisibleForTesting setOveruseHandlingDelay(long millis)562 void setOveruseHandlingDelay(long millis) { 563 mWatchdogPerfHandler.setOveruseHandlingDelay(millis); 564 } 565 getWatchdogDirFile()566 static File getWatchdogDirFile() { 567 SystemInterface systemInterface = CarLocalServices.getService(SystemInterface.class); 568 String systemCarDirPath = systemInterface == null ? FALLBACK_DATA_SYSTEM_CAR_DIR_PATH 569 : systemInterface.getSystemCarDir().getAbsolutePath(); 570 return new File(systemCarDirPath, WATCHDOG_DIR_NAME); 571 } 572 notifyAllUserStates()573 private void notifyAllUserStates() { 574 UserManager userManager = mContext.getSystemService(UserManager.class); 575 List<UserHandle> users = userManager.getUserHandles(/* excludeDying= */ false); 576 try { 577 // TODO(b/152780162): reduce the number of RPC calls(isUserRunning). 578 for (int i = 0; i < users.size(); ++i) { 579 UserHandle user = users.get(i); 580 int userState = userManager.isUserRunning(user) 581 ? UserState.USER_STATE_STARTED 582 : UserState.USER_STATE_STOPPED; 583 mCarWatchdogDaemonHelper.notifySystemStateChange(StateType.USER_STATE, 584 user.getIdentifier(), userState); 585 mWatchdogProcessHandler.updateUserState(user.getIdentifier(), 586 userState == UserState.USER_STATE_STOPPED); 587 } 588 if (DEBUG) { 589 Slogf.d(TAG, "Notified car watchdog daemon of user states"); 590 } 591 } catch (RemoteException | RuntimeException e) { 592 // When car watchdog daemon is not connected, the {@link mCarWatchdogDaemonHelper} 593 // throws IllegalStateException. Catch the exception to avoid crashing the process. 594 Slogf.w(TAG, e, "Notifying latest user states failed"); 595 } 596 } 597 notifyPowerCycleChange(@owerCycle int powerCycle)598 private void notifyPowerCycleChange(@PowerCycle int powerCycle) { 599 if (!Car.getPlatformVersion().isAtLeast(VERSION_CODES.TIRAMISU_2) 600 && powerCycle == PowerCycle.POWER_CYCLE_SUSPEND_EXIT) { 601 return; 602 } 603 try { 604 mCarWatchdogDaemonHelper.notifySystemStateChange( 605 StateType.POWER_CYCLE, powerCycle, MISSING_ARG_VALUE); 606 if (DEBUG) { 607 Slogf.d(TAG, "Notified car watchdog daemon of power cycle(%d)", powerCycle); 608 } 609 } catch (RemoteException | RuntimeException e) { 610 // When car watchdog daemon is not connected, the {@link mCarWatchdogDaemonHelper} 611 // throws IllegalStateException. Catch the exception to avoid crashing the process. 612 Slogf.w(TAG, e, "Notifying power cycle change to %d failed", powerCycle); 613 } 614 } 615 notifyGarageModeChange(@arageMode int garageMode)616 private void notifyGarageModeChange(@GarageMode int garageMode) { 617 try { 618 mCarWatchdogDaemonHelper.notifySystemStateChange( 619 StateType.GARAGE_MODE, garageMode, MISSING_ARG_VALUE); 620 if (DEBUG) { 621 Slogf.d(TAG, "Notified car watchdog daemon of garage mode(%d)", garageMode); 622 } 623 } catch (RemoteException | RuntimeException e) { 624 // When car watchdog daemon is not connected, the {@link mCarWatchdogDaemonHelper} 625 // throws IllegalStateException. Catch the exception to avoid crashing the process. 626 Slogf.w(TAG, e, "Notifying garage mode change to %d failed", garageMode); 627 } 628 } 629 postRegisterToDaemonMessage()630 private void postRegisterToDaemonMessage() { 631 CarServiceUtils.runOnMain(() -> { 632 synchronized (mLock) { 633 mReadyToRespond = true; 634 } 635 registerToDaemon(); 636 }); 637 } 638 registerToDaemon()639 private void registerToDaemon() { 640 synchronized (mLock) { 641 if (!mIsConnected || !mReadyToRespond) { 642 return; 643 } 644 } 645 try { 646 mCarWatchdogDaemonHelper.registerCarWatchdogService(mWatchdogServiceForSystem); 647 if (DEBUG) { 648 Slogf.d(TAG, "CarWatchdogService registers to car watchdog daemon"); 649 } 650 } catch (RemoteException | RuntimeException e) { 651 // When car watchdog daemon is not connected, the {@link mCarWatchdogDaemonHelper} 652 // throws IllegalStateException. Catch the exception to avoid crashing the process. 653 Slogf.w(TAG, e, "Cannot register to car watchdog daemon"); 654 } 655 notifyAllUserStates(); 656 CarPowerManagementService powerService = 657 CarLocalServices.getService(CarPowerManagementService.class); 658 if (powerService != null) { 659 int powerState = powerService.getPowerState(); 660 int powerCycle = carPowerStateToPowerCycle(powerState); 661 if (powerCycle >= 0) { 662 notifyPowerCycleChange(powerCycle); 663 } else { 664 Slogf.i(TAG, "Skipping notifying %d power state", powerState); 665 } 666 } 667 int garageMode; 668 synchronized (mLock) { 669 // To avoid race condition, fetch {@link mCurrentGarageMode} just before 670 // the {@link notifyGarageModeChange} call. For instance, if {@code mCurrentGarageMode} 671 // changes before the above {@link notifyPowerCycleChange} call returns, 672 // the {@link garageMode}'s value will be out of date. 673 garageMode = mCurrentGarageMode; 674 } 675 notifyGarageModeChange(garageMode); 676 } 677 unregisterFromDaemon()678 private void unregisterFromDaemon() { 679 try { 680 mCarWatchdogDaemonHelper.unregisterCarWatchdogService(mWatchdogServiceForSystem); 681 if (DEBUG) { 682 Slogf.d(TAG, "CarWatchdogService unregisters from car watchdog daemon"); 683 } 684 } catch (RemoteException | RuntimeException e) { 685 // When car watchdog daemon is not connected, the {@link mCarWatchdogDaemonHelper} 686 // throws IllegalStateException. Catch the exception to avoid crashing the process. 687 Slogf.w(TAG, e, "Cannot unregister from car watchdog daemon"); 688 } 689 } 690 subscribePowerManagementService()691 private void subscribePowerManagementService() { 692 CarPowerManagementService powerService = 693 CarLocalServices.getService(CarPowerManagementService.class); 694 if (powerService == null) { 695 Slogf.w(TAG, "Cannot get CarPowerManagementService"); 696 return; 697 } 698 powerService.registerListener(mCarPowerStateListener); 699 powerService.addPowerPolicyListener( 700 new CarPowerPolicyFilter.Builder().setComponents(PowerComponent.DISPLAY).build(), 701 mCarDisplayPowerPolicyListener); 702 } 703 unsubscribePowerManagementService()704 private void unsubscribePowerManagementService() { 705 CarPowerManagementService powerService = 706 CarLocalServices.getService(CarPowerManagementService.class); 707 if (powerService == null) { 708 Slogf.w(TAG, "Cannot get CarPowerManagementService"); 709 return; 710 } 711 powerService.unregisterListener(mCarPowerStateListener); 712 powerService.removePowerPolicyListener(mCarDisplayPowerPolicyListener); 713 } 714 subscribeUserStateChange()715 private void subscribeUserStateChange() { 716 CarUserService userService = CarLocalServices.getService(CarUserService.class); 717 if (userService == null) { 718 Slogf.w(TAG, "Cannot get CarUserService"); 719 return; 720 } 721 UserLifecycleEventFilter userEventFilter = 722 new UserLifecycleEventFilter.Builder() 723 .addEventType(USER_LIFECYCLE_EVENT_TYPE_STARTING) 724 .addEventType(USER_LIFECYCLE_EVENT_TYPE_SWITCHING) 725 .addEventType(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING) 726 .addEventType(USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED) 727 .addEventType(USER_LIFECYCLE_EVENT_TYPE_STOPPED).build(); 728 userService.addUserLifecycleListener(userEventFilter, (event) -> { 729 if (!isEventAnyOfTypes(TAG, event, USER_LIFECYCLE_EVENT_TYPE_STARTING, 730 USER_LIFECYCLE_EVENT_TYPE_SWITCHING, USER_LIFECYCLE_EVENT_TYPE_UNLOCKING, 731 USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED, USER_LIFECYCLE_EVENT_TYPE_STOPPED)) { 732 return; 733 } 734 if (!Car.getPlatformVersion().isAtLeast(VERSION_CODES.TIRAMISU_1) 735 && !isEventAnyOfTypes(TAG, event, USER_LIFECYCLE_EVENT_TYPE_STARTING, 736 USER_LIFECYCLE_EVENT_TYPE_STOPPED)) { 737 return; 738 } 739 740 int userId = event.getUserHandle().getIdentifier(); 741 int userState; 742 String userStateDesc; 743 switch (event.getEventType()) { 744 case USER_LIFECYCLE_EVENT_TYPE_STARTING: 745 mWatchdogProcessHandler.updateUserState(userId, /*isStopped=*/ false); 746 userState = UserState.USER_STATE_STARTED; 747 userStateDesc = "STARTING"; 748 break; 749 case USER_LIFECYCLE_EVENT_TYPE_SWITCHING: 750 userState = UserState.USER_STATE_SWITCHING; 751 userStateDesc = "SWITCHING"; 752 break; 753 case USER_LIFECYCLE_EVENT_TYPE_UNLOCKING: 754 userState = UserState.USER_STATE_UNLOCKING; 755 userStateDesc = "UNLOCKING"; 756 break; 757 case USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED: 758 userState = UserState.USER_STATE_POST_UNLOCKED; 759 userStateDesc = "POST_UNLOCKED"; 760 break; 761 case USER_LIFECYCLE_EVENT_TYPE_STOPPED: 762 mWatchdogProcessHandler.updateUserState(userId, /*isStopped=*/ true); 763 userState = UserState.USER_STATE_STOPPED; 764 userStateDesc = "STOPPING"; 765 break; 766 default: 767 return; 768 } 769 try { 770 mCarWatchdogDaemonHelper.notifySystemStateChange(StateType.USER_STATE, userId, 771 userState); 772 if (DEBUG) { 773 Slogf.d(TAG, "Notified car watchdog daemon user %d's user state, %s", 774 userId, userStateDesc); 775 } 776 } catch (RemoteException | RuntimeException e) { 777 // When car watchdog daemon is not connected, the {@link mCarWatchdogDaemonHelper} 778 // throws IllegalStateException. Catch the exception to avoid crashing the process. 779 Slogf.w(TAG, e, "Notifying user state change failed"); 780 } 781 }); 782 } 783 subscribeBroadcastReceiver()784 private void subscribeBroadcastReceiver() { 785 IntentFilter filter = new IntentFilter(); 786 filter.addAction(ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION); 787 filter.addAction(ACTION_GARAGE_MODE_ON); 788 filter.addAction(ACTION_GARAGE_MODE_OFF); 789 filter.addAction(ACTION_LAUNCH_APP_SETTINGS); 790 filter.addAction(ACTION_RESOURCE_OVERUSE_DISABLE_APP); 791 filter.addAction(ACTION_USER_REMOVED); 792 filter.addAction(ACTION_REBOOT); 793 filter.addAction(ACTION_SHUTDOWN); 794 795 mContext.registerReceiverForAllUsers(mBroadcastReceiver, filter, 796 Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG, /* scheduler= */ null, 797 Context.RECEIVER_NOT_EXPORTED); 798 799 // The package data scheme applies only for the ACTION_PACKAGE_CHANGED action. So, add a 800 // filter for this action separately. Otherwise, the broadcast receiver won't receive 801 // notifications for other actions. 802 IntentFilter packageChangedFilter = new IntentFilter(); 803 packageChangedFilter.addAction(ACTION_PACKAGE_CHANGED); 804 packageChangedFilter.addDataScheme("package"); 805 806 mContext.registerReceiverForAllUsers(mBroadcastReceiver, packageChangedFilter, 807 /* broadcastPermission= */ null, /* scheduler= */ null, 808 Context.RECEIVER_NOT_EXPORTED); 809 } 810 carPowerStateToPowerCycle(int powerState)811 private static int carPowerStateToPowerCycle(int powerState) { 812 switch (powerState) { 813 // SHUTDOWN_PREPARE covers suspend and shutdown. 814 case CarPowerManager.STATE_SHUTDOWN_PREPARE: 815 return PowerCycle.POWER_CYCLE_SHUTDOWN_PREPARE; 816 case CarPowerManager.STATE_SHUTDOWN_ENTER: 817 case CarPowerManager.STATE_SUSPEND_ENTER: 818 case CarPowerManager.STATE_HIBERNATION_ENTER: 819 return PowerCycle.POWER_CYCLE_SHUTDOWN_ENTER; 820 case CarPowerManager.STATE_SUSPEND_EXIT: 821 case CarPowerManager.STATE_HIBERNATION_EXIT: 822 return PowerCycle.POWER_CYCLE_SUSPEND_EXIT; 823 // ON covers resume. 824 case CarPowerManager.STATE_ON: 825 return PowerCycle.POWER_CYCLE_RESUME; 826 } 827 return -1; 828 } 829 toGarageModeString(@arageMode int garageMode)830 private static String toGarageModeString(@GarageMode int garageMode) { 831 switch (garageMode) { 832 case GarageMode.GARAGE_MODE_OFF: 833 return "GARAGE_MODE_OFF"; 834 case GarageMode.GARAGE_MODE_ON: 835 return "GARAGE_MODE_ON"; 836 } 837 return "INVALID"; 838 } 839 840 private static final class ICarWatchdogServiceForSystemImpl 841 extends ICarWatchdogServiceForSystem.Stub { 842 private final WeakReference<CarWatchdogService> mService; 843 ICarWatchdogServiceForSystemImpl(CarWatchdogService service)844 ICarWatchdogServiceForSystemImpl(CarWatchdogService service) { 845 mService = new WeakReference<>(service); 846 } 847 848 @Override checkIfAlive(int sessionId, int timeout)849 public void checkIfAlive(int sessionId, int timeout) { 850 CarWatchdogService service = mService.get(); 851 if (service == null) { 852 Slogf.w(TAG, "CarWatchdogService is not available"); 853 return; 854 } 855 service.mWatchdogProcessHandler.postHealthCheckMessage(sessionId); 856 } 857 858 @Override prepareProcessTermination()859 public void prepareProcessTermination() { 860 Slogf.w(TAG, "CarWatchdogService is about to be killed by car watchdog daemon"); 861 } 862 863 @Override getPackageInfosForUids( int[] uids, List<String> vendorPackagePrefixes)864 public List<PackageInfo> getPackageInfosForUids( 865 int[] uids, List<String> vendorPackagePrefixes) { 866 if (ArrayUtils.isEmpty(uids)) { 867 Slogf.w(TAG, "UID list is empty"); 868 return null; 869 } 870 CarWatchdogService service = mService.get(); 871 if (service == null) { 872 Slogf.w(TAG, "CarWatchdogService is not available"); 873 return null; 874 } 875 return service.mPackageInfoHandler.getPackageInfosForUids(uids, vendorPackagePrefixes); 876 } 877 878 @Override latestIoOveruseStats(List<PackageIoOveruseStats> packageIoOveruseStats)879 public void latestIoOveruseStats(List<PackageIoOveruseStats> packageIoOveruseStats) { 880 if (packageIoOveruseStats.isEmpty()) { 881 Slogf.w(TAG, "Latest I/O overuse stats is empty"); 882 return; 883 } 884 CarWatchdogService service = mService.get(); 885 if (service == null) { 886 Slogf.w(TAG, "CarWatchdogService is not available"); 887 return; 888 } 889 service.mWatchdogPerfHandler.latestIoOveruseStats(packageIoOveruseStats); 890 } 891 892 @Override resetResourceOveruseStats(List<String> packageNames)893 public void resetResourceOveruseStats(List<String> packageNames) { 894 if (packageNames.isEmpty()) { 895 Slogf.w(TAG, "Provided an empty package name to reset resource overuse stats"); 896 return; 897 } 898 CarWatchdogService service = mService.get(); 899 if (service == null) { 900 Slogf.w(TAG, "CarWatchdogService is not available"); 901 return; 902 } 903 service.mWatchdogPerfHandler.resetResourceOveruseStats(new ArraySet<>(packageNames)); 904 } 905 906 @Override getTodayIoUsageStats()907 public List<UserPackageIoUsageStats> getTodayIoUsageStats() { 908 CarWatchdogService service = mService.get(); 909 if (service == null) { 910 Slogf.w(TAG, "CarWatchdogService is not available"); 911 return null; 912 } 913 return service.mWatchdogPerfHandler.getTodayIoUsageStats(); 914 } 915 916 @Override getInterfaceHash()917 public String getInterfaceHash() { 918 return ICarWatchdogServiceForSystemImpl.HASH; 919 } 920 921 @Override getInterfaceVersion()922 public int getInterfaceVersion() { 923 return ICarWatchdogServiceForSystemImpl.VERSION; 924 } 925 } 926 } 927