• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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