1 /* 2 * Copyright (C) 2019 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.pm; 18 19 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_INVISIBLE; 20 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED; 21 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING; 22 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED; 23 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_VISIBLE; 24 import static android.content.Context.BIND_AUTO_CREATE; 25 import static android.os.Process.INVALID_UID; 26 27 import static com.android.car.CarLog.TAG_AM; 28 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO; 29 import static com.android.car.internal.util.VersionUtils.isPlatformVersionAtLeastU; 30 31 import android.annotation.Nullable; 32 import android.annotation.SuppressLint; 33 import android.annotation.UserIdInt; 34 import android.app.ActivityManager; 35 import android.car.builtin.util.Slogf; 36 import android.car.hardware.power.CarPowerManager; 37 import android.car.hardware.power.ICarPowerStateListener; 38 import android.car.user.CarUserManager.UserLifecycleEvent; 39 import android.car.user.CarUserManager.UserLifecycleListener; 40 import android.car.user.UserLifecycleEventFilter; 41 import android.content.BroadcastReceiver; 42 import android.content.ComponentName; 43 import android.content.Context; 44 import android.content.Intent; 45 import android.content.IntentFilter; 46 import android.content.ServiceConnection; 47 import android.content.res.Resources; 48 import android.net.Uri; 49 import android.os.Handler; 50 import android.os.IBinder; 51 import android.os.Looper; 52 import android.os.Message; 53 import android.os.UserHandle; 54 import android.os.UserManager; 55 import android.text.TextUtils; 56 import android.util.Log; 57 58 import com.android.car.CarLocalServices; 59 import com.android.car.CarLog; 60 import com.android.car.R; 61 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 62 import com.android.car.internal.util.IndentingPrintWriter; 63 import com.android.car.power.CarPowerManagementService; 64 import com.android.car.user.CarUserService; 65 import com.android.internal.annotations.VisibleForTesting; 66 67 import java.io.PrintWriter; 68 import java.util.ArrayList; 69 import java.util.Iterator; 70 import java.util.List; 71 import java.util.Map; 72 import java.util.Objects; 73 import java.util.Set; 74 import java.util.concurrent.ConcurrentHashMap; 75 import java.util.concurrent.Executor; 76 77 /** 78 * Class that responsible for controlling vendor services that was opted in to be bound/started 79 * by the Car Service. 80 * 81 * <p>Thread-safety note: all code runs in the {@code Handler} provided in the constructor, whenever 82 * possible pass {@link #mHandler} when subscribe for callbacks otherwise redirect code to the 83 * handler. 84 */ 85 final class VendorServiceController implements UserLifecycleListener { 86 87 @VisibleForTesting 88 static final String TAG = CarLog.tagFor(VendorServiceController.class); 89 90 private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG); 91 private static final String PACKAGE_DATA_SCHEME = "package"; 92 93 private final List<VendorServiceInfo> mVendorServiceInfos = new ArrayList<>(); 94 private final Map<ConnectionKey, VendorServiceConnection> mConnections = 95 new ConcurrentHashMap<>(); 96 private final Context mContext; 97 private final UserManager mUserManager; 98 private final Handler mHandler; 99 private CarUserService mCarUserService; 100 private CarPowerManagementService mPowerManagementService; 101 102 private final BroadcastReceiver mPackageChangeReceiver = new BroadcastReceiver() { 103 @Override 104 public void onReceive(Context context, Intent intent) { 105 String action = intent.getAction(); 106 if (DBG) { 107 Slogf.d(TAG_AM, "Package change received with action = %s", action); 108 } 109 110 Uri packageData = intent.getData(); 111 if (packageData == null) { 112 Slogf.wtf(TAG_AM, "null packageData"); 113 return; 114 } 115 String packageName = packageData.getSchemeSpecificPart(); 116 if (packageName == null) { 117 Slogf.w(TAG_AM, "null packageName"); 118 return; 119 } 120 int uid = intent.getIntExtra(Intent.EXTRA_UID, INVALID_UID); 121 int userId = UserHandle.getUserHandleForUid(uid).getIdentifier(); 122 123 switch (action) { 124 case Intent.ACTION_PACKAGE_CHANGED: 125 // Fall through 126 case Intent.ACTION_PACKAGE_REPLACED: 127 // Fall through 128 case Intent.ACTION_PACKAGE_ADDED: 129 startOrBindServiceForPackage(packageName, userId); 130 break; 131 case Intent.ACTION_PACKAGE_REMOVED: 132 stopOrUnbindService(packageName, userId); 133 break; 134 default: 135 Slogf.w(TAG_AM, "This package change event (%s) can't be handled.", 136 action); 137 } 138 } 139 }; 140 141 private final ICarPowerStateListener mCarPowerStateListener = 142 new ICarPowerStateListener.Stub() { 143 @Override 144 public void onStateChanged(int state, long expirationTimeMs) { 145 if (DBG) { 146 Slogf.d(TAG, "Power state change received. State = %d", state); 147 } 148 if (state == CarPowerManager.STATE_HIBERNATION_EXIT 149 || state == CarPowerManager.STATE_SUSPEND_EXIT) { 150 onPowerResumed(); 151 } 152 } 153 }; 154 VendorServiceController(Context context, Looper looper)155 VendorServiceController(Context context, Looper looper) { 156 mContext = context; 157 mUserManager = context.getSystemService(UserManager.class); 158 mHandler = new Handler(looper); 159 } 160 init()161 void init() { 162 if (!loadXmlConfiguration()) { 163 return; // Nothing to do 164 } 165 166 mPowerManagementService = CarLocalServices.getService(CarPowerManagementService.class); 167 mCarUserService = CarLocalServices.getService(CarUserService.class); 168 UserLifecycleEventFilter userLifecycleEventFilter = 169 new UserLifecycleEventFilter.Builder() 170 .addEventType(USER_LIFECYCLE_EVENT_TYPE_SWITCHING) 171 .addEventType(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) 172 .addEventType(USER_LIFECYCLE_EVENT_TYPE_VISIBLE) 173 .addEventType(USER_LIFECYCLE_EVENT_TYPE_INVISIBLE) 174 .addEventType(USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED).build(); 175 mCarUserService.addUserLifecycleListener(userLifecycleEventFilter, this); 176 177 startOrBindServicesIfNeeded(); 178 mPowerManagementService.registerListener(mCarPowerStateListener); 179 registerPackageChangeReceiver(); 180 } 181 release()182 void release() { 183 if (mVendorServiceInfos.isEmpty()) { 184 Slogf.d(TAG_AM, "Releasing VendorServiceController without deep cleaning as no vendor " 185 + "service info present. "); 186 return; 187 } 188 if (mCarUserService != null) { 189 mCarUserService.removeUserLifecycleListener(this); 190 } 191 unregisterPackageChangeReceiver(); 192 mPowerManagementService.unregisterListener(mCarPowerStateListener); 193 for (ConnectionKey key : mConnections.keySet()) { 194 stopOrUnbindService(key.mVendorServiceInfo, key.mUserHandle); 195 } 196 mVendorServiceInfos.clear(); 197 mConnections.clear(); 198 } 199 200 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dump(IndentingPrintWriter writer)201 public void dump(IndentingPrintWriter writer) { 202 writer.println("VendorServiceController:"); 203 204 writer.increaseIndent(); 205 writer.printf("DBG=%b\n", DBG); 206 207 writer.println("VendorServiceInfo:"); 208 writer.increaseIndent(); 209 for (VendorServiceInfo info : mVendorServiceInfos) { 210 writer.println(info.toString()); 211 } 212 writer.decreaseIndent(); // end of VendorServiceInfo: 213 214 writer.println("Connections:"); 215 writer.increaseIndent(); 216 for (VendorServiceConnection connection : mConnections.values()) { 217 connection.dump(writer); 218 } 219 writer.decreaseIndent(); // end of Connections: 220 221 writer.decreaseIndent(); // end of VendorServiceController: 222 } 223 224 @Override onEvent(UserLifecycleEvent event)225 public void onEvent(UserLifecycleEvent event) { 226 if (DBG) { 227 Slogf.d(TAG, "onEvent(" + event + ")"); 228 } 229 int userId = event.getUserId(); 230 switch (event.getEventType()) { 231 case USER_LIFECYCLE_EVENT_TYPE_VISIBLE: 232 mHandler.post(() -> handleOnUserVisible(userId)); 233 break; 234 case USER_LIFECYCLE_EVENT_TYPE_INVISIBLE: 235 mHandler.post(() -> handleOnUserInvisible(userId)); 236 break; 237 case USER_LIFECYCLE_EVENT_TYPE_SWITCHING: 238 mHandler.post(() -> handleOnUserSwitching(userId)); 239 break; 240 case USER_LIFECYCLE_EVENT_TYPE_UNLOCKED: 241 mHandler.post(() -> handleOnUserUnlocked(userId, /* forPostUnlock= */ false)); 242 break; 243 case USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED: 244 mHandler.post(() -> handleOnUserUnlocked(userId, /* forPostUnlock= */ true)); 245 break; 246 default: 247 // Shouldn't happen as listener was registered with filter 248 Slogf.wtf(TAG, "Invalid event: %s", event); 249 } 250 } 251 252 /** Handles power resume events, starting services with `trigger=resume`. */ onPowerResumed()253 private void onPowerResumed() { 254 if (DBG) { 255 Slogf.d(TAG, "onPowerResumed()"); 256 } 257 258 int size = mVendorServiceInfos.size(); 259 for (int i = 0; i < size; i++) { 260 VendorServiceInfo serviceInfo = mVendorServiceInfos.get(i); 261 // RESUME events handle the system user only. Current or visible users are handled by 262 // user lifecycle events (unlock, visible, etc). 263 boolean isForSystemOrAllUsers = serviceInfo.isSystemUserService(); 264 boolean isResumeTrigger = serviceInfo.shouldStartOnResume(); 265 if (isForSystemOrAllUsers && isResumeTrigger) { 266 startOrBindService(serviceInfo, UserHandle.SYSTEM); 267 } 268 } 269 } 270 registerPackageChangeReceiver()271 private void registerPackageChangeReceiver() { 272 IntentFilter filter = new IntentFilter(); 273 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 274 filter.addAction(Intent.ACTION_PACKAGE_REPLACED); 275 filter.addAction(Intent.ACTION_PACKAGE_ADDED); 276 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 277 filter.addDataScheme(PACKAGE_DATA_SCHEME); 278 mContext.registerReceiverForAllUsers(mPackageChangeReceiver, filter, 279 /* broadcastPermission= */ null, /* scheduler= */ null, 280 Context.RECEIVER_NOT_EXPORTED); 281 } 282 unregisterPackageChangeReceiver()283 private void unregisterPackageChangeReceiver() { 284 mContext.unregisterReceiver(mPackageChangeReceiver); 285 } 286 startOrBindServiceForPackage(String packageName, @UserIdInt int userId)287 private void startOrBindServiceForPackage(String packageName, @UserIdInt int userId) { 288 if (DBG) { 289 Slogf.d(TAG, "startOrBindServiceForPackage() for package=%s, userId=%d", 290 packageName, userId); 291 } 292 293 int currentUserId = ActivityManager.getCurrentUser(); 294 int size = mVendorServiceInfos.size(); 295 for (int i = 0; i < size; i++) { 296 VendorServiceInfo serviceInfo = mVendorServiceInfos.get(i); 297 // Start or bind the service when the package name matches and the user is in scope. 298 if (packageName.equals(serviceInfo.getIntent().getComponent().getPackageName()) 299 && isUserInScope(userId, serviceInfo, mCarUserService, currentUserId)) { 300 startOrBindService(serviceInfo, UserHandle.of(userId)); 301 } 302 } 303 } 304 305 /** Checks if the given {@code serviceInfo} satisfies the user scope. */ isUserInScope(@serIdInt int userId, VendorServiceInfo serviceInfo, CarUserService carUserService, @UserIdInt int currentUserId)306 private static boolean isUserInScope(@UserIdInt int userId, VendorServiceInfo serviceInfo, 307 CarUserService carUserService, @UserIdInt int currentUserId) { 308 boolean isSystemUser = userId == UserHandle.SYSTEM.getIdentifier(); 309 boolean isCurrentUser = userId == currentUserId; 310 311 return (isSystemUser && serviceInfo.isSystemUserService()) 312 || (isCurrentUser && serviceInfo.isForegroundUserService()) 313 || ((serviceInfo.isVisibleUserService() 314 || (!isCurrentUser && serviceInfo.isBackgroundVisibleUserService())) 315 && carUserService.isUserVisible(userId)); 316 } 317 handleOnUserSwitching(@serIdInt int userId)318 private void handleOnUserSwitching(@UserIdInt int userId) { 319 // The user switch notification is obsolete if userId is different from the current 320 // foreground user. Ignore it. 321 int currentUserId = ActivityManager.getCurrentUser(); 322 if (currentUserId != userId) { 323 Slogf.w(TAG, "Received userSwitch event for user " + userId 324 + " while current foreground user is " + currentUserId + "." 325 + " Ignore the switch user event."); 326 return; 327 } 328 329 // Clean up the services which do not satisfy their configured user scope. 330 for (VendorServiceConnection connection : mConnections.values()) { 331 int connectedUserId = connection.mUser.getIdentifier(); 332 if (!isUserInScope(connectedUserId, connection.mVendorServiceInfo, mCarUserService, 333 currentUserId)) { 334 connection.stopOrUnbindService(); 335 } 336 } 337 338 if (userId != UserHandle.SYSTEM.getIdentifier()) { 339 startOrBindServicesForUser(UserHandle.of(userId), /* forPostUnlock= */ null); 340 } else { 341 Slogf.wtf(TAG, "Unexpected to receive switch user event for system user"); 342 } 343 } 344 handleOnUserInvisible(@serIdInt int userId)345 private void handleOnUserInvisible(@UserIdInt int userId) { 346 if (DBG) { 347 Slogf.d(TAG, "handleOnUserInvisible(): user=%d", userId); 348 } 349 350 for (VendorServiceConnection connection : mConnections.values()) { 351 VendorServiceInfo serviceInfo = connection.mVendorServiceInfo; 352 if (connection.isUser(userId) 353 && (serviceInfo.isVisibleUserService() 354 || serviceInfo.isBackgroundVisibleUserService()) 355 && !serviceInfo.isAllUserService()) { 356 connection.stopOrUnbindService(); 357 } 358 } 359 } 360 handleOnUserVisible(@serIdInt int userId)361 private void handleOnUserVisible(@UserIdInt int userId) { 362 if (DBG) { 363 Slogf.d(TAG, "handleOnUserVisible(): user=%d", userId); 364 } 365 366 startOrBindServicesForUser(UserHandle.of(userId), /* forPostUnlock= */ null); 367 } 368 handleOnUserUnlocked(@serIdInt int userId, boolean forPostUnlock)369 private void handleOnUserUnlocked(@UserIdInt int userId, boolean forPostUnlock) { 370 if (DBG) { 371 Slogf.d(TAG, "handleOnUserUnlocked(): user=%d", userId); 372 } 373 374 startOrBindServicesForUser(UserHandle.of(userId), forPostUnlock); 375 } 376 startOrBindServicesForUser(UserHandle user, @Nullable Boolean forPostUnlock)377 private void startOrBindServicesForUser(UserHandle user, @Nullable Boolean forPostUnlock) { 378 boolean unlocked = mUserManager.isUserUnlockingOrUnlocked(user); 379 int currentUserId = ActivityManager.getCurrentUser(); 380 int userId = user.getIdentifier(); 381 for (VendorServiceInfo service: mVendorServiceInfos) { 382 if (forPostUnlock != null 383 && service.shouldStartOnPostUnlock() != forPostUnlock.booleanValue()) { 384 continue; 385 } 386 387 boolean userScopeChecked = isUserInScope(userId, service, mCarUserService, 388 currentUserId); 389 boolean triggerChecked = service.shouldStartAsap() || unlocked; 390 391 if (userScopeChecked && triggerChecked) { 392 startOrBindService(service, user); 393 } 394 } 395 } 396 397 @SuppressLint("NewApi") startOrBindServicesIfNeeded()398 private void startOrBindServicesIfNeeded() { 399 // Start/bind service for system user. 400 startOrBindServicesForUser(UserHandle.SYSTEM, /* forPostUnlock= */ null); 401 402 if (!isPlatformVersionAtLeastU()) { 403 // `user=visible` is not supported before U. Just need to handle the current user. 404 startOrBindServicesForUser(UserHandle.of(ActivityManager.getCurrentUser()), 405 /* forPostUnlock= */ null); 406 } else { 407 // Start/bind service for all visible users. 408 Set<UserHandle> visibleUsers = mUserManager.getVisibleUsers(); 409 for (Iterator<UserHandle> iterator = visibleUsers.iterator(); iterator.hasNext(); ) { 410 UserHandle userHandle = iterator.next(); 411 startOrBindServicesForUser(userHandle, /* forPostUnlock= */ null); 412 } 413 } 414 } 415 startOrBindService(VendorServiceInfo service, UserHandle user)416 private void startOrBindService(VendorServiceInfo service, UserHandle user) { 417 ConnectionKey key = ConnectionKey.of(service, user); 418 VendorServiceConnection connection = getOrCreateConnection(key); 419 if (!connection.startOrBindService()) { 420 Slogf.e(TAG, "Failed to start or bind service " + service); 421 mConnections.remove(key); 422 } 423 } 424 stopOrUnbindService(VendorServiceInfo service, UserHandle user)425 private void stopOrUnbindService(VendorServiceInfo service, UserHandle user) { 426 ConnectionKey key = ConnectionKey.of(service, user); 427 VendorServiceConnection connection = mConnections.get(key); 428 if (connection != null) { 429 connection.stopOrUnbindService(); 430 } 431 } 432 433 /** 434 * Unbinds the VendorServiceController from all the services with the given {@code packageName} 435 * and running as {@code userId}. 436 */ stopOrUnbindService(String packageName, @UserIdInt int userId)437 private void stopOrUnbindService(String packageName, @UserIdInt int userId) { 438 for (VendorServiceConnection connection : mConnections.values()) { 439 if (connection.isUser(userId) 440 && packageName.equals(connection.mVendorServiceInfo.getIntent().getComponent() 441 .getPackageName())) { 442 Slogf.d(TAG, "Stopping the connection to service %s", 443 connection.mVendorServiceInfo); 444 connection.stopOrUnbindService(); 445 } 446 } 447 } 448 getOrCreateConnection(ConnectionKey key)449 private VendorServiceConnection getOrCreateConnection(ConnectionKey key) { 450 VendorServiceConnection connection = mConnections.get(key); 451 if (connection == null) { 452 connection = new VendorServiceConnection(mContext, mHandler, key.mVendorServiceInfo, 453 key.mUserHandle); 454 mConnections.put(key, connection); 455 } 456 457 return connection; 458 } 459 460 /** Loads data from XML resources and returns true if any services needs to be started/bound. */ loadXmlConfiguration()461 private boolean loadXmlConfiguration() { 462 final Resources res = mContext.getResources(); 463 for (String rawServiceInfo: res.getStringArray(R.array.config_earlyStartupServices)) { 464 if (TextUtils.isEmpty(rawServiceInfo)) { 465 continue; 466 } 467 VendorServiceInfo service = VendorServiceInfo.parse(rawServiceInfo); 468 // `user=visible` and `user=backgroundVisible` are not supported before U. 469 // Log an error and ignore the service. 470 if ((service.isVisibleUserService() || service.isBackgroundVisibleUserService()) 471 && !service.isAllUserService() && !isPlatformVersionAtLeastU()) { 472 Slogf.e(TAG, "user=visible and user=backgroundVisible are not supported in " 473 + "this platform version. %s is ignored. Check your config.xml file.", 474 service.toShortString()); 475 continue; 476 } 477 mVendorServiceInfos.add(service); 478 if (DBG) { 479 Slogf.i(TAG, "Registered vendor service: " + service); 480 } 481 } 482 Slogf.i(TAG, "Found " + mVendorServiceInfos.size() 483 + " services to be started/bound"); 484 485 return !mVendorServiceInfos.isEmpty(); 486 } 487 488 /** 489 * Represents connection to the vendor service. 490 */ 491 @VisibleForTesting 492 public static final class VendorServiceConnection implements ServiceConnection, Executor { 493 private static final int INITIAL_REBIND_DELAY_MS = 4000; // 4 sec. 494 private static final int DEFAULT_FAILURE_COUNTER_RESET_TIMEOUT = 5 * 60 * 1000; // 5 min. 495 private static final int MSG_REBIND = 0; 496 private static final int MSG_FAILURE_COUNTER_RESET = 1; 497 498 private int mRecentFailures = 0; 499 private boolean mBound = false; 500 private boolean mStarted = false; 501 private boolean mStopRequested = false; 502 private final VendorServiceInfo mVendorServiceInfo; 503 private final UserHandle mUser; 504 private final CarUserService mCarUserService; 505 private final Context mUserContext; 506 private final Handler mHandler; 507 private final Handler mFailureHandler; 508 VendorServiceConnection(Context context, Handler handler, VendorServiceInfo vendorServiceInfo, UserHandle user)509 VendorServiceConnection(Context context, Handler handler, 510 VendorServiceInfo vendorServiceInfo, UserHandle user) { 511 mHandler = handler; 512 mVendorServiceInfo = vendorServiceInfo; 513 mUser = user; 514 mUserContext = context.createContextAsUser(mUser, /* flags= */ 0); 515 mCarUserService = CarLocalServices.getService(CarUserService.class); 516 517 mFailureHandler = new Handler(handler.getLooper()) { 518 @Override 519 public void handleMessage(Message msg) { 520 handleFailureMessage(msg); 521 } 522 }; 523 } 524 525 @Override toString()526 public String toString() { 527 return "VendorServiceConnection[user=" + mUser 528 + ", service=" + mVendorServiceInfo + "]"; 529 } 530 531 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dump(PrintWriter writer)532 public void dump(PrintWriter writer) { 533 writer.printf("%s, mRecentFailures=%d, mBound=%b, mStarted=%b, mStopRequested=%b\n", 534 toString(), mRecentFailures, mBound, mStarted, mStopRequested); 535 } 536 isUser(@serIdInt int userId)537 private boolean isUser(@UserIdInt int userId) { 538 return mUser.getIdentifier() == userId; 539 } 540 startOrBindService()541 boolean startOrBindService() { 542 if (mStarted || mBound) { 543 return true; // Already started or bound 544 } 545 546 if (DBG) { 547 Slogf.d(TAG, "startOrBindService " 548 + mVendorServiceInfo.toShortString() + ", as user: " + mUser + ", bind: " 549 + mVendorServiceInfo.shouldBeBound()); 550 } 551 mStopRequested = false; 552 553 Intent intent = mVendorServiceInfo.getIntent(); 554 if (mVendorServiceInfo.shouldBeBound()) { 555 return mUserContext.bindService(intent, BIND_AUTO_CREATE, /* executor= */ this, 556 /* conn= */ this); 557 } else if (mVendorServiceInfo.shouldBeStartedInForeground()) { 558 mStarted = mUserContext.startForegroundService(intent) != null; 559 return mStarted; 560 } else { 561 mStarted = mUserContext.startService(intent) != null; 562 return mStarted; 563 } 564 } 565 stopOrUnbindService()566 void stopOrUnbindService() { 567 mStopRequested = true; 568 if (mStarted) { 569 if (DBG) Slogf.d(TAG, "Stopping %s", this); 570 mUserContext.stopService(mVendorServiceInfo.getIntent()); 571 mStarted = false; 572 } else if (mBound) { 573 if (DBG) Slogf.d(TAG, "Unbinding %s", this); 574 mUserContext.unbindService(this); 575 mBound = false; 576 } 577 } 578 579 @Override // From Executor execute(Runnable command)580 public void execute(Runnable command) { 581 mHandler.post(command); 582 } 583 584 @Override onServiceConnected(ComponentName name, IBinder service)585 public void onServiceConnected(ComponentName name, IBinder service) { 586 mBound = true; 587 if (DBG) { 588 Slogf.d(TAG, "onServiceConnected, name: %s", name); 589 } 590 if (mStopRequested) { 591 stopOrUnbindService(); 592 } 593 } 594 595 @Override onServiceDisconnected(ComponentName name)596 public void onServiceDisconnected(ComponentName name) { 597 mBound = false; 598 if (DBG) { 599 Slogf.d(TAG, "onServiceDisconnected, name: " + name); 600 } 601 tryToRebind(); 602 } 603 604 @Override onBindingDied(ComponentName name)605 public void onBindingDied(ComponentName name) { 606 mBound = false; 607 if (DBG) { 608 Slogf.d(TAG, "onBindingDied, name: " + name); 609 } 610 tryToRebind(); 611 } 612 tryToRebind()613 private void tryToRebind() { 614 if (mStopRequested) { 615 return; 616 } 617 618 if (mFailureHandler.hasMessages(MSG_REBIND)) { 619 if (DBG) { 620 Slogf.d(TAG, "Rebind already scheduled for " 621 + mVendorServiceInfo.toShortString()); 622 } 623 return; 624 } 625 626 int currentUserId = ActivityManager.getCurrentUser(); 627 if (isUserInScope(mUser.getIdentifier(), mVendorServiceInfo, mCarUserService, 628 currentUserId)) { 629 // Double the delay after each failure. 630 int rebindDelay = INITIAL_REBIND_DELAY_MS * (1 << mRecentFailures); 631 Slogf.i(TAG, "tryToRebind(): after " + mRecentFailures + " recent failures," 632 + " trying to rebind service " + mVendorServiceInfo.toShortString() 633 + " for user " + mUser.getIdentifier() + " in " + rebindDelay + "ms"); 634 mFailureHandler.sendMessageDelayed( 635 mFailureHandler.obtainMessage(MSG_REBIND), rebindDelay); 636 scheduleResetFailureCounter(); 637 } else { 638 Slogf.w(TAG, "No need to rebind anymore as the service no longer satisfies " 639 + " the user scope."); 640 } 641 } 642 scheduleResetFailureCounter()643 private void scheduleResetFailureCounter() { 644 mFailureHandler.removeMessages(MSG_FAILURE_COUNTER_RESET); 645 // Reset the failure counter after the timeout. We take the max, to ensure 646 // that we are not resetting the counter before exhausting all retries. 647 int failureCounterResetTimeout = 648 INITIAL_REBIND_DELAY_MS * (1 << (mVendorServiceInfo.getMaxRetries() + 1)); 649 failureCounterResetTimeout = 650 failureCounterResetTimeout > DEFAULT_FAILURE_COUNTER_RESET_TIMEOUT 651 ? failureCounterResetTimeout : DEFAULT_FAILURE_COUNTER_RESET_TIMEOUT; 652 mFailureHandler.sendMessageDelayed( 653 mFailureHandler.obtainMessage(MSG_FAILURE_COUNTER_RESET), 654 failureCounterResetTimeout); 655 } 656 handleFailureMessage(Message msg)657 private void handleFailureMessage(Message msg) { 658 switch (msg.what) { 659 case MSG_REBIND: { 660 if (mBound) { 661 Slogf.d(TAG, "Service " + mVendorServiceInfo.toShortString() 662 + " is already bound. Ignoring MSG_REBIND"); 663 } else if (mRecentFailures < mVendorServiceInfo.getMaxRetries()) { 664 Slogf.i(TAG, "Attempting to rebind to the service " 665 + mVendorServiceInfo.toShortString() + " (" + (mRecentFailures + 1) 666 + " out of " + mVendorServiceInfo.getMaxRetries() + " max tries)"); 667 ++mRecentFailures; 668 startOrBindService(); 669 } else { 670 Slogf.w(TAG, "Exceeded maximum number of attempts (" 671 + mVendorServiceInfo.getMaxRetries() + ") to rebind to the service " 672 + mVendorServiceInfo.toShortString()); 673 } 674 break; 675 } 676 case MSG_FAILURE_COUNTER_RESET: 677 mRecentFailures = 0; 678 break; 679 default: 680 Slogf.e(TAG, "Unexpected message received in failure handler: " + msg.what); 681 } 682 } 683 } 684 685 /** Defines a key in the HashMap to store connection on per user and vendor service basis */ 686 private static class ConnectionKey { 687 private final UserHandle mUserHandle; 688 private final VendorServiceInfo mVendorServiceInfo; 689 ConnectionKey(VendorServiceInfo service, UserHandle user)690 private ConnectionKey(VendorServiceInfo service, UserHandle user) { 691 mVendorServiceInfo = service; 692 mUserHandle = user; 693 } 694 of(VendorServiceInfo service, UserHandle user)695 static ConnectionKey of(VendorServiceInfo service, UserHandle user) { 696 return new ConnectionKey(service, user); 697 } 698 699 @Override equals(Object o)700 public boolean equals(Object o) { 701 if (this == o) { 702 return true; 703 } 704 if (!(o instanceof ConnectionKey)) { 705 return false; 706 } 707 ConnectionKey that = (ConnectionKey) o; 708 return Objects.equals(mUserHandle, that.mUserHandle) 709 && Objects.equals(mVendorServiceInfo, that.mVendorServiceInfo); 710 } 711 712 @Override hashCode()713 public int hashCode() { 714 return Objects.hash(mUserHandle, mVendorServiceInfo); 715 } 716 } 717 } 718