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