1 /* 2 * Copyright (C) 2022 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.remoteaccess; 18 19 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED; 20 import static android.content.Context.BIND_AUTO_CREATE; 21 22 import static com.android.car.CarServiceUtils.isEventOfType; 23 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE; 24 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO; 25 26 import android.annotation.Nullable; 27 import android.app.ActivityManager; 28 import android.car.Car; 29 import android.car.builtin.util.Slogf; 30 import android.car.hardware.power.CarPowerManager; 31 import android.car.hardware.power.ICarPowerStateListener; 32 import android.car.remoteaccess.CarRemoteAccessManager; 33 import android.car.remoteaccess.ICarRemoteAccessCallback; 34 import android.car.remoteaccess.ICarRemoteAccessService; 35 import android.car.remoteaccess.RemoteTaskClientRegistrationInfo; 36 import android.car.user.CarUserManager.UserLifecycleListener; 37 import android.car.user.UserLifecycleEventFilter; 38 import android.content.ComponentName; 39 import android.content.Context; 40 import android.content.Intent; 41 import android.content.ServiceConnection; 42 import android.content.pm.PackageManager; 43 import android.content.pm.ResolveInfo; 44 import android.content.pm.ServiceInfo; 45 import android.hardware.automotive.remoteaccess.IRemoteAccess; 46 import android.os.Binder; 47 import android.os.Handler; 48 import android.os.HandlerThread; 49 import android.os.IBinder; 50 import android.os.Looper; 51 import android.os.Message; 52 import android.os.RemoteException; 53 import android.os.SystemClock; 54 import android.os.UserHandle; 55 import android.os.UserManager; 56 import android.util.ArrayMap; 57 import android.util.ArraySet; 58 import android.util.Log; 59 import android.util.SparseArray; 60 61 import com.android.car.CarLocalServices; 62 import com.android.car.CarLog; 63 import com.android.car.CarServiceBase; 64 import com.android.car.CarServiceUtils; 65 import com.android.car.R; 66 import com.android.car.hal.PowerHalService; 67 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 68 import com.android.car.internal.util.IndentingPrintWriter; 69 import com.android.car.power.CarPowerManagementService; 70 import com.android.car.remoteaccess.RemoteAccessStorage.ClientIdEntry; 71 import com.android.car.remoteaccess.hal.RemoteAccessHalCallback; 72 import com.android.car.remoteaccess.hal.RemoteAccessHalWrapper; 73 import com.android.car.systeminterface.SystemInterface; 74 import com.android.car.user.CarUserService; 75 import com.android.internal.annotations.GuardedBy; 76 import com.android.internal.annotations.VisibleForTesting; 77 import com.android.internal.util.Preconditions; 78 79 import java.lang.ref.WeakReference; 80 import java.time.Duration; 81 import java.util.ArrayList; 82 import java.util.List; 83 import java.util.Set; 84 import java.util.concurrent.atomic.AtomicBoolean; 85 import java.util.concurrent.atomic.AtomicLong; 86 import java.util.concurrent.atomic.AtomicReference; 87 88 /** 89 * Service to implement CarRemoteAccessManager API. 90 */ 91 public final class CarRemoteAccessService extends ICarRemoteAccessService.Stub 92 implements CarServiceBase { 93 94 private static final String TAG = CarLog.tagFor(CarRemoteAccessService.class); 95 private static final boolean DEBUG = Slogf.isLoggable(TAG, Log.DEBUG); 96 private static final int MILLI_TO_SECOND = 1000; 97 private static final String TASK_PREFIX = "task"; 98 private static final String CLIENT_PREFIX = "client"; 99 private static final int RANDOM_STRING_LENGTH = 12; 100 private static final int MIN_SYSTEM_UPTIME_FOR_REMOTE_ACCESS_IN_SEC = 30; 101 // Client ID remains valid for 30 days since issued. 102 private static final long CLIENT_ID_EXPIRATION_IN_MILLIS = 30L * 24L * 60L * 60L * 1000L; 103 private static final Duration PACKAGE_SEARCH_DELAY = Duration.ofSeconds(1); 104 // Remote task client can use up to 30 seconds to initialize and upload necessary info to the 105 // server. 106 private static final long ALLOWED_TIME_FOR_REMOTE_TASK_CLIENT_INIT_MS = 30_000; 107 private static final long SHUTDOWN_WARNING_MARGIN_IN_MS = 5000; 108 private static final long INVALID_ALLOWED_SYSTEM_UPTIME = -1; 109 private static final int NOTIFY_AP_STATE_RETRY_SLEEP_IN_MS = 100; 110 private static final int NOTIFY_AP_STATE_MAX_RETRY = 10; 111 // The buffer time after all the tasks for a specific remote task client service is completed 112 // before we unbind the service. 113 private static final int TASK_UNBIND_DELAY_MS = 1000; 114 // The max time in ms allowed for a task after it is received by the car service, before the 115 // remote task client service is started and it is delivered to that service. This period will 116 // include waiting for the remote task client service to be started if it is not already bound. 117 private static final int MAX_TASK_PENDING_MS = 60_000; 118 119 private final Object mLock = new Object(); 120 private final Context mContext; 121 private final PackageManager mPackageManager; 122 private final HandlerThread mHandlerThread = 123 CarServiceUtils.getHandlerThread(getClass().getSimpleName()); 124 private final RemoteTaskClientServiceHandler mHandler = 125 new RemoteTaskClientServiceHandler(mHandlerThread.getLooper(), this); 126 private long mAllowedTimeForRemoteTaskClientInitMs = 127 ALLOWED_TIME_FOR_REMOTE_TASK_CLIENT_INIT_MS; 128 private long mTaskUnbindDelayMs = TASK_UNBIND_DELAY_MS; 129 private long mMaxTaskPendingMs = MAX_TASK_PENDING_MS; 130 private final AtomicLong mTaskCount = new AtomicLong(/* initialValue= */ 0); 131 private final AtomicLong mClientCount = new AtomicLong(/* initialValue= */ 0); 132 @GuardedBy("mLock") 133 private final ArrayMap<String, String> mUidByClientId = new ArrayMap<>(); 134 @GuardedBy("mLock") 135 private final ArrayMap<String, ArrayList<RemoteTask>> mTasksToBeNotifiedByClientId = 136 new ArrayMap<>(); 137 @GuardedBy("mLock") 138 private final ArrayMap<String, ClientToken> mClientTokenByUidName = new ArrayMap<>(); 139 @GuardedBy("mLock") 140 private final ArrayMap<String, RemoteTaskClientServiceInfo> mClientServiceInfoByUid = 141 new ArrayMap<>(); 142 @GuardedBy("mLock") 143 private boolean mIsReadyForRemoteTask; 144 @GuardedBy("mLock") 145 private boolean mIsWakeupRequired; 146 @GuardedBy("mLock") 147 private int mNotifyApPowerStateRetryCount; 148 @GuardedBy("mLock") 149 private final ArrayMap<String, Integer> mUidByName = new ArrayMap<>(); 150 @GuardedBy("mLock") 151 private final SparseArray<String> mNameByUid = new SparseArray<>(); 152 153 private final RemoteAccessStorage mRemoteAccessStorage; 154 155 private final ICarPowerStateListener mCarPowerStateListener = 156 new ICarPowerStateListener.Stub() { 157 @Override 158 public void onStateChanged(int state, long expirationTimeMs) { 159 // isReadyForRemoteTask and isWakeupRequired are only valid when apStateChangeRequired 160 // is true. 161 Slogf.i(TAG, "power state change, new state: %d", state); 162 boolean apStateChangeRequired = false; 163 boolean isReadyForRemoteTask = false; 164 boolean isWakeupRequired = false; 165 boolean needsComplete = false; 166 167 switch (state) { 168 case CarPowerManager.STATE_SHUTDOWN_PREPARE: 169 apStateChangeRequired = true; 170 isReadyForRemoteTask = false; 171 isWakeupRequired = false; 172 173 needsComplete = true; 174 // If this shutdown is initiated by remote access service, then all remote task 175 // client services should already be unbound and this will do nothing. This is 176 // useful for cases when the shutdown is not initiated by us (e.g. by user). 177 unbindAllServices(); 178 break; 179 case CarPowerManager.STATE_WAIT_FOR_VHAL: 180 case CarPowerManager.STATE_SUSPEND_EXIT: 181 case CarPowerManager.STATE_HIBERNATION_EXIT: 182 apStateChangeRequired = true; 183 isReadyForRemoteTask = true; 184 isWakeupRequired = false; 185 break; 186 case CarPowerManager.STATE_POST_SHUTDOWN_ENTER: 187 case CarPowerManager.STATE_POST_SUSPEND_ENTER: 188 case CarPowerManager.STATE_POST_HIBERNATION_ENTER: 189 apStateChangeRequired = true; 190 isReadyForRemoteTask = false; 191 isWakeupRequired = true; 192 193 needsComplete = true; 194 break; 195 } 196 if (apStateChangeRequired) { 197 synchronized (mLock) { 198 mIsReadyForRemoteTask = isReadyForRemoteTask; 199 mIsWakeupRequired = isWakeupRequired; 200 } 201 mHandler.cancelNotifyApStateChange(); 202 if (!mRemoteAccessHalWrapper.notifyApStateChange( 203 isReadyForRemoteTask, isWakeupRequired)) { 204 Slogf.e(TAG, "Cannot notify AP state change according to power state(%d)", 205 state); 206 } 207 } 208 if (needsComplete) { 209 mPowerService.finished(state, this); 210 } 211 } 212 }; 213 maybeStartNewRemoteTask(String clientId)214 private void maybeStartNewRemoteTask(String clientId) { 215 ICarRemoteAccessCallback callback; 216 List<RemoteTask> remoteTasksToNotify = null; 217 RemoteTaskClientServiceInfo serviceInfo; 218 int taskMaxDurationInSec; 219 long taskMaxDurationInMs; 220 String uidName; 221 ClientToken token; 222 223 synchronized (mLock) { 224 if (mTasksToBeNotifiedByClientId.get(clientId) == null) { 225 return; 226 } 227 taskMaxDurationInMs = calcTaskMaxDurationInMsLocked(); 228 taskMaxDurationInSec = (int) (taskMaxDurationInMs / MILLI_TO_SECOND); 229 if (taskMaxDurationInSec <= 0) { 230 Slogf.w(TAG, "onRemoteTaskRequested: system shutdown was supposed to start, " 231 + "but still on: expected shutdown time=%d, current time=%d", 232 mShutdownTimeInMs, SystemClock.uptimeMillis()); 233 // Remove all tasks for this client ID. 234 Slogf.w(TAG, "Removing all the pending tasks for client ID: %s", clientId); 235 mTasksToBeNotifiedByClientId.remove(clientId); 236 return; 237 } 238 // If this clientId has never been stored on this device before, 239 uidName = mUidByClientId.get(clientId); 240 if (uidName == null) { 241 Slogf.w(TAG, "Cannot notify task: client(%s) is not registered.", clientId); 242 Slogf.w(TAG, "Removing all the pending tasks for client ID: %s", clientId); 243 mTasksToBeNotifiedByClientId.remove(clientId); 244 return; 245 } 246 // Token must not be null if mUidByClientId contains clientId. 247 token = mClientTokenByUidName.get(uidName); 248 if (!token.isClientIdValid()) { 249 // TODO(b/266371728): Handle client ID expiration. 250 Slogf.w(TAG, "Cannot notify task: clientID has expired: token = %s", token); 251 Slogf.w(TAG, "Removing all the pending tasks for client ID: %s", clientId); 252 // Remove all tasks for this client ID. 253 mTasksToBeNotifiedByClientId.remove(clientId); 254 return; 255 } 256 serviceInfo = mClientServiceInfoByUid.get(uidName); 257 if (serviceInfo == null) { 258 Slogf.w(TAG, "Notifying task is delayed: the remote client service information " 259 + "for %s is not registered yet", uidName); 260 // We don't have to start the service explicitly because it will be started 261 // after searching for remote task client service is done. 262 return; 263 } 264 callback = token.getCallback(); 265 if (callback != null) { 266 remoteTasksToNotify = popTasksFromPendingQueueLocked(clientId); 267 } 268 } 269 // Always try to bind the remote task client service. This will starts the service if 270 // it is not active. This will also keep the service alive during the task period. 271 startRemoteTaskClientService(serviceInfo, uidName, taskMaxDurationInMs); 272 273 if (callback == null) { 274 Slogf.w(TAG, "Notifying task is delayed: the callback for token: %s " 275 + "is not registered yet", token); 276 return; 277 } 278 279 if (remoteTasksToNotify != null && !remoteTasksToNotify.isEmpty()) { 280 invokeTaskRequestCallbacks(serviceInfo.getServiceConnection(), callback, clientId, 281 remoteTasksToNotify, taskMaxDurationInSec); 282 } 283 } 284 285 private final RemoteAccessHalCallback mHalCallback = new RemoteAccessHalCallback() { 286 @Override 287 public void onRemoteTaskRequested(String clientId, byte[] data) { 288 if (DEBUG) { 289 Slogf.d(TAG, "Remote task is requested through the HAL to client(%s)", clientId); 290 } 291 String taskId = generateNewTaskId(); 292 long now = SystemClock.uptimeMillis(); 293 long timeoutInMs = now + mMaxTaskPendingMs; 294 synchronized (mLock) { 295 pushTaskToPendingQueueLocked(clientId, new RemoteTask(taskId, data, clientId, 296 timeoutInMs)); 297 } 298 maybeStartNewRemoteTask(clientId); 299 } 300 }; 301 private RemoteAccessHalWrapper mRemoteAccessHalWrapper; 302 private PowerHalService mPowerHalService; 303 private final UserManager mUserManager; 304 private final long mShutdownTimeInMs; 305 private final long mAllowedSystemUptimeMs; 306 307 private String mWakeupServiceName = ""; 308 private String mVehicleId = ""; 309 private String mProcessorId = ""; 310 @GuardedBy("mLock") 311 private int mNextPowerState; 312 @GuardedBy("mLock") 313 private boolean mRunGarageMode; 314 private CarPowerManagementService mPowerService; 315 private AtomicBoolean mInitialized; 316 317 private CarRemoteAccessServiceDep mDep; 318 CarRemoteAccessService(Context context, SystemInterface systemInterface, PowerHalService powerHalService)319 public CarRemoteAccessService(Context context, SystemInterface systemInterface, 320 PowerHalService powerHalService) { 321 this(context, systemInterface, powerHalService, /* dep= */ null, 322 /* remoteAccessHal= */ null, /* remoteAccessStorage= */ null, 323 INVALID_ALLOWED_SYSTEM_UPTIME, /* inMemoryStorage= */ false); 324 } 325 326 /** 327 * Dependencies for stubbing. 328 */ 329 @VisibleForTesting 330 public interface CarRemoteAccessServiceDep { 331 /** 332 * Gets the calling UID. Must be used in a binder context. 333 */ getCallingUid()334 int getCallingUid(); 335 336 /** 337 * Gets the current user. 338 */ getCurrentUser()339 int getCurrentUser(); 340 } 341 342 @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE) 343 private class CarRemoteAccessServiceDepImpl implements CarRemoteAccessServiceDep { getCallingUid()344 public int getCallingUid() { 345 return Binder.getCallingUid(); 346 } 347 getCurrentUser()348 public int getCurrentUser() { 349 return ActivityManager.getCurrentUser(); 350 } 351 } 352 353 @VisibleForTesting CarRemoteAccessService(Context context, SystemInterface systemInterface, PowerHalService powerHalService, @Nullable CarRemoteAccessServiceDep dep, @Nullable IRemoteAccess remoteAccessHal, @Nullable RemoteAccessStorage remoteAccessStorage, long allowedSystemUptimeMs, boolean inMemoryStorage)354 public CarRemoteAccessService(Context context, SystemInterface systemInterface, 355 PowerHalService powerHalService, @Nullable CarRemoteAccessServiceDep dep, 356 @Nullable IRemoteAccess remoteAccessHal, 357 @Nullable RemoteAccessStorage remoteAccessStorage, long allowedSystemUptimeMs, 358 boolean inMemoryStorage) { 359 mContext = context; 360 mUserManager = mContext.getSystemService(UserManager.class); 361 mPowerHalService = powerHalService; 362 mDep = dep != null ? dep : new CarRemoteAccessServiceDepImpl(); 363 mPackageManager = mContext.getPackageManager(); 364 mRemoteAccessHalWrapper = new RemoteAccessHalWrapper(mHalCallback, remoteAccessHal); 365 mAllowedSystemUptimeMs = allowedSystemUptimeMs == INVALID_ALLOWED_SYSTEM_UPTIME 366 ? getAllowedSystemUptimeForRemoteTaskInMs() : allowedSystemUptimeMs; 367 mShutdownTimeInMs = SystemClock.uptimeMillis() + mAllowedSystemUptimeMs; 368 mRemoteAccessStorage = remoteAccessStorage != null ? remoteAccessStorage : 369 new RemoteAccessStorage(context, systemInterface, inMemoryStorage); 370 // TODO(b/263807920): CarService restart should be handled. 371 systemInterface.scheduleActionForBootCompleted(() -> searchForRemoteTaskClientPackages(), 372 PACKAGE_SEARCH_DELAY); 373 } 374 375 @VisibleForTesting setRemoteAccessHalWrapper(RemoteAccessHalWrapper remoteAccessHalWrapper)376 public void setRemoteAccessHalWrapper(RemoteAccessHalWrapper remoteAccessHalWrapper) { 377 mRemoteAccessHalWrapper = remoteAccessHalWrapper; 378 } 379 380 @VisibleForTesting setPowerHal(PowerHalService powerHalService)381 public void setPowerHal(PowerHalService powerHalService) { 382 mPowerHalService = powerHalService; 383 } 384 385 @VisibleForTesting setAllowedTimeForRemoteTaskClientInitMs(long allowedTimeForRemoteTaskClientInitMs)386 public void setAllowedTimeForRemoteTaskClientInitMs(long allowedTimeForRemoteTaskClientInitMs) { 387 mAllowedTimeForRemoteTaskClientInitMs = allowedTimeForRemoteTaskClientInitMs; 388 } 389 390 @VisibleForTesting setTaskUnbindDelayMs(long taskUnbindDelayMs)391 public void setTaskUnbindDelayMs(long taskUnbindDelayMs) { 392 mTaskUnbindDelayMs = taskUnbindDelayMs; 393 } 394 395 @VisibleForTesting setMaxTaskPendingMs(long maxTaskPendingMs)396 public void setMaxTaskPendingMs(long maxTaskPendingMs) { 397 mMaxTaskPendingMs = maxTaskPendingMs; 398 } 399 400 @Override init()401 public void init() { 402 mPowerService = CarLocalServices.getService(CarPowerManagementService.class); 403 populatePackageClientIdMapping(); 404 mRemoteAccessHalWrapper.init(); 405 try { 406 mWakeupServiceName = mRemoteAccessHalWrapper.getWakeupServiceName(); 407 mVehicleId = mRemoteAccessHalWrapper.getVehicleId(); 408 mProcessorId = mRemoteAccessHalWrapper.getProcessorId(); 409 } catch (IllegalStateException e) { 410 Slogf.e(TAG, e, "Cannot get vehicle/processor/service info from remote access HAL"); 411 } 412 synchronized (mLock) { 413 mNextPowerState = getLastShutdownState(); 414 mIsReadyForRemoteTask = true; 415 mIsWakeupRequired = false; 416 } 417 418 mPowerService.registerListenerWithCompletion(mCarPowerStateListener); 419 420 long delayForShutdowWarningMs = mAllowedSystemUptimeMs - SHUTDOWN_WARNING_MARGIN_IN_MS; 421 if (delayForShutdowWarningMs > 0) { 422 mHandler.postNotifyShutdownStarting(delayForShutdowWarningMs); 423 } 424 mHandler.postWrapUpRemoteAccessService(mAllowedSystemUptimeMs); 425 mHandler.postNotifyApStateChange(0); 426 } 427 428 @Override release()429 public void release() { 430 Slogf.i(TAG, "release CarRemoteAccessService"); 431 mHandler.cancelAll(); 432 mRemoteAccessHalWrapper.release(); 433 mRemoteAccessStorage.release(); 434 } 435 printMap(IndentingPrintWriter writer, ArrayMap<?, ?> map)436 private void printMap(IndentingPrintWriter writer, ArrayMap<?, ?> map) { 437 writer.increaseIndent(); 438 for (int i = 0; i < map.size(); i++) { 439 writer.printf("%d: %s ==> %s\n", i, map.keyAt(i), map.valueAt(i)); 440 } 441 writer.decreaseIndent(); 442 } 443 444 @Override 445 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dump(IndentingPrintWriter writer)446 public void dump(IndentingPrintWriter writer) { 447 synchronized (mLock) { 448 writer.println("*Car Remote Access Service*"); 449 writer.printf("mShutdownTimeInMs: %d\n", mShutdownTimeInMs); 450 writer.printf("mNextPowerState: %d\n", mNextPowerState); 451 writer.printf("mRunGarageMode: %b\n", mRunGarageMode); 452 writer.printf("mWakeupServiceName: %s\n", mWakeupServiceName); 453 writer.printf("mVehicleId: %s\n", mVehicleId); 454 writer.printf("mProcessorId: %s\n", mProcessorId); 455 writer.println("mClientTokenByUidName:"); 456 printMap(writer, mClientTokenByUidName); 457 writer.println("mClientServiceInfoByUid:"); 458 printMap(writer, mClientServiceInfoByUid); 459 writer.println("mUidAByName:"); 460 printMap(writer, mUidByName); 461 writer.println("mTasksToBeNotifiedByClientId"); 462 writer.increaseIndent(); 463 for (int i = 0; i < mTasksToBeNotifiedByClientId.size(); i++) { 464 String clientId = mTasksToBeNotifiedByClientId.keyAt(i); 465 List<String> taskIds = new ArrayList<>(); 466 List<RemoteTask> tasks = mTasksToBeNotifiedByClientId.valueAt(i); 467 for (int j = 0; j < tasks.size(); j++) { 468 taskIds.add(tasks.get(j).id); 469 } 470 writer.printf("%d: %s ==> %s\n", i, clientId, taskIds); 471 } 472 writer.decreaseIndent(); 473 writer.println("active task count by Uid:"); 474 writer.increaseIndent(); 475 for (int i = 0; i < mClientServiceInfoByUid.size(); i++) { 476 String uidName = mClientServiceInfoByUid.keyAt(i); 477 RemoteTaskClientServiceInfo serviceInfo = mClientServiceInfoByUid.valueAt(i); 478 int count = 0; 479 if (serviceInfo.getServiceConnection() != null) { 480 count = serviceInfo.getServiceConnection().getActiveTaskCount(); 481 } 482 writer.printf("%d: %s ==> %d\n", i, uidName, count); 483 } 484 writer.decreaseIndent(); 485 } 486 } 487 488 /** 489 * Registers {@code ICarRemoteAccessCallback}. 490 * 491 * <p>When a callback is registered for a package, calling {@code addCarRemoteTaskClient} will 492 * replace the registered callback with the new one. 493 * 494 * @param callback {@code ICarRemoteAccessCallback} that listens to remote access events. 495 * @throws IllegalArgumentException When {@code callback} is {@code null}. 496 */ 497 @Override addCarRemoteTaskClient(ICarRemoteAccessCallback callback)498 public void addCarRemoteTaskClient(ICarRemoteAccessCallback callback) { 499 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_REMOTE_ACCESS); 500 Preconditions.checkArgument(callback != null, "callback cannot be null"); 501 int callingUid = mDep.getCallingUid(); 502 ClientToken token; 503 String uidName; 504 synchronized (mLock) { 505 uidName = getNameForUidLocked(callingUid); 506 Slogf.i(TAG, "addCarRemoteTaskClient from uid: %s", uidName); 507 token = mClientTokenByUidName.get(uidName); 508 if (token != null) { 509 ICarRemoteAccessCallback oldCallback = token.getCallback(); 510 if (oldCallback != null) { 511 oldCallback.asBinder().unlinkToDeath(token, /* flags= */ 0); 512 } 513 } else { 514 // Creates a new client ID with a null callback. 515 token = new ClientToken(generateNewClientId(), System.currentTimeMillis()); 516 mClientTokenByUidName.put(uidName, token); 517 mUidByClientId.put(token.getClientId(), uidName); 518 } 519 try { 520 callback.asBinder().linkToDeath(token, /* flags= */ 0); 521 } catch (RemoteException e) { 522 token.setCallback(null); 523 throw new IllegalStateException("Failed to linkToDeath callback"); 524 } 525 } 526 saveClientIdInDb(token, uidName); 527 postRegistrationUpdated(callback, token); 528 } 529 530 /** 531 * Unregisters {@code ICarRemoteAccessCallback}. 532 * 533 * @param callback {@code ICarRemoteAccessCallback} that listens to remote access events. 534 * @throws IllegalArgumentException When {@code callback} is {@code null}. 535 */ 536 @Override removeCarRemoteTaskClient(ICarRemoteAccessCallback callback)537 public void removeCarRemoteTaskClient(ICarRemoteAccessCallback callback) { 538 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_REMOTE_ACCESS); 539 Preconditions.checkArgument(callback != null, "callback cannot be null"); 540 int callingUid = mDep.getCallingUid(); 541 RemoteTaskClientServiceConnection connection = null; 542 String uidName; 543 synchronized (mLock) { 544 uidName = getNameForUidLocked(callingUid); 545 Slogf.i(TAG, "removeCarRemoteTaskClient from uid: %s", uidName); 546 ClientToken token = mClientTokenByUidName.get(uidName); 547 if (token == null) { 548 Slogf.w(TAG, "Cannot remove callback. Callback has not been registered for %s", 549 uidName); 550 return; 551 } 552 if (token.getCallback() == null) { 553 Slogf.w(TAG, "The callback to remove is already dead, do nothing"); 554 return; 555 } 556 if (token.getCallback().asBinder() != callback.asBinder()) { 557 Slogf.w(TAG, "Cannot remove callback. Provided callback is not the same as the " 558 + "registered callback for %s", uidName); 559 return; 560 } 561 callback.asBinder().unlinkToDeath(token, /* flags= */ 0); 562 token.setCallback(null); 563 connection = getServiceConnectionLocked(uidName); 564 } 565 if (connection == null) { 566 Slogf.w(TAG, "No active service connection for uid: %s", uidName); 567 return; 568 } 569 connection.removeAllActiveTasks(); 570 Slogf.i(TAG, "All active tasks removed for uid: %s, after %d ms, check whether we should " 571 + "shutdown", uidName, mTaskUnbindDelayMs); 572 mHandler.postMaybeShutdown(/* delayMs= */ mTaskUnbindDelayMs); 573 } 574 575 @GuardedBy("mLock") getTokenForUidNameAndCheckClientIdLocked(String uidName, String clientId)576 private ClientToken getTokenForUidNameAndCheckClientIdLocked(String uidName, String clientId) 577 throws IllegalArgumentException { 578 ClientToken token = mClientTokenByUidName.get(uidName); 579 if (token == null) { 580 throw new IllegalArgumentException("Callback has not been registered"); 581 } 582 // TODO(b/252698817): Update the validity checking logic. 583 if (!clientId.equals(token.getClientId())) { 584 throw new IllegalArgumentException("Client ID(" + clientId + ") doesn't match the " 585 + "registered one(" + token.getClientId() + ")"); 586 } 587 return token; 588 } 589 590 @GuardedBy("mLock") getServiceConnectionLocked(String uidName)591 private @Nullable RemoteTaskClientServiceConnection getServiceConnectionLocked(String uidName) { 592 if (DEBUG) { 593 Slogf.d(TAG, "getServiceConnectionLocked for uid: %s", uidName); 594 } 595 RemoteTaskClientServiceInfo serviceInfo = mClientServiceInfoByUid.get(uidName); 596 if (serviceInfo == null) { 597 if (DEBUG) { 598 Slogf.d(TAG, "the service info for uid: %s is null", uidName); 599 } 600 return null; 601 } 602 return serviceInfo.getServiceConnection(); 603 } 604 605 /** 606 * Reports that the task of {@code taskId} is completed. 607 * 608 * @param clientId ID of a client that has completed the task. 609 * @param taskId ID of a task that has been completed. 610 * @throws IllegalArgumentException When {@code clientId} is not valid, or {@code taskId} is not 611 * valid. 612 */ 613 @Override reportRemoteTaskDone(String clientId, String taskId)614 public void reportRemoteTaskDone(String clientId, String taskId) { 615 Slogf.i(TAG, "reportRemoteTaskDone for client: %s, task: %s", clientId, taskId); 616 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_REMOTE_ACCESS); 617 Preconditions.checkArgument(clientId != null, "clientId cannot be null"); 618 Preconditions.checkArgument(taskId != null, "taskId cannot be null"); 619 int callingUid = mDep.getCallingUid(); 620 String uidName; 621 RemoteTaskClientServiceConnection serviceConnection; 622 synchronized (mLock) { 623 uidName = getNameForUidLocked(callingUid); 624 getTokenForUidNameAndCheckClientIdLocked(uidName, clientId); 625 serviceConnection = getServiceConnectionLocked(uidName); 626 } 627 if (serviceConnection == null) { 628 throw new IllegalArgumentException("No active service connection, uidName: " + uidName 629 + ", clientId: " + clientId); 630 } 631 if (!serviceConnection.removeActiveTasks(new ArraySet<>(Set.of(taskId)))) { 632 throw new IllegalArgumentException("Task ID(" + taskId + ") is not valid"); 633 } 634 if (DEBUG) { 635 Slogf.d(TAG, "Task: %s complete, after %d ms, check whether we should shutdown", 636 taskId, mTaskUnbindDelayMs); 637 } 638 mHandler.postMaybeShutdown(/* delayMs= */ mTaskUnbindDelayMs); 639 } 640 641 @Override setPowerStatePostTaskExecution(int nextPowerState, boolean runGarageMode)642 public void setPowerStatePostTaskExecution(int nextPowerState, boolean runGarageMode) { 643 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_REMOTE_ACCESS); 644 Slogf.i(TAG, "setPowerStatePostTaskExecution, nextPowerState: %d, runGarageMode: %B", 645 nextPowerState, runGarageMode); 646 647 synchronized (mLock) { 648 mNextPowerState = nextPowerState; 649 mRunGarageMode = runGarageMode; 650 } 651 } 652 653 @Override confirmReadyForShutdown(String clientId)654 public void confirmReadyForShutdown(String clientId) { 655 CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_REMOTE_ACCESS); 656 Preconditions.checkArgument(clientId != null, "clientId cannot be null"); 657 int callingUid = mDep.getCallingUid(); 658 boolean isAllClientReadyForShutDown = true; 659 synchronized (mLock) { 660 String uidName = getNameForUidLocked(callingUid); 661 Slogf.i(TAG, "confirmReadyForShutdown from client: %s, uidName: %s", clientId, uidName); 662 ClientToken token = getTokenForUidNameAndCheckClientIdLocked(uidName, clientId); 663 token.setIsReadyForShutdown(); 664 665 for (int i = 0; i < mClientTokenByUidName.size(); i++) { 666 ClientToken clientToken = mClientTokenByUidName.valueAt(i); 667 if (clientToken.getCallback() == null) { 668 continue; 669 } 670 if (!clientToken.isReadyForShutdown()) { 671 isAllClientReadyForShutDown = false; 672 } 673 } 674 } 675 676 if (isAllClientReadyForShutDown) { 677 mHandler.postWrapUpRemoteAccessService(/* delayMs= */ 0); 678 } 679 } 680 681 @VisibleForTesting getRemoteAccessHalCallback()682 RemoteAccessHalCallback getRemoteAccessHalCallback() { 683 return mHalCallback; 684 } 685 686 @VisibleForTesting getAllowedSystemUptimeMs()687 long getAllowedSystemUptimeMs() { 688 return mAllowedSystemUptimeMs; 689 } 690 populatePackageClientIdMapping()691 private void populatePackageClientIdMapping() { 692 List<ClientIdEntry> clientIdEntries = mRemoteAccessStorage.getClientIdEntries(); 693 if (clientIdEntries == null) return; 694 695 synchronized (mLock) { 696 for (int i = 0; i < clientIdEntries.size(); i++) { 697 ClientIdEntry entry = clientIdEntries.get(i); 698 mUidByClientId.put(entry.clientId, entry.uidName); 699 mClientTokenByUidName.put(entry.uidName, 700 new ClientToken(entry.clientId, entry.idCreationTime)); 701 } 702 } 703 } 704 saveClientIdInDb(ClientToken token, String uidName)705 private void saveClientIdInDb(ClientToken token, String uidName) { 706 ClientIdEntry entry = new ClientIdEntry(token.getClientId(), token.getIdCreationTime(), 707 uidName); 708 if (!mRemoteAccessStorage.updateClientId(entry)) { 709 Slogf.e(TAG, "Failed to save %s for %s in the database", token, uidName); 710 } 711 } 712 postRegistrationUpdated(ICarRemoteAccessCallback callback, ClientToken token)713 private void postRegistrationUpdated(ICarRemoteAccessCallback callback, ClientToken token) { 714 String clientId = token.getClientId(); 715 mHandler.post(() -> { 716 try { 717 if (DEBUG) { 718 Slogf.d(TAG, "Calling onClientRegistrationUpdated: serviceName=%s, " 719 + "vehicleId=%s, processorId=%s, clientId=%s", mWakeupServiceName, 720 mVehicleId, mProcessorId, clientId); 721 } 722 callback.onClientRegistrationUpdated(new RemoteTaskClientRegistrationInfo( 723 mWakeupServiceName, mVehicleId, mProcessorId, clientId)); 724 } catch (RemoteException e) { 725 Slogf.e(TAG, e, "Calling onClientRegistrationUpdated() failed: clientId = %s", 726 clientId); 727 } 728 729 // After notify the client about the registration info, the callback is registered. 730 token.setCallback(callback); 731 732 // Just after a registration callback is invoked, let's call onRemoteTaskRequested 733 // callback if there are pending tasks. 734 maybeStartNewRemoteTask(clientId); 735 }); 736 } 737 shutdownIfNeeded(boolean force)738 private void shutdownIfNeeded(boolean force) { 739 if (DEBUG) { 740 Slogf.d(TAG, "shutdownIfNeeded, force: %B", force); 741 } 742 int nextPowerState; 743 boolean runGarageMode; 744 synchronized (mLock) { 745 if (mNextPowerState == CarRemoteAccessManager.NEXT_POWER_STATE_ON) { 746 Slogf.i(TAG, "Will not shutdown. The next power state is ON."); 747 return; 748 } 749 if (mPowerHalService.isVehicleInUse()) { 750 Slogf.i(TAG, "Will not shutdown. The vehicle is in use."); 751 return; 752 } 753 int taskCount = getActiveTaskCountLocked(); 754 if (!force && taskCount > 0) { 755 Slogf.i(TAG, "Will not shutdown. The activen task count is %d.", taskCount); 756 return; 757 } 758 nextPowerState = mNextPowerState; 759 runGarageMode = mRunGarageMode; 760 } 761 if (DEBUG) { 762 Slogf.d(TAG, "unbindAllServices before shutdown"); 763 } 764 unbindAllServices(); 765 // Send SHUTDOWN_REQUEST to VHAL. 766 Slogf.i(TAG, "Requesting shutdown of AP: nextPowerState = %d, runGarageMode = %b", 767 nextPowerState, runGarageMode); 768 try { 769 mPowerService.requestShutdownAp(nextPowerState, runGarageMode); 770 } catch (Exception e) { 771 Slogf.e(TAG, e, "Cannot shutdown to %s", nextPowerStateToString(nextPowerState)); 772 } 773 } 774 775 /** 776 * Unbinds all the remote task client services. 777 */ unbindAllServices()778 public void unbindAllServices() { 779 Slogf.i(TAG, "unbind all the remote task client services"); 780 ArrayMap<String, RemoteTaskClientServiceInfo> clientServiceInfoByUid; 781 synchronized (mLock) { 782 clientServiceInfoByUid = new ArrayMap<>(mClientServiceInfoByUid); 783 } 784 for (int i = 0; i < clientServiceInfoByUid.size(); i++) { 785 unbindRemoteTaskClientService(clientServiceInfoByUid.valueAt(i), 786 /* force= */ true); 787 } 788 } 789 790 @GuardedBy("mLock") calcTaskMaxDurationInMsLocked()791 private long calcTaskMaxDurationInMsLocked() { 792 long taskMaxDurationInMs; 793 if (mNextPowerState == CarRemoteAccessManager.NEXT_POWER_STATE_ON 794 || mPowerHalService.isVehicleInUse()) { 795 // If next power state is ON or vehicle is in use, the mShutdownTimeInMs does not make 796 // sense because shutdown will not happen. We always allow task to execute for 797 // mAllowedSystemUptimMs. 798 taskMaxDurationInMs = mAllowedSystemUptimeMs; 799 } else { 800 taskMaxDurationInMs = mShutdownTimeInMs - SystemClock.uptimeMillis(); 801 } 802 if (DEBUG) { 803 Slogf.d(TAG, "Task max duration in ms: %d", taskMaxDurationInMs); 804 } 805 return taskMaxDurationInMs; 806 } 807 808 @VisibleForTesting getActiveTaskCount()809 int getActiveTaskCount() { 810 synchronized (mLock) { 811 return getActiveTaskCountLocked(); 812 } 813 } 814 815 @GuardedBy("mLock") getActiveTaskCountLocked()816 private int getActiveTaskCountLocked() { 817 int count = 0; 818 for (int i = 0; i < mClientServiceInfoByUid.size(); i++) { 819 RemoteTaskClientServiceInfo serviceInfo = mClientServiceInfoByUid.valueAt(i); 820 if (serviceInfo.getServiceConnection() != null) { 821 count += serviceInfo.getServiceConnection().getActiveTaskCount(); 822 } 823 } 824 return count; 825 } 826 getLastShutdownState()827 private int getLastShutdownState() { 828 return mPowerService.getLastShutdownState(); 829 } 830 getAllowedSystemUptimeForRemoteTaskInMs()831 private long getAllowedSystemUptimeForRemoteTaskInMs() { 832 long timeout = mContext.getResources() 833 .getInteger(R.integer.config_allowedSystemUptimeForRemoteAccess); 834 if (timeout < MIN_SYSTEM_UPTIME_FOR_REMOTE_ACCESS_IN_SEC) { 835 timeout = MIN_SYSTEM_UPTIME_FOR_REMOTE_ACCESS_IN_SEC; 836 Slogf.w(TAG, "config_allowedSystemUptimeForRemoteAccess(%d) should be no less than %d", 837 timeout, MIN_SYSTEM_UPTIME_FOR_REMOTE_ACCESS_IN_SEC); 838 } 839 return timeout * MILLI_TO_SECOND; 840 } 841 842 // Gets the UID name for the specified UID. Read from a cached map if exists. Uses package 843 // manager to get UID if it does not exist in cached map. 844 @GuardedBy("mLock") getNameForUidLocked(int uid)845 private String getNameForUidLocked(int uid) { 846 String uidName = mNameByUid.get(uid); 847 if (uidName != null) { 848 return uidName; 849 } 850 uidName = mPackageManager.getNameForUid(uid); 851 mUidByName.put(uidName, uid); 852 mNameByUid.put(uid, uidName); 853 return uidName; 854 } 855 856 // Searchs for all remote task client service packages accroding to the declared intent and 857 // filter them according to their permissions. 858 // This will start the found remote task client services (as system user) for init registration. searchForRemoteTaskClientPackages()859 private void searchForRemoteTaskClientPackages() { 860 // TODO(b/266129982): Query for all users. 861 if (DEBUG) { 862 Slogf.d(TAG, "searchForRemoteTaskClientPackages"); 863 } 864 List<ResolveInfo> services = mPackageManager.queryIntentServicesAsUser( 865 new Intent(Car.CAR_REMOTEACCESS_REMOTE_TASK_CLIENT_SERVICE), /* flags= */ 0, 866 UserHandle.SYSTEM); 867 ArrayMap<String, RemoteTaskClientServiceInfo> serviceInfoByUidName = new ArrayMap<>(); 868 synchronized (mLock) { 869 for (int i = 0; i < services.size(); i++) { 870 ServiceInfo info = services.get(i).serviceInfo; 871 String packageName = info.packageName; 872 ComponentName componentName = new ComponentName(packageName, info.name); 873 // We require client to has PERMISSION_CONTROL_REMOTE_ACCESS which is a system API 874 // so that they can be launched as systme user. 875 if (mPackageManager.checkPermission(Car.PERMISSION_CONTROL_REMOTE_ACCESS, 876 packageName) != PackageManager.PERMISSION_GRANTED) { 877 Slogf.w(TAG, "Component(%s) has %s intent but doesn't have %s permission", 878 componentName.flattenToString(), 879 Car.CAR_REMOTEACCESS_REMOTE_TASK_CLIENT_SERVICE, 880 Car.PERMISSION_CONTROL_REMOTE_ACCESS); 881 continue; 882 } 883 // TODO(b/263798644): mClientServiceInfoByUid should be updated when packages 884 // are added, removed, updated. 885 RemoteTaskClientServiceInfo serviceInfo = 886 new RemoteTaskClientServiceInfo(componentName); 887 String uidName = getNameForUidLocked(info.applicationInfo.uid); 888 mClientServiceInfoByUid.put(uidName, serviceInfo); 889 if (DEBUG) { 890 Slogf.d(TAG, "Package(%s) is found as a remote task client service", 891 packageName); 892 } 893 // Store the service info to be started later outside the lock. 894 serviceInfoByUidName.put(uidName, serviceInfo); 895 } 896 } 897 // Start the remote task client services outside the lock since binding might be a slow 898 // operation. 899 for (int i = 0; i < serviceInfoByUidName.size(); i++) { 900 startRemoteTaskClientService(serviceInfoByUidName.valueAt(i), 901 serviceInfoByUidName.keyAt(i), mAllowedTimeForRemoteTaskClientInitMs); 902 } 903 } 904 905 // Starts the remote task client service if not already started and extends its liftime. startRemoteTaskClientService(RemoteTaskClientServiceInfo serviceInfo, String uidName, long taskDurationMs)906 private void startRemoteTaskClientService(RemoteTaskClientServiceInfo serviceInfo, 907 String uidName, long taskDurationMs) { 908 ComponentName serviceName = serviceInfo.getServiceComponentName(); 909 910 // Critical section to protect modification to serviceInfo. 911 RemoteTaskClientServiceConnection serviceConnection; 912 synchronized (mLock) { 913 // TODO(b/266129982): Start a service for the user under which the task needs to be 914 // executed. 915 if (serviceInfo.getServiceConnection() != null) { 916 serviceConnection = serviceInfo.getServiceConnection(); 917 } else { 918 int uid = mUidByName.get(uidName); 919 serviceConnection = new RemoteTaskClientServiceConnection(mContext, mHandler, 920 mUserManager, serviceName, UserHandle.SYSTEM, uid, mTaskUnbindDelayMs); 921 serviceInfo.setServiceConnection(serviceConnection); 922 } 923 } 924 long taskTimeoutMs = SystemClock.uptimeMillis() + taskDurationMs; 925 Slogf.i(TAG, "Service(%s) is bound to give a time to register as a remote task client", 926 serviceName.flattenToString()); 927 928 serviceConnection.bindServiceAndExtendTaskTimeoutMs(taskTimeoutMs); 929 } 930 onServiceTimeout(int uid)931 private void onServiceTimeout(int uid) { 932 RemoteTaskClientServiceInfo serviceInfo; 933 synchronized (mLock) { 934 String uidName = getNameForUidLocked(uid); 935 serviceInfo = mClientServiceInfoByUid.get(uidName); 936 if (serviceInfo == null) { 937 Slogf.e(TAG, "No service connection info for %s, must not happen", uidName); 938 return; 939 } 940 } 941 Slogf.w(TAG, "The service: %s timeout, clearing all pending tasks and " 942 + "unbind", serviceInfo.getServiceComponentName()); 943 unbindRemoteTaskClientService(serviceInfo, /* force= */ false); 944 } 945 946 // Stops the remote task client service. If {@code force} is true, the service will always be 947 // unbound if it is binding or already bound. If it is false, the service will be unbound if 948 // the service passed its liftime. unbindRemoteTaskClientService(RemoteTaskClientServiceInfo serviceInfo, boolean force)949 private void unbindRemoteTaskClientService(RemoteTaskClientServiceInfo serviceInfo, 950 boolean force) { 951 if (DEBUG) { 952 Slogf.d(TAG, "Unbinding remote task client service, force: %B", force); 953 } 954 RemoteTaskClientServiceConnection connection = serviceInfo.getServiceConnection(); 955 if (connection == null) { 956 Slogf.w(TAG, "Cannot unbind remote task client service: no service connection"); 957 return; 958 } 959 ComponentName serviceName = serviceInfo.getServiceComponentName(); 960 if (connection.unbindService(force)) { 961 Slogf.i(TAG, "Service(%s) is unbound from CarRemoteAccessService", serviceName); 962 } else { 963 Slogf.w(TAG, "Failed to unbind remote task client service(%s)", serviceName); 964 } 965 } 966 notifyApStateChange()967 private void notifyApStateChange() { 968 if (DEBUG) { 969 Slogf.d(TAG, "notify ap state change"); 970 } 971 boolean isReadyForRemoteTask; 972 boolean isWakeupRequired; 973 synchronized (mLock) { 974 isReadyForRemoteTask = mIsReadyForRemoteTask; 975 isWakeupRequired = mIsWakeupRequired; 976 mNotifyApPowerStateRetryCount++; 977 if (mNotifyApPowerStateRetryCount > NOTIFY_AP_STATE_MAX_RETRY) { 978 Slogf.e(TAG, "Reached max retry count for trying to notify AP state change, " 979 + "Failed to notify AP state Change!!!"); 980 return; 981 } 982 } 983 if (!mRemoteAccessHalWrapper.notifyApStateChange(isReadyForRemoteTask, isWakeupRequired)) { 984 Slogf.e(TAG, "Cannot notify AP state change, waiting for " 985 + NOTIFY_AP_STATE_RETRY_SLEEP_IN_MS + "ms and retry"); 986 mHandler.postNotifyApStateChange(NOTIFY_AP_STATE_RETRY_SLEEP_IN_MS); 987 return; 988 } 989 synchronized (mLock) { 990 mNotifyApPowerStateRetryCount = 0; 991 } 992 if (DEBUG) { 993 Slogf.d(TAG, "Notified AP about new state, isReadyForRemoteTask: %B, " 994 + "isWakeupRequired: %B", isReadyForRemoteTask, isWakeupRequired); 995 } 996 } 997 notifyShutdownStarting()998 private void notifyShutdownStarting() { 999 List<ICarRemoteAccessCallback> callbacks = new ArrayList<>(); 1000 Slogf.i(TAG, "notifyShutdownStarting"); 1001 synchronized (mLock) { 1002 if (mNextPowerState == CarRemoteAccessManager.NEXT_POWER_STATE_ON) { 1003 Slogf.i(TAG, "Skipping notifyShutdownStarting because the next power state is ON"); 1004 return; 1005 } 1006 if (mPowerHalService.isVehicleInUse()) { 1007 Slogf.i(TAG, "Skipping notifyShutdownStarting because vehicle is currently in use"); 1008 return; 1009 } 1010 for (int i = 0; i < mClientTokenByUidName.size(); i++) { 1011 ClientToken token = mClientTokenByUidName.valueAt(i); 1012 if (token.getCallback() == null || !token.isClientIdValid()) { 1013 Slogf.w(TAG, "Notifying client(%s) of shutdownStarting is skipped: invalid " 1014 + "client token", token); 1015 continue; 1016 } 1017 callbacks.add(token.getCallback()); 1018 } 1019 } 1020 for (int i = 0; i < callbacks.size(); i++) { 1021 ICarRemoteAccessCallback callback = callbacks.get(i); 1022 try { 1023 callback.onShutdownStarting(); 1024 } catch (RemoteException e) { 1025 Slogf.e(TAG, "Calling onShutdownStarting() failed: package", e); 1026 } 1027 } 1028 } 1029 wrapUpRemoteAccessServiceIfNeeded()1030 private void wrapUpRemoteAccessServiceIfNeeded() { 1031 synchronized (mLock) { 1032 if (mNextPowerState != CarRemoteAccessManager.NEXT_POWER_STATE_ON 1033 && !mPowerHalService.isVehicleInUse()) { 1034 Slogf.i(TAG, "Remote task execution time has expired: wrapping up the service"); 1035 } 1036 } 1037 shutdownIfNeeded(/* force= */ true); 1038 } 1039 1040 @Nullable getRemoteTaskClientServiceInfo(String clientId)1041 RemoteTaskClientServiceInfo getRemoteTaskClientServiceInfo(String clientId) { 1042 synchronized (mLock) { 1043 String uidName = mUidByClientId.get(clientId); 1044 if (uidName == null) { 1045 Slogf.w(TAG, "Cannot get package name for client ID(%s)", clientId); 1046 return null; 1047 } 1048 return mClientServiceInfoByUid.get(uidName); 1049 } 1050 } 1051 invokeTaskRequestCallbacks(RemoteTaskClientServiceConnection serviceConnection, ICarRemoteAccessCallback callback, String clientId, List<RemoteTask> tasks, int taskMaxDurationInSec)1052 private void invokeTaskRequestCallbacks(RemoteTaskClientServiceConnection serviceConnection, 1053 ICarRemoteAccessCallback callback, String clientId, List<RemoteTask> tasks, 1054 int taskMaxDurationInSec) { 1055 ArraySet<String> taskIds = new ArraySet<>(); 1056 for (int i = 0; i < tasks.size(); i++) { 1057 taskIds.add(tasks.get(i).id); 1058 } 1059 serviceConnection.addActiveTasks(taskIds); 1060 1061 ArraySet<String> failedTaskIds = new ArraySet<>(); 1062 for (int i = 0; i < tasks.size(); i++) { 1063 RemoteTask task = tasks.get(i); 1064 try { 1065 Slogf.i(TAG, "Delivering remote task, clientId: %s, taskId: %s, " 1066 + "max duration: %d sec", clientId, task.id, taskMaxDurationInSec); 1067 callback.onRemoteTaskRequested(clientId, task.id, task.data, taskMaxDurationInSec); 1068 } catch (RemoteException e) { 1069 Slogf.e(TAG, e, "Calling onRemoteTaskRequested() failed: clientId = %s, " 1070 + "taskId = %s, data size = %d, taskMaxDurationInSec = %d", clientId, 1071 task.id, task.data != null ? task.data.length : 0, taskMaxDurationInSec); 1072 failedTaskIds.add(task.id); 1073 } 1074 } 1075 if (!failedTaskIds.isEmpty()) { 1076 serviceConnection.removeActiveTasks(failedTaskIds); 1077 } 1078 } 1079 1080 @GuardedBy("mLock") pushTaskToPendingQueueLocked(String clientId, RemoteTask task)1081 private void pushTaskToPendingQueueLocked(String clientId, RemoteTask task) { 1082 if (DEBUG) { 1083 Slogf.d(TAG, "received a new remote task: %s", task); 1084 } 1085 1086 ArrayList remoteTasks = mTasksToBeNotifiedByClientId.get(clientId); 1087 if (remoteTasks == null) { 1088 remoteTasks = new ArrayList<RemoteTask>(); 1089 mTasksToBeNotifiedByClientId.put(clientId, remoteTasks); 1090 } 1091 remoteTasks.add(task); 1092 mHandler.postPendingTaskTimeout(task, task.timeoutInMs); 1093 } 1094 onPendingTaskTimeout(RemoteTask task)1095 private void onPendingTaskTimeout(RemoteTask task) { 1096 long now = SystemClock.uptimeMillis(); 1097 Slogf.w(TAG, "Pending task: %s timeout at %d", task, now); 1098 synchronized (mLock) { 1099 List<RemoteTask> pendingTasks = mTasksToBeNotifiedByClientId.get(task.clientId); 1100 if (pendingTasks == null) { 1101 // The task is already delivered. Do nothing. 1102 return; 1103 } 1104 pendingTasks.remove(task); 1105 } 1106 } 1107 1108 @GuardedBy("mLock") 1109 @Nullable popTasksFromPendingQueueLocked(String clientId)1110 private List<RemoteTask> popTasksFromPendingQueueLocked(String clientId) { 1111 if (DEBUG) { 1112 Slogf.d(TAG, "Pop pending remote tasks from queue for client ID: %s", clientId); 1113 } 1114 List<RemoteTask> pendingTasks = mTasksToBeNotifiedByClientId.get(clientId); 1115 if (pendingTasks == null) { 1116 return null; 1117 } 1118 mTasksToBeNotifiedByClientId.remove(clientId); 1119 for (int i = 0; i < pendingTasks.size(); i++) { 1120 if (DEBUG) { 1121 Slogf.d(TAG, "Prepare to deliver remote task: %s", pendingTasks.get(i)); 1122 } 1123 mHandler.cancelPendingTaskTimeout(pendingTasks.get(i)); 1124 } 1125 return pendingTasks; 1126 } 1127 generateNewTaskId()1128 private String generateNewTaskId() { 1129 return TASK_PREFIX + "_" + mTaskCount.incrementAndGet() + "_" 1130 + CarServiceUtils.generateRandomAlphaNumericString(RANDOM_STRING_LENGTH); 1131 } 1132 generateNewClientId()1133 private String generateNewClientId() { 1134 return CLIENT_PREFIX + "_" + mClientCount.incrementAndGet() + "_" 1135 + CarServiceUtils.generateRandomAlphaNumericString(RANDOM_STRING_LENGTH); 1136 } 1137 1138 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) nextPowerStateToString(int nextPowerState)1139 private static String nextPowerStateToString(int nextPowerState) { 1140 switch (nextPowerState) { 1141 case CarRemoteAccessManager.NEXT_POWER_STATE_ON: 1142 return "ON"; 1143 case CarRemoteAccessManager.NEXT_POWER_STATE_OFF: 1144 return "OFF"; 1145 case CarRemoteAccessManager.NEXT_POWER_STATE_SUSPEND_TO_RAM: 1146 return "Suspend-to-RAM"; 1147 case CarRemoteAccessManager.NEXT_POWER_STATE_SUSPEND_TO_DISK: 1148 return "Suspend-to-disk"; 1149 default: 1150 return "Unknown(" + nextPowerState + ")"; 1151 } 1152 } 1153 1154 private static final class RemoteTaskClientServiceInfo { 1155 private final ComponentName mServiceComponentName; 1156 private final AtomicReference<RemoteTaskClientServiceConnection> mConnection = 1157 new AtomicReference<>(null); 1158 RemoteTaskClientServiceInfo(ComponentName componentName)1159 private RemoteTaskClientServiceInfo(ComponentName componentName) { 1160 mServiceComponentName = componentName; 1161 } 1162 getServiceComponentName()1163 public ComponentName getServiceComponentName() { 1164 return mServiceComponentName; 1165 } 1166 getServiceConnection()1167 public RemoteTaskClientServiceConnection getServiceConnection() { 1168 return mConnection.get(); 1169 } 1170 setServiceConnection(@ullable RemoteTaskClientServiceConnection connection)1171 public void setServiceConnection(@Nullable RemoteTaskClientServiceConnection connection) { 1172 mConnection.set(connection); 1173 } 1174 1175 @Override toString()1176 public String toString() { 1177 return new StringBuilder() 1178 .append("RemoteTaskClientServiceInfo[") 1179 .append("Component name=") 1180 .append(mServiceComponentName) 1181 .append(", hasConnection=") 1182 .append(mConnection.get() != null) 1183 .append("]") 1184 .toString(); 1185 } 1186 } 1187 1188 private static final class RemoteTask { 1189 public final String id; 1190 public final byte[] data; 1191 public final String clientId; 1192 public final long timeoutInMs; 1193 RemoteTask(String id, byte[] data, String clientId, long timeoutInMs)1194 private RemoteTask(String id, byte[] data, String clientId, long timeoutInMs) { 1195 this.id = id; 1196 this.data = data; 1197 this.clientId = clientId; 1198 this.timeoutInMs = timeoutInMs; 1199 } 1200 1201 @Override toString()1202 public String toString() { 1203 return new StringBuilder() 1204 .append("RemoteTask[") 1205 .append("taskId=") 1206 .append(id) 1207 .append("clientId=") 1208 .append(clientId) 1209 .append("timeoutInMs=") 1210 .append(timeoutInMs) 1211 .append("]") 1212 .toString(); 1213 } 1214 } 1215 1216 private static final class ClientToken implements IBinder.DeathRecipient { 1217 1218 private final Object mTokenLock = new Object(); 1219 private final String mClientId; 1220 private final long mIdCreationTimeInMs; 1221 1222 @GuardedBy("mTokenLock") 1223 private ICarRemoteAccessCallback mCallback; 1224 @GuardedBy("mTokenLock") 1225 private boolean mIsReadyForShutdown; 1226 ClientToken(String clientId, long idCreationTimeInMs)1227 private ClientToken(String clientId, long idCreationTimeInMs) { 1228 mClientId = clientId; 1229 mIdCreationTimeInMs = idCreationTimeInMs; 1230 } 1231 getClientId()1232 public String getClientId() { 1233 return mClientId; 1234 } 1235 getIdCreationTime()1236 public long getIdCreationTime() { 1237 return mIdCreationTimeInMs; 1238 } 1239 getCallback()1240 public ICarRemoteAccessCallback getCallback() { 1241 synchronized (mTokenLock) { 1242 return mCallback; 1243 } 1244 } 1245 isClientIdValid()1246 public boolean isClientIdValid() { 1247 long now = System.currentTimeMillis(); 1248 return mClientId != null 1249 && (now - mIdCreationTimeInMs) < CLIENT_ID_EXPIRATION_IN_MILLIS; 1250 } 1251 setCallback(ICarRemoteAccessCallback callback)1252 public void setCallback(ICarRemoteAccessCallback callback) { 1253 synchronized (mTokenLock) { 1254 mCallback = callback; 1255 } 1256 } 1257 setIsReadyForShutdown()1258 public void setIsReadyForShutdown() { 1259 synchronized (mTokenLock) { 1260 mIsReadyForShutdown = true; 1261 } 1262 } 1263 isReadyForShutdown()1264 public boolean isReadyForShutdown() { 1265 synchronized (mTokenLock) { 1266 return mIsReadyForShutdown; 1267 } 1268 } 1269 1270 @Override binderDied()1271 public void binderDied() { 1272 synchronized (mTokenLock) { 1273 Slogf.w(TAG, "Client token callback binder died"); 1274 mCallback = null; 1275 } 1276 } 1277 1278 @Override toString()1279 public String toString() { 1280 synchronized (mTokenLock) { 1281 return new StringBuilder() 1282 .append("ClientToken[") 1283 .append("mClientId=").append(mClientId) 1284 .append(", mIdCreationTimeInMs=").append(mIdCreationTimeInMs) 1285 .append(", hasCallback=").append(mCallback != null) 1286 .append(']') 1287 .toString(); 1288 } 1289 } 1290 } 1291 1292 private static final class RemoteTaskClientServiceConnection implements ServiceConnection { 1293 1294 private static final String TAG = RemoteTaskClientServiceConnection.class.getSimpleName(); 1295 1296 private final Object mServiceLock = new Object(); 1297 private final Context mContext; 1298 private final Intent mIntent; 1299 private final UserHandle mUser; 1300 private final RemoteTaskClientServiceHandler mHandler; 1301 private final UserManager mUserManager; 1302 private final int mUid; 1303 private final long mTaskUnbindDelayMs; 1304 1305 private final CarUserService mCarUserService; 1306 1307 // The following three variables represent the state machine of this connection: 1308 // 1. Init state (Binding: F, Bound: F, WaitingForUserUnlock: F) 1309 // 2. Waiting for user unlock (Binding: F, Bound: F, WaitingForUserUnlock: T) 1310 // 3. Binding state (Binding: T, Bound: F, WaitingForUserUnlock: F) 1311 // 4. Bound state (Binding: F, Bound: T, WaitingForUserUnlock: F) 1312 // 1313 // 1->2 If user is currently locked 1314 // 2->3 Aftr receiving user unlock intent. 1315 // 1->3 If user is currently unlocked 1316 // 3->4 After onNullBinding callback. 1317 @GuardedBy("mServiceLock") 1318 private boolean mBound; 1319 @GuardedBy("mServiceLock") 1320 private boolean mBinding; 1321 @GuardedBy("mServiceLock") 1322 private boolean mWaitingForUserUnlock; 1323 @GuardedBy("mServiceLock") 1324 private long mTaskTimeoutMs; 1325 @GuardedBy("mServiceLock") 1326 private final Set<String> mActiveTasks = new ArraySet<>(); 1327 1328 private final UserLifecycleListener mUserLifecycleListener; 1329 RemoteTaskClientServiceConnection(Context context, RemoteTaskClientServiceHandler handler, UserManager userManager, ComponentName serviceName, UserHandle user, int uid, long taskUnbindDelayMs)1330 private RemoteTaskClientServiceConnection(Context context, 1331 RemoteTaskClientServiceHandler handler, UserManager userManager, 1332 ComponentName serviceName, UserHandle user, int uid, long taskUnbindDelayMs) { 1333 mContext = context; 1334 mHandler = handler; 1335 mUserManager = userManager; 1336 mIntent = new Intent(); 1337 mIntent.setComponent(serviceName); 1338 mUser = user; 1339 mUid = uid; 1340 mTaskUnbindDelayMs = taskUnbindDelayMs; 1341 mCarUserService = CarLocalServices.getService(CarUserService.class); 1342 mUserLifecycleListener = event -> { 1343 if (!isEventOfType(TAG, event, USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)) { 1344 return; 1345 } 1346 1347 if (event.getUserId() == mUser.getIdentifier()) { 1348 onReceiveUserUnlock(); 1349 } 1350 }; 1351 } 1352 1353 @Override onNullBinding(ComponentName name)1354 public void onNullBinding(ComponentName name) { 1355 synchronized (mServiceLock) { 1356 mBound = true; 1357 mBinding = false; 1358 } 1359 Slogf.i(TAG, "Service(%s) is bound", name.flattenToShortString()); 1360 } 1361 1362 @Override onServiceConnected(ComponentName name, IBinder service)1363 public void onServiceConnected(ComponentName name, IBinder service) { 1364 // Do nothing. 1365 } 1366 1367 @Override onServiceDisconnected(ComponentName name)1368 public void onServiceDisconnected(ComponentName name) { 1369 // Do nothing. 1370 } 1371 1372 @Override onBindingDied(ComponentName name)1373 public void onBindingDied(ComponentName name) { 1374 Slogf.w(TAG, "Service(%s) died", name.flattenToShortString()); 1375 unbindService(/* force= */ true); 1376 } 1377 onReceiveUserUnlock()1378 private void onReceiveUserUnlock() { 1379 synchronized (mServiceLock) { 1380 mWaitingForUserUnlock = false; 1381 Slogf.i(TAG, "received user unlock notification"); 1382 if (mBinding || mBound) { 1383 // bindService is called again after user is unlocked, which caused binding to 1384 // happen, so we don't need to do anything here. 1385 if (DEBUG) { 1386 Slogf.d(TAG, "a binding is already created, ignore the user unlock intent"); 1387 } 1388 return; 1389 } 1390 bindServiceLocked(); 1391 } 1392 } 1393 1394 @GuardedBy("mServiceLock") waitForUserUnlockServiceLocked()1395 private void waitForUserUnlockServiceLocked() { 1396 UserLifecycleEventFilter userUnlockEventFilter = new UserLifecycleEventFilter.Builder() 1397 .addEventType(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED).addUser(mUser).build(); 1398 mCarUserService.addUserLifecycleListener(userUnlockEventFilter, mUserLifecycleListener); 1399 mWaitingForUserUnlock = true; 1400 } 1401 1402 @GuardedBy("mServiceLock") cancelWaitForUserUnlockServiceLocked()1403 private void cancelWaitForUserUnlockServiceLocked() { 1404 mCarUserService.removeUserLifecycleListener(mUserLifecycleListener); 1405 mWaitingForUserUnlock = false; 1406 } 1407 1408 @GuardedBy("mServiceLock") bindServiceLocked()1409 private void bindServiceLocked() { 1410 Slogf.i(TAG, "Bind service %s as user %s", mIntent, mUser); 1411 boolean status = mContext.bindServiceAsUser(mIntent, /* conn= */ this, 1412 BIND_AUTO_CREATE, mUser); 1413 if (!status) { 1414 Slogf.w(TAG, "Failed to bind service %s as user %s", mIntent, mUser); 1415 mContext.unbindService(/* conn= */ this); 1416 return; 1417 } 1418 mBinding = true; 1419 } 1420 1421 @GuardedBy("mServiceLock") bindServiceIfUserUnlockedLocked()1422 private void bindServiceIfUserUnlockedLocked() { 1423 if (DEBUG) { 1424 Slogf.d(TAG, "Try to bind service %s as user %s if unlocked", mIntent, mUser); 1425 } 1426 if (mBinding) { 1427 Slogf.w(TAG, "%s binding is already ongoing, ignore the new bind request", 1428 mIntent); 1429 return; 1430 } 1431 if (mWaitingForUserUnlock) { 1432 Slogf.w(TAG, 1433 "%s binding is waiting for user unlock, ignore the new bind request", 1434 mIntent); 1435 return; 1436 } 1437 if (mBound) { 1438 Slogf.w(TAG, "%s is already bound", mIntent); 1439 return; 1440 } 1441 // Start listening for unlock event before checking so that we don't miss any 1442 // unlock intent. 1443 waitForUserUnlockServiceLocked(); 1444 if (mUserManager.isUserUnlocked(mUser)) { 1445 if (DEBUG) { 1446 Slogf.d(TAG, "User %s is unlocked, start binding", mUser); 1447 } 1448 cancelWaitForUserUnlockServiceLocked(); 1449 } else { 1450 Slogf.w(TAG, "User %s is not unlocked, waiting for it to be unlocked", mUser); 1451 return; 1452 } 1453 bindServiceLocked(); 1454 } 1455 unbindService(boolean force)1456 public boolean unbindService(boolean force) { 1457 synchronized (mServiceLock) { 1458 return unbindServiceLocked(force); 1459 } 1460 } 1461 1462 @GuardedBy("mServiceLock") unbindServiceLocked(boolean force)1463 private boolean unbindServiceLocked(boolean force) { 1464 long currentTimeMs = SystemClock.uptimeMillis(); 1465 if (!force && currentTimeMs < mTaskTimeoutMs) { 1466 Slogf.w(TAG, "Unbind request is out-dated and is ignored"); 1467 return false; 1468 } 1469 Slogf.i(TAG, "unbindServiceLocked"); 1470 mActiveTasks.clear(); 1471 mHandler.cancelServiceTimeout(mUid); 1472 if (mWaitingForUserUnlock) { 1473 cancelWaitForUserUnlockServiceLocked(); 1474 Slogf.w(TAG, "Still waiting for user unlock and bind has not started, " 1475 + "ignore unbind"); 1476 return false; 1477 } 1478 if (!mBound && !mBinding) { 1479 // If we do not have an active bounding. 1480 Slogf.w(TAG, "No active binding, ignore unbind"); 1481 return false; 1482 } 1483 mBinding = false; 1484 mBound = false; 1485 try { 1486 mContext.unbindService(/* conn= */ this); 1487 } catch (Exception e) { 1488 Slogf.e(TAG, e, "failed to unbind service"); 1489 } 1490 return true; 1491 } 1492 1493 // Bind the service if user is unlocked or waiting for user unlock. Extend the task timeout 1494 // to be taskTimeoutMs. bindServiceAndExtendTaskTimeoutMs(long taskTimeoutMs)1495 public void bindServiceAndExtendTaskTimeoutMs(long taskTimeoutMs) { 1496 Slogf.i(TAG, "Try to bind service %s as user %s if unlocked, timeout: %d", mIntent, 1497 mUser, taskTimeoutMs); 1498 synchronized (mServiceLock) { 1499 // Always bind the service to extend its lifetime. If the service is already bound, 1500 // it will do nothing. 1501 bindServiceIfUserUnlockedLocked(); 1502 if (mTaskTimeoutMs >= taskTimeoutMs) { 1503 if (DEBUG) { 1504 Slogf.d(TAG, "The service: %s new task timeout: %d ms is <= existing" 1505 + " task timeout: %d ms, ignore", mIntent, taskTimeoutMs, 1506 mTaskTimeoutMs); 1507 } 1508 return; 1509 } 1510 mTaskTimeoutMs = taskTimeoutMs; 1511 mHandler.postServiceTimeout(mUid, taskTimeoutMs); 1512 } 1513 } 1514 getActiveTaskCount()1515 public int getActiveTaskCount() { 1516 synchronized (mServiceLock) { 1517 return mActiveTasks.size(); 1518 } 1519 } 1520 addActiveTasks(ArraySet<String> tasks)1521 public void addActiveTasks(ArraySet<String> tasks) { 1522 if (DEBUG) { 1523 Slogf.d(TAG, "Add active tasks: %s for service %s", tasks, mIntent); 1524 } 1525 synchronized (mServiceLock) { 1526 for (int i = 0; i < tasks.size(); i++) { 1527 mActiveTasks.add(tasks.valueAt(i)); 1528 } 1529 } 1530 } 1531 1532 // Remove the task IDs from the active tasks list for this connection. Return false if 1533 // one of the provided task is not in the list. removeActiveTasks(ArraySet<String> tasks)1534 public boolean removeActiveTasks(ArraySet<String> tasks) { 1535 synchronized (mServiceLock) { 1536 if (DEBUG) { 1537 Slogf.d(TAG, "Remove active tasks: %s for service %s, current active tasks %s", 1538 tasks, mIntent, mActiveTasks); 1539 } 1540 for (int i = 0; i < tasks.size(); i++) { 1541 if (!mActiveTasks.contains(tasks.valueAt(i))) { 1542 return false; 1543 } 1544 mActiveTasks.remove(tasks.valueAt(i)); 1545 } 1546 if (mActiveTasks.isEmpty()) { 1547 handleAllTasksCompletionLocked(); 1548 } 1549 } 1550 return true; 1551 } 1552 removeAllActiveTasks()1553 public void removeAllActiveTasks() { 1554 synchronized (mServiceLock) { 1555 mActiveTasks.clear(); 1556 handleAllTasksCompletionLocked(); 1557 } 1558 } 1559 1560 @GuardedBy("mServiceLock") handleAllTasksCompletionLocked()1561 private void handleAllTasksCompletionLocked() { 1562 // All active tasks are completed for this package, we can now unbind the service after 1563 // mTaskUnbindDelayMs. 1564 Slogf.i(TAG, "All tasks completed for service: %s", mIntent); 1565 long currentTimeMs = SystemClock.uptimeMillis(); 1566 if (DEBUG) { 1567 Slogf.d(TAG, "Unbind remote task client service: %s after %d ms, " 1568 + "current time: %d ms", mIntent, mTaskUnbindDelayMs, 1569 currentTimeMs); 1570 } 1571 mTaskTimeoutMs = currentTimeMs + mTaskUnbindDelayMs; 1572 mHandler.postServiceTimeout(mUid, mTaskTimeoutMs); 1573 } 1574 } 1575 1576 private static final class RemoteTaskClientServiceHandler extends Handler { 1577 1578 private static final String TAG = RemoteTaskClientServiceHandler.class.getSimpleName(); 1579 private static final int MSG_SERVICE_TIMEOUT = 1; 1580 private static final int MSG_WRAP_UP_REMOTE_ACCESS_SERVICE = 2; 1581 private static final int MSG_NOTIFY_SHUTDOWN_STARTING = 3; 1582 private static final int MSG_NOTIFY_AP_STATE_CHANGE = 4; 1583 private static final int MSG_MAYBE_SHUTDOWN = 5; 1584 private static final int MSG_PENDING_TASK_TIMEOUT = 6; 1585 1586 // Lock to synchronize remove messages and add messages. 1587 private final Object mHandlerLock = new Object(); 1588 private final WeakReference<CarRemoteAccessService> mService; 1589 RemoteTaskClientServiceHandler(Looper looper, CarRemoteAccessService service)1590 private RemoteTaskClientServiceHandler(Looper looper, CarRemoteAccessService service) { 1591 super(looper); 1592 mService = new WeakReference<>(service); 1593 } 1594 1595 // Must use uid instead of uidName here because message object is compared using "==" 1596 // instead fo equals, so two same string might not "==" each other. postServiceTimeout(Integer uid, long msgTimeMs)1597 private void postServiceTimeout(Integer uid, long msgTimeMs) { 1598 synchronized (mHandlerLock) { 1599 removeMessages(MSG_SERVICE_TIMEOUT, uid); 1600 Message msg = obtainMessage(MSG_SERVICE_TIMEOUT, uid); 1601 sendMessageAtTime(msg, msgTimeMs); 1602 } 1603 } 1604 postNotifyShutdownStarting(long delayMs)1605 private void postNotifyShutdownStarting(long delayMs) { 1606 synchronized (mHandlerLock) { 1607 removeMessages(MSG_NOTIFY_SHUTDOWN_STARTING); 1608 Message msg = obtainMessage(MSG_NOTIFY_SHUTDOWN_STARTING); 1609 sendMessageDelayed(msg, delayMs); 1610 } 1611 } 1612 postWrapUpRemoteAccessService(long delayMs)1613 private void postWrapUpRemoteAccessService(long delayMs) { 1614 synchronized (mHandlerLock) { 1615 removeMessages(MSG_WRAP_UP_REMOTE_ACCESS_SERVICE); 1616 Message msg = obtainMessage(MSG_WRAP_UP_REMOTE_ACCESS_SERVICE); 1617 sendMessageDelayed(msg, delayMs); 1618 } 1619 } 1620 postNotifyApStateChange(long delayMs)1621 private void postNotifyApStateChange(long delayMs) { 1622 synchronized (mHandlerLock) { 1623 removeMessages(MSG_NOTIFY_AP_STATE_CHANGE); 1624 Message msg = obtainMessage(MSG_NOTIFY_AP_STATE_CHANGE); 1625 sendMessageDelayed(msg, delayMs); 1626 } 1627 } 1628 postMaybeShutdown(long delayMs)1629 private void postMaybeShutdown(long delayMs) { 1630 synchronized (mHandlerLock) { 1631 removeMessages(MSG_MAYBE_SHUTDOWN); 1632 Message msg = obtainMessage(MSG_MAYBE_SHUTDOWN); 1633 sendMessageDelayed(msg, delayMs); 1634 } 1635 } 1636 postPendingTaskTimeout(RemoteTask task, long msgTimeMs)1637 private void postPendingTaskTimeout(RemoteTask task, long msgTimeMs) { 1638 Message msg = obtainMessage(MSG_PENDING_TASK_TIMEOUT, task); 1639 sendMessageAtTime(msg, msgTimeMs); 1640 } 1641 cancelServiceTimeout(int uid)1642 private void cancelServiceTimeout(int uid) { 1643 removeMessages(MSG_SERVICE_TIMEOUT, uid); 1644 } 1645 cancelAllServiceTimeout()1646 private void cancelAllServiceTimeout() { 1647 removeMessages(MSG_SERVICE_TIMEOUT); 1648 } 1649 cancelNotifyShutdownStarting()1650 private void cancelNotifyShutdownStarting() { 1651 removeMessages(MSG_NOTIFY_SHUTDOWN_STARTING); 1652 } 1653 cancelWrapUpRemoteAccessService()1654 private void cancelWrapUpRemoteAccessService() { 1655 removeMessages(MSG_WRAP_UP_REMOTE_ACCESS_SERVICE); 1656 } 1657 cancelNotifyApStateChange()1658 private void cancelNotifyApStateChange() { 1659 removeMessages(MSG_NOTIFY_AP_STATE_CHANGE); 1660 } 1661 cancelMaybeShutdown()1662 private void cancelMaybeShutdown() { 1663 removeMessages(MSG_MAYBE_SHUTDOWN); 1664 } 1665 cancelPendingTaskTimeout(RemoteTask task)1666 private void cancelPendingTaskTimeout(RemoteTask task) { 1667 removeMessages(MSG_PENDING_TASK_TIMEOUT, task); 1668 } 1669 cancelAllPendingTaskTimeout()1670 private void cancelAllPendingTaskTimeout() { 1671 removeMessages(MSG_PENDING_TASK_TIMEOUT); 1672 } 1673 cancelAll()1674 private void cancelAll() { 1675 cancelAllServiceTimeout(); 1676 cancelNotifyShutdownStarting(); 1677 cancelWrapUpRemoteAccessService(); 1678 cancelNotifyApStateChange(); 1679 cancelMaybeShutdown(); 1680 cancelAllPendingTaskTimeout(); 1681 } 1682 1683 @Override handleMessage(Message msg)1684 public void handleMessage(Message msg) { 1685 CarRemoteAccessService service = mService.get(); 1686 if (service == null) { 1687 Slogf.w(TAG, "CarRemoteAccessService is not available"); 1688 return; 1689 } 1690 switch (msg.what) { 1691 case MSG_SERVICE_TIMEOUT: 1692 service.onServiceTimeout((Integer) msg.obj); 1693 break; 1694 case MSG_WRAP_UP_REMOTE_ACCESS_SERVICE: 1695 service.wrapUpRemoteAccessServiceIfNeeded(); 1696 break; 1697 case MSG_NOTIFY_SHUTDOWN_STARTING: 1698 service.notifyShutdownStarting(); 1699 break; 1700 case MSG_NOTIFY_AP_STATE_CHANGE: 1701 service.notifyApStateChange(); 1702 break; 1703 case MSG_MAYBE_SHUTDOWN: 1704 service.shutdownIfNeeded(/* force= */ false); 1705 break; 1706 case MSG_PENDING_TASK_TIMEOUT: 1707 service.onPendingTaskTimeout((RemoteTask) msg.obj); 1708 break; 1709 default: 1710 Slogf.w(TAG, "Unknown(%d) message", msg.what); 1711 } 1712 } 1713 } 1714 } 1715