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