1 /* 2 * Copyright (C) 2023 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.occupantconnection; 18 19 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; 20 import static android.car.CarOccupantZoneManager.INVALID_USER_ID; 21 import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_INSTALLED; 22 import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_IN_FOREGROUND; 23 import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_RUNNING; 24 import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_SAME_LONG_VERSION; 25 import static android.car.CarRemoteDeviceManager.FLAG_CLIENT_SAME_SIGNATURE; 26 import static android.car.CarRemoteDeviceManager.FLAG_OCCUPANT_ZONE_CONNECTION_READY; 27 import static android.car.CarRemoteDeviceManager.FLAG_OCCUPANT_ZONE_POWER_ON; 28 import static android.car.CarRemoteDeviceManager.FLAG_OCCUPANT_ZONE_SCREEN_UNLOCKED; 29 import static android.car.builtin.display.DisplayManagerHelper.EVENT_FLAG_DISPLAY_CHANGED; 30 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_INVISIBLE; 31 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED; 32 import static android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES; 33 34 import static com.android.car.CarServiceUtils.assertPermission; 35 import static com.android.car.CarServiceUtils.checkCalledByPackage; 36 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DEBUGGING_CODE; 37 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO; 38 import static com.android.car.internal.util.VersionUtils.isPlatformVersionAtLeastU; 39 40 import android.annotation.IntDef; 41 import android.annotation.Nullable; 42 import android.annotation.RequiresApi; 43 import android.app.ActivityManager; 44 import android.app.ActivityManager.RunningAppProcessInfo; 45 import android.car.Car; 46 import android.car.CarOccupantZoneManager.OccupantZoneInfo; 47 import android.car.CarRemoteDeviceManager.AppState; 48 import android.car.CarRemoteDeviceManager.OccupantZoneState; 49 import android.car.builtin.app.ActivityManagerHelper.ProcessObserverCallback; 50 import android.car.builtin.display.DisplayManagerHelper; 51 import android.car.builtin.util.Slogf; 52 import android.car.occupantconnection.ICarRemoteDevice; 53 import android.car.occupantconnection.IStateCallback; 54 import android.car.user.CarUserManager; 55 import android.car.user.UserLifecycleEventFilter; 56 import android.content.BroadcastReceiver; 57 import android.content.Context; 58 import android.content.Intent; 59 import android.content.IntentFilter; 60 import android.content.pm.PackageInfo; 61 import android.content.pm.PackageManager; 62 import android.hardware.display.DisplayManager.DisplayListener; 63 import android.os.Binder; 64 import android.os.Build; 65 import android.os.RemoteException; 66 import android.os.UserHandle; 67 import android.os.UserManager; 68 import android.util.ArrayMap; 69 import android.util.ArraySet; 70 import android.util.Log; 71 import android.util.SparseArray; 72 73 import com.android.car.CarLocalServices; 74 import com.android.car.CarOccupantZoneService; 75 import com.android.car.CarServiceBase; 76 import com.android.car.SystemActivityMonitoringService; 77 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 78 import com.android.car.internal.util.BinderKeyValueContainer; 79 import com.android.car.internal.util.IndentingPrintWriter; 80 import com.android.car.power.CarPowerManagementService; 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.lang.annotation.Retention; 86 import java.lang.annotation.RetentionPolicy; 87 import java.util.Arrays; 88 import java.util.List; 89 import java.util.Set; 90 91 /** 92 * Service to implement APIs defined in {@link android.car.CarRemoteDeviceManager}. 93 * <p> 94 * In this class, a discovering client refers to a client that has registered an {@link 95 * IStateCallback}, and discovered apps refer to the peer apps of the discovering client. 96 * <p> 97 * This class can monitor the states of occupant zones in the car and the peer clients in 98 * those occupant zones. There are 3 {@link OccupantZoneState}s: 99 * <ul> 100 * <li> {@link android.car.CarRemoteDeviceManager#FLAG_OCCUPANT_ZONE_POWER_ON} is updated by the 101 * DisplayListener. 102 * <li> TODO(b/257117236): implement FLAG_OCCUPANT_ZONE_SCREEN_UNLOCKED. 103 * <li> {@link android.car.CarRemoteDeviceManager#FLAG_OCCUPANT_ZONE_CONNECTION_READY} is updated 104 * by the ICarOccupantZoneCallback. 105 * </ul> 106 * There are 5 {@link AppState}s: 107 * <ul> 108 * <li> App install states ({@link android.car.CarRemoteDeviceManager#FLAG_CLIENT_INSTALLED}, 109 * {@link android.car.CarRemoteDeviceManager#FLAG_CLIENT_SAME_LONG_VERSION}, 110 * {@link android.car.CarRemoteDeviceManager#FLAG_CLIENT_SAME_SIGNATURE}) are updated by the 111 * PackageChangeReceiver. 112 * <li> App running states ({@link android.car.CarRemoteDeviceManager#FLAG_CLIENT_RUNNING}, 113 * {@link android.car.CarRemoteDeviceManager#FLAG_CLIENT_IN_FOREGROUND}) are updated by the 114 * ProcessRunningStateCallback. Note: these states won't be updated for apps that share the 115 * same user ID through the "sharedUserId" mechanism. 116 * </ul> 117 */ 118 public class CarRemoteDeviceService extends ICarRemoteDevice.Stub implements 119 CarServiceBase { 120 121 private static final String TAG = CarRemoteDeviceService.class.getSimpleName(); 122 private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG); 123 private static final String INDENTATION_2 = " "; 124 private static final String INDENTATION_4 = " "; 125 126 private static final int PROCESS_NOT_RUNNING = 0; 127 private static final int PROCESS_RUNNING_IN_BACKGROUND = 1; 128 private static final int PROCESS_RUNNING_IN_FOREGROUND = 2; 129 130 @IntDef(flag = false, prefix = {"PROCESS_"}, value = { 131 PROCESS_NOT_RUNNING, 132 PROCESS_RUNNING_IN_BACKGROUND, 133 PROCESS_RUNNING_IN_FOREGROUND 134 }) 135 @Retention(RetentionPolicy.SOURCE) 136 @interface ProcessRunningState { 137 } 138 139 @VisibleForTesting 140 @AppState 141 static final int INITIAL_APP_STATE = 0; 142 @VisibleForTesting 143 @OccupantZoneState 144 static final int INITIAL_OCCUPANT_ZONE_STATE = 0; 145 146 private final Object mLock = new Object(); 147 private final Context mContext; 148 private final CarOccupantZoneService mOccupantZoneService; 149 private final CarPowerManagementService mPowerManagementService; 150 private final SystemActivityMonitoringService mSystemActivityMonitoringService; 151 private final ActivityManager mActivityManager; 152 private final UserManager mUserManager; 153 154 /** A map of discovering client to its callback. */ 155 @GuardedBy("mLock") 156 private final BinderKeyValueContainer<ClientId, IStateCallback> mCallbackMap; 157 158 /** A map of client app to its {@link AppState}. */ 159 @GuardedBy("mLock") 160 private final ArrayMap<ClientId, Integer> mAppStateMap; 161 162 /** 163 * A map of occupant zone to its {@link OccupantZoneState}. Its keys are all the occupant 164 * zones on this SoC and will never change after initialization. 165 */ 166 @GuardedBy("mLock") 167 private final ArrayMap<OccupantZoneInfo, Integer> mOccupantZoneStateMap; 168 169 /** A map of secondary user (non-system user) ID to PerUserInfo. */ 170 @GuardedBy("mLock") 171 private final SparseArray<PerUserInfo> mPerUserInfoMap; 172 173 private final ProcessObserverCallback mProcessObserver = new ProcessObserver(); 174 175 private final CarUserManager.UserLifecycleListener mUserLifecycleListener = event -> { 176 Slogf.v(TAG, "onEvent(%s)", event); 177 handleUserChange(); 178 }; 179 180 private final class PackageChangeReceiver extends BroadcastReceiver { 181 182 /** The user ID that this receiver registered as. */ 183 private final int mUserId; 184 /** The occupant zone that the user runs in. */ 185 private final OccupantZoneInfo mOccupantZone; 186 187 @VisibleForTesting PackageChangeReceiver(int userId, OccupantZoneInfo occupantZone)188 PackageChangeReceiver(int userId, OccupantZoneInfo occupantZone) { 189 super(); 190 this.mUserId = userId; 191 this.mOccupantZone = occupantZone; 192 } 193 194 @Override onReceive(Context context, Intent intent)195 public void onReceive(Context context, Intent intent) { 196 String packageName = intent.getData().getSchemeSpecificPart(); 197 synchronized (mLock) { 198 if (!isDiscoveringLocked(packageName)) { 199 // There is no peer client discovering this app, so ignore its install/uninstall 200 // event. 201 if (DBG) { 202 Slogf.v(TAG, "Ignore package change for %s as user %d because there is no " 203 + "peer client discovering this app", packageName, mUserId); 204 } 205 return; 206 } 207 ClientId clientId = new ClientId(mOccupantZone, mUserId, packageName); 208 if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) { 209 Slogf.v(TAG, "%s was installed", clientId); 210 @AppState int newState = calculateAppStateLocked(clientId); 211 setAppStateLocked(clientId, newState, /* callbackToNotify= */ null); 212 } else if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) { 213 Slogf.v(TAG, "%s was uninstalled", clientId); 214 setAppStateLocked(clientId, INITIAL_APP_STATE, /* callbackToNotify= */ null); 215 } 216 } 217 } 218 } 219 220 private final class ProcessObserver extends ProcessObserverCallback { 221 @Override onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities)222 public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) { 223 handleProcessRunningStateChange(uid, foregroundActivities 224 ? PROCESS_RUNNING_IN_FOREGROUND 225 : PROCESS_RUNNING_IN_BACKGROUND); 226 } 227 228 @Override onProcessDied(int pid, int uid)229 public void onProcessDied(int pid, int uid) { 230 handleProcessRunningStateChange(uid, PROCESS_NOT_RUNNING); 231 } 232 } 233 234 /** Wrapper class for objects that are specific to a non-system user. */ 235 @VisibleForTesting 236 static final class PerUserInfo { 237 238 /** The occupant zone that the user runs in. */ 239 public final OccupantZoneInfo zone; 240 241 /** The Context of the user. Used to register and unregister the receiver. */ 242 public final Context context; 243 244 /** The PackageManager of the user. */ 245 public final PackageManager pm; 246 247 /** The PackageChangeReceiver. Used to listen to package install/uninstall events. */ 248 public final BroadcastReceiver receiver; 249 250 @VisibleForTesting PerUserInfo(OccupantZoneInfo zone, Context context, PackageManager pm, BroadcastReceiver receiver)251 PerUserInfo(OccupantZoneInfo zone, Context context, PackageManager pm, 252 BroadcastReceiver receiver) { 253 this.zone = zone; 254 this.context = context; 255 this.pm = pm; 256 this.receiver = receiver; 257 } 258 } 259 CarRemoteDeviceService(Context context, CarOccupantZoneService occupantZoneService, CarPowerManagementService powerManagementService, SystemActivityMonitoringService systemActivityMonitoringService)260 public CarRemoteDeviceService(Context context, 261 CarOccupantZoneService occupantZoneService, 262 CarPowerManagementService powerManagementService, 263 SystemActivityMonitoringService systemActivityMonitoringService) { 264 this(context, occupantZoneService, powerManagementService, systemActivityMonitoringService, 265 context.getSystemService(ActivityManager.class), 266 context.getSystemService(UserManager.class), 267 /* perUserInfoMap= */ new SparseArray<>(), 268 /* callbackMap= */ new BinderKeyValueContainer<>(), 269 /* appStateMap= */ new ArrayMap<>(), 270 /* occupantZoneStateMap= */ new ArrayMap<>()); 271 } 272 273 @VisibleForTesting CarRemoteDeviceService(Context context, CarOccupantZoneService occupantZoneService, CarPowerManagementService powerManagementService, SystemActivityMonitoringService systemActivityMonitoringService, ActivityManager activityManager, UserManager userManager, SparseArray<PerUserInfo> perUserInfoMap, BinderKeyValueContainer<ClientId, IStateCallback> callbackMap, ArrayMap<ClientId, Integer> appStateMap, ArrayMap<OccupantZoneInfo, Integer> occupantZoneStateMap)274 CarRemoteDeviceService(Context context, 275 CarOccupantZoneService occupantZoneService, 276 CarPowerManagementService powerManagementService, 277 SystemActivityMonitoringService systemActivityMonitoringService, 278 ActivityManager activityManager, 279 UserManager userManager, 280 SparseArray<PerUserInfo> perUserInfoMap, 281 BinderKeyValueContainer<ClientId, IStateCallback> callbackMap, 282 ArrayMap<ClientId, Integer> appStateMap, 283 ArrayMap<OccupantZoneInfo, Integer> occupantZoneStateMap) { 284 mContext = context; 285 mOccupantZoneService = occupantZoneService; 286 mPowerManagementService = powerManagementService; 287 mSystemActivityMonitoringService = systemActivityMonitoringService; 288 mActivityManager = activityManager; 289 mUserManager = userManager; 290 mPerUserInfoMap = perUserInfoMap; 291 mCallbackMap = callbackMap; 292 mAppStateMap = appStateMap; 293 mOccupantZoneStateMap = occupantZoneStateMap; 294 } 295 296 @Override init()297 public void init() { 298 if (!isPlatformVersionAtLeastU()) { 299 Slogf.w(TAG, "CarRemoteDeviceService should run on Android U+"); 300 return; 301 } 302 initAllOccupantZones(); 303 registerUserLifecycleListener(); 304 initAssignedUsers(); 305 registerDisplayListener(); 306 } 307 308 @Override release()309 public void release() { 310 // TODO(b/257117236): implement this method. 311 } 312 313 /** Run `adb shell dumpsys car_service --services CarRemoteDeviceService` to dump. */ 314 @Override 315 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dump(IndentingPrintWriter writer)316 public void dump(IndentingPrintWriter writer) { 317 writer.println("*CarRemoteDeviceService*"); 318 synchronized (mLock) { 319 writer.printf("%smCallbackMap:\n", INDENTATION_2); 320 for (int i = 0; i < mCallbackMap.size(); i++) { 321 ClientId discoveringClient = mCallbackMap.keyAt(i); 322 IStateCallback callback = mCallbackMap.valueAt(i); 323 writer.printf("%s%s, callback:%s\n", INDENTATION_4, discoveringClient, callback); 324 } 325 writer.printf("%smAppStateMap:\n", INDENTATION_2); 326 for (int i = 0; i < mAppStateMap.size(); i++) { 327 ClientId client = mAppStateMap.keyAt(i); 328 @AppState int state = mAppStateMap.valueAt(i); 329 writer.printf("%s%s, state:%s\n", INDENTATION_4, client, appStateToString(state)); 330 } 331 writer.printf("%smOccupantZoneStateMap:\n", INDENTATION_2); 332 for (int i = 0; i < mOccupantZoneStateMap.size(); i++) { 333 OccupantZoneInfo occupantZone = mOccupantZoneStateMap.keyAt(i); 334 @OccupantZoneState int state = mOccupantZoneStateMap.valueAt(i); 335 writer.printf("%s%s, state:%s\n", INDENTATION_4, occupantZone, 336 occupantZoneStateToString(state)); 337 } 338 writer.printf("%smPerUserInfoMap:\n", INDENTATION_2); 339 for (int i = 0; i < mPerUserInfoMap.size(); i++) { 340 int userId = mPerUserInfoMap.keyAt(i); 341 PerUserInfo info = mPerUserInfoMap.valueAt(i); 342 writer.printf("%suserId:%s, %s, %s, %s, %s\n", INDENTATION_4, userId, info.zone, 343 info.context, info.pm, info.receiver); 344 } 345 } 346 } 347 348 @Override registerStateCallback(String packageName, IStateCallback callback)349 public void registerStateCallback(String packageName, IStateCallback callback) { 350 assertPermission(mContext, Car.PERMISSION_MANAGE_REMOTE_DEVICE); 351 checkCalledByPackage(mContext, packageName); 352 353 ClientId discoveringClient = getCallingClientId(packageName); 354 synchronized (mLock) { 355 assertNoDuplicateCallbackLock(discoveringClient); 356 boolean firstDiscoverer = mCallbackMap.size() == 0; 357 mCallbackMap.put(discoveringClient, callback); 358 // Notify the discoverer of the latest states. 359 updateAllOccupantZoneStateLocked(callback); 360 updateAllAppStateWithPackageNameLocked(discoveringClient.packageName, callback); 361 362 if (firstDiscoverer) { 363 mSystemActivityMonitoringService.registerProcessObserverCallback(mProcessObserver); 364 } 365 } 366 } 367 368 @Override unregisterStateCallback(String packageName)369 public void unregisterStateCallback(String packageName) { 370 assertPermission(mContext, Car.PERMISSION_MANAGE_REMOTE_DEVICE); 371 checkCalledByPackage(mContext, packageName); 372 373 ClientId discoveringClient = getCallingClientId(packageName); 374 synchronized (mLock) { 375 assertHasCallbackLock(discoveringClient); 376 mCallbackMap.remove(discoveringClient); 377 if (mCallbackMap.size() == 0) { 378 mSystemActivityMonitoringService.unregisterProcessObserverCallback( 379 mProcessObserver); 380 } 381 // If this discoverer is the last discoverer with the package name, remove the app state 382 // of all the apps with the package name. 383 if (!isDiscoveringLocked(packageName)) { 384 clearAllAppStateWithPackageNameLocked(packageName); 385 } 386 } 387 } 388 389 @Override getEndpointPackageInfo(int occupantZoneId, String packageName)390 public PackageInfo getEndpointPackageInfo(int occupantZoneId, String packageName) { 391 assertPermission(mContext, Car.PERMISSION_MANAGE_REMOTE_DEVICE); 392 checkCalledByPackage(mContext, packageName); 393 394 int userId = mOccupantZoneService.getUserForOccupant(occupantZoneId); 395 if (userId == INVALID_USER_ID) { 396 Slogf.e(TAG, "Failed to get PackageInfo of %s in occupant zone %d because it has no " 397 + "user assigned", packageName, occupantZoneId); 398 return null; 399 } 400 return getPackageInfoAsUser(packageName, userId); 401 } 402 403 @Override setOccupantZonePower(OccupantZoneInfo occupantZone, boolean powerOn)404 public void setOccupantZonePower(OccupantZoneInfo occupantZone, boolean powerOn) { 405 assertPermission(mContext, Car.PERMISSION_MANAGE_REMOTE_DEVICE); 406 407 int[] displayIds = mOccupantZoneService.getAllDisplaysForOccupantZone(occupantZone.zoneId); 408 for (int id : displayIds) { 409 mPowerManagementService.setDisplayPowerState(id, powerOn); 410 } 411 } 412 413 @Override isOccupantZonePowerOn(OccupantZoneInfo occupantZone)414 public boolean isOccupantZonePowerOn(OccupantZoneInfo occupantZone) { 415 assertPermission(mContext, Car.PERMISSION_MANAGE_REMOTE_DEVICE); 416 417 return mOccupantZoneService.areDisplaysOnForOccupantZone(occupantZone.zoneId); 418 } 419 initAllOccupantZones()420 private void initAllOccupantZones() { 421 List<OccupantZoneInfo> allOccupantZones = mOccupantZoneService.getAllOccupantZones(); 422 synchronized (mLock) { 423 for (int i = 0; i < allOccupantZones.size(); i++) { 424 OccupantZoneInfo occupantZone = allOccupantZones.get(i); 425 @OccupantZoneState int initialState = calculateOccupantZoneState(occupantZone); 426 Slogf.v(TAG, "The state of %s is initialized to %s", occupantZone, 427 occupantZoneStateToString(initialState)); 428 mOccupantZoneStateMap.put(occupantZone, initialState); 429 } 430 } 431 } 432 registerUserLifecycleListener()433 private void registerUserLifecycleListener() { 434 CarUserService userService = CarLocalServices.getService(CarUserService.class); 435 UserLifecycleEventFilter userEventFilter = new UserLifecycleEventFilter.Builder() 436 // UNLOCKED event indicates the connection becomes ready, while INVISIBLE event 437 // indicates the connection changes to not ready. 438 .addEventType(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) 439 .addEventType(USER_LIFECYCLE_EVENT_TYPE_INVISIBLE) 440 .build(); 441 userService.addUserLifecycleListener(userEventFilter, mUserLifecycleListener); 442 } 443 444 /** 445 * Handles the user change in all the occpant zones, including the driver occupant zone and 446 * passenger occupant zones. 447 */ handleUserChange()448 private void handleUserChange() { 449 synchronized (mLock) { 450 for (int i = 0; i < mOccupantZoneStateMap.size(); i++) { 451 OccupantZoneInfo occupantZone = mOccupantZoneStateMap.keyAt(i); 452 int oldUserId = getAssignedUserLocked(occupantZone); 453 int newUserId = 454 mOccupantZoneService.getUserForOccupant(occupantZone.zoneId); 455 Slogf.i(TAG, "In %s, old user was %d, new user is %d", 456 occupantZone, oldUserId, newUserId); 457 boolean hasOldUser = (oldUserId != INVALID_USER_ID); 458 boolean hasNewUser = isNonSystemUser(newUserId); 459 460 if (!hasOldUser && !hasNewUser) { 461 // Still no user secondary assigned in this occupant zone, so do nothing. 462 Slogf.v(TAG, "Still no user secondary assigned in %s", occupantZone); 463 continue; 464 } 465 if (oldUserId == newUserId) { 466 // The user ID doesn't change in this occupant zone, but the user lifecycle 467 // might have changed, so try to update the occupant zone state. 468 handleSameUserUpdateLocked(newUserId, occupantZone); 469 continue; 470 } 471 if (hasOldUser && !hasNewUser) { 472 // The old user was unassigned. 473 handleUserUnassignedLocked(oldUserId, occupantZone); 474 continue; 475 } 476 if (!hasOldUser && hasNewUser) { 477 // The new user was assigned. 478 handleUserAssignedLocked(newUserId, occupantZone); 479 continue; 480 } 481 // The old user switched to a different new user. 482 handleUserSwitchedLocked(oldUserId, newUserId, occupantZone); 483 } 484 } 485 } 486 487 @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) registerDisplayListener()488 private void registerDisplayListener() { 489 DisplayManagerHelper.registerDisplayListener(mContext, new DisplayListener() { 490 @Override 491 public void onDisplayAdded(int displayId) { 492 // No-op. 493 } 494 495 @Override 496 public void onDisplayRemoved(int displayId) { 497 // No-op. 498 } 499 500 @Override 501 public void onDisplayChanged(int displayId) { 502 Slogf.v(TAG, "onDisplayChanged(): displayId %d", displayId); 503 OccupantZoneInfo occupantZone = 504 mOccupantZoneService.getOccupantZoneForDisplayId(displayId); 505 if (occupantZone == null) { 506 Slogf.i(TAG, "Display %d has no occupant zone assigned", displayId); 507 return; 508 } 509 synchronized (mLock) { 510 updateOccupantZoneStateLocked(occupantZone, 511 /* callbackToNotify= */null); 512 } 513 } 514 }, /* handler= */null, EVENT_FLAG_DISPLAY_CHANGED); 515 } 516 handleProcessRunningStateChange(int uid, @ProcessRunningState int newState)517 private void handleProcessRunningStateChange(int uid, @ProcessRunningState int newState) { 518 UserHandle userHandle = UserHandle.getUserHandleForUid(uid); 519 if (userHandle.isSystem()) { 520 if (DBG) { 521 Slogf.v(TAG, "Skip ProcessRunningState change for process with uid %d because " 522 + "the process runs as system user", uid); 523 } 524 return; 525 } 526 synchronized (mLock) { 527 String packageName = getUniquePackageNameByUidLocked(uid); 528 if (packageName == null) { 529 return; 530 } 531 if (!isDiscoveringLocked(packageName)) { 532 // There is no peer client discovering this app, so ignore its running state change 533 // event. 534 if (DBG) { 535 Slogf.v(TAG, "Skip ProcessRunningState change for %s because there is no peer " 536 + "client discovering this app", packageName); 537 } 538 return; 539 } 540 Slogf.v(TAG, "%s 's running state changed to %s", packageName, 541 processRunningStateToString(newState)); 542 int userId = userHandle.getIdentifier(); 543 // Note: userInfo can't be null here, otherwise getUniquePackageNameByUidLocked() would 544 // return null, and it wouldn't get here. 545 PerUserInfo userInfo = mPerUserInfoMap.get(userId); 546 ClientId clientId = new ClientId(userInfo.zone, userId, packageName); 547 @AppState int newAppState = 548 convertProcessRunningStateToAppStateLocked(packageName, userId, newState); 549 setAppStateLocked(clientId, newAppState, /* callbackToNotify= */ null); 550 } 551 } 552 initAssignedUsers()553 private void initAssignedUsers() { 554 synchronized (mLock) { 555 for (int i = 0; i < mOccupantZoneStateMap.size(); i++) { 556 OccupantZoneInfo occupantZone = mOccupantZoneStateMap.keyAt(i); 557 int userId = mOccupantZoneService.getUserForOccupant(occupantZone.zoneId); 558 Slogf.v(TAG, "User ID of %s is %d ", occupantZone, userId); 559 if (!isNonSystemUser(userId)) { 560 continue; 561 } 562 initAssignedUserLocked(userId, occupantZone); 563 } 564 } 565 } 566 567 /** 568 * Initializes PerUserInfo for the given user, and registers a PackageChangeReceiver for the 569 * given user. 570 * 571 * @return {@code true} if the PerUserInfo was initialized successfully 572 */ 573 @GuardedBy("mLock") initAssignedUserLocked(int userId, OccupantZoneInfo occupantZone)574 private boolean initAssignedUserLocked(int userId, OccupantZoneInfo occupantZone) { 575 if (!isNonSystemUser(userId)) { 576 Slogf.w(TAG, "%s is assigned to user %d", occupantZone, userId); 577 return false; 578 } 579 PerUserInfo userInfo = mPerUserInfoMap.get(userId); 580 if (userInfo != null && userInfo.zone.equals(occupantZone)) { 581 Slogf.v(TAG, "Skip initializing PerUserInfo of user %d because it exists already", 582 userId); 583 return true; 584 } 585 586 // Init PackageChangeReceiver. 587 PackageChangeReceiver receiver = new PackageChangeReceiver(userId, occupantZone); 588 IntentFilter filter = new IntentFilter(); 589 filter.addAction(Intent.ACTION_PACKAGE_ADDED); 590 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 591 filter.addDataScheme("package"); 592 593 // Init user Context. 594 Context userContext = mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0); 595 if (userContext == null) { 596 Slogf.e(TAG, "Failed to create Context as user %d", userId); 597 return false; 598 } 599 Slogf.v(TAG, "registerReceiver() as user %d", userId); 600 601 // Register PackageChangeReceiver. 602 userContext.registerReceiver(receiver, filter); 603 604 // Init PackageManager. 605 PackageManager pm = userContext.getPackageManager(); 606 if (pm == null) { 607 Slogf.e(TAG, "Failed to create PackageManager as user %d", userId); 608 return false; 609 } 610 611 userInfo = new PerUserInfo(occupantZone, userContext, pm, receiver); 612 mPerUserInfoMap.put(userId, userInfo); 613 return true; 614 } 615 616 /** 617 * Removes PerUserInfo of the given user, and unregisters the PackageChangeReceiver for the 618 * given user. This method is called when the given {@code userId} is unassigned. 619 */ 620 @GuardedBy("mLock") removeUnassignedUserLocked(int userId)621 private void removeUnassignedUserLocked(int userId) { 622 PerUserInfo userInfo = mPerUserInfoMap.get(userId); 623 if (userInfo == null) { 624 Slogf.v(TAG, "Skip removing PerUserInfo of user %d because it doesn't exist", userId); 625 return; 626 } 627 Slogf.v(TAG, "unregisterReceiver() as user %d", userId); 628 userInfo.context.unregisterReceiver(userInfo.receiver); 629 630 mPerUserInfoMap.remove(userId); 631 } 632 633 @GuardedBy("mLock") handleSameUserUpdateLocked(int userId, OccupantZoneInfo occupantZone)634 private void handleSameUserUpdateLocked(int userId, OccupantZoneInfo occupantZone) { 635 Slogf.v(TAG, "User %d lifecycle might have changed in %s", userId, occupantZone); 636 updateOccupantZoneStateLocked(occupantZone, /* callbackToNotify= */ null); 637 } 638 639 @GuardedBy("mLock") handleUserUnassignedLocked(int userId, OccupantZoneInfo occupantZone)640 private void handleUserUnassignedLocked(int userId, OccupantZoneInfo occupantZone) { 641 Slogf.v(TAG, "User %d was unassigned in %s", userId, occupantZone); 642 removeUnassignedUserLocked(userId); 643 updateOccupantZoneStateLocked(occupantZone, /* callbackToNotify= */ null); 644 clearAllAppStateAsUserLocked(userId); 645 } 646 647 @GuardedBy("mLock") handleUserAssignedLocked(int userId, OccupantZoneInfo occupantZone)648 private void handleUserAssignedLocked(int userId, OccupantZoneInfo occupantZone) { 649 Slogf.v(TAG, "User %d was assigned in %s", userId, occupantZone); 650 initAssignedUserLocked(userId, occupantZone); 651 updateOccupantZoneStateLocked(occupantZone, /* callbackToNotify= */ null); 652 updateAllAppStateForNewUserLocked(userId, occupantZone); 653 } 654 655 @GuardedBy("mLock") handleUserSwitchedLocked(int oldUserId, int newUserId, OccupantZoneInfo occupantZone)656 private void handleUserSwitchedLocked(int oldUserId, int newUserId, 657 OccupantZoneInfo occupantZone) { 658 Slogf.v(TAG, "User %d was switched to %d in %s", oldUserId, newUserId, occupantZone); 659 removeUnassignedUserLocked(oldUserId); 660 clearAllAppStateAsUserLocked(oldUserId); 661 662 initAssignedUserLocked(newUserId, occupantZone); 663 updateAllAppStateForNewUserLocked(newUserId, occupantZone); 664 665 updateOccupantZoneStateLocked(occupantZone, /* callbackToNotify= */ null); 666 } 667 getCallingClientId(String packageName)668 private ClientId getCallingClientId(String packageName) { 669 UserHandle callingUserHandle = Binder.getCallingUserHandle(); 670 int callingUserId = callingUserHandle.getIdentifier(); 671 OccupantZoneInfo occupantZone = 672 mOccupantZoneService.getOccupantZoneForUser(callingUserHandle); 673 // Note: the occupantZone is not null because the calling user must be a valid user. 674 return new ClientId(occupantZone, callingUserId, packageName); 675 } 676 677 /** 678 * Updates the states of all the occupant zones, notifies the newly registered callback 679 * {@code callbackToNotify} of the latest state if it is not {@code null}, and notifies other 680 * callbacks of the latest state if the state has changed. 681 */ 682 @GuardedBy("mLock") updateAllOccupantZoneStateLocked(@ullable IStateCallback callbackToNotify)683 private void updateAllOccupantZoneStateLocked(@Nullable IStateCallback callbackToNotify) { 684 for (int i = 0; i < mOccupantZoneStateMap.size(); i++) { 685 OccupantZoneInfo occupantZone = mOccupantZoneStateMap.keyAt(i); 686 updateOccupantZoneStateLocked(occupantZone, callbackToNotify); 687 } 688 } 689 690 /** 691 * Updates the state of the given occupant zone, notifies the newly registered callback 692 * {@code callbackToNotify} of the latest state if it is not {@code null}, and notifies other 693 * callbacks of the latest state if the state has changed. 694 */ 695 @GuardedBy("mLock") updateOccupantZoneStateLocked(OccupantZoneInfo occupantZone, @Nullable IStateCallback callbackToNotify)696 private void updateOccupantZoneStateLocked(OccupantZoneInfo occupantZone, 697 @Nullable IStateCallback callbackToNotify) { 698 @OccupantZoneState int oldState = mOccupantZoneStateMap.get(occupantZone); 699 @OccupantZoneState int newState = calculateOccupantZoneState(occupantZone); 700 boolean stateChanged = (oldState != newState); 701 if (!stateChanged && callbackToNotify == null) { 702 Slogf.v(TAG, "Skip updateOccupantZoneStateLocked() for %s because OccupantZoneState" 703 + " stays the same and there is no newly registered callback", occupantZone); 704 return; 705 } 706 Slogf.v(TAG, "The state of %s is changed from %s to %s", occupantZone, 707 occupantZoneStateToString(oldState), occupantZoneStateToString(newState)); 708 mOccupantZoneStateMap.put(occupantZone, newState); 709 710 for (int i = 0; i < mCallbackMap.size(); i++) { 711 ClientId discoveringClient = mCallbackMap.keyAt(i); 712 // Don't notify discovering clients that are running in this occupant zone. 713 if (discoveringClient.occupantZone.equals(occupantZone)) { 714 continue; 715 } 716 IStateCallback callback = mCallbackMap.valueAt(i); 717 // If the callback is newly registered, invoke it anyway. Otherwise, invoke it only 718 // when the state has changed 719 if ((callback == callbackToNotify) || stateChanged) { 720 try { 721 callback.onOccupantZoneStateChanged(occupantZone, newState); 722 } catch (RemoteException e) { 723 Slogf.e(TAG, e, "Failed to notify %s of OccupantZoneState change", 724 discoveringClient); 725 } 726 } 727 } 728 } 729 730 @VisibleForTesting 731 @OccupantZoneState calculateOccupantZoneState(OccupantZoneInfo occupantZone)732 int calculateOccupantZoneState(OccupantZoneInfo occupantZone) { 733 @OccupantZoneState int occupantZoneState = INITIAL_OCCUPANT_ZONE_STATE; 734 // The three occupant zones states are independent of each other. 735 if (isPowerOn(occupantZone)) { 736 occupantZoneState |= FLAG_OCCUPANT_ZONE_POWER_ON; 737 } 738 if (isScreenUnlocked(occupantZone)) { 739 occupantZoneState |= FLAG_OCCUPANT_ZONE_SCREEN_UNLOCKED; 740 } 741 if (isConnectionReady(occupantZone)) { 742 occupantZoneState |= FLAG_OCCUPANT_ZONE_CONNECTION_READY; 743 } 744 return occupantZoneState; 745 } 746 isPowerOn(OccupantZoneInfo occupantZone)747 private boolean isPowerOn(OccupantZoneInfo occupantZone) { 748 return mOccupantZoneService.areDisplaysOnForOccupantZone(occupantZone.zoneId); 749 } 750 isScreenUnlocked(OccupantZoneInfo occupantZone)751 private boolean isScreenUnlocked(OccupantZoneInfo occupantZone) { 752 // TODO(b/257117236): implement this method. 753 return false; 754 } 755 756 /** 757 * Returns {@code true} if the given {@code occupantZone} is ready to handle connection request. 758 * Returns {@code false} otherwise. 759 * <p> 760 * If the {@code occupantZone} is on the same SoC as the caller occupant zone, connection ready 761 * means the user is ready. If the {@code occupantZone} is on another SoC, connection ready 762 * means user ready and internet connection from the caller occupant zone to the {@code 763 * occupantZone} is good. User ready means the user has been allocated to the occupant zone, 764 * is actively running, is unlocked, and is visible. 765 */ 766 // TODO(b/257118327): support multi-SoC. isConnectionReady(OccupantZoneInfo occupantZone)767 boolean isConnectionReady(OccupantZoneInfo occupantZone) { 768 if (!isPlatformVersionAtLeastU()) { 769 Slogf.w(TAG, "CarRemoteDeviceService should run on Android U+"); 770 return false; 771 } 772 int userId = mOccupantZoneService.getUserForOccupant(occupantZone.zoneId); 773 if (!isNonSystemUser(userId)) { 774 return false; 775 } 776 UserHandle userHandle = UserHandle.of(userId); 777 return mUserManager.isUserRunning(userHandle) && mUserManager.isUserUnlocked(userHandle) 778 && mUserManager.getVisibleUsers().contains(userHandle); 779 } 780 781 /** 782 * Updates the {@link AppState} of all the apps with the given {@code packageName}, notifies 783 * the newly registered callback {@code callbackToNotify} of the latest state, and notifies 784 * other callbacks of the latest state if the state has changed. 785 */ 786 @GuardedBy("mLock") updateAllAppStateWithPackageNameLocked(String packageName, IStateCallback callbackToNotify)787 private void updateAllAppStateWithPackageNameLocked(String packageName, 788 IStateCallback callbackToNotify) { 789 for (int i = 0; i < mPerUserInfoMap.size(); i++) { 790 int userId = mPerUserInfoMap.keyAt(i); 791 OccupantZoneInfo occupantZone = mPerUserInfoMap.valueAt(i).zone; 792 ClientId discoveredClient = new ClientId(occupantZone, userId, packageName); 793 @AppState int newState = calculateAppStateLocked(discoveredClient); 794 setAppStateLocked(discoveredClient, newState, callbackToNotify); 795 } 796 } 797 798 /** 799 * Updates the {@link AppState} of all the clients that run as {@code userId}, and notifies 800 * the discoverers of the state change. This method is invoked when a new user is assigned to 801 * the given occupant zone. 802 */ 803 @GuardedBy("mLock") updateAllAppStateForNewUserLocked(int userId, OccupantZoneInfo occupantZone)804 private void updateAllAppStateForNewUserLocked(int userId, OccupantZoneInfo occupantZone) { 805 Set<String> updatedApps = new ArraySet<>(); 806 for (int i = 0; i < mCallbackMap.size(); i++) { 807 ClientId discoveringClient = mCallbackMap.keyAt(i); 808 // For a given package name, there might be several discoverers (peer clients that have 809 // registered a callback), but we only need to update the state of the changed client 810 // once. 811 if (updatedApps.contains(discoveringClient.packageName)) { 812 continue; 813 } 814 updatedApps.add(discoveringClient.packageName); 815 816 ClientId clientId = new ClientId(occupantZone, userId, discoveringClient.packageName); 817 @AppState int newAppState = calculateAppStateLocked(clientId); 818 setAppStateLocked(clientId, newAppState, /* callbackToNotify= */ null); 819 } 820 } 821 822 /** 823 * Clears the {@link AppState} of all the apps that run as {@code userId}. 824 * This method is called when the given {@code userId} is unassigned for the occupantZone, 825 * for which the discoverers are already notified, so there is no need to notify the discoverers 826 * in this method. 827 */ 828 @GuardedBy("mLock") clearAllAppStateAsUserLocked(int userId)829 private void clearAllAppStateAsUserLocked(int userId) { 830 for (int i = 0; i < mAppStateMap.size(); i++) { 831 ClientId clientId = mAppStateMap.keyAt(i); 832 if (clientId.userId == userId) { 833 mAppStateMap.removeAt(i); 834 } 835 } 836 } 837 838 /** 839 * Clears the {@link AppState} of all the apps that have the given {@code packageName}. 840 * This method is called when the last discoverer with the package name is unregistered , so 841 * there is no need to notify the discoverers in this method. 842 */ 843 @GuardedBy("mLock") clearAllAppStateWithPackageNameLocked(String packageName)844 private void clearAllAppStateWithPackageNameLocked(String packageName) { 845 for (int i = 0; i < mAppStateMap.size(); i++) { 846 ClientId clientId = mAppStateMap.keyAt(i); 847 if (clientId.packageName.equals(packageName)) { 848 mAppStateMap.removeAt(i); 849 } 850 } 851 } 852 853 @GuardedBy("mLock") getPackageManagerAsUserLocked(int userId)854 private PackageManager getPackageManagerAsUserLocked(int userId) { 855 PerUserInfo userInfo = mPerUserInfoMap.get(userId); 856 if (userInfo == null) { 857 Slogf.e(TAG, "Failed to get PackageManager as user %d because the user is not" 858 + " assigned to an occupant zone yet", userId); 859 return null; 860 } 861 return userInfo.pm; 862 } 863 864 @GuardedBy("mLock") assertNoDuplicateCallbackLock(ClientId discoveredClient)865 private void assertNoDuplicateCallbackLock(ClientId discoveredClient) { 866 if (mCallbackMap.containsKey(discoveredClient)) { 867 throw new IllegalStateException("The client already registered a StateCallback: " 868 + discoveredClient); 869 } 870 } 871 872 @GuardedBy("mLock") assertHasCallbackLock(ClientId discoveredClient)873 private void assertHasCallbackLock(ClientId discoveredClient) { 874 if (!mCallbackMap.containsKey(discoveredClient)) { 875 throw new IllegalStateException("The client has no StateCallback registered: " 876 + discoveredClient); 877 } 878 } 879 880 /** 881 * Returns {@code true} if there is a client with the {@code packageName} has registered an 882 * {@link IStateCallback}. 883 */ 884 @GuardedBy("mLock") isDiscoveringLocked(String packageName)885 private boolean isDiscoveringLocked(String packageName) { 886 for (int i = 0; i < mCallbackMap.size(); i++) { 887 ClientId discoveringClient = mCallbackMap.keyAt(i); 888 if (discoveringClient.packageName.equals(packageName)) { 889 return true; 890 } 891 } 892 return false; 893 } 894 895 /** 896 * Sets the {@link AppState} of the given client, notifies the newly registered callback 897 * {@code callbackToNotify} of the latest state if it is not {@code null}, and notifies other 898 * peer discoverers of the latest state if the state has changed. 899 */ 900 @GuardedBy("mLock") setAppStateLocked(ClientId discoveredClient, @AppState int newState, @Nullable IStateCallback callbackToNotify)901 private void setAppStateLocked(ClientId discoveredClient, @AppState int newState, 902 @Nullable IStateCallback callbackToNotify) { 903 Integer oldAppState = mAppStateMap.get(discoveredClient); 904 boolean stateChanged = (oldAppState == null || oldAppState.intValue() != newState); 905 if (!stateChanged && callbackToNotify == null) { 906 Slogf.v(TAG, "Skip setAppStateLocked() because AppState stays the same and there" 907 + " is no newly registered callback"); 908 return; 909 } 910 Slogf.v(TAG, "The app state of %s is set from %s to %s", discoveredClient, 911 oldAppState == null ? "null" : appStateToString(oldAppState), 912 appStateToString(newState)); 913 mAppStateMap.put(discoveredClient, newState); 914 915 // Notify its peer clients that are discovering. 916 for (int i = 0; i < mCallbackMap.size(); i++) { 917 ClientId discoveringClient = mCallbackMap.keyAt(i); 918 // A peer client is a client that has the same package name but runs as another user. 919 // If it is not a peer client, skip it. 920 if (!discoveringClient.packageName.equals(discoveredClient.packageName) 921 || discoveringClient.userId == discoveredClient.userId) { 922 continue; 923 } 924 IStateCallback callback = mCallbackMap.valueAt(i); 925 // If the callback is newly registered, invoke it anyway. Otherwise, invoke it only 926 // when the state has changed 927 if (callback == callbackToNotify || stateChanged) { 928 try { 929 callback.onAppStateChanged(discoveredClient.occupantZone, newState); 930 } catch (RemoteException e) { 931 Slogf.e(TAG, e, "Failed to notify %d of AppState change", discoveringClient); 932 } 933 } 934 } 935 } 936 937 @GuardedBy("mLock") 938 @AppState calculateAppStateLocked(ClientId clientId)939 private int calculateAppStateLocked(ClientId clientId) { 940 @AppState int appState = INITIAL_APP_STATE; 941 if (isAppInstalledAsUserLocked(clientId.packageName, clientId.userId)) { 942 appState |= FLAG_CLIENT_INSTALLED; 943 // In single-SoC model, the peer client is guaranteed to have the same 944 // signing info and long version code. 945 // TODO(b/257118327): support multiple-SoC. 946 appState |= FLAG_CLIENT_SAME_LONG_VERSION | FLAG_CLIENT_SAME_SIGNATURE; 947 948 RunningAppProcessInfo info = 949 getRunningAppProcessInfoAsUserLocked(clientId.packageName, clientId.userId); 950 if (isAppRunning(info)) { 951 appState |= FLAG_CLIENT_RUNNING; 952 if (isAppRunningInForeground(info)) { 953 appState |= FLAG_CLIENT_IN_FOREGROUND; 954 } 955 } 956 } 957 return appState; 958 } 959 960 @GuardedBy("mLock") getAssignedUserLocked(OccupantZoneInfo occupantZone)961 private int getAssignedUserLocked(OccupantZoneInfo occupantZone) { 962 for (int i = 0; i < mPerUserInfoMap.size(); i++) { 963 if (occupantZone.equals(mPerUserInfoMap.valueAt(i).zone)) { 964 return mPerUserInfoMap.keyAt(i); 965 } 966 } 967 return INVALID_USER_ID; 968 } 969 970 /** 971 * This method is an unlocked version of {@link #calculateAppStateLocked} and is used for 972 * testing only. 973 */ 974 @AppState 975 @VisibleForTesting calculateAppState(ClientId clientId)976 int calculateAppState(ClientId clientId) { 977 synchronized (mLock) { 978 return calculateAppStateLocked(clientId); 979 } 980 } 981 982 @GuardedBy("mLock") isAppInstalledAsUserLocked(String packageName, int userId)983 private boolean isAppInstalledAsUserLocked(String packageName, int userId) { 984 return getPackageInfoAsUserLocked(packageName, userId, /* flags= */ 0) != null; 985 } 986 getPackageInfoAsUser(String packageName, int userId)987 PackageInfo getPackageInfoAsUser(String packageName, int userId) { 988 synchronized (mLock) { 989 return getPackageInfoAsUserLocked(packageName, userId, GET_SIGNING_CERTIFICATES); 990 } 991 } 992 993 @GuardedBy("mLock") getPackageInfoAsUserLocked(String packageName, int userId, int flags)994 private PackageInfo getPackageInfoAsUserLocked(String packageName, int userId, int flags) { 995 PackageManager pm = getPackageManagerAsUserLocked(userId); 996 if (pm == null) { 997 return null; 998 } 999 try { 1000 return pm.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(flags)); 1001 } catch (PackageManager.NameNotFoundException e) { 1002 return null; 1003 } 1004 } 1005 1006 @GuardedBy("mLock") getRunningAppProcessInfoAsUserLocked(String packageName, int userId)1007 private RunningAppProcessInfo getRunningAppProcessInfoAsUserLocked(String packageName, 1008 int userId) { 1009 List<RunningAppProcessInfo> infos = mActivityManager.getRunningAppProcesses(); 1010 if (infos == null) { 1011 return null; 1012 } 1013 for (int i = 0; i < infos.size(); i++) { 1014 RunningAppProcessInfo processInfo = infos.get(i); 1015 if (processInfo.processName.equals(packageName)) { 1016 UserHandle processUserHandle = UserHandle.getUserHandleForUid(processInfo.uid); 1017 if (processUserHandle.getIdentifier() == userId) { 1018 return processInfo; 1019 } 1020 } 1021 } 1022 return null; 1023 } 1024 1025 @GuardedBy("mLock") getUniquePackageNameByUidLocked(int uid)1026 private String getUniquePackageNameByUidLocked(int uid) { 1027 UserHandle userHandle = UserHandle.getUserHandleForUid(uid); 1028 int userId = userHandle.getIdentifier(); 1029 PerUserInfo userInfo = mPerUserInfoMap.get(userId); 1030 if (userInfo == null) { 1031 // When an occupant zone is assigned with a user, the associated PerUserInfo will be 1032 // initialized in the ICarOccupantZoneCallback. But the ICarOccupantZoneCallback may be 1033 // invoked after this method (called by ProcessObserverCallback). In that case, the 1034 // PerUserInfo will be null (b/277956688). So let's try to initialize the PerUserInfo 1035 // here. 1036 Slogf.v(TAG, "PerUserIno for user %d is not initialized yet", userId); 1037 OccupantZoneInfo occupantZone = mOccupantZoneService.getOccupantZoneForUser(userHandle); 1038 if (occupantZone == null) { 1039 // This shouldn't happen. Let's log an error. 1040 Slogf.e(TAG, "The running state of the process (uid %d) has changed, but the user" 1041 + " %d is not assigned to any occupant zone yet", uid, userId); 1042 return null; 1043 } 1044 boolean success = initAssignedUserLocked(userId, occupantZone); 1045 if (!success) { 1046 Slogf.wtf(TAG, "Failed to initialize PerUserInfo for user %d in %s", userId, 1047 occupantZone); 1048 return null; 1049 } 1050 // Note: userInfo must not be null here because it was initialized successfully. 1051 userInfo = mPerUserInfoMap.get(userId); 1052 } 1053 String[] packageNames = userInfo.pm.getPackagesForUid(uid); 1054 if (packageNames == null) { 1055 return null; 1056 } 1057 if (packageNames.length == 1) { 1058 return packageNames[0]; 1059 } 1060 // packageNames.length can't be 0. 1061 // Multiple package names means multiple apps share the same user ID through the 1062 // "sharedUserId" mechanism. However, "sharedUserId" mechanism is deprecated in 1063 // API level 29, so let's log an error. 1064 Slogf.i(TAG, "Failed to get the package name by uid! Apps shouldn't use sharedUserId" 1065 + " because it's deprecated in API level 29: %s", Arrays.toString(packageNames)); 1066 return null; 1067 } 1068 1069 @GuardedBy("mLock") 1070 @AppState convertProcessRunningStateToAppStateLocked(String packageName, int userId, @ProcessRunningState int state)1071 private int convertProcessRunningStateToAppStateLocked(String packageName, int userId, 1072 @ProcessRunningState int state) { 1073 // Note: In single-SoC model, the peer client is guaranteed to have the same 1074 // signing info and long version code. 1075 // TODO(b/257118327): support multiple-SoC. 1076 switch (state) { 1077 case PROCESS_RUNNING_IN_BACKGROUND: 1078 return FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION 1079 | FLAG_CLIENT_SAME_SIGNATURE | FLAG_CLIENT_RUNNING; 1080 case PROCESS_RUNNING_IN_FOREGROUND: 1081 return FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION 1082 | FLAG_CLIENT_SAME_SIGNATURE | FLAG_CLIENT_RUNNING 1083 | FLAG_CLIENT_IN_FOREGROUND; 1084 case PROCESS_NOT_RUNNING: 1085 return isAppInstalledAsUserLocked(packageName, userId) 1086 ? FLAG_CLIENT_INSTALLED | FLAG_CLIENT_SAME_LONG_VERSION 1087 | FLAG_CLIENT_SAME_SIGNATURE 1088 : INITIAL_APP_STATE; 1089 1090 } 1091 throw new IllegalArgumentException("Undefined ProcessRunningState: " + state); 1092 } 1093 isAppRunning(RunningAppProcessInfo info)1094 private static boolean isAppRunning(RunningAppProcessInfo info) { 1095 return info != null; 1096 } 1097 isAppRunningInForeground(RunningAppProcessInfo info)1098 private static boolean isAppRunningInForeground(RunningAppProcessInfo info) { 1099 return info != null && info.importance == IMPORTANCE_FOREGROUND; 1100 } 1101 1102 /** Returns {@code true} if the given user is a valid user and is not the system user. */ isNonSystemUser(int userId)1103 private static boolean isNonSystemUser(int userId) { 1104 return userId != INVALID_USER_ID && !UserHandle.of(userId).isSystem(); 1105 } 1106 1107 @ExcludeFromCodeCoverageGeneratedReport(reason = DEBUGGING_CODE) occupantZoneStateToString(@ccupantZoneState int state)1108 private static String occupantZoneStateToString(@OccupantZoneState int state) { 1109 boolean powerOn = (state & FLAG_OCCUPANT_ZONE_POWER_ON) != 0; 1110 boolean screenUnlocked = (state & FLAG_OCCUPANT_ZONE_SCREEN_UNLOCKED) != 0; 1111 boolean connectionReady = (state & FLAG_OCCUPANT_ZONE_CONNECTION_READY) != 0; 1112 return new StringBuilder(64) 1113 .append("[") 1114 .append(powerOn ? "on, " : "off, ") 1115 .append(screenUnlocked ? "unlocked, " : "locked, ") 1116 .append(connectionReady ? "ready" : "not-ready") 1117 .append("]") 1118 .toString(); 1119 1120 } 1121 1122 @ExcludeFromCodeCoverageGeneratedReport(reason = DEBUGGING_CODE) appStateToString(@ppState int state)1123 private static String appStateToString(@AppState int state) { 1124 boolean installed = (state & FLAG_CLIENT_INSTALLED) != 0; 1125 boolean sameVersion = (state & FLAG_CLIENT_SAME_LONG_VERSION) != 0; 1126 boolean sameSignature = (state & FLAG_CLIENT_SAME_SIGNATURE) != 0; 1127 boolean running = (state & FLAG_CLIENT_RUNNING) != 0; 1128 boolean inForeground = (state & FLAG_CLIENT_IN_FOREGROUND) != 0; 1129 return new StringBuilder(64) 1130 .append("[") 1131 .append(installed ? "installed, " : "not-installed, ") 1132 .append(sameVersion ? "same-version, " : "different-version, ") 1133 .append(sameSignature ? "same-signature, " : "different-signature, ") 1134 .append(!running 1135 ? "not-running" 1136 : (inForeground ? "foreground" : "background")) 1137 .append("]") 1138 .toString(); 1139 } 1140 1141 @ExcludeFromCodeCoverageGeneratedReport(reason = DEBUGGING_CODE) processRunningStateToString(@rocessRunningState int state)1142 private static String processRunningStateToString(@ProcessRunningState int state) { 1143 switch (state) { 1144 case PROCESS_NOT_RUNNING: 1145 return "not-running"; 1146 case PROCESS_RUNNING_IN_BACKGROUND: 1147 return "background"; 1148 case PROCESS_RUNNING_IN_FOREGROUND: 1149 return "foreground"; 1150 default: 1151 throw new IllegalArgumentException("Undefined ProcessRunningState: " + state); 1152 } 1153 } 1154 } 1155